SNIClient: dynamically generate patch file identifier (#2870)

Co-authored-by: beauxq <beauxq@yahoo.com>
This commit is contained in:
Silvris
2024-03-07 03:18:22 -06:00
committed by GitHub
parent 862d77820d
commit b4bb88fcf7
8 changed files with 50 additions and 5 deletions

View File

@@ -1,11 +1,35 @@
from __future__ import annotations
import abc
from typing import TYPE_CHECKING, ClassVar, Dict, Tuple, Any, Optional
from typing import TYPE_CHECKING, ClassVar, Dict, Iterable, Tuple, Any, Optional, Union
from typing_extensions import TypeGuard
from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components
if TYPE_CHECKING:
from SNIClient import SNIContext
component = Component('SNI Client', 'SNIClient', component_type=Type.CLIENT, file_identifier=SuffixIdentifier(".apsoe"))
components.append(component)
def valid_patch_suffix(obj: object) -> TypeGuard[Union[str, Iterable[str]]]:
""" make sure this is a valid value for the class variable `patch_suffix` """
def valid_individual(one: object) -> TypeGuard[str]:
""" check an individual suffix """
# TODO: decide: len(one) > 3 and one.startswith(".ap") ?
# or keep it more general?
return isinstance(one, str) and len(one) > 1 and one.startswith(".")
if isinstance(obj, str):
return valid_individual(obj)
if not isinstance(obj, Iterable):
return False
obj_it: Iterable[object] = obj
return all(valid_individual(each) for each in obj_it)
class AutoSNIClientRegister(abc.ABCMeta):
game_handlers: ClassVar[Dict[str, SNIClient]] = {}
@@ -15,6 +39,22 @@ class AutoSNIClientRegister(abc.ABCMeta):
new_class = super().__new__(cls, name, bases, dct)
if "game" in dct:
AutoSNIClientRegister.game_handlers[dct["game"]] = new_class()
if "patch_suffix" in dct:
patch_suffix = dct["patch_suffix"]
assert valid_patch_suffix(patch_suffix), f"class {name} defining invalid {patch_suffix=}"
existing_identifier = component.file_identifier
assert isinstance(existing_identifier, SuffixIdentifier), f"{existing_identifier=}"
new_suffixes = [*existing_identifier.suffixes]
if isinstance(patch_suffix, str):
new_suffixes.append(patch_suffix)
else:
new_suffixes.extend(patch_suffix)
component.file_identifier = SuffixIdentifier(*new_suffixes)
return new_class
@staticmethod
@@ -27,6 +67,9 @@ class AutoSNIClientRegister(abc.ABCMeta):
class SNIClient(abc.ABC, metaclass=AutoSNIClientRegister):
patch_suffix: ClassVar[Union[str, Iterable[str]]] = ()
"""The file extension(s) this client is meant to open and patch (e.g. ".aplttp")"""
@abc.abstractmethod
async def validate_rom(self, ctx: SNIContext) -> bool:
""" TODO: interface documentation here """