From ca96e7e2941325c46035a5f69775b5baffbf18e0 Mon Sep 17 00:00:00 2001 From: Kaito Sinclaire Date: Fri, 16 Aug 2024 13:20:02 -0700 Subject: [PATCH] Fix !remaining for cross-world items (#3732) * Fix !remaining for other worlds * Typing fixes for the previous change * Update LocationStore test to match what get_remaining now returns --- MultiServer.py | 18 +++++++++--------- NetUtils.py | 8 ++++---- _speedups.pyx | 8 ++++---- test/netutils/test_location_store.py | 6 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index f59855fca6a4..b7c0e0f74555 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -991,7 +991,7 @@ def collect_player(ctx: Context, team: int, slot: int, is_group: bool = False): collect_player(ctx, team, group, True) -def get_remaining(ctx: Context, team: int, slot: int) -> typing.List[int]: +def get_remaining(ctx: Context, team: int, slot: int) -> typing.List[typing.Tuple[int, int]]: return ctx.locations.get_remaining(ctx.location_checks, team, slot) @@ -1350,10 +1350,10 @@ def _cmd_collect(self) -> bool: def _cmd_remaining(self) -> bool: """List remaining items in your game, but not their location or recipient""" if self.ctx.remaining_mode == "enabled": - remaining_item_ids = get_remaining(self.ctx, self.client.team, self.client.slot) - if remaining_item_ids: - self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[self.client.slot]][item_id] - for item_id in remaining_item_ids)) + rest_locations = get_remaining(self.ctx, self.client.team, self.client.slot) + if rest_locations: + self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[slot]][item_id] + for slot, item_id in rest_locations)) else: self.output("No remaining items found.") return True @@ -1363,10 +1363,10 @@ def _cmd_remaining(self) -> bool: return False else: # is goal if self.ctx.client_game_state[self.client.team, self.client.slot] == ClientStatus.CLIENT_GOAL: - remaining_item_ids = get_remaining(self.ctx, self.client.team, self.client.slot) - if remaining_item_ids: - self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[self.client.slot]][item_id] - for item_id in remaining_item_ids)) + rest_locations = get_remaining(self.ctx, self.client.team, self.client.slot) + if rest_locations: + self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[slot]][item_id] + for slot, item_id in rest_locations)) else: self.output("No remaining items found.") return True diff --git a/NetUtils.py b/NetUtils.py index f8d698c74fcc..f79773728cd6 100644 --- a/NetUtils.py +++ b/NetUtils.py @@ -397,12 +397,12 @@ def get_missing(self, state: typing.Dict[typing.Tuple[int, int], typing.Set[int] location_id not in checked] def get_remaining(self, state: typing.Dict[typing.Tuple[int, int], typing.Set[int]], team: int, slot: int - ) -> typing.List[int]: + ) -> typing.List[typing.Tuple[int, int]]: checked = state[team, slot] player_locations = self[slot] - return sorted([player_locations[location_id][0] for - location_id in player_locations if - location_id not in checked]) + return sorted([(player_locations[location_id][1], player_locations[location_id][0]) for + location_id in player_locations if + location_id not in checked]) if typing.TYPE_CHECKING: # type-check with pure python implementation until we have a typing stub diff --git a/_speedups.pyx b/_speedups.pyx index 4b083c2f9aef..dc039e336500 100644 --- a/_speedups.pyx +++ b/_speedups.pyx @@ -287,15 +287,15 @@ cdef class LocationStore: entry in self.entries[start:start + count] if entry.location not in checked] - def get_remaining(self, state: State, team: int, slot: int) -> List[int]: + def get_remaining(self, state: State, team: int, slot: int) -> List[Tuple[int, int]]: cdef LocationEntry* entry cdef ap_player_t sender = slot cdef size_t start = self.sender_index[sender].start cdef size_t count = self.sender_index[sender].count cdef set checked = state[team, slot] - return sorted([entry.item for - entry in self.entries[start:start+count] if - entry.location not in checked]) + return sorted([(entry.receiver, entry.item) for + entry in self.entries[start:start+count] if + entry.location not in checked]) @cython.auto_pickle(False) diff --git a/test/netutils/test_location_store.py b/test/netutils/test_location_store.py index f3e83989bea4..1b984015844d 100644 --- a/test/netutils/test_location_store.py +++ b/test/netutils/test_location_store.py @@ -130,9 +130,9 @@ def test_get_missing(self) -> None: def test_get_remaining(self) -> None: self.assertEqual(self.store.get_remaining(full_state, 0, 1), []) - self.assertEqual(self.store.get_remaining(one_state, 0, 1), [13, 21]) - self.assertEqual(self.store.get_remaining(empty_state, 0, 1), [13, 21, 22]) - self.assertEqual(self.store.get_remaining(empty_state, 0, 3), [99]) + self.assertEqual(self.store.get_remaining(one_state, 0, 1), [(1, 13), (2, 21)]) + self.assertEqual(self.store.get_remaining(empty_state, 0, 1), [(1, 13), (2, 21), (2, 22)]) + self.assertEqual(self.store.get_remaining(empty_state, 0, 3), [(4, 99)]) def test_location_set_intersection(self) -> None: locations = {10, 11, 12}