mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-20 11:51:32 -06:00
Core: MultiData typing (#5071)
This commit is contained in:
23
Main.py
23
Main.py
@@ -1,9 +1,11 @@
|
||||
import collections
|
||||
from collections.abc import Mapping
|
||||
import concurrent.futures
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
from typing import Any
|
||||
import zipfile
|
||||
import zlib
|
||||
|
||||
@@ -239,11 +241,13 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)
|
||||
def write_multidata():
|
||||
import NetUtils
|
||||
from NetUtils import HintStatus
|
||||
slot_data = {}
|
||||
client_versions = {}
|
||||
games = {}
|
||||
minimum_versions = {"server": AutoWorld.World.required_server_version, "clients": client_versions}
|
||||
slot_info = {}
|
||||
slot_data: dict[int, Mapping[str, Any]] = {}
|
||||
client_versions: dict[int, tuple[int, int, int]] = {}
|
||||
games: dict[int, str] = {}
|
||||
minimum_versions: NetUtils.MinimumVersions = {
|
||||
"server": AutoWorld.World.required_server_version, "clients": client_versions
|
||||
}
|
||||
slot_info: dict[int, NetUtils.NetworkSlot] = {}
|
||||
names = [[name for player, name in sorted(multiworld.player_name.items())]]
|
||||
for slot in multiworld.player_ids:
|
||||
player_world: AutoWorld.World = multiworld.worlds[slot]
|
||||
@@ -258,7 +262,9 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)
|
||||
group_members=sorted(group["players"]))
|
||||
precollected_items = {player: [item.code for item in world_precollected if type(item.code) == int]
|
||||
for player, world_precollected in multiworld.precollected_items.items()}
|
||||
precollected_hints = {player: set() for player in range(1, multiworld.players + 1 + len(multiworld.groups))}
|
||||
precollected_hints: dict[int, set[NetUtils.Hint]] = {
|
||||
player: set() for player in range(1, multiworld.players + 1 + len(multiworld.groups))
|
||||
}
|
||||
|
||||
for slot in multiworld.player_ids:
|
||||
slot_data[slot] = multiworld.worlds[slot].fill_slot_data()
|
||||
@@ -315,7 +321,7 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)
|
||||
if current_sphere:
|
||||
spheres.append(dict(current_sphere))
|
||||
|
||||
multidata = {
|
||||
multidata: NetUtils.MultiData | bytes = {
|
||||
"slot_data": slot_data,
|
||||
"slot_info": slot_info,
|
||||
"connect_names": {name: (0, player) for player, name in multiworld.player_name.items()},
|
||||
@@ -325,7 +331,7 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)
|
||||
"er_hint_data": er_hint_data,
|
||||
"precollected_items": precollected_items,
|
||||
"precollected_hints": precollected_hints,
|
||||
"version": tuple(version_tuple),
|
||||
"version": (version_tuple.major, version_tuple.minor, version_tuple.build),
|
||||
"tags": ["AP"],
|
||||
"minimum_versions": minimum_versions,
|
||||
"seed_name": multiworld.seed_name,
|
||||
@@ -333,6 +339,7 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)
|
||||
"datapackage": data_package,
|
||||
"race_mode": int(multiworld.is_race),
|
||||
}
|
||||
# TODO: change to `"version": version_tuple` after getting better serialization
|
||||
AutoWorld.call_all(multiworld, "modify_multidata", multidata)
|
||||
|
||||
for key in ("slot_data", "er_hint_data"):
|
||||
|
@@ -43,7 +43,7 @@ import NetUtils
|
||||
import Utils
|
||||
from Utils import version_tuple, restricted_loads, Version, async_start, get_intended_text
|
||||
from NetUtils import Endpoint, ClientStatus, NetworkItem, decode, encode, NetworkPlayer, Permission, NetworkSlot, \
|
||||
SlotType, LocationStore, Hint, HintStatus
|
||||
SlotType, LocationStore, MultiData, Hint, HintStatus
|
||||
from BaseClasses import ItemClassification
|
||||
|
||||
|
||||
@@ -445,7 +445,7 @@ class Context:
|
||||
raise Utils.VersionException("Incompatible multidata.")
|
||||
return restricted_loads(zlib.decompress(data[1:]))
|
||||
|
||||
def _load(self, decoded_obj: dict, game_data_packages: typing.Dict[str, typing.Any],
|
||||
def _load(self, decoded_obj: MultiData, game_data_packages: typing.Dict[str, typing.Any],
|
||||
use_embedded_server_options: bool):
|
||||
|
||||
self.read_data = {}
|
||||
|
39
NetUtils.py
39
NetUtils.py
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
import typing
|
||||
import enum
|
||||
import warnings
|
||||
@@ -83,7 +84,7 @@ class NetworkSlot(typing.NamedTuple):
|
||||
name: str
|
||||
game: str
|
||||
type: SlotType
|
||||
group_members: typing.Union[typing.List[int], typing.Tuple] = () # only populated if type == group
|
||||
group_members: Sequence[int] = () # only populated if type == group
|
||||
|
||||
|
||||
class NetworkItem(typing.NamedTuple):
|
||||
@@ -471,6 +472,42 @@ class _LocationStore(dict, typing.MutableMapping[int, typing.Dict[int, typing.Tu
|
||||
location_id not in checked])
|
||||
|
||||
|
||||
class MinimumVersions(typing.TypedDict):
|
||||
server: tuple[int, int, int]
|
||||
clients: dict[int, tuple[int, int, int]]
|
||||
|
||||
|
||||
class GamesPackage(typing.TypedDict, total=False):
|
||||
item_name_groups: dict[str, list[str]]
|
||||
item_name_to_id: dict[str, int]
|
||||
location_name_groups: dict[str, list[str]]
|
||||
location_name_to_id: dict[str, int]
|
||||
checksum: str
|
||||
|
||||
|
||||
class DataPackage(typing.TypedDict):
|
||||
games: dict[str, GamesPackage]
|
||||
|
||||
|
||||
class MultiData(typing.TypedDict):
|
||||
slot_data: dict[int, Mapping[str, typing.Any]]
|
||||
slot_info: dict[int, NetworkSlot]
|
||||
connect_names: dict[str, tuple[int, int]]
|
||||
locations: dict[int, dict[int, tuple[int, int, int]]]
|
||||
checks_in_area: dict[int, dict[str, int | list[int]]]
|
||||
server_options: dict[str, object]
|
||||
er_hint_data: dict[int, dict[int, str]]
|
||||
precollected_items: dict[int, list[int]]
|
||||
precollected_hints: dict[int, set[Hint]]
|
||||
version: tuple[int, int, int]
|
||||
tags: list[str]
|
||||
minimum_versions: MinimumVersions
|
||||
seed_name: str
|
||||
spheres: list[dict[int, set[int]]]
|
||||
datapackage: dict[str, GamesPackage]
|
||||
race_mode: int
|
||||
|
||||
|
||||
if typing.TYPE_CHECKING: # type-check with pure python implementation until we have a typing stub
|
||||
LocationStore = _LocationStore
|
||||
else:
|
||||
|
@@ -13,9 +13,8 @@ from pony.orm.core import TransactionIntegrityError
|
||||
import schema
|
||||
|
||||
import MultiServer
|
||||
from NetUtils import SlotType
|
||||
from NetUtils import GamesPackage, SlotType
|
||||
from Utils import VersionException, __version__
|
||||
from worlds import GamesPackage
|
||||
from worlds.Files import AutoPatchRegister
|
||||
from worlds.AutoWorld import data_package_checksum
|
||||
from . import app
|
||||
|
@@ -539,7 +539,7 @@ In addition, the following methods can be implemented and are called in this ord
|
||||
creates the output files if there is output to be generated. When this is called,
|
||||
`self.multiworld.get_locations(self.player)` has all locations for the player, with attribute `item` pointing to the
|
||||
item. `location.item.player` can be used to see if it's a local item.
|
||||
* `fill_slot_data(self)` and `modify_multidata(self, multidata: Dict[str, Any])` can be used to modify the data that
|
||||
* `fill_slot_data(self)` and `modify_multidata(self, multidata: MultiData)` can be used to modify the data that
|
||||
will be used by the server to host the MultiWorld.
|
||||
|
||||
All instance methods can, optionally, have a class method defined which will be called after all instance methods are
|
||||
|
@@ -16,7 +16,7 @@ from Utils import deprecate
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from BaseClasses import MultiWorld, Item, Location, Tutorial, Region, Entrance
|
||||
from . import GamesPackage
|
||||
from NetUtils import GamesPackage, MultiData
|
||||
from settings import Group
|
||||
|
||||
perf_logger = logging.getLogger("performance")
|
||||
@@ -450,7 +450,7 @@ class World(metaclass=AutoWorldRegister):
|
||||
"""
|
||||
pass
|
||||
|
||||
def modify_multidata(self, multidata: Dict[str, Any]) -> None: # TODO: TypedDict for multidata?
|
||||
def modify_multidata(self, multidata: "MultiData") -> None:
|
||||
"""For deeper modification of server multidata."""
|
||||
pass
|
||||
|
||||
|
@@ -7,8 +7,9 @@ import warnings
|
||||
import zipimport
|
||||
import time
|
||||
import dataclasses
|
||||
from typing import Dict, List, TypedDict
|
||||
from typing import List
|
||||
|
||||
from NetUtils import DataPackage
|
||||
from Utils import local_path, user_path
|
||||
|
||||
local_folder = os.path.dirname(__file__)
|
||||
@@ -24,8 +25,6 @@ __all__ = {
|
||||
"world_sources",
|
||||
"local_folder",
|
||||
"user_folder",
|
||||
"GamesPackage",
|
||||
"DataPackage",
|
||||
"failed_world_loads",
|
||||
}
|
||||
|
||||
@@ -33,18 +32,6 @@ __all__ = {
|
||||
failed_world_loads: List[str] = []
|
||||
|
||||
|
||||
class GamesPackage(TypedDict, total=False):
|
||||
item_name_groups: Dict[str, List[str]]
|
||||
item_name_to_id: Dict[str, int]
|
||||
location_name_groups: Dict[str, List[str]]
|
||||
location_name_to_id: Dict[str, int]
|
||||
checksum: str
|
||||
|
||||
|
||||
class DataPackage(TypedDict):
|
||||
games: Dict[str, GamesPackage]
|
||||
|
||||
|
||||
@dataclasses.dataclass(order=True)
|
||||
class WorldSource:
|
||||
path: str # typically relative path from this module
|
||||
|
Reference in New Issue
Block a user