Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def get_msbt_hashes(lang: str = 'USen') -> {}:
"""
Gets the MSBT hash table for the given language, or US English by default
:param lang: The game language to use, defaults to USen.
:type lang: str, optional
:returns: A dictionary of MSBT files and their vanilla hashes.
:rtype: dict of str: str
"""
if not hasattr(get_msbt_hashes, 'texthashes'):
get_msbt_hashes.texthashes = {}
if lang not in get_msbt_hashes.texthashes:
hash_table = util.get_exec_dir() / 'data' / 'msyt' / \
f'Msg_{lang}_hashes.csv'
if hash_table.exists():
get_msbt_hashes.texthashes[lang] = {}
with hash_table.open('r') as h_file:
csv_loop = csv.reader(h_file)
for row in csv_loop:
get_msbt_hashes.texthashes[lang][row[0]] = row[1]
elif util.get_game_file(f'Pack/Bootup_{lang}.pack').exists():
get_msbt_hashes.texthashes[lang] = {}
with util.get_game_file(f'Pack/Bootup_{lang}.pack').open('rb') as b_file:
bootup_pack = sarc.read_file_and_make_sarc(b_file)
msg_bytes = util.decompress(
bootup_pack.get_file_data(f'Message/Msg_{lang}.product.ssarc').tobytes())
msg_pack = sarc.SARC(msg_bytes)
for msbt in msg_pack.list_files():
get_msbt_hashes.texthashes[lang][msbt] = xxhash.xxh32(
"""
Creates a backup of the current mod installations. Saves it as a 7z file in
`CEMU_DIR/bcml_backups`.
:param name: The name to give the backup, defaults to "BCML_Backup_YYYY-MM-DD"
:type name: str, optional
"""
import re
if not name:
name = f'BCML_Backup_{datetime.datetime.now().strftime("%Y-%m-%d")}'
else:
name = re.sub(r'(?u)[^-\w.]', '', name.strip().replace(' ', '_'))
output = util.get_cemu_dir() / 'bcml_backups' / f'{name}.7z'
output.parent.mkdir(parents=True, exist_ok=True)
print(f'Saving backup {name}...')
x_args = [str(util.get_exec_dir() / 'helpers' / '7z.exe'),
'a', str(output), f'{str(util.get_modpack_dir() / "*")}']
subprocess.run(x_args, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, creationflags=util.CREATE_NO_WINDOW)
print(f'Backup "{name}" created')
def get_entry_hashes() -> dict:
"""
Gets the text entry hash table
:return: A dict containing the hashes of every text entry in every game language
:rtype: dict
"""
if not hasattr(get_entry_hashes, 'hashes'):
from json import loads
get_entry_hashes.hashes = loads(
(util.get_exec_dir() / 'data' / 'msyt' / 'lang_hashes.json').read_text(encoding='utf-8')
)
return get_entry_hashes.hashes
"""
Extracts a provided mod and returns the root path of the graphicpack inside
:param path: The path to the mod archive.
:type path: class:`pathlib.Path`
:returns: The path to the extracted root of the mod where the rules.txt file is found.
:rtype: class:`pathlib.Path`
"""
if isinstance(path, str):
path = Path(path)
tmpdir = util.get_work_dir() / f'tmp_{xxhash.xxh32(str(path)).hexdigest()}'
formats = ['.rar', '.zip', '.7z', '.bnp']
if tmpdir.exists():
shutil.rmtree(tmpdir, ignore_errors=True)
if path.suffix.lower() in formats:
x_args = [str(util.get_exec_dir() / 'helpers' / '7z.exe'),
'x', str(path), f'-o{str(tmpdir)}']
subprocess.run(x_args, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, creationflags=util.CREATE_NO_WINDOW)
else:
raise Exception('The mod provided was not a supported archive (BNP, ZIP, RAR, or 7z).')
if not tmpdir.exists():
raise Exception('No files were extracted.')
rulesdir = tmpdir
found_rules = (rulesdir / 'rules.txt').exists()
if not found_rules:
for subdir in tmpdir.rglob('*'):
if (subdir / 'rules.txt').exists():
rulesdir = subdir
found_rules = True
break
if not found_rules:
def main(debug: bool = False):
set_start_method("spawn", True)
global logger # pylint: disable=invalid-name,global-statement
logger = None
try:
if SYSTEM != "Windows":
chmod(util.get_exec_dir() / "helpers/msyt", int("755", 8))
chmod(util.get_exec_dir() / "helpers/7z", int("755", 8))
LOG.parent.mkdir(parents=True, exist_ok=True)
for folder in util.get_work_dir().glob("*"):
rmtree(folder)
except (FileNotFoundError, OSError, PermissionError):
pass
_oneclick.register_handlers()
oneclick = Thread(target=_oneclick.listen)
oneclick.daemon = True
oneclick.start()
server_port = util.get_open_port()
server = Process(target=start_server, args=(server_port,))
server.daemon = True
server.start()
host = f"http://localhost:{server_port}"
def __init__(self, *args, **kwargs):
# pylint: disable=unused-argument
super(PackageDialog, self).__init__()
self.setupUi(self)
self._options = {}
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(str(util.get_exec_dir() / 'data' / 'bcml.ico')))
self.setWindowIcon(icon)
self.btnBrowseContent.clicked.connect(self.BrowseContentClicked)
self.btnBrowseImg.clicked.connect(self.BrowseImgClicked)
self.btnAdvanced.clicked.connect(self.AdvancedClicked)
'titleIds = 00050000101C9300,00050000101C9400,00050000101C9500\n',
'name = Exported BCML Mod\n',
'path = The Legend of Zelda: Breath of the Wild/Mods/Exported BCML\n',
f'description = Exported merge of {", ".join([mod.name for mod in mods])}\n',
'version = 4\n'
])
if output.suffix == '.bnp' or output.name.endswith('.bnp.7z'):
print('Exporting BNP...')
install.create_bnp_mod(
mod=tmp_dir,
output=output,
options={'rstb':{'guess':True}}
)
else:
print('Exporting as graphic pack mod...')
x_args = [str(util.get_exec_dir() / 'helpers' / '7z.exe'),
'a', str(output), f'{str(tmp_dir / "*")}']
subprocess.run(x_args, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, creationflags=util.CREATE_NO_WINDOW)
shutil.rmtree(str(tmp_dir))
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=str(get_exec_dir() / "assets"), **kwargs)
def msbt_to_msyt(tmp_dir: Path = util.get_work_dir() / 'tmp_text'):
""" Converts MSBTs in given temp dir to MSYTs """
subprocess.run([str(util.get_exec_dir() / 'helpers' / 'msyt.exe'),
'export', '-d', str(tmp_dir)], creationflags=util.CREATE_NO_WINDOW)
fix_msbts = [msbt for msbt in tmp_dir.rglob(
'**/*.msbt') if not msbt.with_suffix('.msyt').exists()]
if fix_msbts:
print('Some MSBTs failed to convert. Trying again individually...')
pool = multiprocessing.Pool(processes=min(
multiprocessing.cpu_count(), len(fix_msbts)))
pool.map(_msyt_file, fix_msbts)
pool.close()
pool.join()
fix_msbts = [msbt for msbt in tmp_dir.rglob(
'**/*.msbt') if not msbt.with_suffix('.msyt').exists()]
if fix_msbts:
print(
f'{len(fix_msbts)} MSBT files failed to convert. They will not be merged.')
for msbt_file in tmp_dir.rglob('**/*.msbt'):
def get_msyt_hashes() -> dict:
if not hasattr(get_msyt_hashes, 'hashes'):
import json
get_msyt_hashes.hashes = json.loads(
(util.get_exec_dir() / 'data' / 'msyt' / 'msyt_hashes.json')\
.read_text(encoding='utf-8'),
encoding='utf-8'
)
return get_msyt_hashes.hashes