From dc218b79974f5d0418b5d2e200106519256751a0 Mon Sep 17 00:00:00 2001 From: Mrks <68022469+mrkssr@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:56:40 +0200 Subject: [PATCH] LADX: Adding Slot Data For Magpie Tracker (#3582) * wip: LADX slot_data * LADX: slot_data * Sending slot_data to magpie. * Moved sending slot_data from pushing to pull by Magpie request. * Adding EoF newline to tracker.py. * Update Tracker.py * Update __init__.py * Update LinksAwakeningClient.py --------- Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> --- LinksAwakeningClient.py | 5 +++++ worlds/ladx/Tracker.py | 18 +++++++++++++++++- worlds/ladx/__init__.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/LinksAwakeningClient.py b/LinksAwakeningClient.py index a51645fe..29878809 100644 --- a/LinksAwakeningClient.py +++ b/LinksAwakeningClient.py @@ -467,6 +467,8 @@ class LinksAwakeningContext(CommonContext): def __init__(self, server_address: typing.Optional[str], password: typing.Optional[str], magpie: typing.Optional[bool]) -> None: self.client = LinksAwakeningClient() + self.slot_data = {} + if magpie: self.magpie_enabled = True self.magpie = MagpieBridge() @@ -564,6 +566,8 @@ class LinksAwakeningContext(CommonContext): def on_package(self, cmd: str, args: dict): if cmd == "Connected": self.game = self.slot_info[self.slot].game + self.slot_data = args.get("slot_data", {}) + # TODO - use watcher_event if cmd == "ReceivedItems": for index, item in enumerate(args["items"], start=args["index"]): @@ -628,6 +632,7 @@ class LinksAwakeningContext(CommonContext): self.magpie.set_checks(self.client.tracker.all_checks) await self.magpie.set_item_tracker(self.client.item_tracker) await self.magpie.send_gps(self.client.gps_tracker) + self.magpie.slot_data = self.slot_data except Exception: # Don't let magpie errors take out the client pass diff --git a/worlds/ladx/Tracker.py b/worlds/ladx/Tracker.py index 851fca16..5f48b64c 100644 --- a/worlds/ladx/Tracker.py +++ b/worlds/ladx/Tracker.py @@ -149,6 +149,8 @@ class MagpieBridge: item_tracker = None ws = None features = [] + slot_data = {} + async def handler(self, websocket): self.ws = websocket while True: @@ -163,6 +165,9 @@ class MagpieBridge: await self.send_all_inventory() if "checks" in self.features: await self.send_all_checks() + if "slot_data" in self.features: + await self.send_slot_data(self.slot_data) + # Translate renamed IDs back to LADXR IDs @staticmethod def fixup_id(the_id): @@ -222,6 +227,18 @@ class MagpieBridge: return await gps.send_location(self.ws) + async def send_slot_data(self, slot_data): + if not self.ws: + return + + logger.debug("Sending slot_data to magpie.") + message = { + "type": "slot_data", + "slot_data": slot_data + } + + await self.ws.send(json.dumps(message)) + async def serve(self): async with websockets.serve(lambda w: self.handler(w), "", 17026, logger=logger): await asyncio.Future() # run forever @@ -237,4 +254,3 @@ class MagpieBridge: await self.send_all_inventory() else: await self.send_inventory_diffs() - diff --git a/worlds/ladx/__init__.py b/worlds/ladx/__init__.py index c958ef21..79f1fe47 100644 --- a/worlds/ladx/__init__.py +++ b/worlds/ladx/__init__.py @@ -512,3 +512,31 @@ class LinksAwakeningWorld(World): if change and item.name in self.rupees: state.prog_items[self.player]["RUPEES"] -= self.rupees[item.name] return change + + def fill_slot_data(self): + slot_data = {} + + if not self.multiworld.is_race: + # all of these option are NOT used by the LADX- or Text-Client. + # they are used by Magpie tracker (https://github.com/kbranch/Magpie/wiki/Autotracker-API) + # for convenient auto-tracking of the generated settings and adjusting the tracker accordingly + + slot_options = ["instrument_count"] + + slot_options_display_name = [ + "goal", "logic", "tradequest", "rooster", + "experimental_dungeon_shuffle", "experimental_entrance_shuffle", "trendy_game", "gfxmod", + "shuffle_nightmare_keys", "shuffle_small_keys", "shuffle_maps", + "shuffle_compasses", "shuffle_stone_beaks", "shuffle_instruments", "nag_messages" + ] + + # use the default behaviour to grab options + slot_data = self.options.as_dict(*slot_options) + + # for options which should not get the internal int value but the display name use the extra handling + slot_data.update({ + option: value.current_key + for option, value in dataclasses.asdict(self.options).items() if option in slot_options_display_name + }) + + return slot_data