From af277a3c9391674fd00d8ad10d369c8fd1a23b17 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:29:32 +0200 Subject: [PATCH 01/18] CounterOption --- Options.py | 13 +++++----- Utils.py | 3 +++ WebHostLib/options.py | 4 +-- .../templates/playerOptions/macros.html | 2 +- .../playerOptions/playerOptions.html | 8 +++--- .../templates/weightedOptions/macros.html | 2 +- .../weightedOptions/weightedOptions.html | 4 +-- worlds/witness/options.py | 26 +++++++++++-------- 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/Options.py b/Options.py index d040828509d1..37f9b7942fe0 100644 --- a/Options.py +++ b/Options.py @@ -1,6 +1,7 @@ from __future__ import annotations import abc +import collections import functools import logging import math @@ -855,13 +856,13 @@ def __len__(self) -> int: return self.value.__len__() -class ItemDict(OptionDict): - verify_item_name = True - +class CounterOption(OptionDict): def __init__(self, value: typing.Dict[str, int]): - if any(item_count < 1 for item_count in value.values()): - raise Exception("Cannot have non-positive item counts.") - super(ItemDict, self).__init__(value) + super(CounterOption, self).__init__(collections.Counter(value)) + + +class ItemDict(CounterOption): + verify_item_name = True class OptionList(Option[typing.List[typing.Any]], VerifyKeys): diff --git a/Utils.py b/Utils.py index f89330cf7c65..d3d910072061 100644 --- a/Utils.py +++ b/Utils.py @@ -419,6 +419,9 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def find_class(self, module: str, name: str) -> type: if module == "builtins" and name in safe_builtins: return getattr(builtins, name) + # used by CounterOption + if module == "collections" and name == "Counter": + return collections.Counter # used by MultiServer -> savegame/multidata if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint", "SlotType", "NetworkSlot"}: return getattr(self.net_utils_module, name) diff --git a/WebHostLib/options.py b/WebHostLib/options.py index 15b7bd61ceee..e91d0f3f707c 100644 --- a/WebHostLib/options.py +++ b/WebHostLib/options.py @@ -108,7 +108,7 @@ def option_presets(game: str) -> Response: f"Expected {option.special_range_names.keys()} or {option.range_start}-{option.range_end}." presets[preset_name][preset_option_name] = option.value - elif isinstance(option, (Options.Range, Options.OptionSet, Options.OptionList, Options.ItemDict)): + elif isinstance(option, (Options.Range, Options.OptionSet, Options.OptionList, Options.CounterOption)): presets[preset_name][preset_option_name] = option.value elif isinstance(preset_option, str): # Ensure the option value is valid for Choice and Toggle options @@ -216,7 +216,7 @@ def generate_yaml(game: str): for key, val in options.copy().items(): key_parts = key.rsplit("||", 2) - # Detect and build ItemDict options from their name pattern + # Detect and build CounterOption options from their name pattern if key_parts[-1] == "qty": if key_parts[0] not in options: options[key_parts[0]] = {} diff --git a/WebHostLib/templates/playerOptions/macros.html b/WebHostLib/templates/playerOptions/macros.html index 30a4fc78dff3..f035b74ceb6c 100644 --- a/WebHostLib/templates/playerOptions/macros.html +++ b/WebHostLib/templates/playerOptions/macros.html @@ -111,7 +111,7 @@ {% endmacro %} -{% macro ItemDict(option_name, option) %} +{% macro CounterOption(option_name, option) %} {{ OptionTitle(option_name, option) }}