CommonClient: reset session state when connecting to a different room or slot (#6231)

This commit is contained in:
James White
2026-08-16 10:24:28 +02:00
committed by GitHub
parent c6d9411814
commit 21e728c38d
2 changed files with 30 additions and 4 deletions
+30
View File
@@ -341,6 +341,10 @@ class CommonContext:
"""Name used in Connect packet"""
seed_name: str | None
"""Seed name that will be validated on opening a socket if present"""
server_seed_name: str | None
"""Actual seed_name reported by the server in RoomInfo"""
connected_identity: tuple[str, int, int] | None
"""(server_seed_name, team, slot) of the last successful connection, used to detect a session switch"""
# locations
locations_checked: set[int]
@@ -399,6 +403,10 @@ class CommonContext:
self.slot = None
self.auth = None
self.seed_name = None
self.server_seed_name = None
self.connected_identity = None
# decouple from the class-level mutable set so tag changes (e.g. DeathLink) don't leak across instances
self.tags = set(type(self).tags)
self.locations_checked = set() # local state
self.locations_scouted = set()
@@ -459,6 +467,7 @@ class CommonContext:
self.team = None
self.items_received = []
self.locations_info = {}
self.server_seed_name = None
self.server_version = Version(0, 0, 0)
self.generator_version = Version(0, 0, 0)
self.server = None
@@ -470,6 +479,21 @@ class CommonContext:
"remaining": "disabled",
}
def reset_session_state(self):
"""Clear local progress and data-storage state tied to a single session."""
self.locations_checked = set()
self.locations_scouted = set()
self.locations_info = {}
self.items_received = []
self.missing_locations = set()
self.checked_locations = set()
self.server_locations = set()
self.finished_game = False
self.ready = False
self.stored_data = {}
self.stored_data_notification_keys = set()
self.current_energy_link_value = None
async def disconnect(self, allow_autoreconnect: bool = False):
if not allow_autoreconnect:
self.disconnected_intentionally = True
@@ -924,6 +948,7 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
logger.exception(f"Could not get command from {args}")
raise
if cmd == 'RoomInfo':
ctx.server_seed_name = args["seed_name"]
if ctx.seed_name and ctx.seed_name != args["seed_name"]:
msg = "The server is running a different multiworld than your client is. (invalid seed_name)"
logger.info(msg, extra={'compact_gui': True})
@@ -1004,6 +1029,11 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
ctx.username = ctx.auth
ctx.team = args["team"]
ctx.slot = args["slot"]
# on a switch to a different session, clear session state before stale checks/goal are replayed below
identity = (ctx.server_seed_name, ctx.team, ctx.slot)
if ctx.connected_identity is not None and identity != ctx.connected_identity:
ctx.reset_session_state()
ctx.connected_identity = identity
# int keys get lost in JSON transfer
ctx.slot_info = {0: NetworkSlot("Archipelago", "Archipelago", SlotType.player)}
ctx.slot_info.update({int(pid): data for pid, data in args["slot_info"].items()})
-4
View File
@@ -120,7 +120,6 @@ class BizHawkClientCommandProcessor(ClientCommandProcessor):
class BizHawkClientContext(CommonContext):
command_processor = BizHawkClientCommandProcessor
text_passthrough_categories: set[str]
server_seed_name: str | None = None
auth_status: AuthStatus
password_requested: bool
client_handler: BizHawkClient | None
@@ -169,8 +168,6 @@ class BizHawkClientContext(CommonContext):
if cmd == "Connected":
self.slot_data = args.get("slot_data", None)
self.auth_status = AuthStatus.AUTHENTICATED
elif cmd == "RoomInfo":
self.server_seed_name = args.get("seed_name", None)
if self.client_handler is not None:
self.client_handler.on_package(self, cmd, args)
@@ -203,7 +200,6 @@ class BizHawkClientContext(CommonContext):
async def disconnect(self, allow_autoreconnect: bool=False):
self.auth_status = AuthStatus.NOT_AUTHENTICATED
self.server_seed_name = None
await super().disconnect(allow_autoreconnect)