From 6ddfbdf709410929921c76ff3a840e5ae72d0386 Mon Sep 17 00:00:00 2001 From: CaitSith2 Date: Wed, 3 Mar 2021 02:20:37 -0800 Subject: [PATCH] Allow pre-rolling yaml settings, and re-using the exact same pre-rolled settings later, for different actual seeds. --- MultiMystery.py | 6 ++++++ Mystery.py | 30 ++++++++++++++++++++++++++---- Utils.py | 2 ++ host.yaml | 5 +++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/MultiMystery.py b/MultiMystery.py index 237e432b..f78a6b66 100644 --- a/MultiMystery.py +++ b/MultiMystery.py @@ -61,6 +61,8 @@ if __name__ == "__main__": player_name = multi_mystery_options["player_name"] meta_file_path = multi_mystery_options["meta_file_path"] weights_file_path = multi_mystery_options["weights_file_path"] + pre_roll = multi_mystery_options["pre_roll"] + use_pre_rolled = multi_mystery_options["use_pre_rolled"] teams = multi_mystery_options["teams"] rom_file = options["general_options"]["rom_file"] host = options["server_options"]["host"] @@ -119,6 +121,10 @@ if __name__ == "__main__": command += f" --meta {os.path.join(player_files_path, meta_file_path)}" if os.path.exists(weights_file_path): command += f" --weights {weights_file_path}" + if pre_roll: + command += " --pre_roll" + if use_pre_rolled: + command += " --use_pre_rolled" logging.info(command) import time diff --git a/Mystery.py b/Mystery.py index d6d55bde..72fcaac4 100644 --- a/Mystery.py +++ b/Mystery.py @@ -12,7 +12,7 @@ from BaseClasses import PlandoItem, PlandoConnection ModuleUpdate.update() import Bosses -from Utils import parse_yaml +from Utils import parse_yaml, unsafe_parse_yaml from Rom import Sprite from EntranceRandomizer import parse_arguments from Main import main as ERmain @@ -37,6 +37,8 @@ def mystery_argparse(): parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) parser.add_argument('--create_spoiler', action='store_true') parser.add_argument('--skip_playthrough', action='store_true') + parser.add_argument('--pre_roll', action='store_true') + parser.add_argument('--use_pre_rolled', action='store_true') parser.add_argument('--rom') parser.add_argument('--enemizercli') parser.add_argument('--outputpath') @@ -93,7 +95,7 @@ def main(args=None, callback=ERmain): if path: try: if path not in weights_cache: - weights_cache[path] = get_weights(path) + weights_cache[path] = get_weights(path, args.use_pre_rolled) print(f"P{player} Weights: {path} >> " f"{get_choice('description', weights_cache[path], 'No description specified')}") @@ -180,6 +182,23 @@ def main(args=None, callback=ERmain): settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist.") + if args.pre_roll: + import yaml + if path == args.weights: + settings.name = f"Player{player}" + elif not settings.name: + settings.name = os.path.split(path)[-1].split(".")[0] + + if "-" not in settings.shuffle and settings.shuffle != "vanilla": + settings.shuffle += f"-{random.randint(0, 2 ** 64)}" + + if "-" not in settings.door_shuffle and settings.door_shuffle != "vanilla": + settings.door_shuffle += f"-{random.randint(0, 2 ** 64)}" + + pre_rolled = dict() + pre_rolled["pre_rolled"] = settings + with open(os.path.join(args.outputpath if args.outputpath else ".", f"{os.path.split(path)[-1].split('.')[0]}_pre_rolled_{seedname}.yaml"), "wt") as f: + yaml.dump(pre_rolled, f) for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v @@ -223,7 +242,7 @@ def main(args=None, callback=ERmain): callback(erargs, seed) -def get_weights(path): +def get_weights(path, use_pre_rolled=False): try: if urllib.parse.urlparse(path).scheme: yaml = str(urllib.request.urlopen(path).read(), "utf-8") @@ -233,7 +252,7 @@ def get_weights(path): except Exception as e: raise Exception(f"Failed to read weights ({path})") from e - return parse_yaml(yaml) + return unsafe_parse_yaml(yaml) if use_pre_rolled else parse_yaml(yaml) def interpret_on_off(value): @@ -349,6 +368,9 @@ def roll_triggers(weights: dict) -> dict: return weights def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("bosses"))): + if "pre_rolled" in weights: + return weights["pre_rolled"] + if "linked_options" in weights: weights = roll_linked_options(weights) diff --git a/Utils.py b/Utils.py index 758f0058..489f7995 100644 --- a/Utils.py +++ b/Utils.py @@ -213,6 +213,8 @@ def get_default_options() -> dict: "players": 0, "weights_file_path": "weights.yaml", "meta_file_path": "meta.yaml", + "pre_roll": False, + "use_pre_rolled": False, "player_name": "", "create_spoiler": 1, "zip_roms": 0, diff --git a/host.yaml b/host.yaml index bccfc9e5..933f393f 100644 --- a/host.yaml +++ b/host.yaml @@ -66,6 +66,11 @@ multi_mystery_options: weights_file_path: "weights.yaml" # Meta file name, within the stated player_files_path location meta_file_path: "meta.yaml" + # Option to pre-roll a yaml that will be used to roll future seeds with the exact same settings every single time. + pre_roll: false + # Option to use pre-rolled settings. If not enabled, attempts to use a pre-rolled yaml WILL fail with + # "Please fix your yaml." + use_pre_rolled: false # Automatically launches {player_name}.yaml's ROM file using the OS's default program once generation completes. (likely your emulator) # Does nothing if the name is not found # Example: player_name = "Berserker"