| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | import asyncio | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import multiprocessing | 
					
						
							|  |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  | import zipfile | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | from asyncio import StreamReader, StreamWriter | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-30 00:36:30 +02:00
										 |  |  | # CommonClient import first to trigger ModuleUpdater | 
					
						
							|  |  |  | from CommonClient import CommonContext, server_loop, gui_enabled, \ | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |     ClientCommandProcessor, logger, get_base_parser | 
					
						
							|  |  |  | import Utils | 
					
						
							| 
									
										
										
										
											2022-11-02 07:51:35 -07:00
										 |  |  | from Utils import async_start | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | from worlds import network_data_package | 
					
						
							|  |  |  | from worlds.oot.Rom import Rom, compress_rom_file | 
					
						
							|  |  |  | from worlds.oot.N64Patch import apply_patch_file | 
					
						
							|  |  |  | from worlds.oot.Utils import data_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-15 00:17:33 -07:00
										 |  |  | CONNECTION_TIMING_OUT_STATUS = "Connection timing out. Please restart your emulator, then restart connector_oot.lua" | 
					
						
							|  |  |  | CONNECTION_REFUSED_STATUS = "Connection refused. Please start your emulator and make sure connector_oot.lua is running" | 
					
						
							|  |  |  | CONNECTION_RESET_STATUS = "Connection was reset. Please restart your emulator, then restart connector_oot.lua" | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | CONNECTION_TENTATIVE_STATUS = "Initial Connection Made" | 
					
						
							|  |  |  | CONNECTION_CONNECTED_STATUS = "Connected" | 
					
						
							|  |  |  | CONNECTION_INITIAL_STATUS = "Connection has not been initiated" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | Payload: lua -> client | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     playerName: string, | 
					
						
							|  |  |  |     locations: dict, | 
					
						
							|  |  |  |     deathlinkActive: bool, | 
					
						
							|  |  |  |     isDead: bool, | 
					
						
							|  |  |  |     gameComplete: bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Payload: client -> lua | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     items: list, | 
					
						
							|  |  |  |     playerNames: list, | 
					
						
							|  |  |  |     triggerDeath: bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Deathlink logic: | 
					
						
							|  |  |  | "Dead" is true <-> Link is at 0 hp. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | deathlink_pending: we need to kill the player | 
					
						
							|  |  |  | deathlink_sent_this_death: we interacted with the multiworld on this death, waiting to reset with living link | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | oot_loc_name_to_id = network_data_package["games"]["Ocarina of Time"]["location_name_to_id"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  | script_version: int = 3 | 
					
						
							| 
									
										
										
										
											2022-04-27 22:11:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | def get_item_value(ap_id): | 
					
						
							|  |  |  |     return ap_id - 66000 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-27 22:11:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | class OoTCommandProcessor(ClientCommandProcessor): | 
					
						
							|  |  |  |     def __init__(self, ctx):  | 
					
						
							|  |  |  |         super().__init__(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _cmd_n64(self): | 
					
						
							|  |  |  |         """Check N64 Connection State""" | 
					
						
							|  |  |  |         if isinstance(self.ctx, OoTContext): | 
					
						
							|  |  |  |             logger.info(f"N64 Status: {self.ctx.n64_status}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-26 01:50:49 -05:00
										 |  |  |     def _cmd_deathlink(self): | 
					
						
							|  |  |  |         """Toggle deathlink from client. Overrides default setting.""" | 
					
						
							|  |  |  |         if isinstance(self.ctx, OoTContext): | 
					
						
							|  |  |  |             self.ctx.deathlink_client_override = True | 
					
						
							|  |  |  |             self.ctx.deathlink_enabled = not self.ctx.deathlink_enabled | 
					
						
							| 
									
										
										
										
											2022-11-02 07:51:35 -07:00
										 |  |  |             async_start(self.ctx.update_death_link(self.ctx.deathlink_enabled), name="Update Deathlink") | 
					
						
							| 
									
										
										
										
											2022-05-26 01:50:49 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | class OoTContext(CommonContext): | 
					
						
							|  |  |  |     command_processor = OoTCommandProcessor | 
					
						
							|  |  |  |     items_handling = 0b001  # full local | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, server_address, password): | 
					
						
							|  |  |  |         super().__init__(server_address, password) | 
					
						
							|  |  |  |         self.game = 'Ocarina of Time' | 
					
						
							|  |  |  |         self.n64_streams: (StreamReader, StreamWriter) = None | 
					
						
							|  |  |  |         self.n64_sync_task = None | 
					
						
							|  |  |  |         self.n64_status = CONNECTION_INITIAL_STATUS | 
					
						
							|  |  |  |         self.awaiting_rom = False | 
					
						
							|  |  |  |         self.location_table = {} | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |         self.collectible_table = {} | 
					
						
							|  |  |  |         self.collectible_override_flags_address = 0 | 
					
						
							|  |  |  |         self.collectible_offsets = {} | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |         self.deathlink_enabled = False | 
					
						
							|  |  |  |         self.deathlink_pending = False | 
					
						
							|  |  |  |         self.deathlink_sent_this_death = False | 
					
						
							| 
									
										
										
										
											2022-05-26 01:50:49 -05:00
										 |  |  |         self.deathlink_client_override = False | 
					
						
							| 
									
										
										
										
											2022-05-25 23:10:51 -05:00
										 |  |  |         self.version_warning = False | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     async def server_auth(self, password_requested: bool = False): | 
					
						
							|  |  |  |         if password_requested and not self.password: | 
					
						
							|  |  |  |             await super(OoTContext, self).server_auth(password_requested) | 
					
						
							|  |  |  |         if not self.auth: | 
					
						
							|  |  |  |             self.awaiting_rom = True | 
					
						
							| 
									
										
										
										
											2023-06-26 16:53:44 +10:00
										 |  |  |             logger.info('Awaiting connection to EmuHawk to get player information') | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await self.send_connect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def on_deathlink(self, data: dict): | 
					
						
							|  |  |  |         self.deathlink_pending = True | 
					
						
							|  |  |  |         super().on_deathlink(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-27 22:11:11 +02:00
										 |  |  |     def run_gui(self): | 
					
						
							|  |  |  |         from kvui import GameManager | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class OoTManager(GameManager): | 
					
						
							|  |  |  |             logging_pairs = [ | 
					
						
							|  |  |  |                 ("Client", "Archipelago") | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             base_title = "Archipelago Ocarina of Time Client" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.ui = OoTManager(self) | 
					
						
							|  |  |  |         self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |     def on_package(self, cmd, args): | 
					
						
							|  |  |  |         if cmd == 'Connected': | 
					
						
							|  |  |  |             slot_data = args.get('slot_data', None) | 
					
						
							|  |  |  |             if slot_data: | 
					
						
							|  |  |  |                 self.collectible_override_flags_address = slot_data.get('collectible_override_flags', 0) | 
					
						
							|  |  |  |                 self.collectible_offsets = slot_data.get('collectible_flag_offsets', {}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | def get_payload(ctx: OoTContext): | 
					
						
							|  |  |  |     if ctx.deathlink_enabled and ctx.deathlink_pending: | 
					
						
							|  |  |  |         trigger_death = True | 
					
						
							|  |  |  |         ctx.deathlink_sent_this_death = True | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         trigger_death = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |     payload = json.dumps({ | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |             "items": [get_item_value(item.item) for item in ctx.items_received], | 
					
						
							|  |  |  |             "playerNames": [name for (i, name) in ctx.player_names.items() if i != 0], | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |             "triggerDeath": trigger_death, | 
					
						
							|  |  |  |             "collectibleOverrides": ctx.collectible_override_flags_address, | 
					
						
							|  |  |  |             "collectibleOffsets": ctx.collectible_offsets | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |     return payload | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async def parse_payload(payload: dict, ctx: OoTContext, force: bool): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 01:32:08 -07:00
										 |  |  |     # Refuse to do anything if ROM is detected as changed | 
					
						
							|  |  |  |     if ctx.auth and payload['playerName'] != ctx.auth: | 
					
						
							|  |  |  |         logger.warning("ROM change detected. Disconnecting and reconnecting...") | 
					
						
							|  |  |  |         ctx.deathlink_enabled = False | 
					
						
							|  |  |  |         ctx.deathlink_client_override = False | 
					
						
							|  |  |  |         ctx.finished_game = False | 
					
						
							|  |  |  |         ctx.location_table = {} | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |         ctx.collectible_table = {} | 
					
						
							| 
									
										
										
										
											2022-11-02 01:32:08 -07:00
										 |  |  |         ctx.deathlink_pending = False | 
					
						
							|  |  |  |         ctx.deathlink_sent_this_death = False | 
					
						
							|  |  |  |         ctx.auth = payload['playerName'] | 
					
						
							|  |  |  |         await ctx.send_connect() | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-26 01:50:49 -05:00
										 |  |  |     # Turn on deathlink if it is on, and if the client hasn't overriden it | 
					
						
							|  |  |  |     if payload['deathlinkActive'] and not ctx.deathlink_enabled and not ctx.deathlink_client_override: | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |         await ctx.update_death_link(True) | 
					
						
							|  |  |  |         ctx.deathlink_enabled = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Game completion handling | 
					
						
							|  |  |  |     if payload['gameComplete'] and not ctx.finished_game: | 
					
						
							|  |  |  |         await ctx.send_msgs([{ | 
					
						
							|  |  |  |             "cmd": "StatusUpdate", | 
					
						
							|  |  |  |             "status": 30 | 
					
						
							|  |  |  |         }]) | 
					
						
							|  |  |  |         ctx.finished_game = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Locations handling | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |     locations = payload['locations'] | 
					
						
							|  |  |  |     collectibles = payload['collectibles'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-15 17:45:31 -06:00
										 |  |  |     # The Lua JSON library serializes an empty table into a list instead of a dict. Verify types for safety: | 
					
						
							|  |  |  |     if isinstance(locations, list): | 
					
						
							|  |  |  |         locations = {} | 
					
						
							|  |  |  |     if isinstance(collectibles, list): | 
					
						
							|  |  |  |         collectibles = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |     if ctx.location_table != locations or ctx.collectible_table != collectibles: | 
					
						
							|  |  |  |         ctx.location_table = locations | 
					
						
							|  |  |  |         ctx.collectible_table = collectibles | 
					
						
							|  |  |  |         locs1 = [oot_loc_name_to_id[loc] for loc, b in ctx.location_table.items() if b] | 
					
						
							|  |  |  |         locs2 = [int(loc) for loc, b in ctx.collectible_table.items() if b] | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |         await ctx.send_msgs([{ | 
					
						
							|  |  |  |             "cmd": "LocationChecks", | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |             "locations": locs1 + locs2 | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |         }]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Deathlink handling | 
					
						
							|  |  |  |     if ctx.deathlink_enabled: | 
					
						
							|  |  |  |         if payload['isDead']: # link is dead | 
					
						
							|  |  |  |             ctx.deathlink_pending = False | 
					
						
							|  |  |  |             if not ctx.deathlink_sent_this_death: | 
					
						
							|  |  |  |                 ctx.deathlink_sent_this_death = True | 
					
						
							|  |  |  |                 await ctx.send_death() | 
					
						
							|  |  |  |         else: # link is alive | 
					
						
							|  |  |  |             ctx.deathlink_sent_this_death = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async def n64_sync_task(ctx: OoTContext):  | 
					
						
							|  |  |  |     logger.info("Starting n64 connector. Use /n64 for status information.") | 
					
						
							|  |  |  |     while not ctx.exit_event.is_set(): | 
					
						
							|  |  |  |         error_status = None | 
					
						
							|  |  |  |         if ctx.n64_streams: | 
					
						
							|  |  |  |             (reader, writer) = ctx.n64_streams | 
					
						
							|  |  |  |             msg = get_payload(ctx).encode() | 
					
						
							|  |  |  |             writer.write(msg) | 
					
						
							|  |  |  |             writer.write(b'\n') | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 await asyncio.wait_for(writer.drain(), timeout=1.5) | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     data = await asyncio.wait_for(reader.readline(), timeout=10) | 
					
						
							|  |  |  |                     data_decoded = json.loads(data.decode()) | 
					
						
							| 
									
										
										
										
											2022-05-25 23:10:51 -05:00
										 |  |  |                     reported_version = data_decoded.get('scriptVersion', 0) | 
					
						
							| 
									
										
										
										
											2022-07-24 20:07:22 -04:00
										 |  |  |                     if reported_version >= script_version: | 
					
						
							| 
									
										
										
										
											2022-05-25 23:10:51 -05:00
										 |  |  |                         if ctx.game is not None and 'locations' in data_decoded: | 
					
						
							|  |  |  |                             # Not just a keep alive ping, parse | 
					
						
							| 
									
										
										
										
											2022-11-02 07:51:35 -07:00
										 |  |  |                             async_start(parse_payload(data_decoded, ctx, False)) | 
					
						
							| 
									
										
										
										
											2022-05-25 23:10:51 -05:00
										 |  |  |                         if not ctx.auth: | 
					
						
							|  |  |  |                             ctx.auth = data_decoded['playerName'] | 
					
						
							|  |  |  |                             if ctx.awaiting_rom: | 
					
						
							|  |  |  |                                 await ctx.server_auth(False) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         if not ctx.version_warning: | 
					
						
							|  |  |  |                             logger.warning(f"Your Lua script is version {reported_version}, expected {script_version}. " | 
					
						
							|  |  |  |                                 "Please update to the latest version. " | 
					
						
							|  |  |  |                                 "Your connection to the Archipelago server will not be accepted.") | 
					
						
							|  |  |  |                             ctx.version_warning = True | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |                 except asyncio.TimeoutError: | 
					
						
							|  |  |  |                     logger.debug("Read Timed Out, Reconnecting") | 
					
						
							|  |  |  |                     error_status = CONNECTION_TIMING_OUT_STATUS | 
					
						
							|  |  |  |                     writer.close() | 
					
						
							|  |  |  |                     ctx.n64_streams = None | 
					
						
							|  |  |  |                 except ConnectionResetError as e: | 
					
						
							|  |  |  |                     logger.debug("Read failed due to Connection Lost, Reconnecting") | 
					
						
							|  |  |  |                     error_status = CONNECTION_RESET_STATUS | 
					
						
							|  |  |  |                     writer.close() | 
					
						
							|  |  |  |                     ctx.n64_streams = None | 
					
						
							|  |  |  |             except TimeoutError: | 
					
						
							|  |  |  |                 logger.debug("Connection Timed Out, Reconnecting") | 
					
						
							|  |  |  |                 error_status = CONNECTION_TIMING_OUT_STATUS | 
					
						
							|  |  |  |                 writer.close() | 
					
						
							|  |  |  |                 ctx.n64_streams = None | 
					
						
							|  |  |  |             except ConnectionResetError: | 
					
						
							|  |  |  |                 logger.debug("Connection Lost, Reconnecting") | 
					
						
							|  |  |  |                 error_status = CONNECTION_RESET_STATUS | 
					
						
							|  |  |  |                 writer.close() | 
					
						
							|  |  |  |                 ctx.n64_streams = None | 
					
						
							|  |  |  |             if ctx.n64_status == CONNECTION_TENTATIVE_STATUS: | 
					
						
							|  |  |  |                 if not error_status: | 
					
						
							|  |  |  |                     logger.info("Successfully Connected to N64") | 
					
						
							|  |  |  |                     ctx.n64_status = CONNECTION_CONNECTED_STATUS | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     ctx.n64_status = f"Was tentatively connected but error occured: {error_status}" | 
					
						
							|  |  |  |             elif error_status: | 
					
						
							|  |  |  |                 ctx.n64_status = error_status | 
					
						
							|  |  |  |                 logger.info("Lost connection to N64 and attempting to reconnect. Use /n64 for status updates") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 logger.debug("Attempting to connect to N64") | 
					
						
							|  |  |  |                 ctx.n64_streams = await asyncio.wait_for(asyncio.open_connection("localhost", 28921), timeout=10) | 
					
						
							|  |  |  |                 ctx.n64_status = CONNECTION_TENTATIVE_STATUS | 
					
						
							|  |  |  |             except TimeoutError: | 
					
						
							|  |  |  |                 logger.debug("Connection Timed Out, Trying Again") | 
					
						
							|  |  |  |                 ctx.n64_status = CONNECTION_TIMING_OUT_STATUS | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             except ConnectionRefusedError: | 
					
						
							|  |  |  |                 logger.debug("Connection Refused, Trying Again") | 
					
						
							|  |  |  |                 ctx.n64_status = CONNECTION_REFUSED_STATUS | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async def run_game(romfile): | 
					
						
							|  |  |  |     auto_start = Utils.get_options()["oot_options"].get("rom_start", True) | 
					
						
							|  |  |  |     if auto_start is True: | 
					
						
							|  |  |  |         import webbrowser | 
					
						
							|  |  |  |         webbrowser.open(romfile) | 
					
						
							|  |  |  |     elif os.path.isfile(auto_start): | 
					
						
							|  |  |  |         subprocess.Popen([auto_start, romfile], | 
					
						
							|  |  |  |                          stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async def patch_and_run_game(apz5_file): | 
					
						
							| 
									
										
										
										
											2022-12-10 21:11:40 -06:00
										 |  |  |     apz5_file = os.path.abspath(apz5_file) | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |     base_name = os.path.splitext(apz5_file)[0] | 
					
						
							|  |  |  |     decomp_path = base_name + '-decomp.z64' | 
					
						
							|  |  |  |     comp_path = base_name + '.z64' | 
					
						
							|  |  |  |     # Load vanilla ROM, patch file, compress ROM | 
					
						
							| 
									
										
										
										
											2023-03-29 20:14:45 +02:00
										 |  |  |     rom_file_name = Utils.get_options()["oot_options"]["rom_file"] | 
					
						
							|  |  |  |     rom = Rom(rom_file_name) | 
					
						
							| 
									
										
										
										
											2023-04-15 17:45:31 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sub_file = None | 
					
						
							|  |  |  |     if zipfile.is_zipfile(apz5_file): | 
					
						
							|  |  |  |         for name in zipfile.ZipFile(apz5_file).namelist(): | 
					
						
							|  |  |  |             if name.endswith('.zpf'): | 
					
						
							|  |  |  |                 sub_file = name | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     apply_patch_file(rom, apz5_file, sub_file=sub_file) | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |     rom.write_to_file(decomp_path) | 
					
						
							|  |  |  |     os.chdir(data_path("Compress")) | 
					
						
							|  |  |  |     compress_rom_file(decomp_path, comp_path) | 
					
						
							|  |  |  |     os.remove(decomp_path) | 
					
						
							| 
									
										
										
										
											2022-11-02 07:51:35 -07:00
										 |  |  |     async_start(run_game(comp_path)) | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Utils.init_logging("OoTClient") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async def main(): | 
					
						
							|  |  |  |         multiprocessing.freeze_support() | 
					
						
							|  |  |  |         parser = get_base_parser() | 
					
						
							|  |  |  |         parser.add_argument('apz5_file', default="", type=str, nargs="?", | 
					
						
							|  |  |  |                             help='Path to an APZ5 file') | 
					
						
							|  |  |  |         args = parser.parse_args() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if args.apz5_file: | 
					
						
							|  |  |  |             logger.info("APZ5 file supplied, beginning patching process...") | 
					
						
							| 
									
										
										
										
											2022-11-02 07:51:35 -07:00
										 |  |  |             async_start(patch_and_run_game(args.apz5_file)) | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ctx = OoTContext(args.connect, args.password) | 
					
						
							|  |  |  |         ctx.server_task = asyncio.create_task(server_loop(ctx), name="Server Loop") | 
					
						
							|  |  |  |         if gui_enabled: | 
					
						
							| 
									
										
										
										
											2022-04-27 22:11:11 +02:00
										 |  |  |             ctx.run_gui() | 
					
						
							|  |  |  |         ctx.run_cli() | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ctx.n64_sync_task = asyncio.create_task(n64_sync_task(ctx), name="N64 Sync") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await ctx.exit_event.wait() | 
					
						
							|  |  |  |         ctx.server_address = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await ctx.shutdown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ctx.n64_sync_task: | 
					
						
							|  |  |  |             await ctx.n64_sync_task | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     import colorama | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     colorama.init() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-27 22:11:11 +02:00
										 |  |  |     asyncio.run(main()) | 
					
						
							| 
									
										
										
										
											2022-03-27 14:44:22 -05:00
										 |  |  |     colorama.deinit() |