Merge branch 'master' of https://github.com/Berserker66/MultiWorld-Utilities
This commit is contained in:
		
						commit
						3448437815
					
				|  | @ -27,7 +27,7 @@ import Utils | ||||||
| from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem | from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem | ||||||
| from NetUtils import Node, Endpoint | 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_PLAYING = 0 | ||||||
| CLIENT_GOAL = 1 | CLIENT_GOAL = 1 | ||||||
|  | @ -61,7 +61,7 @@ class Context(Node): | ||||||
|         super(Context, self).__init__() |         super(Context, self).__init__() | ||||||
|         self.data_filename = None |         self.data_filename = None | ||||||
|         self.save_filename = None |         self.save_filename = None | ||||||
|         self.disable_save = False |         self.saving = False | ||||||
|         self.player_names = {} |         self.player_names = {} | ||||||
|         self.rom_names = {} |         self.rom_names = {} | ||||||
|         self.remote_items = set() |         self.remote_items = set() | ||||||
|  | @ -82,12 +82,46 @@ class Context(Node): | ||||||
|         self.remaining_mode: str = remaining_mode |         self.remaining_mode: str = remaining_mode | ||||||
|         self.item_cheat = item_cheat |         self.item_cheat = item_cheat | ||||||
|         self.running = True |         self.running = True | ||||||
|         self.client_activity_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datatime of last new item check |         self.client_activity_timers: typing.Dict[ | ||||||
|         self.client_connection_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection |             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.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.er_hint_data: typing.Dict[int, typing.Dict[int, str]] = {} | ||||||
|         self.commandprocessor = ServerCommandProcessor(self) |         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: |     def get_save(self) -> dict: | ||||||
|         d = { |         d = { | ||||||
|             "rom_names": list(self.rom_names.items()), |             "rom_names": list(self.rom_names.items()), | ||||||
|  | @ -361,7 +395,7 @@ def notify_team(ctx: Context, team: int, text: str): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def save(ctx: Context): | def save(ctx: Context): | ||||||
|     if not ctx.disable_save: |     if ctx.saving: | ||||||
|         try: |         try: | ||||||
|             jsonstr = json.dumps(ctx.get_save()) |             jsonstr = json.dumps(ctx.get_save()) | ||||||
|             with open(ctx.save_filename, "wb") as f: |             with open(ctx.save_filename, "wb") as f: | ||||||
|  | @ -668,6 +702,10 @@ class ClientMessageProcessor(CommandProcessor): | ||||||
|                 if item_name in Items.hint_blacklist: |                 if item_name in Items.hint_blacklist: | ||||||
|                     self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.") |                     self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.") | ||||||
|                     hints = [] |                     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 |                 elif item_name in Items.item_table:  # item name | ||||||
|                     hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name) |                     hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name) | ||||||
|                 else:  # location name |                 else:  # location name | ||||||
|  | @ -929,12 +967,15 @@ class ServerCommandProcessor(CommandProcessor): | ||||||
|                     item = " ".join(item_or_location) |                     item = " ".join(item_or_location) | ||||||
|                     item, usable, response = get_intended_text(item) |                     item, usable, response = get_intended_text(item) | ||||||
|                     if usable: |                     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) |                             hints = collect_hints(self.ctx, team, slot, item) | ||||||
|                             notify_hints(self.ctx, team, hints) |  | ||||||
|                         else:  # location name |                         else:  # location name | ||||||
|                             hints = collect_hints_location(self.ctx, team, slot, item) |                             hints = collect_hints_location(self.ctx, team, slot, item) | ||||||
|                             notify_hints(self.ctx, team, hints) |                         notify_hints(self.ctx, team, hints) | ||||||
|                         return True |                         return True | ||||||
|                     else: |                     else: | ||||||
|                         self.output(response) |                         self.output(response) | ||||||
|  | @ -997,51 +1038,27 @@ async def main(args: argparse.Namespace): | ||||||
|     ctx = Context(args.host, args.port, args.password, args.location_check_points, args.hint_cost, |     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) |                   not args.disable_item_cheat, args.forfeit_mode, args.remaining_mode) | ||||||
| 
 | 
 | ||||||
|     ctx.data_filename = args.multidata |     data_filename = args.multidata | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|         if not ctx.data_filename: |         if not data_filename: | ||||||
|             import tkinter |             import tkinter | ||||||
|             import tkinter.filedialog |             import tkinter.filedialog | ||||||
|             root = tkinter.Tk() |             root = tkinter.Tk() | ||||||
|             root.withdraw() |             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: |     except Exception as e: | ||||||
|         logging.exception('Failed to read multiworld data (%s)' % e) |         logging.exception('Failed to read multiworld data (%s)' % e) | ||||||
|         return |         raise | ||||||
| 
 | 
 | ||||||
|     ip = args.host if args.host else Utils.get_public_ipv4() |     ctx.init_save(not args.disable_save) | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     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.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ping_timeout=None, |     ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ping_timeout=None, | ||||||
|                                   ping_interval=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, |     logging.info('Hosting game at %s:%d (%s)' % (ip, ctx.port, | ||||||
|                                                  'No password' if not ctx.password else 'Password: %s' % ctx.password)) |                                                  'No password' if not ctx.password else 'Password: %s' % ctx.password)) | ||||||
|     await ctx.server |     await ctx.server | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue