Webhost: Disallow empty option groups (#3369)
* move item_and_loc_options out of the meta class and into the Options module * don't allow empty world specified option groups * reuse option_group generation code instead of rewriting it * delete the default group if it's empty * indent
This commit is contained in:
parent
d09b214309
commit
8b992cbf00
44
Options.py
44
Options.py
|
@ -1132,7 +1132,37 @@ class OptionGroup(typing.NamedTuple):
|
|||
"""Options to be in the defined group."""
|
||||
|
||||
|
||||
def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], generate_hidden: bool = True):
|
||||
item_and_loc_options = [LocalItems, NonLocalItems, StartInventory, StartInventoryPool, StartHints,
|
||||
StartLocationHints, ExcludeLocations, PriorityLocations, ItemLinks]
|
||||
"""
|
||||
Options that are always populated in "Item & Location Options" Option Group. Cannot be moved to another group.
|
||||
If desired, a custom "Item & Location Options" Option Group can be defined, but only for adding additional options to
|
||||
it.
|
||||
"""
|
||||
|
||||
|
||||
def get_option_groups(world: typing.Type[World], visibility_level: Visibility = Visibility.template) -> typing.Dict[
|
||||
str, typing.Dict[str, typing.Type[Option[typing.Any]]]]:
|
||||
"""Generates and returns a dictionary for the option groups of a specified world."""
|
||||
option_groups = {option: option_group.name
|
||||
for option_group in world.web.option_groups
|
||||
for option in option_group.options}
|
||||
# add a default option group for uncategorized options to get thrown into
|
||||
ordered_groups = ["Game Options"]
|
||||
[ordered_groups.append(group) for group in option_groups.values() if group not in ordered_groups]
|
||||
grouped_options = {group: {} for group in ordered_groups}
|
||||
for option_name, option in world.options_dataclass.type_hints.items():
|
||||
if visibility_level & option.visibility:
|
||||
grouped_options[option_groups.get(option, "Game Options")][option_name] = option
|
||||
|
||||
# if the world doesn't have any ungrouped options, this group will be empty so just remove it
|
||||
if not grouped_options["Game Options"]:
|
||||
del grouped_options["Game Options"]
|
||||
|
||||
return grouped_options
|
||||
|
||||
|
||||
def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], generate_hidden: bool = True) -> None:
|
||||
import os
|
||||
|
||||
import yaml
|
||||
|
@ -1170,17 +1200,7 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
|
|||
|
||||
for game_name, world in AutoWorldRegister.world_types.items():
|
||||
if not world.hidden or generate_hidden:
|
||||
|
||||
option_groups = {option: option_group.name
|
||||
for option_group in world.web.option_groups
|
||||
for option in option_group.options}
|
||||
ordered_groups = ["Game Options"]
|
||||
[ordered_groups.append(group) for group in option_groups.values() if group not in ordered_groups]
|
||||
grouped_options = {group: {} for group in ordered_groups}
|
||||
for option_name, option in world.options_dataclass.type_hints.items():
|
||||
if option.visibility >= Visibility.template:
|
||||
grouped_options[option_groups.get(option, "Game Options")][option_name] = option
|
||||
|
||||
grouped_options = get_option_groups(world)
|
||||
with open(local_path("data", "options.yaml")) as f:
|
||||
file_data = f.read()
|
||||
res = Template(file_data).render(
|
||||
|
|
|
@ -27,26 +27,16 @@ def get_world_theme(game_name: str) -> str:
|
|||
|
||||
|
||||
def render_options_page(template: str, world_name: str, is_complex: bool = False) -> Union[Response, str]:
|
||||
visibility_flag = Options.Visibility.complex_ui if is_complex else Options.Visibility.simple_ui
|
||||
world = AutoWorldRegister.world_types[world_name]
|
||||
if world.hidden or world.web.options_page is False:
|
||||
return redirect("games")
|
||||
|
||||
option_groups = {option: option_group.name
|
||||
for option_group in world.web.option_groups
|
||||
for option in option_group.options}
|
||||
ordered_groups = ["Game Options", *[group.name for group in world.web.option_groups]]
|
||||
grouped_options = {group: {} for group in ordered_groups}
|
||||
for option_name, option in world.options_dataclass.type_hints.items():
|
||||
# Exclude settings from options pages if their visibility is disabled
|
||||
if visibility_flag in option.visibility:
|
||||
grouped_options[option_groups.get(option, "Game Options")][option_name] = option
|
||||
visibility_flag = Options.Visibility.complex_ui if is_complex else Options.Visibility.simple_ui
|
||||
|
||||
return render_template(
|
||||
template,
|
||||
world_name=world_name,
|
||||
world=world,
|
||||
option_groups=grouped_options,
|
||||
option_groups=Options.get_option_groups(world, visibility_level=visibility_flag),
|
||||
issubclass=issubclass,
|
||||
Options=Options,
|
||||
theme=get_world_theme(world_name),
|
||||
|
|
|
@ -10,10 +10,7 @@ from dataclasses import make_dataclass
|
|||
from typing import (Any, Callable, ClassVar, Dict, FrozenSet, List, Mapping, Optional, Set, TextIO, Tuple,
|
||||
TYPE_CHECKING, Type, Union)
|
||||
|
||||
from Options import (
|
||||
ExcludeLocations, ItemLinks, LocalItems, NonLocalItems, OptionGroup, PerGameCommonOptions,
|
||||
PriorityLocations, StartHints, StartInventory, StartInventoryPool, StartLocationHints
|
||||
)
|
||||
from Options import item_and_loc_options, OptionGroup, PerGameCommonOptions
|
||||
from BaseClasses import CollectionState
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -119,12 +116,11 @@ class WebWorldRegister(type):
|
|||
# don't allow an option to appear in multiple groups, allow "Item & Location Options" to appear anywhere by the
|
||||
# dev, putting it at the end if they don't define options in it
|
||||
option_groups: List[OptionGroup] = dct.get("option_groups", [])
|
||||
item_and_loc_options = [LocalItems, NonLocalItems, StartInventory, StartInventoryPool, StartHints,
|
||||
StartLocationHints, ExcludeLocations, PriorityLocations, ItemLinks]
|
||||
seen_options = []
|
||||
item_group_in_list = False
|
||||
for group in option_groups:
|
||||
assert group.name != "Game Options", "Game Options is a pre-determined group and can not be defined."
|
||||
assert group.options, "A custom defined Option Group must contain at least one Option."
|
||||
if group.name == "Item & Location Options":
|
||||
group.options.extend(item_and_loc_options)
|
||||
item_group_in_list = True
|
||||
|
|
Loading…
Reference in New Issue