diff --git a/CommonClient.py b/CommonClient.py index 2e10f6d5..87fa59cb 100644 --- a/CommonClient.py +++ b/CommonClient.py @@ -157,6 +157,7 @@ class CommonContext: disconnected_intentionally: bool = False server: typing.Optional[Endpoint] = None server_version: Version = Version(0, 0, 0) + generator_version: Version = Version(0, 0, 0) current_energy_link_value: typing.Optional[int] = None # to display in UI, gets set by server last_death_link: float = time.time() # last send/received death link on AP layer @@ -260,6 +261,7 @@ class CommonContext: self.items_received = [] self.locations_info = {} self.server_version = Version(0, 0, 0) + self.generator_version = Version(0, 0, 0) self.server = None self.server_task = None self.hint_cost = None @@ -646,11 +648,16 @@ async def process_server_cmd(ctx: CommonContext, args: dict): logger.info('Room Information:') logger.info('--------------------------------') version = args["version"] - ctx.server_version = tuple(version) - version = ".".join(str(item) for item in version) + ctx.server_version = Version(*version) - logger.info(f'Server protocol version: {version}') - logger.info("Server protocol tags: " + ", ".join(args["tags"])) + if "generator_version" in args: + ctx.generator_version = Version(*args["generator_version"]) + logger.info(f'Server protocol version: {ctx.server_version.as_simple_string()}, ' + f'generator version: {ctx.generator_version.as_simple_string()}, ' + f'tags: {", ".join(args["tags"])}') + else: + logger.info(f'Server protocol version: {ctx.server_version.as_simple_string()}, ' + f'tags: {", ".join(args["tags"])}') if args['password']: logger.info('Password required') ctx.update_permissions(args.get("permissions", {})) diff --git a/MultiServer.py b/MultiServer.py index 3d5053bb..0537fd9b 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -3,9 +3,6 @@ from __future__ import annotations import argparse import asyncio import copy -import functools -import logging -import zlib import collections import datetime import functools @@ -162,7 +159,7 @@ class Context: read_data: typing.Dict[str, object] stored_data_notification_clients: typing.Dict[str, typing.Set[Client]] slot_info: typing.Dict[int, NetworkSlot] - + generator_version = Version(0, 0, 0) checksums: typing.Dict[str, str] item_names: typing.Dict[int, str] = Utils.KeyedDefaultDict(lambda code: f'Unknown item (ID:{code})') item_name_groups: typing.Dict[str, typing.Dict[str, typing.Set[str]]] @@ -226,7 +223,7 @@ class Context: self.save_dirty = False self.tags = ['AP'] self.games: typing.Dict[int, str] = {} - self.minimum_client_versions: typing.Dict[int, Utils.Version] = {} + self.minimum_client_versions: typing.Dict[int, Version] = {} self.seed_name = "" self.groups = {} self.group_collected: typing.Dict[int, typing.Set[int]] = {} @@ -384,15 +381,17 @@ class Context: def _load(self, decoded_obj: dict, game_data_packages: typing.Dict[str, typing.Any], use_embedded_server_options: bool): + self.read_data = {} mdata_ver = decoded_obj["minimum_versions"]["server"] - if mdata_ver > Utils.version_tuple: + if mdata_ver > version_tuple: raise RuntimeError(f"Supplied Multidata (.archipelago) requires a server of at least version {mdata_ver}," - f"however this server is of version {Utils.version_tuple}") + f"however this server is of version {version_tuple}") + self.generator_version = Version(*decoded_obj["version"]) clients_ver = decoded_obj["minimum_versions"].get("clients", {}) self.minimum_client_versions = {} for player, version in clients_ver.items(): - self.minimum_client_versions[player] = max(Utils.Version(*version), min_client_version) + self.minimum_client_versions[player] = max(Version(*version), min_client_version) self.slot_info = decoded_obj["slot_info"] self.games = {slot: slot_info.game for slot, slot_info in self.slot_info.items()} @@ -758,7 +757,8 @@ async def on_client_connected(ctx: Context, client: Client): # tags are for additional features in the communication. # Name them by feature or fork, as you feel is appropriate. 'tags': ctx.tags, - 'version': Utils.version_tuple, + 'version': version_tuple, + 'generator_version': ctx.generator_version, 'permissions': get_permissions(ctx), 'hint_cost': ctx.hint_cost, 'location_check_points': ctx.location_check_points, diff --git a/Utils.py b/Utils.py index 8a9478e4..46312dc3 100644 --- a/Utils.py +++ b/Utils.py @@ -38,6 +38,9 @@ class Version(typing.NamedTuple): minor: int build: int + def as_simple_string(self) -> str: + return ".".join(str(item) for item in self) + __version__ = "0.4.1" version_tuple = tuplize_version(__version__) diff --git a/docs/network protocol.md b/docs/network protocol.md index 052d62a5..48cf3318 100644 --- a/docs/network protocol.md +++ b/docs/network protocol.md @@ -67,10 +67,11 @@ Sent to clients when they connect to an Archipelago server. | Name | Type | Notes | |-----------------------|-----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | version | [NetworkVersion](#NetworkVersion) | Object denoting the version of Archipelago which the server is running. | +| generator_version | [NetworkVersion](#NetworkVersion) | Object denoting the version of Archipelago which generated the multiworld. | | tags | list\[str\] | Denotes special features or capabilities that the sender is capable of. Example: `WebHost` | | password | bool | Denoted whether a password is required to join this room. | | permissions | dict\[str, [Permission](#Permission)\[int\]\] | Mapping of permission name to [Permission](#Permission), keys are: "release", "collect" and "remaining". | -| hint_cost | int | The percentage of total locations that need to be checked to receive a hint from the server. | +| hint_cost | int | The percentage of total locations that need to be checked to receive a hint from the server. | | location_check_points | int | The amount of hint points you receive per item/location check completed. | | games | list\[str\] | List of games present in this multiworld. | | datapackage_versions | dict\[str, int\] | Data versions of the individual games' data packages the server will send. Used to decide which games' caches are outdated. See [Data Package Contents](#Data-Package-Contents). **Deprecated. Use `datapackage_checksums` instead.** |