diff --git a/worlds/jakanddaxter/Client.py b/worlds/jakanddaxter/Client.py index f71e94ef75..77db95350b 100644 --- a/worlds/jakanddaxter/Client.py +++ b/worlds/jakanddaxter/Client.py @@ -160,31 +160,35 @@ class JakAndDaxterContext(CommonContext): async def json_to_game_text(self, args: dict): if "type" in args and args["type"] in {"ItemSend"}: + my_item_name = Optional[str] + my_item_finder = Optional[str] + their_item_name = Optional[str] + their_item_owner = Optional[str] item = args["item"] recipient = args["receiving"] # Receiving an item from the server. if self.slot_concerns_self(recipient): - self.repl.my_item_name = self.item_names.lookup_in_game(item.item) + my_item_name = self.item_names.lookup_in_game(item.item) # Did we find it, or did someone else? if self.slot_concerns_self(item.player): - self.repl.my_item_finder = "MYSELF" + my_item_finder = "MYSELF" else: - self.repl.my_item_finder = self.player_names[item.player] + my_item_finder = self.player_names[item.player] # Sending an item to the server. if self.slot_concerns_self(item.player): - self.repl.their_item_name = self.item_names.lookup_in_slot(item.item, recipient) + their_item_name = self.item_names.lookup_in_slot(item.item, recipient) # Does it belong to us, or to someone else? if self.slot_concerns_self(recipient): - self.repl.their_item_owner = "MYSELF" + their_item_owner = "MYSELF" else: - self.repl.their_item_owner = self.player_names[recipient] + their_item_owner = self.player_names[recipient] # Write to game display. - await self.repl.write_game_text() + self.repl.queue_game_text(my_item_name, my_item_finder, their_item_name, their_item_owner) def on_print_json(self, args: dict) -> None: diff --git a/worlds/jakanddaxter/client/ReplClient.py b/worlds/jakanddaxter/client/ReplClient.py index ed0dd7084f..73009f0ad4 100644 --- a/worlds/jakanddaxter/client/ReplClient.py +++ b/worlds/jakanddaxter/client/ReplClient.py @@ -1,7 +1,10 @@ import json +import queue import time import struct import random +from dataclasses import dataclass +from queue import Queue from typing import Dict, Optional import pymem @@ -22,6 +25,14 @@ from ..locs import ( OrbCacheLocations as Caches) +@dataclass +class JsonMessageData: + my_item_name: Optional[str] = None + my_item_finder: Optional[str] = None + their_item_name: Optional[str] = None + their_item_owner: Optional[str] = None + + class JakAndDaxterReplClient: ip: str port: int @@ -40,11 +51,7 @@ class JakAndDaxterReplClient: item_inbox: Dict[int, NetworkItem] = {} inbox_index = 0 - - my_item_name: Optional[str] = None - my_item_finder: Optional[str] = None - their_item_name: Optional[str] = None - their_item_owner: Optional[str] = None + json_message_queue: Queue[JsonMessageData] = queue.Queue() def __init__(self, ip: str = "127.0.0.1", port: int = 8181): self.ip = ip @@ -81,6 +88,13 @@ class JakAndDaxterReplClient: await self.receive_deathlink() self.received_deathlink = False + # Progressively empty the queue during each tick + # if text messages happen to be too slow we could pool dequeuing here, + # but it'd slow down the ItemReceived message during release + if not self.json_message_queue.empty(): + json_txt_data = self.json_message_queue.get_nowait() + await self.write_game_text(json_txt_data) + # This helper function formats and sends `form` as a command to the REPL. # ALL commands to the REPL should be sent using this function. async def send_form(self, form: str, print_ok: bool = True) -> bool: @@ -203,20 +217,25 @@ class JakAndDaxterReplClient: result = result[:32].upper() return f"\"{result}\"" + # Pushes a JsonMessageData object to the json message queue to be processed during the repl main_tick + def queue_game_text(self, my_item_name, my_item_finder, their_item_name, their_item_owner): + self.json_message_queue.put(self.JsonMessageData(my_item_name, my_item_finder, + their_item_name, their_item_owner)) + # OpenGOAL can handle both its own string datatype and C-like character pointers (charp). # So for the game to constantly display this information in the HUD, we have to write it # to a memory address as a char*. - async def write_game_text(self): + async def write_game_text(self, data: JsonMessageData): logger.debug(f"Sending info to in-game display!") await self.send_form(f"(begin " f" (charp<-string (-> *ap-info-jak1* my-item-name) " - f" {self.sanitize_game_text(self.my_item_name)}) " + f" {self.sanitize_game_text(data.my_item_name)}) " f" (charp<-string (-> *ap-info-jak1* my-item-finder) " - f" {self.sanitize_game_text(self.my_item_finder)}) " + f" {self.sanitize_game_text(data.my_item_finder)}) " f" (charp<-string (-> *ap-info-jak1* their-item-name) " - f" {self.sanitize_game_text(self.their_item_name)}) " + f" {self.sanitize_game_text(data.their_item_name)}) " f" (charp<-string (-> *ap-info-jak1* their-item-owner) " - f" {self.sanitize_game_text(self.their_item_owner)}) " + f" {self.sanitize_game_text(data.their_item_owner)}) " f" (none))", print_ok=False) async def receive_item(self):