From 9821e0538641bb4bc5e4adef78641307fd8c07f3 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Mon, 12 Jul 2021 14:35:44 +0200 Subject: [PATCH] Fix: When sending items via send or getitem, only consider items that belong to that world Fix: Allow cheat-sending items into unconnected slots --- MultiServer.py | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index c14283cc..4688db8d 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -25,6 +25,8 @@ import prompt_toolkit from prompt_toolkit.patch_stdout import patch_stdout from fuzzywuzzy import process as fuzzy_process +from worlds.AutoWorld import AutoWorldRegister +proxy_worlds = {name: world(None, 0) for name, world in AutoWorldRegister.world_types.items()} from worlds.alttp import Items, Regions from worlds import network_data_package, lookup_any_item_id_to_name, lookup_any_item_name_to_id, \ lookup_any_location_id_to_name, lookup_any_location_name_to_id @@ -55,6 +57,7 @@ class Client(Endpoint): self.messageprocessor = client_message_processor(ctx, self) self.ctx = weakref.ref(ctx) +team_slot = typing.Tuple[int, int] class Context(Node): simple_options = {"hint_cost": int, @@ -75,7 +78,8 @@ class Context(Node): self.data_filename = None self.save_filename = None self.saving = False - self.player_names = {} + self.player_names: typing.Dict[team_slot, str] = {} + self.player_name_lookup: typing.Dict[str, team_slot] = {} self.connect_names = {} # names of slots clients can connect to self.allow_forfeits = {} self.remote_items = set() @@ -87,21 +91,21 @@ class Context(Node): self.server = None self.countdown_timer = 0 self.received_items = {} - self.name_aliases: typing.Dict[typing.Tuple[int, int], str] = {} + self.name_aliases: typing.Dict[team_slot, str] = {} self.location_checks = collections.defaultdict(set) self.hint_cost = hint_cost self.location_check_points = location_check_points self.hints_used = collections.defaultdict(int) - self.hints: typing.Dict[typing.Tuple[int, int], typing.Set[NetUtils.Hint]] = collections.defaultdict(set) + self.hints: typing.Dict[team_slot, typing.Set[NetUtils.Hint]] = collections.defaultdict(set) self.forfeit_mode: str = forfeit_mode self.remaining_mode: str = remaining_mode self.item_cheat = item_cheat self.running = True self.client_activity_timers: typing.Dict[ - typing.Tuple[int, int], datetime.datetime] = {} # datetime of last new item check + team_slot, datetime.datetime] = {} # datetime of last new item check self.client_connection_timers: typing.Dict[ - typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection - self.client_game_state: typing.Dict[typing.Tuple[int, int], int] = collections.defaultdict(int) + team_slot, datetime.datetime] = {} # datetime of last connection + self.client_game_state: typing.Dict[team_slot, int] = collections.defaultdict(int) self.er_hint_data: typing.Dict[int, typing.Dict[int, str]] = {} self.auto_shutdown = auto_shutdown self.commandprocessor = ServerCommandProcessor(self) @@ -111,7 +115,7 @@ class Context(Node): self.auto_saver_thread = None self.save_dirty = False self.tags = ['AP'] - self.games = {} + self.games: typing.Dict[int, str] = {} self.minimum_client_versions: typing.Dict[int, Utils.Version] = {} self.seed_name = "" @@ -147,7 +151,8 @@ class Context(Node): for team, names in enumerate(decoded_obj['names']): for player, name in enumerate(names, 1): - self.player_names[(team, player)] = name + self.player_names[team, player] = name + self.player_name_lookup[name] = team, player self.seed_name = decoded_obj["seed_name"] self.connect_names = decoded_obj['connect_names'] self.remote_items = decoded_obj['remote_items'] @@ -573,8 +578,7 @@ def json_format_send_event(net_item: NetworkItem, receiving_player: int): "item": net_item} -def get_intended_text(input_text: str, possible_answers: typing.Iterable[str] = all_console_names) -> typing.Tuple[ - str, bool, str]: +def get_intended_text(input_text: str, possible_answers) -> typing.Tuple[str, bool, str]: picks = fuzzy_process.extract(input_text, possible_answers, limit=2) if len(picks) > 1: dif = picks[0][1] - picks[1][1] @@ -865,7 +869,8 @@ class ClientMessageProcessor(CommonCommandProcessor): def _cmd_getitem(self, item_name: str) -> bool: """Cheat in an item, if it is enabled on this server""" if self.ctx.item_cheat: - item_name, usable, response = get_intended_text(item_name, Items.item_table.keys()) + item_name, usable, response = get_intended_text(item_name, + proxy_worlds[self.ctx.games[self.client.slot]].item_names) if usable: new_item = NetworkItem(Items.item_table[item_name][2], -1, self.client.slot) get_received_items(self.ctx, self.client.team, self.client.slot).append(new_item) @@ -1224,17 +1229,16 @@ class ServerCommandProcessor(CommonCommandProcessor): """Sends an item to the specified player""" seeked_player, usable, response = get_intended_text(player_name, self.ctx.player_names.values()) if usable: + team, slot = self.ctx.player_name_lookup[seeked_player] item = " ".join(item_name) - item, usable, response = get_intended_text(item, all_items) + item, usable, response = get_intended_text(item, proxy_worlds[self.ctx.games[slot]].item_names) if usable: - for client in self.ctx.endpoints: - if client.name == seeked_player: - new_item = NetworkItem(lookup_any_item_name_to_id[item], -1, 0) - get_received_items(self.ctx, client.team, client.slot).append(new_item) - self.ctx.notify_all('Cheat console: sending "' + item + '" to ' + - self.ctx.get_aliased_name(client.team, client.slot)) - send_new_items(self.ctx) - return True + new_item = NetworkItem(lookup_any_item_name_to_id[item], -1, 0) + get_received_items(self.ctx, team, slot).append(new_item) + self.ctx.notify_all('Cheat console: sending "' + item + '" to ' + + self.ctx.get_aliased_name(team, slot)) + send_new_items(self.ctx) + return True else: self.output(response) return False @@ -1249,7 +1253,7 @@ class ServerCommandProcessor(CommonCommandProcessor): for (team, slot), name in self.ctx.player_names.items(): if name == seeked_player: item = " ".join(item_or_location) - item, usable, response = get_intended_text(item) + item, usable, response = get_intended_text(item, all_console_names) if usable: if item in Items.item_name_groups: hints = []