Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wip #1

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
489 changes: 482 additions & 7 deletions .gitignore

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[settings]
line_length=150
sections=USER_DATA,FUTURE,STDLIB,THIRDPARTY,PYQT,GID,FIRSTPARTY,LOCALFOLDER
known_pyqt=PyQt5
known_gid=gidtools,gidlogger,gidqtutils,gidviewmodels
known_user_data=gidprojectcreator.init_userdata.user_data_setup
import_heading_stdlib=* Standard Library Imports -->
import_heading_thirdparty=* Third Party Imports -->
import_heading_firstparty=* Local Imports -->
import_heading_pyqt=* PyQt5 Imports -->
import_heading_gid=* Gid Imports -->
import_heading_user_data=*USER_DATA -->
ensure_newline_before_comments=True
balanced_wrapping=True
lines_after_imports=1
length_sort=True
8 changes: 8 additions & 0 deletions .pydeps
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[pydeps]
max_bacon = 4
cluster=True
max_cluster_size=10
min_cluster_size=2
verbose = 0
pylib=False
keep_target_cluster=False
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 Giddius

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
7 changes: 7 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
graft arma_class_parser
prune arma_class_parser/logs
prune temp
prune misc
prune arma_class_parser/reports
exclude .env
exclude .db
51 changes: 1 addition & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,2 @@

<h3 align="center">ArmA Class Parser Utility</h3>

---

---

<p align="center">
<br>
</p>

## 1.1. 📝 Table of Contents

- [1.1. 📝 Table of Contents](#11-%f0%9f%93%9d-table-of-contents)
- [1.2. About <a name = "about"></a>](#12-about)
- [1.2.1. Prerequisites](#121-prerequisites)
- [1.3. Usage <a name="usage"></a>](#13-usage)
- [1.4. ✍️ Authors <a name = "authors"></a>](#14-%e2%9c%8d%ef%b8%8f-authors)
- [1.5. 🎉 Acknowledgements <a name = "acknowledgement"></a>](#15-%f0%9f%8e%89-acknowledgements)

## 1.2. About <a name = "about"></a>

Finding class attributes can be time consuming and you only have the option of searching the config.cpp directly or using the ingame console (as far as I know).
Both ways can have their drawbacks. As I didn't want to switch ingame always and because this is needed for a future Project, I wanted to be able to easily access and find all attributes I need. Currently it just lists all display names, but the goal is a GUI to handle the config easily.

### 1.2.1. Prerequisites

What things you need to install the software and how to install them.

```
Armaclass module
```

## 1.3. Usage <a name="usage"></a>

currently only by installing the Armaclass python module, exchanging the paths in the main script and running it with python. easier use is coming!

[comment]: <> ( 🚀 Deployment <a name = "deployment"></a>)

[comment]: <> ( ⛏️ Built Using <a name = "built_using"></a>)

## 1.4. ✍️ Authors <a name = "authors"></a>

- [@Giddius](https://github.com/Giddius) - Idea & Initial work

## 1.5. 🎉 Acknowledgements <a name = "acknowledgement"></a>

- A big thank you to overfl0 and his Armaclass module <https://github.com/overfl0/Armaclass>
as my programm is based on his module and mostly wraps it in a Interface for ease of use

- References
<h1 align="center">ArmA Class Parser Utility</h3>
File renamed without changes.
17 changes: 17 additions & 0 deletions arma_class_parser/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""parsing ArmA 3 config dump"""

__version__ = '0.1'

import gidlogger as glog
from dotenv import load_dotenv, find_dotenv
import os
import multiprocessing_logging

if os.path.isfile(r"D:\Dropbox\hobby\Modding\Programs\Github\My_Repos\Arma_class_parser_utility\tools\_project_devmeta.env"):
load_dotenv(r"D:\Dropbox\hobby\Modding\Programs\Github\My_Repos\Arma_class_parser_utility\tools\_project_devmeta.env")

log_file = glog.log_folderer(__name__)
log = glog.main_logger(log_file, in_level='debug', log_to='stdout')


multiprocessing_logging.install_mp_handler()
171 changes: 171 additions & 0 deletions arma_class_parser/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@


# region [Imports]

# * Standard Library Imports -->

import asyncio
import gc
import os
import re
import sys
import json
import lzma
import time
import queue
import platform
import subprocess
from enum import Enum, Flag, auto
from time import sleep
from pprint import pprint, pformat
from typing import Union
from datetime import tzinfo, datetime, timezone, timedelta
from functools import wraps, lru_cache, singledispatch, total_ordering, partial
from contextlib import contextmanager
from collections import Counter, ChainMap, deque, namedtuple, defaultdict
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import traceback
import shutil
# * Third Party Imports -->

# import requests
# import pyperclip
# import matplotlib.pyplot as plt
# from bs4 import BeautifulSoup
# from dotenv import load_dotenv
# from github import Github, GithubException
# from jinja2 import BaseLoader, Environment
# from natsort import natsorted
# from fuzzywuzzy import fuzz, process


# * PyQt5 Imports -->

# from PyQt5.QtGui import QFont, QIcon, QBrush, QColor, QCursor, QPixmap, QStandardItem, QRegExpValidator
# from PyQt5.QtCore import (Qt, QRect, QSize, QObject, QRegExp, QThread, QMetaObject, QCoreApplication,
# QFileSystemWatcher, QPropertyAnimation, QAbstractTableModel, pyqtSlot, pyqtSignal)
# from PyQt5.QtWidgets import (QMenu, QFrame, QLabel, QDialog, QLayout, QWidget, QWizard, QMenuBar, QSpinBox, QCheckBox, QComboBox,
# QGroupBox, QLineEdit, QListView, QCompleter, QStatusBar, QTableView, QTabWidget, QDockWidget, QFileDialog,
# QFormLayout, QGridLayout, QHBoxLayout, QHeaderView, QListWidget, QMainWindow, QMessageBox, QPushButton,
# QSizePolicy, QSpacerItem, QToolButton, QVBoxLayout, QWizardPage, QApplication, QButtonGroup, QRadioButton,
# QFontComboBox, QStackedWidget, QListWidgetItem, QTreeWidgetItem, QDialogButtonBox, QAbstractItemView,
# QCommandLinkButton, QAbstractScrollArea, QGraphicsOpacityEffect, QTreeWidgetItemIterator, QAction, QSystemTrayIcon)


# * Gid Imports -->

import gidlogger as glog
from gidtools.gidfiles import (QuickFile, readit, clearit, readbin, writeit, loadjson, pickleit, writebin, pathmaker, writejson,
dir_change, linereadit, get_pickled, ext_splitter, appendwriteit, create_folder, from_dict_to_file)


# * Local Imports -->
from arma_class_parser.extraction.cfg_processing import ConfigDataHolder
from arma_class_parser.extraction.subcfg_processing import SubCfgHolder

# endregion[Imports]

# region [TODO]


# endregion [TODO]

# region [AppUserData]


# endregion [AppUserData]

# region [Logging]

log = glog.aux_logger(__name__)


# endregion[Logging]

# region [Constants]
CONFIG_PATH_DICT = {
"vanilla": "D:/Dropbox/hobby/Modding/Ressources/Templates/Config_dumb/diverse_config_dumps/vanilla/ALL_config_dump_vanilla.cpp",
"rhs": "D:/Dropbox/hobby/Modding/Ressources/Templates/Config_dumb/diverse_config_dumps/RHS/ALL_config_dump_rhs_ace.cpp",
"3cb": "D:/Dropbox/hobby/Modding/Ressources/Templates/Config_dumb/diverse_config_dumps/3CB/ALL_config_dump_rhs_ace_3CB.cpp",
}


OUTPUT_FOLDER = pathmaker(r"D:\Dropbox\hobby\Modding\Programs\Github\My_Repos\Arma_class_parser_utility\temp\temp_output")
INPUT_CONFIG_FILE = CONFIG_PATH_DICT.get('vanilla')
output_path = partial(pathmaker, OUTPUT_FOLDER)
CFG_TO_PROCESS = ['CfgWeapons',
'CfgVehicles',
'CfgUnitInsignia',
'CfgRanks',
'CfgVehicleClasses',
'CfgRoles',
'CfgMagazines',
'CfgAmmo',
'CfgEditorCategories',
'CfgEditorSubcategories',
'CfgFactionClasses',
'CfgGlasses']

# endregion[Constants]


def do_subs(cfg_namepack, holder):
errored_cfg = ''
y = SubCfgHolder(cfg_namepack[0], cfg_namepack[1], holder.raw_content, holder.parsed_content[cfg_namepack[0]])

try:
y.mmake_items()
except AttributeError as error:
log.error(error)
log.critical('AttributeError error was with "%s"', cfg_namepack[0])
errored_cfg = (str(error), traceback.format_exc().splitlines())
appendwriteit('error.txt', "".join(traceback.format_exception(*sys.exc_info())) + '\n\n########\n\n')
except KeyError as error:
log.error(error)
log.critical('KeyError error was with "%s"', cfg_namepack[0])
errored_cfg = (str(error), traceback.format_exc().splitlines())
appendwriteit('error.txt', "".join(traceback.format_exception(*sys.exc_info())) + '\n\n########\n\n')
return y, errored_cfg


def main():
_error_cfg = {}
_sub_cfgs = []
x = ConfigDataHolder.checked_init(INPUT_CONFIG_FILE)
writejson(x.parsed_content, output_path('all_parsed_content.json'), sort_keys=False, indent=4)
writejson(x.cfg_names, output_path('all_cfg_names.json'), sort_keys=False, indent=4)
do_it = partial(do_subs, holder=x)
for pack in x.cfg_pairs:
if pack[0] not in x.cfg_excludes and pack[0].casefold().startswith('cfg'):
if pack[0] in CFG_TO_PROCESS:
cfg_instance, is_error = do_subs(pack, x)
if not is_error:
writejson(cfg_instance.child_parent_map, output_path(f'{cfg_instance.sub_cfg_name}_child_parent_map.json'), sort_keys=False, indent=4)
writejson([item._asdict() for item in cfg_instance.items], output_path(f'{cfg_instance.sub_cfg_name}_items.json'), sort_keys=False, indent=4)
writejson(x.parsed_content[cfg_instance.sub_cfg_name], output_path(f'{cfg_instance.sub_cfg_name}_parsed_content.json'), sort_keys=False, indent=4)
writejson(cfg_instance.item_names(), output_path(f'{cfg_instance.sub_cfg_name}_item_names.json'), sort_keys=False, indent=4)
else:
_error_cfg[cfg_instance.sub_cfg_name] = is_error
# with ThreadPoolExecutor(len(CFG_TO_PROCESS)) as pool:
# results = pool.map(do_it, [pack for pack in x.cfg_pairs if pack[0].casefold() in CFG_TO_PROCESS])
# for result_item in results:
# if result_item[1] is False:
# y = result_item[0]
# writejson(y.child_parent_map, output_path(f'{y.sub_cfg_name}_child_parent_map.json'), sort_keys=False, indent=4)
# writejson(y.items, output_path(f'{y.sub_cfg_name}_items.json'), sort_keys=False, indent=4)
# writejson(x.parsed_content[y.sub_cfg_name], output_path(f'{y.sub_cfg_name}_parsed_content.json'), sort_keys=False, indent=4)
# writejson(y.item_names(), output_path(f'{y.sub_cfg_name}_item_names.json'), sort_keys=False, indent=4)
# else:
# _error_cfg.append(result_item[0].sub_cfg_name)
writejson(_error_cfg, 'error_cfgs.json', sort_keys=False, indent=4)

# region[Main_Exec]


if __name__ == '__main__':
shutil.rmtree(r"D:\Dropbox\hobby\Modding\Programs\Github\My_Repos\Arma_class_parser_utility\temp\temp_output")
if os.path.exists(r"D:\Dropbox\hobby\Modding\Programs\Github\My_Repos\Arma_class_parser_utility\temp\temp_output") is False:
os.makedirs(r"D:\Dropbox\hobby\Modding\Programs\Github\My_Repos\Arma_class_parser_utility\temp\temp_output")
main()

# endregion[Main_Exec]
Empty file.
Loading