added doctype and type hint to all function, replaced copyfile function by shutil.copyfile

This commit is contained in:
raphael60650 2021-07-25 17:53:29 +02:00
parent a6ec86c61d
commit fc3030532b
8 changed files with 195 additions and 83 deletions

View file

@ -7,9 +7,9 @@ from .Cup import Cup
from .Track import Track from .Track import Track
def get_cup_icon(id, font_path: str = "./file/SuperMario256.ttf", cup_icon_dir: str = "./file/cup_icon"): def get_cup_icon(id, font_path: str = "./file/SuperMario256.ttf", cup_icon_dir: str = "./file/cup_icon") -> Image:
""" """
:param id: :param id: id of the cup
:param cup_icon_dir: directory to cup icon :param cup_icon_dir: directory to cup icon
:param font_path: path to the font used to generate icon :param font_path: path to the font used to generate icon
:return: cup icon :return: cup icon
@ -37,8 +37,9 @@ class CT_Config:
self.all_version = {version} self.all_version = {version}
self.gui = gui self.gui = gui
def add_ordered_cup(self, cup: Cup): def add_ordered_cup(self, cup: Cup) -> None:
""" """
add a cup to the config
:param cup: a Cup object to add as an ordered cup :param cup: a Cup object to add as an ordered cup
:return: ? :return: ?
""" """
@ -47,8 +48,9 @@ class CT_Config:
self.all_version.add(track.since_version) self.all_version.add(track.since_version)
self.all_tracks.append(track) self.all_tracks.append(track)
def add_unordered_track(self, track: Track): def add_unordered_track(self, track: Track) -> None:
""" """
add a single track to the config
:param track: a Track object to add as an unordered tracks :param track: a Track object to add as an unordered tracks
:return: ? :return: ?
""" """
@ -56,9 +58,10 @@ class CT_Config:
self.all_version.add(track.since_version) self.all_version.add(track.since_version)
self.all_tracks.append(track) self.all_tracks.append(track)
def create_ctfile(self, directory="./file/", highlight_version=None): def create_ctfile(self, directory: str = "./file/", highlight_version: str = None) -> None:
""" """
:param highlight_version: create a ctfile configuration in a directory
:param highlight_version: highlight a specific version in light blue
:param directory: create CTFILE.txt and RCTFILE.txt in this directory :param directory: create CTFILE.txt and RCTFILE.txt in this directory
:return: None :return: None
""" """
@ -94,7 +97,7 @@ class CT_Config:
ctfile.write(cup.get_ctfile_cup(race=False, highlight_version=highlight_version)) ctfile.write(cup.get_ctfile_cup(race=False, highlight_version=highlight_version))
rctfile.write(cup.get_ctfile_cup(race=True, highlight_version=highlight_version)) rctfile.write(cup.get_ctfile_cup(race=True, highlight_version=highlight_version))
def get_cticon(self): def get_cticon(self) -> Image:
""" """
get all cup icon into a single image get all cup icon into a single image
:return: ct_icon image :return: ct_icon image
@ -114,19 +117,19 @@ class CT_Config:
return ct_icon return ct_icon
def load_ctconfig_file(self, ctconfig_file: str = "./ct_config.json"): def load_ctconfig_file(self, ctconfig_file: str = "./ct_config.json") -> None:
""" """
load a ctconfig from a json file
:param ctconfig_file: path to the ctconfig file :param ctconfig_file: path to the ctconfig file
:return: ?
""" """
with open(ctconfig_file, encoding="utf-8") as f: with open(ctconfig_file, encoding="utf-8") as f:
ctconfig_json = json.load(f) ctconfig_json = json.load(f)
self.load_ctconfig_json(ctconfig_json) self.load_ctconfig_json(ctconfig_json)
def load_ctconfig_json(self, ctconfig_json: dict): def load_ctconfig_json(self, ctconfig_json: dict) -> None:
""" """
load ctconfig from a dictionnary
:param ctconfig_json: json of the ctconfig to load :param ctconfig_json: json of the ctconfig to load
:return: ?
""" """
self.ordered_cups = [] self.ordered_cups = []
self.unordered_tracks = [] self.unordered_tracks = []
@ -152,7 +155,7 @@ class CT_Config:
self.all_version.add(track.since_version) self.all_version.add(track.since_version)
self.all_version = sorted(self.all_version) self.all_version = sorted(self.all_version)
def search_tracks(self, values_list=False, not_value=False, only_unordered_track=False, **kwargs): def search_tracks(self, values_list=False, not_value=False, only_unordered_track=False, **kwargs) -> list:
""" """
:param only_unordered_track: only search in unordered track :param only_unordered_track: only search in unordered track
:param values_list: search track with a value list instead of a single value :param values_list: search track with a value list instead of a single value

View file

@ -6,20 +6,33 @@ class Cup:
track1: Track = None, track1: Track = None,
track2: Track = None, track2: Track = None,
track3: Track = None, track3: Track = None,
track4: Track = None, locked: bool = False, track4: Track = None,
locked: bool = False,
*args, **kwargs): *args, **kwargs):
"""
class of a cup
:param name: name of the cup
:param track1: first track
:param track2: second track
:param track3: third track
:param track4: fourth track
:param locked: is the track locked (used to load ctconfig in CT_Config)
:param args: other args that I could add in the future
:param kwargs: other kwargs that I could add in the future
"""
self.name = name self.name = name
self.locked = locked
self.tracks = [ self.tracks = [
track1 if track1 else Track(), track1 if track1 else Track(),
track2 if track2 else Track(), track2 if track2 else Track(),
track3 if track3 else Track(), track3 if track3 else Track(),
track4 if track4 else Track() track4 if track4 else Track()
] ]
self.locked = locked
def get_ctfile_cup(self, *args, **kwargs): def get_ctfile_cup(self, *args, **kwargs) -> str:
""" """
get the ctfile definition for the cup
:param race: is it a text used for Race_*.szs ? :param race: is it a text used for Race_*.szs ?
:return: ctfile definition for the cup :return: ctfile definition for the cup
""" """
@ -28,7 +41,11 @@ class Cup:
ctfile_cup += track.get_ctfile(*args, **kwargs) ctfile_cup += track.get_ctfile(*args, **kwargs)
return ctfile_cup return ctfile_cup
def load_from_json(self, cup: dict): def load_from_json(self, cup: dict) -> None:
"""
load the cup from a dictionnary
:param cup: dictionnary cup
"""
for key, value in cup.items(): # load all value in the json as class attribute for key, value in cup.items(): # load all value in the json as class attribute
if key != "tracks": if key != "tracks":
setattr(self, key, value) setattr(self, key, value)

View file

@ -1,4 +1,4 @@
from tkinter import messagebox, StringVar, BooleanVar, IntVar from tkinter import messagebox
from PIL import Image from PIL import Image
import shutil import shutil
import glob import glob
@ -7,6 +7,7 @@ import os
from .CT_Config import CT_Config from .CT_Config import CT_Config
from .definition import * from .definition import *
from .Gui import NoGui
from . import wszst from . import wszst
@ -40,23 +41,6 @@ class CantConvertTrack(Exception):
super().__init__("Can't convert track, check if download are enabled.") super().__init__("Can't convert track, check if download are enabled.")
class NoGui:
"""
'fake' gui if no gui are used for compatibility.
"""
def progression(self, *args, **kwargs): print(args, kwargs)
def translate(self, *args, **kwargs): return ""
def log_error(self, *args, **kwargs): print(args, kwargs)
is_dev_version = False
stringvar_game_format = StringVar()
boolvar_disable_download = BooleanVar()
intvar_process_track = IntVar()
boolvar_dont_check_track_sha1 = BooleanVar()
boolvar_del_track_after_conv = BooleanVar()
class Game: class Game:
def __init__(self, path: str = "", region_ID: str = "P", game_ID: str = "RMCP01", gui=None): def __init__(self, path: str = "", region_ID: str = "P", game_ID: str = "RMCP01", gui=None):
""" """
@ -170,7 +154,13 @@ class Game:
self.gui.progress(show=True, indeter=False, statut=self.gui.translate("Installing mod"), max=max_step, self.gui.progress(show=True, indeter=False, statut=self.gui.translate("Installing mod"), max=max_step,
step=0) step=0)
def replace_file(path, file, subpath="/"): def replace_file(path, file, subpath="/") -> None:
"""
Replace subfile in the .szs file
:param path: path to the .szs file
:param file: file to replace
:param subpath: directory between .szs file and file inside to replace
"""
self.gui.progress(statut=self.gui.translate("Editing", "\n", get_nodir(path)), add=1) self.gui.progress(statut=self.gui.translate("Editing", "\n", get_nodir(path)), add=1)
extension = get_extension(path) extension = get_extension(path)
@ -182,14 +172,14 @@ class Game:
szs_extract_path = path + ".d" szs_extract_path = path + ".d"
if os.path.exists(szs_extract_path + subpath): if os.path.exists(szs_extract_path + subpath):
if subpath[-1] == "/": if subpath[-1] == "/":
filecopy(f"./file/{file}", szs_extract_path + subpath + file) shutil.copyfile(f"./file/{file}", szs_extract_path + subpath + file)
else: else:
filecopy(f"./file/{file}", szs_extract_path + subpath) shutil.copyfile(f"./file/{file}", szs_extract_path + subpath)
elif path[-1] == "/": elif path[-1] == "/":
filecopy(f"./file/{file}", path + file) shutil.copyfile(f"./file/{file}", path + file)
else: else:
filecopy(f"./file/{file}", path) shutil.copyfile(f"./file/{file}", path)
for fp in fs: for fp in fs:
for f in glob.glob(self.path + "/files/" + fp, recursive=True): for f in glob.glob(self.path + "/files/" + fp, recursive=True):
@ -215,9 +205,9 @@ class Game:
shutil.copytree("./file/Track/", self.path + "/files/Race/Course/", dirs_exist_ok=True) shutil.copytree("./file/Track/", self.path + "/files/Race/Course/", dirs_exist_ok=True)
if not (os.path.exists(self.path + "/tmp/")): os.makedirs(self.path + "/tmp/") if not (os.path.exists(self.path + "/tmp/")): os.makedirs(self.path + "/tmp/")
filecopy("./file/CTFILE.txt", self.path + "/tmp/CTFILE.txt") shutil.copyfile("./file/CTFILE.txt", self.path + "/tmp/CTFILE.txt")
filecopy("./file/lpar-default.txt", self.path + "/tmp/lpar-default.txt") shutil.copyfile("./file/lpar-default.txt", self.path + "/tmp/lpar-default.txt")
filecopy(f"./file/lecode-{self.region}.bin", self.path + f"/tmp/lecode-{self.region}.bin") shutil.copyfile(f"./file/lecode-{self.region}.bin", self.path + f"/tmp/lecode-{self.region}.bin")
wszst.lec_patch( wszst.lec_patch(
self.path, self.path,
@ -315,7 +305,7 @@ class Game:
if not os.path.exists("./file/tmp/"): os.makedirs("./file/tmp/") if not os.path.exists("./file/tmp/"): os.makedirs("./file/tmp/")
filecopy(gamefile + ".d/message/Common.bmg", "./file/tmp/Common.bmg") shutil.copyfile(gamefile + ".d/message/Common.bmg", "./file/tmp/Common.bmg")
bmgcommon = wszst.ctc_patch_bmg(ctfile="./file/CTFILE.txt", bmgcommon = wszst.ctc_patch_bmg(ctfile="./file/CTFILE.txt",
bmgs=["./file/tmp/Common.bmg", "./file/ExtraCommon.txt"]) bmgs=["./file/tmp/Common.bmg", "./file/ExtraCommon.txt"])
rbmgcommon = wszst.ctc_patch_bmg(ctfile="./file/RCTFILE.txt", rbmgcommon = wszst.ctc_patch_bmg(ctfile="./file/RCTFILE.txt",
@ -374,11 +364,10 @@ class Game:
finally: finally:
self.gui.progress(show=False) self.gui.progress(show=False)
def patch_image(self, fc) -> None: def patch_image(self, fc: dict) -> None:
""" """
Convert .png image into the format wrote in convert_file Convert .png image into the format wrote in convert_file
:param fc: :param fc: file convert, a dictionnary indicating which format a file need to be converted
:return:
""" """
for i, file in enumerate(fc["img"]): for i, file in enumerate(fc["img"]):
self.gui.progress(statut=self.gui.translate("Converting images") + f"\n({i + 1}/{len(fc['img'])}) {file}", self.gui.progress(statut=self.gui.translate("Converting images") + f"\n({i + 1}/{len(fc['img'])}) {file}",
@ -390,7 +379,6 @@ class Game:
patch descriptive image used when the game boot patch descriptive image used when the game boot
:param img_desc_path: directory where original part of the image are stored :param img_desc_path: directory where original part of the image are stored
:param dest_dir: directory where patched image will be saved :param dest_dir: directory where patched image will be saved
:return:
""" """
il = Image.open(img_desc_path + "/illustration.png") il = Image.open(img_desc_path + "/illustration.png")
il_16_9 = il.resize((832, 456)) il_16_9 = il.resize((832, 456))

View file

@ -18,6 +18,28 @@ def restart():
exit() exit()
class NoGui:
"""
'fake' gui if no gui are used for compatibility.
"""
class NoButton:
def grid(self, *args, **kwargs): pass
def config(self, *args, **kwargs): pass
def progress(*args, **kwargs): print(args, kwargs)
def translate(*args, **kwargs): return ""
def log_error(*args, **kwargs): print(args, kwargs)
def restart(self): restart()
is_dev_version = False
button_install_mod = NoButton()
stringvar_game_format = StringVar()
boolvar_disable_download = BooleanVar()
intvar_process_track = IntVar()
boolvar_dont_check_track_sha1 = BooleanVar()
boolvar_del_track_after_conv = BooleanVar()
class Gui: class Gui:
def __init__(self): def __init__(self):
""" """

View file

@ -4,6 +4,9 @@ import os
class Option: class Option:
def __init__(self): def __init__(self):
"""
class for Option
"""
self.language = "en" self.language = "en"
self.format = "FST" self.format = "FST"
self.disable_download = False self.disable_download = False
@ -12,7 +15,14 @@ class Option:
self.dont_check_track_sha1 = False self.dont_check_track_sha1 = False
self.process_track = 8 self.process_track = 8
def edit(self, option, value, need_restart=False, gui=None): def edit(self, option: str, value: any, need_restart: bool = False, gui=None) -> None:
"""
Change the value of a parameter
:param option: the name of the option to change
:param value: the new value for the option
:param need_restart: do this value need a restart ?
:param gui: the gui object to restart
"""
if type(value) in [str, int, bool]: if type(value) in [str, int, bool]:
setattr(self, option, value) setattr(self, option, value)
else: else:
@ -20,17 +30,29 @@ class Option:
self.save_to_file() self.save_to_file()
if need_restart: gui.restart() if need_restart: gui.restart()
def load_from_file(self, option_file: str = "./option.json"): def load_from_file(self, option_file: str = "./option.json") -> None:
"""
Load all options from a json file
:param option_file: the file where to load option
"""
if os.path.exists(option_file): if os.path.exists(option_file):
with open(option_file, encoding="utf-8") as file: with open(option_file, encoding="utf-8") as file:
file_json = json.load(file) file_json = json.load(file)
self.load_from_json(file_json) self.load_from_json(file_json)
def load_from_json(self, option_json: dict): def load_from_json(self, option_json: dict) -> None:
"""
Load all options from a dictionnary
:param option_json: the dictionnary to load
"""
for key, value in option_json.items(): # load all value in the json as class attribute for key, value in option_json.items(): # load all value in the json as class attribute
setattr(self, key, value) setattr(self, key, value)
def save_to_file(self, option_file: str = "./option.json"): def save_to_file(self, option_file: str = "./option.json") -> None:
"""
Save all options to a file
:param option_file: the file where to save option
"""
option_json: dict = self.__dict__ # this return all attribute of the class as a dict option_json: dict = self.__dict__ # this return all attribute of the class as a dict
with open(option_file, "w", encoding="utf-8") as file: with open(option_file, "w", encoding="utf-8") as file:
json.dump(option_json, file, ensure_ascii=False) json.dump(option_json, file, ensure_ascii=False)

View file

@ -65,12 +65,11 @@ class Track:
if wszst.sha1(self.file_wu8) == self.sha1: return 0 if wszst.sha1(self.file_wu8) == self.sha1: return 0
else: return -1 else: return -1
def convert_wu8_to_szs(self) -> str: def convert_wu8_to_szs(self) -> None:
""" """
convert track to szs convert track to szs
:return: path to szs track
""" """
return wszst.normalize(src_file=self.file_wu8) wszst.normalize(src_file=self.file_wu8)
def download_wu8(self, github_content_root: str) -> int: def download_wu8(self, github_content_root: str) -> int:
""" """

View file

@ -95,14 +95,19 @@ region_id_to_name = {
} }
def filecopy(src, dst):
with open(src, "rb") as f1:
with open(dst, "wb") as f2:
f2.write(f1.read()) # could be buffered
def in_thread(func): def in_thread(func):
def wrapped_func(*args, **kwargs): """
instead of calling a function, this will start it in a thread
:param func: function to thread
:return: threaded function
"""
def wrapped_func(*args, **kwargs) -> Thread:
"""
function that will be returned instead of the function, will call it in a thread
:param args: args of the original function
:param kwargs: kwargs of the original function
:return: thread object to the function
"""
thread = Thread(target=func, args=args, kwargs=kwargs) thread = Thread(target=func, args=args, kwargs=kwargs)
thread.setDaemon(True) thread.setDaemon(True)
thread.start() thread.start()

View file

@ -2,9 +2,9 @@ from .definition import *
import subprocess import subprocess
def sha1(file, autoadd_path: str = "./file/auto-add/"): def sha1(file, autoadd_path: str = "./file/auto-add/") -> str:
""" """
:param autoadd_path: :param autoadd_path: directory where is autoadd directory
:param file: track file to check sha1 :param file: track file to check sha1
:return: track's sha1 :return: track's sha1
""" """
@ -14,86 +14,126 @@ def sha1(file, autoadd_path: str = "./file/auto-add/"):
def normalize(src_file: str, dest_dir: str = "./file/Track/", dest_name: str = "%N.szs", def normalize(src_file: str, dest_dir: str = "./file/Track/", dest_name: str = "%N.szs",
output_format: str = "szs", autoadd_path: str = "./file/auto-add/"): output_format: str = "szs", autoadd_path: str = "./file/auto-add/") -> None:
""" """
:param use_popen: True if you want to use Popen to convert convert a track into an another format
:param src_file: source file :param src_file: source file
:param dest_dir: destination directory :param dest_dir: destination directory
:param dest_name: destination filename (%N mean same name as src_file) :param dest_name: destination filename (%N mean same name as src_file)
:param output_format: format of the destination track :param output_format: format of the destination track
:param autoadd_path: path of the auto-add directory :param autoadd_path: path of the auto-add directory
:return: 0
""" """
subprocess.run(["./tools/szs/wszst", "NORMALIZE", src_file, "--DEST", subprocess.run(["./tools/szs/wszst", "NORMALIZE", src_file, "--DEST",
dest_dir+dest_name, "--"+output_format, "--overwrite", "--autoadd-path", dest_dir+dest_name, "--"+output_format, "--overwrite", "--autoadd-path",
autoadd_path], creationflags=CREATE_NO_WINDOW, stderr=subprocess.PIPE) autoadd_path], creationflags=CREATE_NO_WINDOW, stderr=subprocess.PIPE)
def wit_extract(file: str, dest_dir: str): def wit_extract(file: str, dest_dir: str) -> None:
""" """
extract the game into a directory
:param file: game's file to extract (can be WBFS, ISO, CISO) :param file: game's file to extract (can be WBFS, ISO, CISO)
:param dest_dir: where to extract the game :param dest_dir: where to extract the game
:return: ?
""" """
subprocess.run(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir], subprocess.run(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file)) creationflags=CREATE_NO_WINDOW, cwd=get_dir(file))
def create(file: str): def create(file: str) -> None:
""" """
convert a directory into a szs file
:param file: create a .szs file from the directory {file}.d :param file: create a .szs file from the directory {file}.d
:return:
""" """
subprocess.run(["./tools/szs/wszst", "CREATE", get_nodir(file) + ".d", "-d", get_nodir(file), subprocess.run(["./tools/szs/wszst", "CREATE", get_nodir(file) + ".d", "-d", get_nodir(file),
"--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(file), "--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(file),
check=True, stdout=subprocess.PIPE) check=True, stdout=subprocess.PIPE)
def str_patch(file: str): def str_patch(path: str) -> None:
subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(file) + "/sys/main.dol", "--clean-dol", """
"--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(file), Patch the main.dol file
:param path: path to the game
"""
subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(path) + "/sys/main.dol", "--clean-dol",
"--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(path),
check=True, stdout=subprocess.PIPE) check=True, stdout=subprocess.PIPE)
def lec_patch(file: str, def lec_patch(path: str,
lecode_file: str = f"./tmp/lecode-PAL.bin", lecode_file: str = f"./tmp/lecode-PAL.bin",
dest_lecode_file: str = f"./files/rel/lecode-PAL.bin", dest_lecode_file: str = f"./files/rel/lecode-PAL.bin",
game_track_path: str = "./files/Race/Course/", game_track_path: str = "./files/Race/Course/",
move_track_path: str = "./files/Race/Course/", move_track_path: str = "./files/Race/Course/",
ctfile_path: str = "./tmp/CTFILE.txt", ctfile_path: str = "./tmp/CTFILE.txt",
lpar_path: str = "./tmp/lpar-default.txt"): lpar_path: str = "./tmp/lpar-default.txt") -> None:
"""
Patch the file with a lecode file (this is the adding track part)
:param path: path to the game file
:param lecode_file: path to the lecode file
:param dest_lecode_file: destination of the lecode file
:param game_track_path: subpath to the track directory
:param move_track_path: where are stored the track to move
:param ctfile_path: where is the ctfile (track and cup definition)
:param lpar_path: where is the lpar_path (game modification like speed, speedometer, ...)
"""
subprocess.run( subprocess.run(
["./tools/szs/wlect", "patch", lecode_file, "-od", ["./tools/szs/wlect", "patch", lecode_file, "-od",
dest_lecode_file, "--track-dir", game_track_path, dest_lecode_file, "--track-dir", game_track_path,
"--move-tracks", move_track_path, "--le-define", ctfile_path, "--lpar", "--move-tracks", move_track_path, "--le-define", ctfile_path, "--lpar",
lpar_path, "--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=file, check=True, stdout=subprocess.PIPE) lpar_path, "--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=path, check=True, stdout=subprocess.PIPE)
def edit(file, region_ID: str = "P", name: str = "Mario Kart Wii"): def edit(file: str, region_ID: str = "P", name: str = "Mario Kart Wii") -> None:
"""
Edit game property like region or name
:param file: game's file
:param region_ID: new region_ID
:param name: new name
"""
subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(file), "--id", subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(file), "--id",
f"RMC{region_ID}60", "--name", name, "--modify", "ALL"], f"RMC{region_ID}60", "--name", name, "--modify", "ALL"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file), creationflags=CREATE_NO_WINDOW, cwd=get_dir(file),
check=True, stdout=subprocess.PIPE) check=True, stdout=subprocess.PIPE)
def autoadd(file: str, dest_dir: str): def autoadd(file: str, dest_dir: str) -> None:
"""
Create an auto_add directory from a game file
:param file: the game's path
:param dest_dir: directory where to store autoadd file
"""
subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(file) + "/files/Race/Course/", "--DEST", dest_dir], subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(file) + "/files/Race/Course/", "--DEST", dest_dir],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file), creationflags=CREATE_NO_WINDOW, cwd=get_dir(file),
check=True, stdout=subprocess.PIPE) check=True, stdout=subprocess.PIPE)
def bmg_encode(file: str): def bmg_encode(file: str) -> None:
"""
Encode a txt file into a bmg file
:param file: txt file to convert
"""
subprocess.run(["./tools/szs/wbmgt", "ENCODE", get_nodir(file), "--overwrite"], subprocess.run(["./tools/szs/wbmgt", "ENCODE", get_nodir(file), "--overwrite"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file)) creationflags=CREATE_NO_WINDOW, cwd=get_dir(file))
def bmg_cat(path: str, subfile: str = ".d/message/Common.bmg"): def bmg_cat(path: str, subfile: str = ".d/message/Common.bmg") -> str:
"""
read a bmg file
:param path: path to a szs file
:param subfile: path to a subdirectory
:return: bmg definition
"""
return subprocess.run(["./tools/szs/wbmgt", "CAT", get_nodir(path) + subfile], return subprocess.run(["./tools/szs/wbmgt", "CAT", get_nodir(path) + subfile],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(path), creationflags=CREATE_NO_WINDOW, cwd=get_dir(path),
check=True, stdout=subprocess.PIPE).stdout.decode() check=True, stdout=subprocess.PIPE).stdout.decode()
def wit_copy(src_path, dst_path, format: str = "ISO"): def wit_copy(src_path, dst_path, format: str = "ISO") -> None:
"""
Copy the game into an another format
:param src_path: original game path
:param dst_path: new game path
:param format: format for the new game
"""
subprocess.run(["./tools/wit/wit", "COPY", get_nodir(src_path), "--DEST", subprocess.run(["./tools/wit/wit", "COPY", get_nodir(src_path), "--DEST",
get_nodir(dst_path), f"--{format.lower()}", "--overwrite"], get_nodir(dst_path), f"--{format.lower()}", "--overwrite"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(dst_path), creationflags=CREATE_NO_WINDOW, cwd=get_dir(dst_path),
@ -101,6 +141,12 @@ def wit_copy(src_path, dst_path, format: str = "ISO"):
def ctc_patch_bmg(bmgs: list, ctfile: str = "./file/CTFILE.txt"): def ctc_patch_bmg(bmgs: list, ctfile: str = "./file/CTFILE.txt"):
"""
Patch a bmg file with a ctfile with OVERWRITE option
:param bmgs: all bmg files
:param ctfile: the ctfile path
:return: combined bmg
"""
bmg_cmd = [] bmg_cmd = []
for bmg in bmgs: bmg_cmd.extend(["--patch-bmg", f"OVERWRITE={bmg}"]) for bmg in bmgs: bmg_cmd.extend(["--patch-bmg", f"OVERWRITE={bmg}"])
return subprocess.run( return subprocess.run(
@ -108,11 +154,21 @@ def ctc_patch_bmg(bmgs: list, ctfile: str = "./file/CTFILE.txt"):
creationflags=CREATE_NO_WINDOW, check=True, stdout=subprocess.PIPE).stdout.decode() creationflags=CREATE_NO_WINDOW, check=True, stdout=subprocess.PIPE).stdout.decode()
def img_encode(src_file, format): def img_encode(src_file: str, format: str) -> None:
"""
Encode an .png image into a new format
:param src_file: .png image
:param format: new image format
"""
subprocess.run(["./tools/szs/wimgt", "ENCODE", src_file, "-x", format, "--overwrite"], subprocess.run(["./tools/szs/wimgt", "ENCODE", src_file, "-x", format, "--overwrite"],
creationflags=CREATE_NO_WINDOW, check=True, stdout=subprocess.PIPE) creationflags=CREATE_NO_WINDOW, check=True, stdout=subprocess.PIPE)
def szs_extract(file, dest_dir): def szs_extract(file: str, dest_dir: str) -> None:
"""
Extract an szs in a directory
:param file: .szs file
:param dest_dir: directory where to extract the file
"""
subprocess.run(["./tools/szs/wszst", "EXTRACT", get_nodir(file), "--DEST", dest_dir+".d"], subprocess.run(["./tools/szs/wszst", "EXTRACT", get_nodir(file), "--DEST", dest_dir+".d"],
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file)) creationflags=CREATE_NO_WINDOW, cwd=get_dir(file))