diff --git a/open_prime_rando/dynamic_schema.py b/open_prime_rando/dynamic_schema.py new file mode 100644 index 0000000..782d9df --- /dev/null +++ b/open_prime_rando/dynamic_schema.py @@ -0,0 +1,33 @@ +import copy + +from open_prime_rando.patcher_editor import PatcherEditor +import open_prime_rando.echoes.asset_ids.world + + +def expand_schema(base_schema: dict, editor: PatcherEditor) -> dict: + schema = copy.deepcopy(base_schema) + + world_props = schema["properties"]["worlds"]["properties"] = {} + for world, mlvl_id in open_prime_rando.echoes.asset_ids.world.NAME_TO_ID.items(): + world_def = copy.deepcopy(schema["$defs"]["world"]) + world_props[world] = world_def + + mlvl = editor.get_mlvl(mlvl_id) + area_props = {} + world_def["properties"]["areas"] = {"type": "object", "additionalProperties": False, "properties": area_props} + + for area in mlvl.areas: + area_def = copy.deepcopy(schema["$defs"]["area"]) + area_props[area.name] = area_def + + area_def["properties"]["layers"] = { + "type": "object", + "properties": { + layer.name: {"type": "boolean"} + for layer in area.layers + }, + "default": {}, + "additionalProperties": False, + } + + return schema diff --git a/open_prime_rando/echoes/schema.json b/open_prime_rando/echoes/schema.json index e29c563..420d77d 100644 --- a/open_prime_rando/echoes/schema.json +++ b/open_prime_rando/echoes/schema.json @@ -6,6 +6,19 @@ "type": "string", "format": "uri" }, + "worlds": { + "type": "object", + "properties": { + "Great Temple": { "$ref": "#/$defs/world" }, + "Temple Grounds": { "$ref": "#/$defs/world" }, + "Agon Wastes": { "$ref": "#/$defs/world" }, + "Torvus Bog": { "$ref": "#/$defs/world" }, + "Sanctuary Fortress": { "$ref": "#/$defs/world" } + }, + "default": {}, + "additionalProperties": false, + "$comment": "The list of properties is replaced in runtime with all worlds in the provided ISO." + }, "small_randomizations": { "properties": { "seed": { @@ -44,5 +57,37 @@ ], "additionalProperties": false, "$defs": { + "world": { + "type": "object", + "properties": { + "areas": { + "type": "object", + "patternProperties": { + ".*": { + "$ref": "#/$defs/area" + } + } + } + }, + "required": ["areas"], + "additionalProperties": false, + "$comment": "The list of areas is replaced in runtime with the existing areas of each specific world." + }, + "area": { + "type": "object", + "properties": { + "layers": { + "type": "object", + "patternProperties": { + ".*": { + "type": "boolean" + } + }, + "default": {}, + "$comment": "The list of layers is replaced in runtime with the existing layers of each specific area." + } + }, + "additionalProperties": false + } } } diff --git a/open_prime_rando/echoes_patcher.py b/open_prime_rando/echoes_patcher.py index 881e2de..8594fc1 100644 --- a/open_prime_rando/echoes_patcher.py +++ b/open_prime_rando/echoes_patcher.py @@ -4,10 +4,12 @@ from retro_data_structures.asset_manager import FileProvider +from open_prime_rando import dynamic_schema from open_prime_rando.echoes.inverted import apply_inverted from open_prime_rando.echoes.small_randomizations import apply_small_randomizations from open_prime_rando.patcher_editor import PatcherEditor from open_prime_rando.validator_with_default import DefaultValidatingDraft7Validator +import open_prime_rando.echoes.asset_ids.world LOG = logging.getLogger("echoes_patcher") @@ -17,15 +19,35 @@ def _read_schema(): return json.load(f) +def apply_area_modifications(editor: PatcherEditor, configuration: dict[str, dict]): + for world_name, world_config in configuration.items(): + mlvl = editor.get_mlvl(open_prime_rando.echoes.asset_ids.world.NAME_TO_ID[world_name]) + + for area in mlvl.areas: + area_name = area.name + if area_name not in world_config["areas"]: + continue + + area_config = world_config["areas"][area_name] + for layer_name, layer_state in area_config["layers"].items(): + LOG.debug("Setting layer %s of %s - %s to %s", layer_name, world_name, area_name, str(layer_state)) + area.get_layer(layer_name).active = layer_state + + def patch_paks(file_provider: FileProvider, output_path: Path, configuration: dict): LOG.info("Will patch files at %s", file_provider) - DefaultValidatingDraft7Validator(_read_schema()).validate(configuration) - editor = PatcherEditor(file_provider) + LOG.info("Preparing schema") + schema = dynamic_schema.expand_schema(_read_schema(), editor) + + LOG.info("Validating schema") + DefaultValidatingDraft7Validator(schema).validate(configuration) + # custom_assets.create_custom_assets(editor) # specific_patches(editor) + apply_area_modifications(editor, configuration["worlds"]) apply_small_randomizations(editor, configuration["small_randomizations"]) # apply_door_rando(editor, [])