adapted safe_eval call and optimised them. MKWF safe_eval are now easier to read

This commit is contained in:
Faraphel 2022-08-06 23:28:52 +02:00
parent c232a8e328
commit b9873a6c49
20 changed files with 130 additions and 96 deletions

View file

@ -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 ''"
}

View file

@ -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 !"
}
}
}

View file

@ -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"],

View file

@ -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"},

View file

@ -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"},

View file

@ -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"},

View file

@ -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"},

View file

@ -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"},

View file

@ -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"},

View file

@ -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"),

View file

@ -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")

View file

@ -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"):

View file

@ -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(

View file

@ -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

View file

@ -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",

View file

@ -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.

View file

@ -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
)

View file

@ -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
)

View file

@ -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:
"""

View file

@ -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_ = {}