From 00d766777114c57a2c2fd919ef8640237f6a3df8 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Sun, 7 Jun 2020 00:19:19 +0200 Subject: [PATCH 1/3] extend hint system with group names --- MultiServer.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index 74adb576..f778d1e2 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -27,7 +27,7 @@ import Utils from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem from NetUtils import Node, Endpoint -console_names = frozenset(set(Items.item_table) | set(Regions.location_table)) +console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups)) CLIENT_PLAYING = 0 CLIENT_GOAL = 1 @@ -668,6 +668,10 @@ class ClientMessageProcessor(CommandProcessor): if item_name in Items.hint_blacklist: self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.") hints = [] + elif item_name in Items.item_name_groups: + hints = [] + for item in Items.item_name_groups[item_name]: + hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item)) elif item_name in Items.item_table: # item name hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name) else: # location name @@ -929,12 +933,15 @@ class ServerCommandProcessor(CommandProcessor): item = " ".join(item_or_location) item, usable, response = get_intended_text(item) if usable: - if item in Items.item_table: # item name + if item in Items.item_name_groups: + hints = [] + for item in Items.item_name_groups[item]: + hints.extend(collect_hints(self.ctx, team, slot, item)) + elif item in Items.item_table: # item name hints = collect_hints(self.ctx, team, slot, item) - notify_hints(self.ctx, team, hints) else: # location name hints = collect_hints_location(self.ctx, team, slot, item) - notify_hints(self.ctx, team, hints) + notify_hints(self.ctx, team, hints) return True else: self.output(response) From 55152515f6969ecf9cb40bd997b1d78af76417bc Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Sun, 7 Jun 2020 00:49:10 +0200 Subject: [PATCH 2/3] move stuff out of main(), for alternative server implementations --- MultiServer.py | 81 ++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index f778d1e2..cac36ffb 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -61,7 +61,7 @@ class Context(Node): super(Context, self).__init__() self.data_filename = None self.save_filename = None - self.disable_save = False + self.saving = False self.player_names = {} self.rom_names = {} self.remote_items = set() @@ -82,12 +82,46 @@ class Context(Node): 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] = {} # datatime of last new item check - self.client_connection_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection + self.client_activity_timers: typing.Dict[ + typing.Tuple[int, int], datetime.datetime] = {} # datatime 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) self.er_hint_data: typing.Dict[int, typing.Dict[int, str]] = {} self.commandprocessor = ServerCommandProcessor(self) + def load(self, multidatapath: str): + with open(multidatapath, 'rb') as f: + self._load(f) + self.data_filename = multidatapath + + def _load(self, fileobj): + jsonobj = json.loads(zlib.decompress(fileobj.read()).decode("utf-8-sig")) + for team, names in enumerate(jsonobj['names']): + for player, name in enumerate(names, 1): + self.player_names[(team, player)] = name + self.rom_names = {tuple(rom): (team, slot) for slot, team, rom in jsonobj['roms']} + self.remote_items = set(jsonobj['remote_items']) + self.locations = {tuple(k): tuple(v) for k, v in jsonobj['locations']} + if "er_hint_data" in jsonobj: + self.er_hint_data = {int(player): {int(address): name for address, name in loc_data.items()} + for player, loc_data in jsonobj["er_hint_data"].items()} + + def init_save(self, enabled: bool): + self.saving = enabled + if self.saving: + if not self.save_filename: + self.save_filename = (self.data_filename[:-9] if self.data_filename[-9:] == 'multidata' else ( + self.data_filename + '_')) + 'multisave' + try: + with open(self.save_filename, 'rb') as f: + jsonobj = json.loads(zlib.decompress(f.read()).decode("utf-8")) + self.set_save(jsonobj) + except FileNotFoundError: + logging.error('No save data found, starting a new game') + except Exception as e: + logging.exception(e) + def get_save(self) -> dict: d = { "rom_names": list(self.rom_names.items()), @@ -361,7 +395,7 @@ def notify_team(ctx: Context, team: int, text: str): def save(ctx: Context): - if not ctx.disable_save: + if ctx.saving: try: jsonstr = json.dumps(ctx.get_save()) with open(ctx.save_filename, "wb") as f: @@ -1004,51 +1038,26 @@ async def main(args: argparse.Namespace): ctx = Context(args.host, args.port, args.password, args.location_check_points, args.hint_cost, not args.disable_item_cheat, args.forfeit_mode, args.remaining_mode) - ctx.data_filename = args.multidata + data_filename = args.multidata try: - if not ctx.data_filename: + if not data_filename: import tkinter import tkinter.filedialog root = tkinter.Tk() root.withdraw() - ctx.data_filename = tkinter.filedialog.askopenfilename(filetypes=(("Multiworld data","*multidata"),)) + data_filename = tkinter.filedialog.askopenfilename(filetypes=(("Multiworld data", "*multidata"),)) + + ctx.load(data_filename) - with open(ctx.data_filename, 'rb') as f: - jsonobj = json.loads(zlib.decompress(f.read()).decode("utf-8-sig")) - for team, names in enumerate(jsonobj['names']): - for player, name in enumerate(names, 1): - ctx.player_names[(team, player)] = name - ctx.rom_names = {tuple(rom): (team, slot) for slot, team, rom in jsonobj['roms']} - ctx.remote_items = set(jsonobj['remote_items']) - ctx.locations = {tuple(k): tuple(v) for k, v in jsonobj['locations']} - if "er_hint_data" in jsonobj: - ctx.er_hint_data = {int(player): {int(address): name for address, name in loc_data.items()} - for player, loc_data in jsonobj["er_hint_data"].items()} except Exception as e: logging.exception('Failed to read multiworld data (%s)' % e) - return - ip = args.host if args.host else Utils.get_public_ipv4() - - - - ctx.disable_save = args.disable_save - if not ctx.disable_save: - if not ctx.save_filename: - ctx.save_filename = (ctx.data_filename[:-9] if ctx.data_filename[-9:] == 'multidata' else ( - ctx.data_filename + '_')) + 'multisave' - try: - with open(ctx.save_filename, 'rb') as f: - jsonobj = json.loads(zlib.decompress(f.read()).decode("utf-8")) - ctx.set_save(jsonobj) - except FileNotFoundError: - logging.error('No save data found, starting a new game') - except Exception as e: - logging.exception(e) + ctx.init_save(not args.disable_save) ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ping_timeout=None, ping_interval=None) + ip = args.host if args.host else Utils.get_public_ipv4() logging.info('Hosting game at %s:%d (%s)' % (ip, ctx.port, 'No password' if not ctx.password else 'Password: %s' % ctx.password)) await ctx.server From b36738f3f49a4b98258c9cb1c053a6c438f91b9a Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Sun, 7 Jun 2020 00:50:39 +0200 Subject: [PATCH 3/3] reraise the crash --- MultiServer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/MultiServer.py b/MultiServer.py index cac36ffb..b2ddaa13 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -1052,6 +1052,7 @@ async def main(args: argparse.Namespace): except Exception as e: logging.exception('Failed to read multiworld data (%s)' % e) + raise ctx.init_save(not args.disable_save)