Launcher: generate templates for option presets (#5062)

This commit is contained in:
Silvris
2026-02-15 12:22:40 -06:00
committed by GitHub
parent 13b6a5f4b2
commit 21c7f3cd92
3 changed files with 74 additions and 44 deletions

View File

@@ -1747,8 +1747,10 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
from Utils import local_path, __version__ from Utils import local_path, __version__
full_path: str full_path: str
preset_folder = os.path.join(target_folder, "Presets")
os.makedirs(target_folder, exist_ok=True) os.makedirs(target_folder, exist_ok=True)
os.makedirs(preset_folder, exist_ok=True)
# clean out old # clean out old
for file in os.listdir(target_folder): for file in os.listdir(target_folder):
@@ -1756,11 +1758,16 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
if os.path.isfile(full_path) and full_path.endswith(".yaml"): if os.path.isfile(full_path) and full_path.endswith(".yaml"):
os.unlink(full_path) os.unlink(full_path)
def dictify_range(option: Range): for file in os.listdir(preset_folder):
data = {option.default: 50} full_path = os.path.join(preset_folder, file)
if os.path.isfile(full_path) and full_path.endswith(".yaml"):
os.unlink(full_path)
def dictify_range(option: Range, option_val: int | str):
data = {option_val: 50}
for sub_option in ["random", "random-low", "random-high", for sub_option in ["random", "random-low", "random-high",
f"random-range-{option.range_start}-{option.range_end}"]: f"random-range-{option.range_start}-{option.range_end}"]:
if sub_option != option.default: if sub_option != option_val:
data[sub_option] = 0 data[sub_option] = 0
notes = { notes = {
"random-low": "random value weighted towards lower values", "random-low": "random value weighted towards lower values",
@@ -1773,6 +1780,8 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
if number in data: if number in data:
data[name] = data[number] data[name] = data[number]
del data[number] del data[number]
elif name in data:
pass
else: else:
data[name] = 0 data[name] = 0
@@ -1788,8 +1797,11 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
for game_name, world in AutoWorldRegister.world_types.items(): for game_name, world in AutoWorldRegister.world_types.items():
if not world.hidden or generate_hidden: if not world.hidden or generate_hidden:
option_groups = get_option_groups(world) presets = world.web.options_presets.copy()
presets.update({"": {}})
option_groups = get_option_groups(world)
for name, preset in presets.items():
res = template.render( res = template.render(
option_groups=option_groups, option_groups=option_groups,
__version__=__version__, __version__=__version__,
@@ -1798,9 +1810,13 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
yaml_dump=yaml_dump_scalar, yaml_dump=yaml_dump_scalar,
dictify_range=dictify_range, dictify_range=dictify_range,
cleandoc=cleandoc, cleandoc=cleandoc,
preset_name=name,
preset=preset,
) )
preset_name = f" - {name}" if name else ""
with open(os.path.join(target_folder, get_file_safe_name(game_name) + ".yaml"), "w", encoding="utf-8-sig") as f: with open(os.path.join(preset_folder if name else target_folder,
get_file_safe_name(game_name + preset_name) + ".yaml"),
"w", encoding="utf-8-sig") as f:
f.write(res) f.write(res)

View File

@@ -28,7 +28,7 @@
name: Player{number} name: Player{number}
# Used to describe your yaml. Useful if you have multiple files. # Used to describe your yaml. Useful if you have multiple files.
description: {{ yaml_dump("Default %s Template" % game) }} description: {{ yaml_dump("%s Preset for %s" % (preset_name, game)) if preset_name else yaml_dump("Default %s Template" % game) }}
game: {{ yaml_dump(game) }} game: {{ yaml_dump(game) }}
requires: requires:
@@ -38,11 +38,11 @@ requires:
{{ yaml_dump(game) }}: {{ world_version }} # Version of the world required for this yaml to work as expected. {{ yaml_dump(game) }}: {{ world_version }} # Version of the world required for this yaml to work as expected.
{%- endif %} {%- endif %}
{%- macro range_option(option) %} {%- macro range_option(option, option_val) %}
# You can define additional values between the minimum and maximum values. # You can define additional values between the minimum and maximum values.
# Minimum value is {{ option.range_start }} # Minimum value is {{ option.range_start }}
# Maximum value is {{ option.range_end }} # Maximum value is {{ option.range_end }}
{%- set data, notes = dictify_range(option) %} {%- set data, notes = dictify_range(option, option_val) %}
{%- for entry, default in data.items() %} {%- for entry, default in data.items() %}
{{ entry }}: {{ default }}{% if notes[entry] %} # {{ notes[entry] }}{% endif %} {{ entry }}: {{ default }}{% if notes[entry] %} # {{ notes[entry] }}{% endif %}
{%- endfor -%} {%- endfor -%}
@@ -56,6 +56,10 @@ requires:
{%- for option_key, option in group_options.items() %} {%- for option_key, option in group_options.items() %}
{{ option_key }}: {{ option_key }}:
{%- set option_val = option.default %}
{%- if option_key in preset %}
{%- set option_val = preset[option_key] %}
{%- endif -%}
{%- if option.__doc__ %} {%- if option.__doc__ %}
# {{ cleandoc(option.__doc__) # {{ cleandoc(option.__doc__)
| trim | trim
@@ -69,25 +73,25 @@ requires:
{%- endif -%} {%- endif -%}
{%- if option.range_start is defined and option.range_start is number %} {%- if option.range_start is defined and option.range_start is number %}
{{- range_option(option) -}} {{- range_option(option, option_val) -}}
{%- elif option.options -%} {%- elif option.options -%}
{%- for suboption_option_id, sub_option_name in option.name_lookup.items() %} {%- for suboption_option_id, sub_option_name in option.name_lookup.items() %}
{{ yaml_dump(sub_option_name) }}: {% if suboption_option_id == option.default %}50{% else %}0{% endif %} {{ yaml_dump(sub_option_name) }}: {% if suboption_option_id == option_val or sub_option_name == option_val %}50{% else %}0{% endif %}
{%- endfor -%} {%- endfor -%}
{%- if option.name_lookup[option.default] not in option.options %} {%- if option.name_lookup[option_val] not in option.options and option_val not in option.options %}
{{ yaml_dump(option.default) }}: 50 {{ yaml_dump(option_val) }}: 50
{%- endif -%} {%- endif -%}
{%- elif option.default is string %} {%- elif option_val is string %}
{{ yaml_dump(option.default) }}: 50 {{ yaml_dump(option_val) }}: 50
{%- elif option.default is iterable and option.default is not mapping %} {%- elif option_val is iterable and option_val is not mapping %}
{{ option.default | list }} {{ option_val | list }}
{%- else %} {%- else %}
{{ yaml_dump(option.default) | indent(4, first=false) }} {{ yaml_dump(option_val) | indent(4, first=false) }}
{%- endif -%} {%- endif -%}
{{ "\n" }} {{ "\n" }}
{%- endfor %} {%- endfor %}

View File

@@ -25,22 +25,32 @@ class TestGenerateYamlTemplates(unittest.TestCase):
if "World: with colon" in worlds.AutoWorld.AutoWorldRegister.world_types: if "World: with colon" in worlds.AutoWorld.AutoWorldRegister.world_types:
del worlds.AutoWorld.AutoWorldRegister.world_types["World: with colon"] del worlds.AutoWorld.AutoWorldRegister.world_types["World: with colon"]
def test_name_with_colon(self) -> None: def test_name_with_colon(self) -> None:
from Options import generate_yaml_templates from Options import generate_yaml_templates
from worlds.AutoWorld import AutoWorldRegister from worlds.AutoWorld import AutoWorldRegister
from worlds.AutoWorld import World from worlds.AutoWorld import World, WebWorld
class WebWorldWithColon(WebWorld):
options_presets = {
"Generic": {
"progression_balancing": "disabled",
"accessibility": "minimal",
}
}
class WorldWithColon(World): class WorldWithColon(World):
game = "World: with colon" game = "World: with colon"
item_name_to_id = {} item_name_to_id = {}
location_name_to_id = {} location_name_to_id = {}
web = WebWorldWithColon()
AutoWorldRegister.world_types = {WorldWithColon.game: WorldWithColon} AutoWorldRegister.world_types = {WorldWithColon.game: WorldWithColon}
with TemporaryDirectory(f"archipelago_{__name__}") as temp_dir: with TemporaryDirectory(f"archipelago_{__name__}") as temp_dir:
generate_yaml_templates(temp_dir) generate_yaml_templates(temp_dir)
path: Path path: Path
for path in Path(temp_dir).iterdir(): for path in Path(temp_dir).rglob("*"):
self.assertTrue(path.is_file()) if path.is_file():
self.assertTrue(path.suffix == ".yaml") self.assertTrue(path.suffix == ".yaml")
with path.open(encoding="utf-8") as f: with path.open(encoding="utf-8") as f:
try: try: