From b9873a6c492730c7101334b7016691842796510a Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sat, 6 Aug 2022 23:28:52 +0200 Subject: [PATCH] adapted safe_eval call and optimised them. MKWF safe_eval are now easier to read --- Pack/MKWFaraphel/macros.json | 12 +-- Pack/MKWFaraphel/messages.json | 4 +- Pack/MKWFaraphel/mod_config.json | 102 +++++++++--------- .../specific/_PATCH/files/Boot/Strap/de.json | 2 +- .../specific/_PATCH/files/Boot/Strap/en.json | 2 +- .../specific/_PATCH/files/Boot/Strap/es.json | 2 +- .../specific/_PATCH/files/Boot/Strap/fr.json | 2 +- .../specific/_PATCH/files/Boot/Strap/ge.json | 2 +- .../specific/_PATCH/files/Boot/Strap/it.json | 2 +- source/gui/install.py | 2 +- source/gui/preview/track_selecting.py | 8 +- source/mkw/ExtractedGame.py | 2 +- source/mkw/ModConfig.py | 55 +++++++--- source/mkw/Patch/PatchDirectory.py | 6 +- source/mkw/Patch/PatchFile.py | 6 +- .../PatchOperation/BmgTxtEditor/IDLayer.py | 2 +- .../PatchOperation/BmgTxtEditor/RegexLayer.py | 2 +- .../PatchOperation/ImageEditor/TextLayer.py | 2 +- source/mkw/Track.py | 8 +- source/safe_eval/safe_eval.py | 3 + 20 files changed, 130 insertions(+), 96 deletions(-) diff --git a/Pack/MKWFaraphel/macros.json b/Pack/MKWFaraphel/macros.json index 1aab164..1214d51 100644 --- a/Pack/MKWFaraphel/macros.json +++ b/Pack/MKWFaraphel/macros.json @@ -1,14 +1,14 @@ { - "GAME_REGION": "str(getattr(getattr(getattr(extracted_game, 'original_game'), 'wit_path'), 'region'))", + "GAME_REGION": "str(extracted_game.original_game.wit_path.region)", - "TRACK_TEXT_SCORE": "bmg_color_text(['yellow', 'orange', 'dark red', 'azure'][getattr(track, 'warning', 0)], '\\x'+hex(65296+getattr(track, 'score'))[2:]+' ') if hasattr(track, 'score') else ''", - "TRACK_TEXT_PREFIX": "(prefix+' ') if prefix else ''", - "TRACK_TEXT_SUFFIX": "(' ('+suffix +')') if suffix else ''", + "TRACK_TEXT_SCORE": "bmg_color_text(['yellow', 'orange', 'dark red', 'azure'][getattr(track, 'warning', 0)], f'\\\\x{65296+track.score:x} ') if hasattr(track, 'score') else ''", + "TRACK_TEXT_PREFIX": "f'{prefix} ' if prefix else ''", + "TRACK_TEXT_SUFFIX": "f' ({suffix})' if suffix else ''", "TRACK_TEXT_NAME": "getattr(track, 'name', '')", - "TRACK_TEXT_AUTHORS": "'\\n'.join(getattr(track, 'author')) if isinstance(getattr(track, 'author', ''), list) else getattr(track, 'author', '/')", + "TRACK_TEXT_AUTHORS": "'\\\\n'.join(author) if isinstance(author := getattr(track, 'author', '/'), list) else author", "TRACK_TEXT_WARNING_IF_DISABLED": "bmg_color_text('red', '/') if getattr(track, 'warning', 0) != 0 else ''", - "SETTINGS_MODE": "getattr(getattr(mod_config, 'specific_settings')['mode'], 'value')", + "SETTINGS_MODE": "mod_config.specific_settings['mode'].value", "IF_NO_WARNING": "if getattr(track, 'warning', 0) == 0 else ''" } \ No newline at end of file diff --git a/Pack/MKWFaraphel/messages.json b/Pack/MKWFaraphel/messages.json index b71ecf3..01384c8 100644 --- a/Pack/MKWFaraphel/messages.json +++ b/Pack/MKWFaraphel/messages.json @@ -1,8 +1,8 @@ { "installation_completed": { "text": { - "fr": "TODO", - "en": "Thanks for downloading Mario Kart Wii Faraphel !\nIf You have an issue starting the game with Dolphin, try in Config > Advanced > Enable Emulated Memory Size Override and set MEM2 to 128Mo\n\nHave fun !" + "fr": "Merci d'avoir téléchargé {{ mod_config.name }} !\nSi vous avez un problème en démarrant le jeu avec Dolphin, essayer dans Configurer > Avancé > Modifier la taille de la mémoire émulée et mettre MEM2 à 128MB\n\nAmusez-vous !", + "en": "Thanks for downloading {{ mod_config.name }} !\nIf You have an issue starting the game with Dolphin, try in Config > Advanced > Enable Emulated Memory Size Override and set MEM2 to 128MB\n\nHave fun !" } } } \ No newline at end of file diff --git a/Pack/MKWFaraphel/mod_config.json b/Pack/MKWFaraphel/mod_config.json index 831ce11..f64300d 100644 --- a/Pack/MKWFaraphel/mod_config.json +++ b/Pack/MKWFaraphel/mod_config.json @@ -29,59 +29,59 @@ "lpar_template": "{{ ## SETTINGS_MODE ## if ## SETTINGS_MODE ## is not None else 'normal' }}.lpar", "tags_prefix": { - "MSRDS": "{{ bmg_color_text('green', TAG) }}", - "CTR": "{{ bmg_color_text('orange', TAG) }}", - "CTTR": "{{ bmg_color_text('dark orange', TAG) }}", - "CNR": "{{ bmg_color_text('orange', TAG) }}", - "DKR": "{{ bmg_color_text('dark red', TAG) }}", - "LCP": "{{ bmg_color_text('green', TAG) }}", - "LEGO-R": "{{ bmg_color_text('light red', TAG) }}", - "MP9": "{{ bmg_color_text('neon yellow', TAG) }}", - "MSUSA": "{{ bmg_color_text('green', TAG) }}", - "FZMV": "{{ bmg_color_text('yellow', TAG) }}", - "KAR": "{{ bmg_color_text('green', TAG) }}", - "KO": "{{ bmg_color_text('dark orange', TAG) }}", - "FZ": "{{ bmg_color_text('yellow', TAG) }}", - "RV": "{{ bmg_color_text('white', TAG) }}", - "SADX": "{{ bmg_color_text('dark blue', TAG) }}", - "SCR": "{{ bmg_color_text('yellow', TAG) }}", - "SH": "{{ bmg_color_text('pink', TAG) }}", - "SM64": "{{ bmg_color_text('pink', TAG) }}", - "SMB1": "{{ bmg_color_text('light red', TAG) }}", - "SMB2": "{{ bmg_color_text('red', TAG) }}", - "SSBB": "{{ bmg_color_text('vivid red', TAG) }}", - "SMS": "{{ bmg_color_text('dark red', TAG) }}", - "SMO": "{{ bmg_color_text('apple red', TAG) }}", - "VVVVVV": "{{ bmg_color_text('azure', TAG) }}", - "WF": "{{ bmg_color_text('green', TAG) }}", - "WP": "{{ bmg_color_text('neon yellow 2', TAG) }}", - "Zelda OoT": "{{ bmg_color_text('green', TAG) }}", - "Zelda TP": "{{ bmg_color_text('green', TAG) }}", - "Zelda WW": "{{ bmg_color_text('green', TAG) }}", - "PMWR": "{{ bmg_color_text('neon yellow 2', TAG) }}", - "SHR": "{{ bmg_color_text('green', TAG) }}", - "SK64": "{{ bmg_color_text('green', TAG) }}", - "SMG": "{{ bmg_color_text('light red', TAG) }}", - "Spyro 1": "{{ bmg_color_text('azure', TAG) }}", - "Switch": "{{ bmg_color_text('vivid red', TAG) }}", - "Wii": "{{ bmg_color_text('azure', TAG) }}", - "3DS": "{{ bmg_color_text('light orange', TAG) }}", - "DS": "{{ bmg_color_text('white', TAG) }}", - "GCN": "{{ bmg_color_text('azure', TAG) }}", - "GBA": "{{ bmg_color_text('dark blue', TAG) }}", - "N64": "{{ bmg_color_text('pink', TAG) }}", - "SNES": "{{ bmg_color_text('green', TAG) }}", - "RMX": "{{ bmg_color_text('orange', TAG) }}", - "MKT": "{{ bmg_color_text('dark orange', TAG) }}", - "GP": "{{ bmg_color_text('dark red', TAG) }}", - "UT": "{{ bmg_color_text('red', TAG) }}", - "GK2": "{{ bmg_color_text('green', TAG) }}", - "GK3": "{{ bmg_color_text('green', TAG) }}", - "GK7": "{{ bmg_color_text('green', TAG) }}", - "FGKR": "{{ bmg_color_text('dark orange', TAG) }}" + "MSRDS": "{{ bmg_color_text('green', tag) }}", + "CTR": "{{ bmg_color_text('orange', tag) }}", + "CTTR": "{{ bmg_color_text('dark orange', tag) }}", + "CNR": "{{ bmg_color_text('orange', tag) }}", + "DKR": "{{ bmg_color_text('dark red', tag) }}", + "LCP": "{{ bmg_color_text('green', tag) }}", + "LEGO-R": "{{ bmg_color_text('light red', tag) }}", + "MP9": "{{ bmg_color_text('neon yellow', tag) }}", + "MSUSA": "{{ bmg_color_text('green', tag) }}", + "FZMV": "{{ bmg_color_text('yellow', tag) }}", + "KAR": "{{ bmg_color_text('green', tag) }}", + "KO": "{{ bmg_color_text('dark orange', tag) }}", + "FZ": "{{ bmg_color_text('yellow', tag) }}", + "RV": "{{ bmg_color_text('white', tag) }}", + "SADX": "{{ bmg_color_text('dark blue', tag) }}", + "SCR": "{{ bmg_color_text('yellow', tag) }}", + "SH": "{{ bmg_color_text('pink', tag) }}", + "SM64": "{{ bmg_color_text('pink', tag) }}", + "SMB1": "{{ bmg_color_text('light red', tag) }}", + "SMB2": "{{ bmg_color_text('red', tag) }}", + "SSBB": "{{ bmg_color_text('vivid red', tag) }}", + "SMS": "{{ bmg_color_text('dark red', tag) }}", + "SMO": "{{ bmg_color_text('apple red', tag) }}", + "VVVVVV": "{{ bmg_color_text('azure', tag) }}", + "WF": "{{ bmg_color_text('green', tag) }}", + "WP": "{{ bmg_color_text('neon yellow 2', tag) }}", + "Zelda OoT": "{{ bmg_color_text('green', tag) }}", + "Zelda TP": "{{ bmg_color_text('green', tag) }}", + "Zelda WW": "{{ bmg_color_text('green', tag) }}", + "PMWR": "{{ bmg_color_text('neon yellow 2', tag) }}", + "SHR": "{{ bmg_color_text('green', tag) }}", + "SK64": "{{ bmg_color_text('green', tag) }}", + "SMG": "{{ bmg_color_text('light red', tag) }}", + "Spyro 1": "{{ bmg_color_text('azure', tag) }}", + "Switch": "{{ bmg_color_text('vivid red', tag) }}", + "Wii": "{{ bmg_color_text('azure', tag) }}", + "3DS": "{{ bmg_color_text('light orange', tag) }}", + "DS": "{{ bmg_color_text('white', tag) }}", + "GCN": "{{ bmg_color_text('azure', tag) }}", + "GBA": "{{ bmg_color_text('dark blue', tag) }}", + "N64": "{{ bmg_color_text('pink', tag) }}", + "SNES": "{{ bmg_color_text('green', tag) }}", + "RMX": "{{ bmg_color_text('orange', tag) }}", + "MKT": "{{ bmg_color_text('dark orange', tag) }}", + "GP": "{{ bmg_color_text('dark red', tag) }}", + "UT": "{{ bmg_color_text('red', tag) }}", + "GK2": "{{ bmg_color_text('green', tag) }}", + "GK3": "{{ bmg_color_text('green', tag) }}", + "GK7": "{{ bmg_color_text('green', tag) }}", + "FGKR": "{{ bmg_color_text('dark orange', tag) }}" }, "tags_suffix": { - "Boost": "{{ bmg_color_text('orange', TAG) }}" + "Boost": "{{ bmg_color_text('orange', tag) }}" }, "tags_cups": ["Switch", "3DS", "DS", "GCN", "GBA", "N64", "SNES", "MKT", "RMX", "DX", "GP"], diff --git a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/de.json b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/de.json index ee170d7..f9db81e 100644 --- a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/de.json +++ b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/de.json @@ -5,7 +5,7 @@ "layers": [ {"type": "color", "color": [0, 0, 0, 255]}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"}, - {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, + {"type": "text", "x": 0.01, "y": 0.00, "text": "{{ mod_config.name }}", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Elke track heeft een score tussen 1 en 5 sterren", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " speelbaar", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfect", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, diff --git a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/en.json b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/en.json index 9af8b23..a72821c 100644 --- a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/en.json +++ b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/en.json @@ -5,7 +5,7 @@ "layers": [ {"type": "color", "color": [0, 0, 0, 255]}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"}, - {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, + {"type": "text", "x": 0.01, "y": 0.00, "text": "{{ mod_config.name }}", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Every track has a score between 1 and 5 stars", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " playable", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfect", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, diff --git a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/es.json b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/es.json index dea29a4..cb35000 100644 --- a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/es.json +++ b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/es.json @@ -5,7 +5,7 @@ "layers": [ {"type": "color", "color": [0, 0, 0, 255]}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"}, - {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, + {"type": "text", "x": 0.01, "y": 0.00, "text": "{{ mod_config.name }}", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Cada pista tiene una puntuación entre 1 y 5 estrellas", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " interpretable", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfecto", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, diff --git a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/fr.json b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/fr.json index 9dca782..e07990f 100644 --- a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/fr.json +++ b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/fr.json @@ -5,7 +5,7 @@ "layers": [ {"type": "color", "color": [0, 0, 0, 255]}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"}, - {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, + {"type": "text", "x": 0.01, "y": 0.00, "text": "{{ mod_config.name }}", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Chaque course possède une note allant de 1 à 5 étoiles", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " jouable", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " parfait", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, diff --git a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/ge.json b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/ge.json index f2b3dc3..1c4aad8 100644 --- a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/ge.json +++ b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/ge.json @@ -5,7 +5,7 @@ "layers": [ {"type": "color", "color": [0, 0, 0, 255]}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"}, - {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, + {"type": "text", "x": 0.01, "y": 0.00, "text": "{{ mod_config.name }}", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Jeder track hat eine Punktzahl zwischen 1 und 5 sternen", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " spielbar", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfekt", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, diff --git a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/it.json b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/it.json index dbaa2af..35105a8 100644 --- a/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/it.json +++ b/Pack/MKWFaraphel/specific/_PATCH/files/Boot/Strap/it.json @@ -5,7 +5,7 @@ "layers": [ {"type": "color", "color": [0, 0, 0, 255]}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"}, - {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, + {"type": "text", "x": 0.01, "y": 0.00, "text": "{{ mod_config.name }}", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Ogni traccia ha un punteggio compreso tra 1 e 5 stelle", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " giocabile", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfetto", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}, diff --git a/source/gui/install.py b/source/gui/install.py index 3e0bdbc..7892f15 100644 --- a/source/gui/install.py +++ b/source/gui/install.py @@ -420,7 +420,7 @@ class ButtonInstall(ttk.Button): message = message_texts.get(self.root.options["language"]) if message is None: message = message_texts.get("*") if message is None: message = _('NO_MESSAGE_FROM_AUTHOR') - message = mod_config.safe_eval(message, multiple=True) + message = mod_config.multiple_safe_eval(message) messagebox.showinfo( _("INSTALLATION_COMPLETED"), diff --git a/source/gui/preview/track_selecting.py b/source/gui/preview/track_selecting.py index fa638d8..bc0982b 100644 --- a/source/gui/preview/track_selecting.py +++ b/source/gui/preview/track_selecting.py @@ -78,8 +78,14 @@ class Window(AbstractPreviewWindow): self.text_track_select.configure(state=tkinter.NORMAL) self.text_track_select.delete(1.0, tkinter.END) + template_func = self.mod_config.safe_eval( + self.entry_template_input.get(), + return_lambda=True, lambda_args=["track"] + ) + for track in self.mod_config.get_all_tracks(ignore_filter=True): - value = self.mod_config.safe_eval(self.entry_template_input.get(), env={"track": track}) == "True" + value: bool = template_func(track) is True + self.text_track_select.insert(tkinter.END, f"{value}\n") self.text_track_select.tag_add(str(value), "end-1c-1l", "end-1c") diff --git a/source/mkw/ExtractedGame.py b/source/mkw/ExtractedGame.py index 09a9926..6783ffe 100644 --- a/source/mkw/ExtractedGame.py +++ b/source/mkw/ExtractedGame.py @@ -127,7 +127,7 @@ class ExtractedGame: ct_file.write_text(mod_config.get_ctfile(template="-")) lpar_dir: Path = mod_config.path.parent / "_LPAR/" - lpar: Path = lpar_dir / mod_config.safe_eval(mod_config.lpar_template, multiple=True) + lpar: Path = lpar_dir / mod_config.multiple_safe_eval(mod_config.lpar_template) if not lpar.is_relative_to(lpar_dir): raise PathOutsideMod(lpar, lpar_dir) for lecode_file in (self.path / "files/rel/").glob("lecode-*.bin"): diff --git a/source/mkw/ModConfig.py b/source/mkw/ModConfig.py index 54afdcd..b07655d 100644 --- a/source/mkw/ModConfig.py +++ b/source/mkw/ModConfig.py @@ -1,6 +1,6 @@ import shutil from pathlib import Path -from typing import Generator +from typing import Generator, Callable from PIL import Image @@ -159,19 +159,32 @@ class ModConfig: messages=json.loads(messages_file.read_text(encoding="utf8")) if messages_file.exists() else None, ) - def safe_eval(self, template: str, multiple: bool = False, env: dict[str, any] = None) -> str: + def get_safe_eval_env(self, base_env: dict[str, any] = None) -> dict[str, any]: """ - Safe eval with a patch environment - :param multiple: should the expression be a multiple safe eval or a single safe eval - :param env: other variable that are allowed in the safe_eval - :param template: template to evaluate + Return the env for the modconfig safe_eval function + :param base_env: additional environment + :return: the modconfig environment + """ + return { + "mod_config": self, + "bmg_color_text": bmg_color_text + } | ( + base_env if base_env is not None else {} + ) + + def safe_eval(self, *args, env: dict[str, any] = None, **kwargs) -> any: + """ + Safe eval with useful modconfig environment :return: the result of the evaluation """ - return (multiple_safe_eval if multiple else safe_eval)( - template, - env={"mod_config": self, "bmg_color_text": bmg_color_text} | (env if env is not None else {}), - macros=self.macros, - ) + return safe_eval(*args, env=self.get_safe_eval_env(base_env=env), macros=self.macros, **kwargs) + + def multiple_safe_eval(self, *args, env: dict[str, any] = None, **kwargs) -> str: + """ + Multiple safe eval with useful modconfig environment + :return: the str result of the evaluation + """ + return multiple_safe_eval(*args, env=self.get_safe_eval_env(base_env=env), macros=self.macros, **kwargs) def get_mod_directory(self) -> Path: """ @@ -197,12 +210,16 @@ class ModConfig: filter_template: str | None = self.global_settings["include_track_if"].value if not ignore_filter else None + # filter_template_func is the function checking if the track should be included. If no parameter is set, + # then always return True + filter_template_func: Callable = self.safe_eval( + filter_template, return_lambda=True, lambda_args=["track"] + ) if filter_template is not None else ( + lambda track: True + ) + # Go though all the tracks and filter them if enabled - for track in filter( - lambda track: True if filter_template is None else - self.safe_eval(filter_template, env={"track": track}) == "True", - self._tracks - ): + for track in filter(lambda track: filter_template_func(track=track) is True, self._tracks): yield track def get_ordered_cups(self) -> Generator["Cup", None, None]: @@ -370,6 +387,10 @@ class ModConfig: normalize_threads = list(filter(lambda thread: thread["thread"].is_alive(), normalize_threads)) track_directory = self.path.parent / "_TRACKS" + multiplayer_disable_if_func: Callable = self.safe_eval( + self.multiplayer_disable_if, + return_lambda=True, lambda_args=["track"] + ) for track in self.get_all_tracks(): track_file: Path = next( @@ -384,7 +405,7 @@ class ModConfig: format="szs" ) - if safe_eval(self.multiplayer_disable_if, {"track": track}) == "True": + if multiplayer_disable_if_func(track=track) is True: # if the track should use the default track instead in multiplayer, # copy the default track to the same file but with a _d at the end shutil.copy( diff --git a/source/mkw/Patch/PatchDirectory.py b/source/mkw/Patch/PatchDirectory.py index d04c21b..33b23be 100644 --- a/source/mkw/Patch/PatchDirectory.py +++ b/source/mkw/Patch/PatchDirectory.py @@ -24,8 +24,10 @@ class PatchDirectory(PatchObject): """ yield {"description": f"Patching {self}"} - if self.patch.mod_config.safe_eval(self.configuration["if"], env={"extracted_game": extracted_game}) != "True": - return + if self.patch.mod_config.safe_eval( + self.configuration["if"], + env={"extracted_game": extracted_game} + ) is not True: return match self.configuration["mode"]: # if the mode is copy, then simply patch the subfile into the game with the same path diff --git a/source/mkw/Patch/PatchFile.py b/source/mkw/Patch/PatchFile.py index 6723d19..58cf763 100644 --- a/source/mkw/Patch/PatchFile.py +++ b/source/mkw/Patch/PatchFile.py @@ -31,8 +31,10 @@ class PatchFile(PatchObject): yield {"description": f"Patching {self}"} # check if the file should be patched considering the "if" configuration - if self.patch.mod_config.safe_eval(self.configuration["if"], env={"extracted_game": extracted_game}) != "True": - return + if self.patch.mod_config.safe_eval( + self.configuration["if"], + env={"extracted_game": extracted_game} + ) is not True: return # check if the path to the game_subpath is inside a szs, and if yes extract it for szs_subpath in filter(lambda path: path.suffix == ".d", diff --git a/source/mkw/Patch/PatchOperation/BmgTxtEditor/IDLayer.py b/source/mkw/Patch/PatchOperation/BmgTxtEditor/IDLayer.py index 9981338..bd7779d 100644 --- a/source/mkw/Patch/PatchOperation/BmgTxtEditor/IDLayer.py +++ b/source/mkw/Patch/PatchOperation/BmgTxtEditor/IDLayer.py @@ -16,6 +16,6 @@ class IDLayer(AbstractLayer): def patch_bmg(self, patch: "Patch", decoded_content: str) -> str: return decoded_content + "\n" + ("\n".join( - [f" {id}\t= {patch.mod_config.safe_eval(repl, multiple=True)}" for id, repl in self.template.items()] + [f" {id}\t= {patch.mod_config.multiple_safe_eval(repl)}" for id, repl in self.template.items()] )) + "\n" # add new bmg definition at the end of the bmg file, overwritting old id. diff --git a/source/mkw/Patch/PatchOperation/BmgTxtEditor/RegexLayer.py b/source/mkw/Patch/PatchOperation/BmgTxtEditor/RegexLayer.py index 33ec038..1c87f73 100644 --- a/source/mkw/Patch/PatchOperation/BmgTxtEditor/RegexLayer.py +++ b/source/mkw/Patch/PatchOperation/BmgTxtEditor/RegexLayer.py @@ -28,7 +28,7 @@ class RegexLayer(AbstractLayer): for pattern, repl in self.template.items(): value = re.sub( pattern, - patch.mod_config.safe_eval(repl, multiple=True), + patch.mod_config.multiple_safe_eval(repl), value, flags=re.DOTALL ) diff --git a/source/mkw/Patch/PatchOperation/ImageEditor/TextLayer.py b/source/mkw/Patch/PatchOperation/ImageEditor/TextLayer.py index d9794f7..86de89c 100644 --- a/source/mkw/Patch/PatchOperation/ImageEditor/TextLayer.py +++ b/source/mkw/Patch/PatchOperation/ImageEditor/TextLayer.py @@ -38,7 +38,7 @@ class TextLayer(AbstractLayer): ) draw.text( self.get_layer_position(image), - text=patch.mod_config.safe_eval(self.text, multiple=True), + text=patch.mod_config.multiple_safe_eval(self.text), fill=self.color, font=font ) diff --git a/source/mkw/Track.py b/source/mkw/Track.py index 704f004..e98b879 100644 --- a/source/mkw/Track.py +++ b/source/mkw/Track.py @@ -50,14 +50,13 @@ class Track: :return: formatted representation of the track """ - return mod_config.safe_eval( + return mod_config.multiple_safe_eval( template, env={ "track": self, "prefix": self.get_prefix(mod_config, ""), "suffix": self.get_suffix(mod_config, "") }, - multiple=True ) def get_tag_template(self, mod_config: "ModConfig", templates: dict[str, str], default: any = None) -> any: @@ -70,7 +69,7 @@ class Track: """ for tag in filter(lambda tag: tag in templates, self.tags): template: str = templates[tag] - return mod_config.safe_eval(template, env={"TAG": tag}, multiple=True) + return mod_config.multiple_safe_eval(template, env={"tag": tag}) return default def get_prefix(self, mod_config: "ModConfig", default: any = None) -> any: @@ -101,7 +100,8 @@ class Track: # if the random new have been forced in the settings, use it instead of the default one template: str = mod_config.global_settings["force_random_new"].value if template is None: template = mod_config.track_new_if - return mod_config.safe_eval(template, multiple=False, env={"track": self}) == "True" + + return mod_config.safe_eval(template, env={"track": self}) is True def get_ctfile(self, mod_config: "ModConfig", template: str, hidden: bool = False) -> str: """ diff --git a/source/safe_eval/safe_eval.py b/source/safe_eval/safe_eval.py index 7a65904..1944b00 100644 --- a/source/safe_eval/safe_eval.py +++ b/source/safe_eval/safe_eval.py @@ -36,6 +36,9 @@ def safe_eval(template: str, env: dict[str, any] = None, macros: dict[str, str] # replace the macro in the template template = replace_macro(template=template, macros=macros) + # escape backslash to avoid unreadable expression + template = template.replace("\\", "\\\\") + # prepare the execution environment globals_ = all_globals | env locals_ = {}