import time import struct from socket import socket, AF_INET, SOCK_STREAM import pymem from pymem.exception import ProcessNotFound, ProcessError from CommonClient import logger from worlds.jakanddaxter.locs import CellLocations as Cells, ScoutLocations as Flies, OrbLocations as Orbs from worlds.jakanddaxter.GameID import jak1_id class JakAndDaxterReplClient: ip: str port: int sock: socket connected: bool = False initiated_connect: bool = False # Signals when user tells us to try reconnecting. # The REPL client needs the REPL/compiler process running, but that process # also needs the game running. Therefore, the REPL client needs both running. gk_process: pymem.process = None goalc_process: pymem.process = None item_inbox = {} inbox_index = 0 def __init__(self, ip: str = "127.0.0.1", port: int = 8181): self.ip = ip self.port = port self.connect() async def main_tick(self): if self.initiated_connect: await self.connect() self.initiated_connect = False if self.connected: try: self.gk_process.read_bool(self.gk_process.base_address) # Ping to see if it's alive. except ProcessError: logger.error("The gk process has died. Restart the game and run \"/repl connect\" again.") self.connected = False try: self.goalc_process.read_bool(self.goalc_process.base_address) # Ping to see if it's alive. except ProcessError: logger.error("The goalc process has died. Restart the compiler and run \"/repl connect\" again.") self.connected = False else: return # Receive Items from AP. Handle 1 item per tick. if len(self.item_inbox) > self.inbox_index: self.receive_item() self.inbox_index += 1 # This helper function formats and sends `form` as a command to the REPL. # ALL commands to the REPL should be sent using this function. # TODO - this blocks on receiving an acknowledgement from the REPL server. But it doesn't print # any log info in the meantime. Is that a problem? def send_form(self, form: str, print_ok: bool = True) -> bool: header = struct.pack(" jak1_id + Orbs.orb_offset: pass # TODO def receive_power_cell(self, ap_id: int) -> bool: cell_id = Cells.to_game_id(ap_id) ok = self.send_form("(send-event " "*target* \'get-archipelago " "(pickup-type fuel-cell) " "(the float " + str(cell_id) + "))") if ok: logger.info(f"Received power cell {cell_id}!") else: logger.error(f"Unable to receive power cell {cell_id}!") return ok def receive_scout_fly(self, ap_id: int) -> bool: fly_id = Flies.to_game_id(ap_id) ok = self.send_form("(send-event " "*target* \'get-archipelago " "(pickup-type buzzer) " "(the float " + str(fly_id) + "))") if ok: logger.info(f"Received scout fly {fly_id}!") else: logger.error(f"Unable to receive scout fly {fly_id}!") return ok