From 57efdf2da3ac407815bf307b7e01d5a41002b831 Mon Sep 17 00:00:00 2001 From: raphael60650 Date: Sat, 17 Jul 2021 19:30:51 +0200 Subject: [PATCH] edited source to use CT_Config, Game, Cup and Track --- main.pyw | 8 +-- source/CT_Config.py | 27 ++++++---- source/Cup.py | 13 +---- source/Game.py | 41 +++++++++++---- source/Progress.py | 9 ++-- source/Track.py | 12 +++-- source/__init__.py | 72 ++++++------------------- source/check_update.py | 3 -- source/create_lecode_config.py | 80 ---------------------------- source/definition.py | 30 +++-------- source/get_github_file.py | 9 +--- source/install_mod.py | 45 ++++++++-------- source/option.py | 3 ++ source/patch_bmg.py | 2 +- source/patch_ct_icon.py | 49 ----------------- source/patch_file.py | 13 +++-- source/patch_track.py | 96 ++++++++-------------------------- source/translate.py | 2 +- source/wszst.py | 29 ++++++++-- translation.json | 1 + 20 files changed, 169 insertions(+), 375 deletions(-) delete mode 100644 source/create_lecode_config.py delete mode 100644 source/patch_ct_icon.py diff --git a/main.pyw b/main.pyw index 39f49a7..5b6bfbd 100644 --- a/main.pyw +++ b/main.pyw @@ -20,18 +20,18 @@ class ClassApp(): from source.Progress import Progress from source.check_update import check_update from source.StateButton import StateButton - from source.create_lecode_config import create_lecode_config from source.patch_file import patch_file from source.patch_bmg import patch_bmg from source.install_mod import install_mod from source.restart import restart from source.patch_img_desc import patch_img_desc - from source.patch_ct_icon import patch_ct_icon from source.log_error import log_error - from source.get_github_file import get_github_file, check_track_sha1 - from source.patch_track import load_ct_config, patch_track, patch_autoadd, get_trackctname, get_trackname + from source.get_github_file import get_github_file + from source.patch_track import patch_track, patch_autoadd from source.patch_image import patch_image from source.option import load_option, change_option + from source.CT_Config import CT_Config + from source.Game import Game, InvalidGamePath, InvalidFormat App = ClassApp() diff --git a/source/CT_Config.py b/source/CT_Config.py index f1731a4..85d00f1 100644 --- a/source/CT_Config.py +++ b/source/CT_Config.py @@ -1,30 +1,37 @@ from .Cup import * import math from PIL import Image, ImageFont, ImageDraw +import json import os -def get_cup_icon(i): - if os.path.exists(f"./file/cup_icon/{i}.png"): - cup_icon = Image.open(f"./file/cup_icon/{i}.png").resize((128, 128)) +def get_cup_icon(cup_id, font_path: str = "./file/SuperMario256.ttf", cup_icon_dir: str = "./file/cup_icon"): + """ + :param cup_icon_dir: directory to cup icon + :param font_path: path to the font used to generate icon + :param cup_id: id of the cup + :return: cup icon + """ + if os.path.exists(f"{cup_icon_dir}/{cup_id}.png"): + cup_icon = Image.open(f"{cup_icon_dir}/{cup_id}.png").resize((128, 128)) else: cup_icon = Image.new("RGBA", (128, 128)) draw = ImageDraw.Draw(cup_icon) - font = ImageFont.truetype("./file/SuperMario256.ttf", 90) + font = ImageFont.truetype(font_path, 90) draw.text((4 - 2, 4 - 2), "CT", (0, 0, 0), font=font) draw.text((4 + 2, 4 - 2), "CT", (0, 0, 0), font=font) draw.text((4 - 2, 4 + 2), "CT", (0, 0, 0), font=font) draw.text((4 + 2, 4 + 2), "CT", (0, 0, 0), font=font) draw.text((4, 4), "CT", (255, 165, 0), font=font) - font = ImageFont.truetype("./file/SuperMario256.ttf", 60) - draw.text((5 - 2, 80 - 2), "%03i" % i, (0, 0, 0), font=font) - draw.text((5 + 2, 80 - 2), "%03i" % i, (0, 0, 0), font=font) - draw.text((5 - 2, 80 + 2), "%03i" % i, (0, 0, 0), font=font) - draw.text((5 + 2, 80 + 2), "%03i" % i, (0, 0, 0), font=font) + font = ImageFont.truetype(font_path, 60) + draw.text((5 - 2, 80 - 2), "%03i" % cup_id, (0, 0, 0), font=font) + draw.text((5 + 2, 80 - 2), "%03i" % cup_id, (0, 0, 0), font=font) + draw.text((5 - 2, 80 + 2), "%03i" % cup_id, (0, 0, 0), font=font) + draw.text((5 + 2, 80 + 2), "%03i" % cup_id, (0, 0, 0), font=font) - draw.text((5, 80), "%03i" % i, (255, 165, 0), font=font) + draw.text((5, 80), "%03i" % cup_id, (255, 165, 0), font=font) return cup_icon diff --git a/source/Cup.py b/source/Cup.py index bf51994..79b2716 100644 --- a/source/Cup.py +++ b/source/Cup.py @@ -1,6 +1,4 @@ from .Track import * -from PIL import Image -from .patch_ct_icon import get_cup_icon class Cup: @@ -8,8 +6,7 @@ class Cup: track1: Track = None, track2: Track = None, track3: Track = None, - track4: Track = None, - icon: Image = None, locked: bool = False, + track4: Track = None, locked: bool = False, *args, **kwargs): self.name = name @@ -19,7 +16,6 @@ class Cup: track3 if track3 else Track(), track4 if track4 else Track() ] - self.icon = icon self.locked = locked def load_from_json(self, cup: dict): @@ -38,10 +34,3 @@ class Cup: for track in self.tracks: ctfile_cup += track.get_ctfile_track(race) return ctfile_cup - - def get_icon(self, id: int): - """ - :param id: cup number - :return: icon of the cup - """ - return self.icon if self.icon else get_cup_icon(id) diff --git a/source/Game.py b/source/Game.py index 187c0ff..a852a95 100644 --- a/source/Game.py +++ b/source/Game.py @@ -3,33 +3,52 @@ from .definition import * import glob import os +region_id_to_name = { + "J": "JAP", + "P": "PAL", + "K": "KO", + "E": "USA" +} + +class InvalidGamePath(Exception): + def __init__(self): + super().__init__("This path is not valid !") + + +class InvalidFormat(Exception): + def __init__(self): + super().__init__("This game format is not supported !") + class Game: - def __init__(self, path: str, region: str = "PAL", game_ID: str = "RMCP01"): - self.extension = get_extension(path) + def __init__(self, path: str, region_ID: str = "P", game_ID: str = "RMCP01"): + if not os.path.exists(path): raise InvalidGamePath() + self.extension = get_extension(path).upper() self.path = path - self.region_ID = region_ID[region] - self.region = region + self.region = region_id_to_name[region_ID] + self.region_ID = region_ID self.game_ID = game_ID def extract_game(self): - if self.extension.upper() == "DOL": + if self.extension == "DOL": self.path = os.path.realpath(self.path + "/../../") # main.dol is in PATH/sys/, so go back 2 dir upper - elif self.extension.upper() in ["ISO", "WBFS", "CSIO"]: + elif self.extension in ["ISO", "WBFS", "CSIO"]: # Fiding a directory name that doesn't already exist directory_name, i = "MKWiiFaraphel", 1 while True: - self.path = os.path.realpath(self.path + f"/../{directory_name}") - if not (os.path.exists(self.path)): break + path_dir = os.path.realpath(self.path + f"/../{directory_name}") + if not (os.path.exists(path_dir)): break directory_name, i = f"MKWiiFaraphel ({i})", i + 1 - wszst.extract(self.path, self.path) + wszst.extract(self.path, path_dir) + + self.path = path_dir if os.path.exists(self.path + "/DATA"): self.path += "/DATA" self.extension = "DOL" else: - raise Exception("This format is not supported !") + raise InvalidFormat() if glob.glob(self.path + "/files/rel/lecode-???.bin"): # if a LECODE file is already here raise Warning("ROM Already patched") # warning already patched @@ -39,7 +58,7 @@ class Game: self.game_ID = setup[:setup.find("\n")] self.region_ID = self.game_ID[3] - self.region = region_ID[self.region_ID] if self.region_ID in region_ID else self.region + self.region = region_id_to_name[self.region_ID] if self.region_ID in region_id_to_name else self.region def install_mod(self): pass diff --git a/source/Progress.py b/source/Progress.py index 5573acc..9552819 100644 --- a/source/Progress.py +++ b/source/Progress.py @@ -1,16 +1,15 @@ def Progress(self, show=None, indeter=None, step=None, statut=None, max=None, add=None): - if indeter == True: + if indeter is True: self.progressbar.config(mode="indeterminate") self.progressbar.start(50) - elif indeter == False: + elif indeter is False: self.progressbar.config(mode="determinate") self.progressbar.stop() - if show == True: + if show is True: self.StateButton(enable=False) self.progressbar.grid(row=100, column=1, sticky="NEWS") self.progresslabel.grid(row=101, column=1, sticky="NEWS") - - elif show == False: + elif show is False: self.StateButton(enable=True) self.progressbar.grid_forget() self.progresslabel.grid_forget() diff --git a/source/Track.py b/source/Track.py index 72b4399..4503c14 100644 --- a/source/Track.py +++ b/source/Track.py @@ -19,11 +19,11 @@ class Track: self.score = score # Track score between 1 and 3 stars self.warning = warning # Track bug level (1 = minor, 2 = major) self.note = note # Note about the track - self.file_wu8 = file_wu8 - self.file_szs = file_szs + self.file_wu8 = f"./file/Track-WU8/{self.get_track_name()}.wu8" + self.file_szs = f"./file/Track/{self.get_track_name()}.szs" def __repr__(self): - return f"{self.get_track_name()} sha1={self.sha1}" + return f"{self.get_track_name()} sha1={self.sha1} score={self.score}" def get_track_name(self): prefix = self.prefix + " " if self.prefix else "" @@ -61,11 +61,11 @@ class Track: suffix = "(" + trackname_color[self.suffix] + ")" name = (star_text + prefix + hl_prefix + self.name + hl_suffix + suffix) - name = name.replace("_", "") + name = name.replace("_", " ") return name def convert_wu8_to_szs(self): - source.wszst.normalize(src_file=self.file_wu8) + return source.wszst.normalize(src_file=self.file_wu8, use_popen=True) def download_wu8(self): pass @@ -96,3 +96,5 @@ class Track: ) return ctfile_text + +# TODO: code download_wu8 \ No newline at end of file diff --git a/source/__init__.py b/source/__init__.py index 1092a56..5dc7a50 100644 --- a/source/__init__.py +++ b/source/__init__.py @@ -8,14 +8,16 @@ import os from .definition import * from .check_update import check_update from .translate import translate +from .CT_Config import * +from .Game import * def __init__(self): try: - self.root = Tk() self.load_option() - self.load_ct_config() + self.ctconfig = CT_Config() + self.ctconfig.load_ctconfig_file("./ct_config.json") self.stringvar_language = StringVar(value=self.option["language"]) self.stringvar_game_format = StringVar(value=self.option["format"]) @@ -61,7 +63,7 @@ def __init__(self): self.menu_marktrackversion = Menu(self.menu_trackselection, tearoff=0) self.menu_trackselection.add_cascade(label=self.translate("Mark all tracks from version"), menu=self.menu_marktrackversion) self.menu_marktrackversion.add_radiobutton(label=self.translate("None"), variable=self.stringvar_mark_track_from_version, value="None") - for version in self.ALL_VERSION: + for version in self.ctconfig.all_version: self.menu_marktrackversion.add_radiobutton(label=f"v{version}", variable=self.stringvar_mark_track_from_version, value=version) self.menu_advanced = Menu(self.menu_bar, tearoff=0) @@ -103,62 +105,18 @@ def __init__(self): def use_path(): def func(): + self.frame_action.grid_forget() try: - self.frame_action.grid_forget() - path = entry_game_path.get() - if not (os.path.exists(path)): - messagebox.showerror(self.translate("Error"), self.translate("The file path in invalid")) - return - - extension = get_extension(path) - if extension.upper() == "DOL": - if messagebox.askyesno(self.translate("Warning"), - self.translate("This directory will be overwritten if you install the " - "mod !\n Are you sure you want to use it ?")): - self.path_mkwf = os.path.realpath(path + "/../../") - else: return - elif extension.upper() in ["ISO", "WBFS", "CSIO"]: - # Fiding a directory name that dosen't already exist - directory_name, i = "MKWiiFaraphel", 1 - while True: - self.path_mkwf = os.path.realpath(path + f"/../{directory_name}") - if not(os.path.exists(self.path_mkwf)): break - directory_name, i = f"MKWiiFaraphel ({i})", i + 1 - - self.Progress(show=True, indeter=True, statut=self.translate("Extracting the game...")) - subprocess.call(["./tools/wit/wit", "EXTRACT", get_nodir(path), "--DEST", directory_name] - , creationflags=CREATE_NO_WINDOW, cwd=get_dir(path)) - - if os.path.exists(self.path_mkwf + "/DATA"): self.path_mkwf += "/DATA" - - self.Progress(show=False) - - else: - messagebox.showerror(self.translate("Error"), self.translate("This file type is not supported")) - self.Progress(show=False) - return - - if glob.glob(self.path_mkwf + "/files/rel/lecode-???.bin"): # if a LECODE file is already here - messagebox.showwarning(self.translate("Warning"), - self.translate("This game is already modded, it is not recommended to " - "use it to install the mod")) - - try: - with open(self.path_mkwf + "/setup.txt") as f: setup = f.read() - setup = setup[setup.find("!part-id = ")+len("!part-id = "):] - self.original_game_ID = setup[:setup.find("\n")] - except: - messagebox.showwarning(self.translate("Warning"), - self.transate("Can't find game region.\nPAL region will be used.")) - self.original_game_ID = "RMCP01" - try: - self.original_region_ID = self.original_game_ID[3] - self.original_region = region_ID[self.original_region_ID] - except: self.original_region = "PAL" - + self.game = Game(path = entry_game_path.get()) + self.Progress(show=True, indeter=True, statut=self.translate("Extracting the game...")) + self.game.extract_game() self.frame_action.grid(row=3, column=1, sticky="NEWS") - - except: self.log_error() + except InvalidGamePath: + messagebox.showerror(self.translate("Error"), self.translate("The file path in invalid")) + except InvalidFormat: + messagebox.showerror(self.translate("Error"), self.translate("This game's format is invalid")) + except: + self.log_error() finally: self.Progress(show=False) diff --git a/source/check_update.py b/source/check_update.py index 6906136..c407020 100644 --- a/source/check_update.py +++ b/source/check_update.py @@ -2,7 +2,6 @@ from tkinter import messagebox import requests import zipfile import json -import sys import os from .definition import * @@ -38,12 +37,10 @@ def check_update(self): os.remove("./download.zip") print(self.translate("starting application...")) os.startfile(os.path.realpath("./Updater/Updater.exe")) - sys.exit() except requests.ConnectionError: messagebox.showwarning(self.translate("Warning"), self.translate("Can't connect to internet. Download will be disabled.")) self.option["disable_download"] = True - except SystemExit: pass except: self.log_error() diff --git a/source/create_lecode_config.py b/source/create_lecode_config.py deleted file mode 100644 index 290edb6..0000000 --- a/source/create_lecode_config.py +++ /dev/null @@ -1,80 +0,0 @@ -import json -from .definition import * - - -def create_lecode_config(self): - try: - def get_star_text(track): - - if "score" in track: - if 0 < track["score"] <= 3: - star_text = "★" * track["score"] + "☆" * (3 - track["score"]) - return trackname_color[star_text] + " " - return "" - - def get_ctfile_text(track, race=False): - if race: - return (f' T {track["music"]}; ' - f'{track["special"]}; ' - f'{"0x01" if track["new"] else "0x00"}; ' - f'"-"; ' - f'"{get_star_text(track)}{self.get_trackctname(track=track, color=True)}\\n{track["author"]}"; ' - f'"-"\n') - else: - return (f' T {track["music"]}; ' - f'{track["special"]}; ' - f'{"0x01" if track["new"] else "0x00"}; ' - f'"{self.get_trackctname(track=track)}"; ' - f'"{get_star_text(track)}{self.get_trackctname(track=track, color=True)}"; ' - f'"-"\n') - - with open("./ct_config.json", encoding="utf-8") as f: - ctconfig = json.load(f) - - with open("./file/CTFILE.txt", "w", encoding="utf-8") as ctfile, \ - open("./file/RCTFILE.txt", "w", encoding="utf-8") as rctfile: - - header = ("#CT-CODE\n" - "[RACING-TRACK-LIST]\n" - "%LE-FLAGS=1\n" - "%WIIMM-CUP=1\n" - "N N$SWAP | N$F_WII\n\n") - ctfile.write(header) - rctfile.write(header) - - for cup in ctconfig["cup"]: # defined cup section - _cup_config = ctconfig["cup"][cup] - if int(cup) >= 9: # Track that are not original and not random selection - cup = f'\nC "{_cup_config["name"]}"\n' - ctfile.write(cup) - rctfile.write(cup) - - for course in _cup_config["courses"]: - _course_config = _cup_config["courses"][course] - ctfile.write(get_ctfile_text(_course_config, race=False)) - rctfile.write(get_ctfile_text(_course_config, race=True)) - - tracks_list = ctconfig["tracks_list"] - if not self.boolvar_use_1star_track.get(): # if 1 star track are disabled, remove them - tracks_list = list(filter(lambda track: track.get("score") != 1, tracks_list)) - if not self.boolvar_use_2star_track.get(): # if 2 stars track are disabled, remove them - tracks_list = list(filter(lambda track: track.get("score") != 2, tracks_list)) - if not self.boolvar_use_3star_track.get(): # if 3 stars track are disabled, remove them - tracks_list = list(filter(lambda track: track.get("score") != 3, tracks_list)) - # using dict.get allow track that with no "score" attribute to not raise an exception by returning None - - for i, _course_config in enumerate(tracks_list): # undefined cup section - if i % 4 == 0: - cup = f'\nC "TL{i//4}"\n' - ctfile.write(cup) - rctfile.write(cup) - - ctfile.write(get_ctfile_text(_course_config, race=False)) - rctfile.write(get_ctfile_text(_course_config, race=True)) - - for _ in range(1, 4-(i%4)): # Complete cup if track are missing - ctfile.write(EMPTY_TRACK) - rctfile.write(EMPTY_TRACK) - - except: - self.log_error() diff --git a/source/definition.py b/source/definition.py index c93c8ff..b749f22 100644 --- a/source/definition.py +++ b/source/definition.py @@ -1,5 +1,3 @@ -import json - CREATE_NO_WINDOW = 0x08000000 GITHUB_REPOSITORY = "Faraphel/MKWF-Install" GITHUB_CONTENT_ROOT = f"https://raw.githubusercontent.com/{GITHUB_REPOSITORY}/master/" @@ -9,31 +7,19 @@ get_filename = lambda file: ".".join(file.split(".")[:-1]) get_nodir = lambda file: file.replace("\\", "/").split("/")[-1] get_dir = lambda file: "/".join(file.replace("\\", "/").split("/")[:-1]) get_extension = lambda file: file.split(".")[-1] -get_track_wu8 = lambda track: f"./file/Track-WU8/{track}.wu8" -get_track_szs = lambda track: f"./file/Track/{track}.szs" - -region_ID = { - "J": "JAP", - "P": "PAL", - "K": "KO", - "E": "USA" -} EMPTY_TRACK = ' T T44; T44; 0x00; "_"; ""; "-"\n' -with open("./translation.json", encoding="utf-8") as f: - translation_dict = json.load(f) - bmgID_track_move = { - "T11": 0x7008, "T12": 0x7001, "T13": 0x7002, "T14": 0x7004, - "T21": 0x7000, "T22": 0x7005, "T23": 0x7006, "T24": 0x7007, - "T31": 0x7009, "T32": 0x700f, "T33": 0x700b, "T34": 0x7003, - "T41": 0x700e, "T42": 0x700a, "T43": 0x700c, "T44": 0x700d, + "T11": 0x7008, "T12": 0x7001, "T13": 0x7002, "T14": 0x7004, + "T21": 0x7000, "T22": 0x7005, "T23": 0x7006, "T24": 0x7007, + "T31": 0x7009, "T32": 0x700f, "T33": 0x700b, "T34": 0x7003, + "T41": 0x700e, "T42": 0x700a, "T43": 0x700c, "T44": 0x700d, - "T51": 0x7010, "T52": 0x7014, "T53": 0x7019, "T54": 0x701a, - "T61": 0x701b, "T62": 0x701f, "T63": 0x7017, "T64": 0x7012, - "T71": 0x7015, "T72": 0x701e, "T73": 0x701d, "T74": 0x7011, - "T81": 0x7018, "T82": 0x7016, "T83": 0x7013, "T84": 0x701c, + "T51": 0x7010, "T52": 0x7014, "T53": 0x7019, "T54": 0x701a, + "T61": 0x701b, "T62": 0x701f, "T63": 0x7017, "T64": 0x7012, + "T71": 0x7015, "T72": 0x701e, "T73": 0x701d, "T74": 0x7011, + "T81": 0x7018, "T82": 0x7016, "T83": 0x7013, "T84": 0x701c, } trackname_color = { "MSRDS": "\\\\c{green}MSRDS\\\\c{off}", diff --git a/source/get_github_file.py b/source/get_github_file.py index 808029a..02361e7 100644 --- a/source/get_github_file.py +++ b/source/get_github_file.py @@ -1,5 +1,4 @@ import requests -import subprocess import os from .definition import * @@ -29,10 +28,4 @@ def get_github_file(self, file): self.log_error() return -1 - -def check_track_sha1(self, file, excepted_sha1): - sha1 = subprocess.run(["./tools/szs/wszst", "SHA1", file, "--autoadd-path", "./file/auto-add/"], - check=True, creationflags=CREATE_NO_WINDOW, - stdout=subprocess.PIPE).stdout.decode().split(" ")[0] - if excepted_sha1 == sha1: return 0 - else: return -1 +# TODO: if version > github version, do not search in master branch but dev branch diff --git a/source/install_mod.py b/source/install_mod.py index ffb1704..aedae4c 100644 --- a/source/install_mod.py +++ b/source/install_mod.py @@ -28,7 +28,7 @@ def install_mod(self): max_step += 1 for fp in fs: - for f in glob.glob(self.path_mkwf + "/files/" + fp, recursive=True): + for f in glob.glob(self.game.path + "/files/" + fp, recursive=True): if type(fs[fp]) == str: count_rf(path=f) elif type(fs[fp]) == dict: @@ -66,7 +66,7 @@ def install_mod(self): filecopy(f"./file/{file}", path) for fp in fs: - for f in glob.glob(self.path_mkwf + "/files/" + fp, recursive=True): + for f in glob.glob(self.game.path + "/files/" + fp, recursive=True): if type(fs[fp]) == str: replace_file(path=f, file=fs[fp]) elif type(fs[fp]) == dict: @@ -84,43 +84,44 @@ def install_mod(self): if os.path.exists(file + ".d"): shutil.rmtree(file + ".d") self.Progress(statut=self.translate("Patch main.dol"), add=1) - subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(self.path_mkwf) + "/sys/main.dol", "--clean-dol", - "--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf), + subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(self.game.path) + "/sys/main.dol", "--clean-dol", + "--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path), check=True, stdout=subprocess.PIPE) self.Progress(statut=self.translate("Patch lecode.bin"), add=1) - shutil.copytree("./file/Track/", self.path_mkwf+"/files/Race/Course/", dirs_exist_ok=True) - if not(os.path.exists(self.path_mkwf+"/tmp/")): os.makedirs(self.path_mkwf+"/tmp/") - filecopy("./file/CTFILE.txt", self.path_mkwf+"/tmp/CTFILE.txt") - filecopy("./file/lpar-default.txt", self.path_mkwf + "/tmp/lpar-default.txt") - filecopy(f"./file/lecode-{self.original_region}.bin", self.path_mkwf + f"/tmp/lecode-{self.original_region}.bin") + shutil.copytree("./file/Track/", self.game.path+"/files/Race/Course/", dirs_exist_ok=True) + if not(os.path.exists(self.game.path+"/tmp/")): os.makedirs(self.game.path+"/tmp/") + filecopy("./file/CTFILE.txt", self.game.path+"/tmp/CTFILE.txt") + filecopy("./file/lpar-default.txt", self.game.path + "/tmp/lpar-default.txt") + filecopy(f"./file/lecode-{self.game.region}.bin", self.game.path + f"/tmp/lecode-{self.game.region}.bin") subprocess.run( - ["./tools/szs/wlect", "patch", f"./tmp/lecode-{self.original_region}.bin", "-od", - f"./files/rel/lecode-{self.original_region}.bin", "--track-dir", "./files/Race/Course/", + ["./tools/szs/wlect", "patch", f"./tmp/lecode-{self.game.region}.bin", "-od", + f"./files/rel/lecode-{self.game.region}.bin", "--track-dir", "./files/Race/Course/", "--move-tracks", "./files/Race/Course/", "--le-define", "./tmp/CTFILE.txt", "--lpar", "./tmp/lpar-default.txt", "--overwrite"], - creationflags=CREATE_NO_WINDOW, cwd=self.path_mkwf, check=True, stdout=subprocess.PIPE) + creationflags=CREATE_NO_WINDOW, cwd=self.game.path, check=True, stdout=subprocess.PIPE) - shutil.rmtree(self.path_mkwf + "/tmp/") + shutil.rmtree(self.game.path + "/tmp/") outputformat = self.stringvar_game_format.get() self.Progress(statut=self.translate("Converting to", " ", outputformat), add=1) if outputformat in ["ISO", "WBFS", "CISO"]: - self.path_mkwf_format = os.path.realpath(self.path_mkwf + "/../MKWFaraphel." + outputformat.lower()) - subprocess.run(["./tools/wit/wit", "COPY", get_nodir(self.path_mkwf), "--DEST", - get_nodir(self.path_mkwf_format), f"--{outputformat.lower()}", "--overwrite"], - creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf), + path_game_format: str = os.path.realpath(self.game.path + "/../MKWFaraphel." + outputformat.lower()) + subprocess.run(["./tools/wit/wit", "COPY", get_nodir(self.game.path), "--DEST", + get_nodir(path_game_format), f"--{outputformat.lower()}", "--overwrite"], + creationflags=CREATE_NO_WINDOW, cwd=get_dir(path_game_format), check=True, stdout=subprocess.PIPE) - shutil.rmtree(self.path_mkwf) + shutil.rmtree(self.game.path) + self.game.path = path_game_format self.Progress(statut=self.translate("Changing game's ID"), add=1) - subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(self.path_mkwf_format), "--id", - f"RMC{self.original_region_ID}60", "--name", f"Mario Kart Wii Faraphel {self.VERSION}", - "--modify", "ALL"], - creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf_format), + subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(self.game.path), "--id", + f"RMC{self.game.region_ID}60", "--name", + f"Mario Kart Wii Faraphel {self.ctconfig.version}", "--modify", "ALL"], + creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path), check=True, stdout=subprocess.PIPE) messagebox.showinfo(self.translate("End"), self.translate("The mod has been installed !")) diff --git a/source/option.py b/source/option.py index 7a1bc7d..35ad8f3 100644 --- a/source/option.py +++ b/source/option.py @@ -11,6 +11,9 @@ default_option = { "process_track": 8 } +with open("./translation.json", encoding="utf-8") as f: + translation_dict = json.load(f) + def change_option(self, option, value, restart=False): if type(value) in [str, int, bool]: self.option[option] = value diff --git a/source/patch_bmg.py b/source/patch_bmg.py index de1d438..83397ee 100644 --- a/source/patch_bmg.py +++ b/source/patch_bmg.py @@ -8,7 +8,7 @@ from .definition import * def patch_bmg(self, gamefile): # gamefile est le fichier .szs trouvé dans le /files/Scene/UI/ du jeu try: NINTENDO_CWF_REPLACE = "Wiimmfi" - MAINMENU_REPLACE = f"MKWFaraphel {self.VERSION}" + MAINMENU_REPLACE = f"MKWFaraphel {self.ctconfig.version}" menu_replacement = { "CWF de Nintendo": NINTENDO_CWF_REPLACE, "Wi-Fi Nintendo": NINTENDO_CWF_REPLACE, diff --git a/source/patch_ct_icon.py b/source/patch_ct_icon.py deleted file mode 100644 index 11ff64f..0000000 --- a/source/patch_ct_icon.py +++ /dev/null @@ -1,49 +0,0 @@ -from PIL import Image, ImageFont, ImageDraw -import json -import math -import os - - -def get_cup_icon(i): - if os.path.exists(f"./file/cup_icon/{id}.png"): - cup_icon = Image.open(f"./file/cup_icon/{id}.png").resize((128, 128)) - - else: - cup_icon = Image.new("RGBA", (128, 128)) - draw = ImageDraw.Draw(cup_icon) - font = ImageFont.truetype("./file/SuperMario256.ttf", 90) - draw.text((4 - 2, 4 - 2), "CT", (0, 0, 0), font=font) - draw.text((4 + 2, 4 - 2), "CT", (0, 0, 0), font=font) - draw.text((4 - 2, 4 + 2), "CT", (0, 0, 0), font=font) - draw.text((4 + 2, 4 + 2), "CT", (0, 0, 0), font=font) - draw.text((4, 4), "CT", (255, 165, 0), font=font) - - font = ImageFont.truetype("./file/SuperMario256.ttf", 60) - draw.text((5 - 2, 80 - 2), "%03i" % (i - 10), (0, 0, 0), font=font) # i-10 because first 8 cup are not - draw.text((5 + 2, 80 - 2), "%03i" % (i - 10), (0, 0, 0), font=font) # counted as new, random cup, - draw.text((5 - 2, 80 + 2), "%03i" % (i - 10), (0, 0, 0), font=font) # left and right arrow - draw.text((5 + 2, 80 + 2), "%03i" % (i - 10), (0, 0, 0), font=font) - - draw.text((5, 80), "%03i" % (i - 10), (255, 165, 0), font=font) - return cup_icon - - -def patch_ct_icon(self): - try: - with open("./ct_config.json", encoding="utf8") as f: config = json.load(f) - - cup_number = len(config["cup"]) + math.ceil(len(config["tracks_list"]) / 4) - ct_icon = Image.new("RGBA", (128, 128 * (cup_number + 2))) - - files = ["left", "right"] - files.extend(config["cup"].keys()) - files.extend(["_"] * ((len(config["tracks_list"]) // 4) + 1)) - - for i, id in enumerate(files): - cup_icon = get_cup_icon(i) - ct_icon.paste(cup_icon, (0, i * 128)) - - ct_icon.save("./file/ct_icons.tpl.png") - - except: - self.log_error() diff --git a/source/patch_file.py b/source/patch_file.py index 24f947d..bc73545 100644 --- a/source/patch_file.py +++ b/source/patch_file.py @@ -9,23 +9,26 @@ def patch_file(self): try: if not(os.path.exists("./file/Track-WU8/")): os.makedirs("./file/Track-WU8/") with open("./convert_file.json") as f: fc = json.load(f) - max_step = len(fc["img"]) + self.TOTAL_TRACK + 3 + len("EGFIS") + max_step = len(fc["img"]) + len(self.ctconfig.all_tracks) + 3 + len("EGFIS") self.Progress(show=True, indeter=False, statut=self.translate("Converting files"), max=max_step, step=0) self.Progress(statut=self.translate("Configurating LE-CODE"), add=1) - self.create_lecode_config() + self.ctconfig.create_ctfile() + self.Progress(statut=self.translate("Creating ct_icon.png"), add=1) - self.patch_ct_icon() + ct_icon = self.ctconfig.get_cticon() + ct_icon.save("./file/ct_icons.tpl.png") + self.Progress(statut=self.translate("Creating descriptive images"), add=1) self.patch_img_desc() self.patch_image(fc) - for file in glob.glob(self.path_mkwf+"/files/Scene/UI/MenuSingle_?.szs"): self.patch_bmg(file) + for file in glob.glob(self.game.path+"/files/Scene/UI/MenuSingle_?.szs"): self.patch_bmg(file) # MenuSingle could be any other file, Common and Menu are all the same in all other files. self.patch_autoadd() if self.patch_track() != 0: return self.button_install_mod.grid(row=2, column=1, columnspan=2, sticky="NEWS") - self.button_install_mod.config(text=self.translate("Install mod", " (v", self.VERSION, ")")) + self.button_install_mod.config(text=self.translate("Install mod", " (v", self.ctconfig.version, ")")) except: self.log_error() finally: self.Progress(show=False) diff --git a/source/patch_track.py b/source/patch_track.py index bce090c..d6b7e2f 100644 --- a/source/patch_track.py +++ b/source/patch_track.py @@ -2,69 +2,18 @@ from .definition import * from tkinter import messagebox import subprocess import shutil -import json import os -def get_trackname(self, track, color=False): - hl_prefix, hl_suffix = "", "" - if color: - if track.get("since_version") == self.stringvar_mark_track_from_version.get(): - hl_prefix, hl_suffix = "\\\\c{blue1}", "\\\\c{off}" - - name = track["name"] - name = hl_prefix + name + hl_suffix - - if "prefix" in track: - prefix = track["prefix"] - if color: - if prefix in trackname_color: - prefix = trackname_color[prefix] - name = prefix + " " + name - if "suffix" in track: - suffix = track["suffix"] - if color: - if suffix in trackname_color: - suffix = trackname_color[suffix] - name = name + " (" + suffix + ")" - - return name - - -def get_trackctname(self, *args, **kwargs): - return self.get_trackname(*args, **kwargs).replace("_", "") - - -def load_ct_config(self): - tracks = [] - with open("./ct_config.json", encoding="utf-8") as f: ctconfig = json.load(f) - - for cup in ctconfig["cup"].values(): # defined order tracks - if not (cup["locked"]): tracks.extend(cup["courses"].values()) - - tracks.extend(ctconfig["tracks_list"]) # unordered tracks - - self.TRACKS = [dict(t) for t in {tuple(d.items()) for d in tracks}] # removing duplicate - self.TOTAL_TRACK = len(tracks) - - self.VERSION = ctconfig["version"] - - self.ALL_VERSION = [] - for track in self.TRACKS: - if not track.get("since_version") in self.ALL_VERSION: - self.ALL_VERSION.append(track["since_version"]) - self.ALL_VERSION.sort() - - def patch_autoadd(self): if os.path.exists("./file/auto-add"): shutil.rmtree("./file/auto-add") - if not os.path.exists(self.path_mkwf + "/tmp/"): os.makedirs(self.path_mkwf + "/tmp/") - subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(self.path_mkwf) + "/files/Race/Course/", - "--DEST", get_nodir(self.path_mkwf) + "/tmp/auto-add/"], - creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path_mkwf), + if not os.path.exists(self.game.path + "/tmp/"): os.makedirs(self.game.path + "/tmp/") + subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(self.game.path) + "/files/Race/Course/", + "--DEST", get_nodir(self.game.path) + "/tmp/auto-add/"], + creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path), check=True, stdout=subprocess.PIPE) - shutil.move(self.path_mkwf + "/tmp/auto-add/", "./file/auto-add/") - shutil.rmtree(self.path_mkwf + "/tmp/") + shutil.move(self.game.path + "/tmp/auto-add/", "./file/auto-add/") + shutil.rmtree(self.game.path + "/tmp/") def patch_track(self): @@ -73,20 +22,21 @@ def patch_track(self): error_count, error_max = 0, 3 def add_process(track): - track_file = self.get_trackname(track=track) nonlocal error_count, error_max, process_list + track_file = track.get_track_name() + total_track = len(self.ctconfig.all_tracks) - process_list[track_file] = None # Used for - self.Progress(statut=self.translate("Converting tracks", f"\n({i + 1}/{self.TOTAL_TRACK})\n", + process_list[track_file] = None # Used for showing track in progress even if there's no process + self.Progress(statut=self.translate("Converting tracks", f"\n({i + 1}/{total_track})\n", "\n".join(process_list.keys())), add=1) - for _track in [get_track_szs(track_file), get_track_wu8(track_file)]: + for _track in [track.file_szs, track.file_wu8]: if os.path.exists(_track): if os.path.getsize(_track) < 1000: # File under this size are corrupted os.remove(_track) while True: - download_returncode = self.get_github_file(get_track_wu8(track_file)) + download_returncode = self.get_github_file(track.file_wu8) if download_returncode == -1: # can't download error_count += 1 if error_count > error_max: # Too much track wasn't correctly converted @@ -100,9 +50,9 @@ def patch_track(self): f" ({error_count} / {error_max})")) elif download_returncode == 2: break # if download is disabled, don't check sha1 - if "sha1" in track: + if track.sha1: if not self.boolvar_dont_check_track_sha1.get(): - if not self.check_track_sha1(get_track_wu8(track_file), track["sha1"]) == 0: # La course est correcte + if not track.check_sha1(): # Check si le sha1 du fichier est le bon error_count += 1 if error_count > error_max: # Too much track wasn't correctly converted messagebox.showerror( @@ -113,18 +63,14 @@ def patch_track(self): break - if not (os.path.exists( - get_track_szs(track_file))) or download_returncode == 3: # returncode 3 is track has been updated - if os.path.exists(get_track_wu8(track_file)): - process_list[track_file] = subprocess.Popen([ - "./tools/szs/wszst", "NORMALIZE", get_track_wu8(track_file), "--DEST", - "./file/Track/%N.szs", "--szs", "--overwrite", "--autoadd-path", - "./file/auto-add/"], creationflags=CREATE_NO_WINDOW, stderr=subprocess.PIPE) + if not (os.path.exists(track.file_szs)) or download_returncode == 3: # returncode 3 is track has been updated + if os.path.exists(track.file_wu8): + process_list[track_file] = track.convert_wu8_to_szs() else: messagebox.showerror(self.translate("Error"), self.translate("Can't convert track.\nEnable track download and retry.")) return -1 - elif self.boolvar_del_track_after_conv.get(): os.remove(get_track_wu8(track_file)) + elif self.boolvar_del_track_after_conv.get(): os.remove(track.file_wu8) return 0 def clean_process(): @@ -138,7 +84,7 @@ def patch_track(self): process_list.pop(track_file) stderr = process.stderr.read() if b"wszst: ERROR" in stderr: # Error occured - os.remove(get_track_szs(track_file)) + os.remove(track.file_szs) error_count += 1 if error_count > error_max: # Too much track wasn't correctly converted messagebox.showerror( @@ -152,7 +98,7 @@ def patch_track(self): "do not have been properly converted.", f" ({error_count} / {error_max})")) else: - if self.boolvar_del_track_after_conv.get(): os.remove(get_track_wu8(track_file)) + if self.boolvar_del_track_after_conv.get(): os.remove(track.file_wu8) else: process_list.pop(track_file) if not(any(process_list.values())): return 1 # si il n'y a plus de processus @@ -160,7 +106,7 @@ def patch_track(self): if len(process_list): return 1 else: return 0 - for i, track in enumerate(self.TRACKS): + for i, track in enumerate(self.ctconfig.all_tracks): while True: if len(process_list) < max_process: returncode = add_process(track) diff --git a/source/translate.py b/source/translate.py index 4f4f947..2025b47 100644 --- a/source/translate.py +++ b/source/translate.py @@ -1,4 +1,4 @@ -from .definition import translation_dict +from .option import translation_dict def translate(self, *texts, lang=None): diff --git a/source/wszst.py b/source/wszst.py index 248b794..fab2de7 100644 --- a/source/wszst.py +++ b/source/wszst.py @@ -13,8 +13,9 @@ def sha1(file): 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/", use_popen: bool = False): """ + :param use_popen: True if you want to use Popen to convert :param src_file: source file :param dest_dir: destination directory :param dest_name: destination filename (%N mean same name as src_file) @@ -22,13 +23,31 @@ def normalize(src_file: str, dest_dir: str = "./file/Track/", dest_name: str = " :param autoadd_path: path of the auto-add directory :return: 0 """ - subprocess.run([ + if use_popen: cmd_process = subprocess.Popen + else: cmd_process = subprocess.run + return cmd_process([ "./tools/szs/wszst", "NORMALIZE", src_file, "--DEST", dest_dir+dest_name, "--"+output_format, "--overwrite", "--autoadd-path", autoadd_path], creationflags=CREATE_NO_WINDOW, stderr=subprocess.PIPE) - return 0 def extract(file: str, dest_dir: str): - subprocess.call(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir], - creationflags=CREATE_NO_WINDOW, cwd=get_dir(file)) \ No newline at end of file + subprocess.run(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir], + creationflags=CREATE_NO_WINDOW, cwd=get_dir(file)) + + +def create(file: str): + pass + + +def wstrt_patch(file: str): + pass + + +def wlect_patch(file: str, + lecode_file: str = f"./files/rel/lecode-PAL.bin", + game_track_path: str = "./files/Race/Course/", + move_track_path: str = "./files/Race/Course/", + ctfile_path: str = "./tmp/CTFILE.txt", + lpar_path: str = "./tmp/lpar-default.txt"): + pass diff --git a/translation.json b/translation.json index b3a4a89..4e402c2 100644 --- a/translation.json +++ b/translation.json @@ -14,6 +14,7 @@ "Wii game": "Jeu Wii", "Error": "Erreur", "The file path in invalid": "Le chemin de fichier est invalide", + "This game's format is invalid": "Le format du jeu est invalide", "Warning": "Attention", "This directory will be overwritten if you install the mod !\nAre you sure you want to use it ?": "Ce dossier sera écrasé si vous installer le mod !\nÊtes-vous sûr de vouloir l'utiliser ?", "Extracting the game...": "Extraction du jeu...",