about summary refs log tree commit diff stats
path: root/apworld/context.py
diff options
context:
space:
mode:
Diffstat (limited to 'apworld/context.py')
-rw-r--r--apworld/context.py83
1 files changed, 80 insertions, 3 deletions
diff --git a/apworld/context.py b/apworld/context.py index 52b04ae..86392f9 100644 --- a/apworld/context.py +++ b/apworld/context.py
@@ -49,6 +49,7 @@ class Lingo2Manager:
49 worldports: set[int] 49 worldports: set[int]
50 goaled: bool 50 goaled: bool
51 latches: set[int] 51 latches: set[int]
52 hinted_locations: set[int]
52 53
53 def __init__(self, game_ctx: "Lingo2GameContext", client_ctx: "Lingo2ClientContext"): 54 def __init__(self, game_ctx: "Lingo2GameContext", client_ctx: "Lingo2ClientContext"):
54 self.game_ctx = game_ctx 55 self.game_ctx = game_ctx
@@ -57,8 +58,6 @@ class Lingo2Manager:
57 self.client_ctx.manager = self 58 self.client_ctx.manager = self
58 self.tracker = Tracker(self) 59 self.tracker = Tracker(self)
59 self.keyboard = {} 60 self.keyboard = {}
60 self.worldports = set()
61 self.latches = set()
62 61
63 self.reset() 62 self.reset()
64 63
@@ -69,6 +68,7 @@ class Lingo2Manager:
69 self.worldports = set() 68 self.worldports = set()
70 self.goaled = False 69 self.goaled = False
71 self.latches = set() 70 self.latches = set()
71 self.hinted_locations = set()
72 72
73 def update_keyboard(self, new_keyboard: dict[str, int]) -> dict[str, int]: 73 def update_keyboard(self, new_keyboard: dict[str, int]) -> dict[str, int]:
74 ret: dict[str, int] = {} 74 ret: dict[str, int] = {}
@@ -101,6 +101,12 @@ class Lingo2Manager:
101 101
102 return ret 102 return ret
103 103
104 def update_hinted_locations(self, new_locs: set[int]) -> set[int]:
105 ret = new_locs.difference(self.hinted_locations)
106 self.hinted_locations.update(new_locs)
107
108 return ret
109
104 110
105class Lingo2GameContext: 111class Lingo2GameContext:
106 server: Endpoint | None 112 server: Endpoint | None
@@ -276,6 +282,28 @@ class Lingo2GameContext:
276 282
277 async_start(self.send_msgs([msg]), name="update latches") 283 async_start(self.send_msgs([msg]), name="update latches")
278 284
285 def send_ignored_locations(self, ignored_locations):
286 if self.server is None:
287 return
288
289 msg = {
290 "cmd": "SetIgnoredLocations",
291 "locations": ignored_locations,
292 }
293
294 async_start(self.send_msgs([msg]), name="set ignored locations")
295
296 def send_update_hinted_locations(self, hinted_locations):
297 if self.server is None:
298 return
299
300 msg = {
301 "cmd": "UpdateHintedLocations",
302 "locations": hinted_locations,
303 }
304
305 async_start(self.send_msgs([msg]), name="update hinted locations")
306
279 async def send_msgs(self, msgs: list[Any]) -> None: 307 async def send_msgs(self, msgs: list[Any]) -> None:
280 """ `msgs` JSON serializable """ 308 """ `msgs` JSON serializable """
281 if not self.server or not self.server.socket.open or self.server.socket.closed: 309 if not self.server or not self.server.socket.open or self.server.socket.closed:
@@ -290,6 +318,7 @@ class Lingo2ClientContext(CommonContext):
290 items_handling = 0b111 318 items_handling = 0b111
291 319
292 slot_data: dict[str, Any] | None 320 slot_data: dict[str, Any] | None
321 hints_data_storage_key: str
293 victory_data_storage_key: str 322 victory_data_storage_key: str
294 323
295 def __init__(self, server_address: str | None = None, password: str | None = None): 324 def __init__(self, server_address: str | None = None, password: str | None = None):
@@ -327,10 +356,12 @@ class Lingo2ClientContext(CommonContext):
327 self.manager.tracker.set_checked_locations(self.checked_locations) 356 self.manager.tracker.set_checked_locations(self.checked_locations)
328 self.manager.game_ctx.send_accessible_locations() 357 self.manager.game_ctx.send_accessible_locations()
329 358
359 self.hints_data_storage_key = f"_read_hints_{self.team}_{self.slot}"
330 self.victory_data_storage_key = f"_read_client_status_{self.team}_{self.slot}" 360 self.victory_data_storage_key = f"_read_client_status_{self.team}_{self.slot}"
331 361
332 self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2"), 362 self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2"),
333 self.victory_data_storage_key, self.get_datastorage_key("latches")) 363 self.victory_data_storage_key, self.get_datastorage_key("latches"),
364 self.get_datastorage_key("ignored_locations"))
334 msg_batch = [{ 365 msg_batch = [{
335 "cmd": "Set", 366 "cmd": "Set",
336 "key": self.get_datastorage_key("keyboard1"), 367 "key": self.get_datastorage_key("keyboard1"),
@@ -349,6 +380,12 @@ class Lingo2ClientContext(CommonContext):
349 "default": [], 380 "default": [],
350 "want_reply": True, 381 "want_reply": True,
351 "operations": [{"operation": "default", "value": []}] 382 "operations": [{"operation": "default", "value": []}]
383 }, {
384 "cmd": "Set",
385 "key": self.get_datastorage_key("ignored_locations"),
386 "default": [],
387 "want_reply": True,
388 "operations": [{"operation": "default", "value": []}]
352 }] 389 }]
353 390
354 if self.slot_data.get("shuffle_worldports", False): 391 if self.slot_data.get("shuffle_worldports", False):
@@ -447,6 +484,8 @@ class Lingo2ClientContext(CommonContext):
447 for k, v in args["keys"].items(): 484 for k, v in args["keys"].items():
448 if k == self.victory_data_storage_key: 485 if k == self.victory_data_storage_key:
449 self.handle_status_update(v) 486 self.handle_status_update(v)
487 elif k == self.hints_data_storage_key:
488 self.update_hints()
450 elif cmd == "SetReply": 489 elif cmd == "SetReply":
451 if args["key"] == self.get_datastorage_key("keyboard1"): 490 if args["key"] == self.get_datastorage_key("keyboard1"):
452 self.handle_keyboard_update(1, args) 491 self.handle_keyboard_update(1, args)
@@ -464,6 +503,10 @@ class Lingo2ClientContext(CommonContext):
464 updates = self.manager.update_latches(door_ids) 503 updates = self.manager.update_latches(door_ids)
465 if len(updates) > 0: 504 if len(updates) > 0:
466 self.manager.game_ctx.send_update_latches(updates) 505 self.manager.game_ctx.send_update_latches(updates)
506 elif args["key"] == self.get_datastorage_key("ignored_locations"):
507 self.manager.game_ctx.send_ignored_locations(args["value"])
508 elif args["key"] == self.hints_data_storage_key:
509 self.update_hints()
467 510
468 def get_datastorage_key(self, name: str): 511 def get_datastorage_key(self, name: str):
469 return f"Lingo2_{self.slot}_{name}" 512 return f"Lingo2_{self.slot}_{name}"
@@ -559,6 +602,36 @@ class Lingo2ClientContext(CommonContext):
559 }] 602 }]
560 }]) 603 }])
561 604
605 async def add_ignored_location(self, loc_id: int):
606 await self.send_msgs([{
607 "cmd": "Set",
608 "key": self.get_datastorage_key("ignored_locations"),
609 "want_reply": True,
610 "operations": [{
611 "operation": "update",
612 "value": [loc_id]
613 }]
614 }])
615
616 async def remove_ignored_location(self, loc_id: int):
617 await self.send_msgs([{
618 "cmd": "Set",
619 "key": self.get_datastorage_key("ignored_locations"),
620 "want_reply": True,
621 "operations": [{
622 "operation": "remove",
623 "value": loc_id
624 }]
625 }])
626
627 def update_hints(self):
628 hints = self.stored_data.get(self.hints_data_storage_key, [])
629
630 hinted_locations = set(hint["location"] for hint in hints if hint["finding_player"] == self.slot)
631 updates = self.manager.update_hinted_locations(hinted_locations)
632 if len(updates) > 0:
633 self.manager.game_ctx.send_update_hinted_locations(updates)
634
562 635
563async def pipe_loop(manager: Lingo2Manager): 636async def pipe_loop(manager: Lingo2Manager):
564 while not manager.client_ctx.exit_event.is_set(): 637 while not manager.client_ctx.exit_event.is_set():
@@ -635,6 +708,10 @@ async def process_game_cmd(manager: Lingo2Manager, args: dict):
635 updates = manager.update_latches({args["door"]}) 708 updates = manager.update_latches({args["door"]})
636 if len(updates) > 0: 709 if len(updates) > 0:
637 async_start(manager.client_ctx.update_latches(updates), name="client update latches") 710 async_start(manager.client_ctx.update_latches(updates), name="client update latches")
711 elif cmd == "IgnoreLocation":
712 async_start(manager.client_ctx.add_ignored_location(args["id"]), name="client ignore loc")
713 elif cmd == "UnignoreLocation":
714 async_start(manager.client_ctx.remove_ignored_location(args["id"]), name="client unignore loc")
638 elif cmd == "Quit": 715 elif cmd == "Quit":
639 manager.client_ctx.exit_event.set() 716 manager.client_ctx.exit_event.set()
640 717