Jak 1: There's magic in the air...

This commit is contained in:
massimilianodelliubaldini
2024-04-29 22:42:52 -04:00
parent 801e50b817
commit 75461d62a0
7 changed files with 60 additions and 25 deletions

View File

@@ -6,9 +6,9 @@ import colorama
import Utils
from CommonClient import ClientCommandProcessor, CommonContext, logger, server_loop, gui_enabled
from .GameID import jak1_name
from .client.ReplClient import JakAndDaxterReplClient
from .client.MemoryReader import JakAndDaxterMemoryReader
from worlds.jakanddaxter.GameID import jak1_name
from worlds.jakanddaxter.client.ReplClient import JakAndDaxterReplClient
from worlds.jakanddaxter.client.MemoryReader import JakAndDaxterMemoryReader
import ModuleUpdate
ModuleUpdate.update()
@@ -96,9 +96,16 @@ class JakAndDaxterContext(CommonContext):
self.ui = JakAndDaxterManager(self)
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
async def server_auth(self, password_requested: bool = False):
if password_requested and not self.password:
await super(JakAndDaxterContext, self).server_auth(password_requested)
await self.get_username()
await self.send_connect()
def on_package(self, cmd: str, args: dict):
if cmd == "ReceivedItems":
for index, item in enumerate(args["items"], start=args["index"]):
logger.info(args)
self.repl.item_inbox[index] = item
async def ap_inform_location_checks(self, location_ids: typing.List[int]):
@@ -109,12 +116,14 @@ class JakAndDaxterContext(CommonContext):
create_task_log_exception(self.ap_inform_location_checks(location_ids))
async def run_repl_loop(self):
await self.repl.main_tick()
await asyncio.sleep(0.1)
while True:
await self.repl.main_tick()
await asyncio.sleep(0.1)
async def run_memr_loop(self):
await self.memr.main_tick(self.on_locations)
await asyncio.sleep(0.1)
while True:
await self.memr.main_tick(self.on_locations)
await asyncio.sleep(0.1)
async def main():
@@ -139,4 +148,4 @@ async def main():
def launch():
colorama.init()
asyncio.run(main())
colorama.deinit()
colorama.deinit()

View File

@@ -2,7 +2,7 @@ import typing
from enum import Enum, auto
from BaseClasses import MultiWorld, Region
from .GameID import jak1_name
from .Options import JakAndDaxterOptions
from .JakAndDaxterOptions import JakAndDaxterOptions
from .Locations import JakAndDaxterLocation, location_table
from .locs import CellLocations as Cells, ScoutLocations as Scouts

View File

@@ -1,5 +1,5 @@
from BaseClasses import MultiWorld, CollectionState
from .Options import JakAndDaxterOptions
from .JakAndDaxterOptions import JakAndDaxterOptions
from .Regions import Jak1Level, Jak1SubLevel, level_table, subLevel_table
from .Locations import location_table as item_table
from .locs import CellLocations as Cells, ScoutLocations as Scouts

View File

@@ -1,6 +1,6 @@
from BaseClasses import Item, ItemClassification, Tutorial
from .GameID import jak1_id, jak1_name
from .Options import JakAndDaxterOptions
from .JakAndDaxterOptions import JakAndDaxterOptions
from .Items import JakAndDaxterItem
from .Locations import JakAndDaxterLocation, location_table as item_table
from .locs import CellLocations as Cells, ScoutLocations as Scouts, OrbLocations as Orbs

View File

@@ -1,8 +1,9 @@
import typing
import subprocess
import pymem
from pymem import pattern
from pymem.exception import ProcessNotFound
from CommonClient import logger
from worlds.jakanddaxter.locs import CellLocations as Cells, ScoutLocations as Flies
# Some helpful constants.
@@ -18,7 +19,7 @@ class JakAndDaxterMemoryReader:
connected: bool = False
marked: bool = False
process = None
process: pymem.process = None
marker_address = None
goal_address = None
@@ -33,17 +34,20 @@ class JakAndDaxterMemoryReader:
async def main_tick(self, location_callback: typing.Callable):
self.read_memory()
location_callback(self.location_outbox)
# Checked Locations in game. Handle 1 location per tick.
# Checked Locations in game. Handle the entire outbox every tick until we're up to speed.
if len(self.location_outbox) > self.outbox_index:
await location_callback(self.location_outbox[self.outbox_index])
location_callback(self.location_outbox)
self.outbox_index += 1
def connect(self) -> bool:
try:
self.process = pymem.Pymem("gk.exe") # The GOAL Kernel
logger.info("Found the gk process: " + str(self.process.process_id))
return True
except ProcessNotFound:
logger.error("Could not find the gk process.")
return False
def find_marker(self) -> bool:
@@ -59,19 +63,40 @@ class JakAndDaxterMemoryReader:
self.goal_address = int.from_bytes(self.process.read_bytes(goal_pointer, 8),
byteorder="little",
signed=False)
logger.info("Found the archipelago memory address: " + str(self.goal_address))
return True
logger.error("Could not find the archipelago memory address.")
return False
def read_memory(self) -> typing.List[int]:
next_cell_index = int.from_bytes(self.process.read_bytes(self.goal_address, 8))
next_buzzer_index = int.from_bytes(self.process.read_bytes(self.goal_address + next_buzzer_index_offset, 8))
next_cell = int.from_bytes(self.process.read_bytes(self.goal_address + cells_offset + (next_cell_index * 4), 4))
next_buzzer = int.from_bytes(self.process.read_bytes(self.goal_address + cells_offset + (next_buzzer_index * 4), 4))
next_cell_index = int.from_bytes(
self.process.read_bytes(self.goal_address, 8),
byteorder="little",
signed=False)
next_buzzer_index = int.from_bytes(
self.process.read_bytes(self.goal_address + next_buzzer_index_offset, 8),
byteorder="little",
signed=False)
if next_cell not in self.location_outbox:
self.location_outbox.append(Cells.to_ap_id(next_cell))
if next_buzzer not in self.location_outbox:
self.location_outbox.append(Flies.to_ap_id(next_buzzer))
for k in range(0, next_cell_index):
next_cell = int.from_bytes(
self.process.read_bytes(self.goal_address + cells_offset + (k * 4), 4),
byteorder="little",
signed=False)
cell_ap_id = Cells.to_ap_id(next_cell)
if cell_ap_id not in self.location_outbox:
self.location_outbox.append(cell_ap_id)
logger.info("Checked power cell: " + str(next_cell))
for k in range(0, next_buzzer_index):
next_buzzer = int.from_bytes(
self.process.read_bytes(self.goal_address + buzzers_offset + (k * 4), 4),
byteorder="little",
signed=False)
buzzer_ap_id = Flies.to_ap_id(next_buzzer)
if buzzer_ap_id not in self.location_outbox:
self.location_outbox.append(buzzer_ap_id)
logger.info("Checked scout fly: " + str(next_buzzer))
return self.location_outbox

View File

@@ -54,7 +54,8 @@ class JakAndDaxterReplClient:
time.sleep(1)
logger.info(self.socket.recv(1024).decode())
return True
except ConnectionRefusedError:
except ConnectionRefusedError as e:
logger.error(e.strerror)
return False
def listen(self) -> bool:
@@ -96,7 +97,7 @@ class JakAndDaxterReplClient:
return True
def receive_item(self):
ap_id = self.item_inbox[self.inbox_index]["item"]
ap_id = getattr(self.item_inbox[self.inbox_index], "item")
# Determine the type of item to receive.
if ap_id in range(jak1_id, jak1_id + Flies.fly_offset):