diff options
Diffstat (limited to 'apworld/context.py')
| -rw-r--r-- | apworld/context.py | 216 |
1 files changed, 207 insertions, 9 deletions
| diff --git a/apworld/context.py b/apworld/context.py index c367b6c..86392f9 100644 --- a/apworld/context.py +++ b/apworld/context.py | |||
| @@ -2,6 +2,7 @@ import asyncio | |||
| 2 | import os | 2 | import os |
| 3 | import pkgutil | 3 | import pkgutil |
| 4 | import subprocess | 4 | import subprocess |
| 5 | import sys | ||
| 5 | from typing import Any | 6 | from typing import Any |
| 6 | 7 | ||
| 7 | import websockets | 8 | import websockets |
| @@ -29,6 +30,16 @@ KEY_STORAGE_MAPPING = { | |||
| 29 | REVERSE_KEY_STORAGE_MAPPING = {t: k for k, t in KEY_STORAGE_MAPPING.items()} | 30 | REVERSE_KEY_STORAGE_MAPPING = {t: k for k, t in KEY_STORAGE_MAPPING.items()} |
| 30 | 31 | ||
| 31 | 32 | ||
| 33 | # There is a distinction between an object's ID and its AP ID. The latter is stable between releases, whereas the former | ||
| 34 | # can change and is also namespaced based on the object type. We should only store AP IDs in multiworld state (such as | ||
| 35 | # slot data and data storage) to increase compatability between releases. The data we currently store is: | ||
| 36 | # - Port pairings for worldport shuffle (slot data) | ||
| 37 | # - Checked worldports for worldport shuffle (data storage) | ||
| 38 | # - Latched doors (data storage) | ||
| 39 | # The client generally deals in the actual object IDs rather than the stable IDs, although it does have to convert the | ||
| 40 | # port pairing IDs when reading them from slot data. The context (this file here) does the work of converting back and | ||
| 41 | # forth between the values. AP IDs are converted to IDs after reading them from data storage, and IDs are converted to | ||
| 42 | # AP IDs before sending them to data storage. | ||
| 32 | class Lingo2Manager: | 43 | class Lingo2Manager: |
| 33 | game_ctx: "Lingo2GameContext" | 44 | game_ctx: "Lingo2GameContext" |
| 34 | client_ctx: "Lingo2ClientContext" | 45 | client_ctx: "Lingo2ClientContext" |
| @@ -37,6 +48,8 @@ class Lingo2Manager: | |||
| 37 | keyboard: dict[str, int] | 48 | keyboard: dict[str, int] |
| 38 | worldports: set[int] | 49 | worldports: set[int] |
| 39 | goaled: bool | 50 | goaled: bool |
| 51 | latches: set[int] | ||
| 52 | hinted_locations: set[int] | ||
| 40 | 53 | ||
| 41 | def __init__(self, game_ctx: "Lingo2GameContext", client_ctx: "Lingo2ClientContext"): | 54 | def __init__(self, game_ctx: "Lingo2GameContext", client_ctx: "Lingo2ClientContext"): |
| 42 | self.game_ctx = game_ctx | 55 | self.game_ctx = game_ctx |
| @@ -45,7 +58,6 @@ class Lingo2Manager: | |||
| 45 | self.client_ctx.manager = self | 58 | self.client_ctx.manager = self |
| 46 | self.tracker = Tracker(self) | 59 | self.tracker = Tracker(self) |
| 47 | self.keyboard = {} | 60 | self.keyboard = {} |
| 48 | self.worldports = set() | ||
| 49 | 61 | ||
| 50 | self.reset() | 62 | self.reset() |
| 51 | 63 | ||
| @@ -55,6 +67,8 @@ class Lingo2Manager: | |||
| 55 | 67 | ||
| 56 | self.worldports = set() | 68 | self.worldports = set() |
| 57 | self.goaled = False | 69 | self.goaled = False |
| 70 | self.latches = set() | ||
| 71 | self.hinted_locations = set() | ||
| 58 | 72 | ||
| 59 | 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]: |
| 60 | ret: dict[str, int] = {} | 74 | ret: dict[str, int] = {} |
| @@ -70,6 +84,7 @@ class Lingo2Manager: | |||
| 70 | 84 | ||
| 71 | return ret | 85 | return ret |
| 72 | 86 | ||
| 87 | # Input should be real IDs, not AP IDs | ||
| 73 | def update_worldports(self, new_worldports: set[int]) -> set[int]: | 88 | def update_worldports(self, new_worldports: set[int]) -> set[int]: |
| 74 | ret = new_worldports.difference(self.worldports) | 89 | ret = new_worldports.difference(self.worldports) |
| 75 | self.worldports.update(new_worldports) | 90 | self.worldports.update(new_worldports) |
| @@ -80,6 +95,18 @@ class Lingo2Manager: | |||
| 80 | 95 | ||
| 81 | return ret | 96 | return ret |
| 82 | 97 | ||
| 98 | def update_latches(self, new_latches: set[int]) -> set[int]: | ||
| 99 | ret = new_latches.difference(self.latches) | ||
| 100 | self.latches.update(new_latches) | ||
| 101 | |||
| 102 | return ret | ||
| 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 | |||
| 83 | 110 | ||
| 84 | class Lingo2GameContext: | 111 | class Lingo2GameContext: |
| 85 | server: Endpoint | None | 112 | server: Endpoint | None |
| @@ -106,6 +133,17 @@ class Lingo2GameContext: | |||
| 106 | 133 | ||
| 107 | async_start(self.send_msgs([msg]), name="game Connected") | 134 | async_start(self.send_msgs([msg]), name="game Connected") |
| 108 | 135 | ||
| 136 | def send_connection_refused(self, text): | ||
| 137 | if self.server is None: | ||
| 138 | return | ||
| 139 | |||
| 140 | msg = { | ||
| 141 | "cmd": "ConnectionRefused", | ||
| 142 | "text": text, | ||
| 143 | } | ||
| 144 | |||
| 145 | async_start(self.send_msgs([msg]), name="game ConnectionRefused") | ||
| 146 | |||
| 109 | def send_item_sent_notification(self, item_name, receiver_name, item_flags): | 147 | def send_item_sent_notification(self, item_name, receiver_name, item_flags): |
| 110 | if self.server is None: | 148 | if self.server is None: |
| 111 | return | 149 | return |
| @@ -206,6 +244,7 @@ class Lingo2GameContext: | |||
| 206 | 244 | ||
| 207 | async_start(self.send_msgs([msg]), name="update keyboard") | 245 | async_start(self.send_msgs([msg]), name="update keyboard") |
| 208 | 246 | ||
| 247 | # Input should be real IDs, not AP IDs | ||
| 209 | def send_update_worldports(self, worldports): | 248 | def send_update_worldports(self, worldports): |
| 210 | if self.server is None: | 249 | if self.server is None: |
| 211 | return | 250 | return |
| @@ -217,6 +256,54 @@ class Lingo2GameContext: | |||
| 217 | 256 | ||
| 218 | async_start(self.send_msgs([msg]), name="update worldports") | 257 | async_start(self.send_msgs([msg]), name="update worldports") |
| 219 | 258 | ||
| 259 | def send_path_reply(self, object_type: str, object_id: int | None, path: list[str]): | ||
| 260 | if self.server is None: | ||
| 261 | return | ||
| 262 | |||
| 263 | msg = { | ||
| 264 | "cmd": "PathReply", | ||
| 265 | "type": object_type, | ||
| 266 | "path": path, | ||
| 267 | } | ||
| 268 | |||
| 269 | if object_id is not None: | ||
| 270 | msg["id"] = object_id | ||
| 271 | |||
| 272 | async_start(self.send_msgs([msg]), name="path reply") | ||
| 273 | |||
| 274 | def send_update_latches(self, latches): | ||
| 275 | if self.server is None: | ||
| 276 | return | ||
| 277 | |||
| 278 | msg = { | ||
| 279 | "cmd": "UpdateLatches", | ||
| 280 | "latches": latches, | ||
| 281 | } | ||
| 282 | |||
| 283 | async_start(self.send_msgs([msg]), name="update latches") | ||
| 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 | |||
| 220 | async def send_msgs(self, msgs: list[Any]) -> None: | 307 | async def send_msgs(self, msgs: list[Any]) -> None: |
| 221 | """ `msgs` JSON serializable """ | 308 | """ `msgs` JSON serializable """ |
| 222 | 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: |
| @@ -231,6 +318,7 @@ class Lingo2ClientContext(CommonContext): | |||
| 231 | items_handling = 0b111 | 318 | items_handling = 0b111 |
| 232 | 319 | ||
| 233 | slot_data: dict[str, Any] | None | 320 | slot_data: dict[str, Any] | None |
| 321 | hints_data_storage_key: str | ||
| 234 | victory_data_storage_key: str | 322 | victory_data_storage_key: str |
| 235 | 323 | ||
| 236 | 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): |
| @@ -242,8 +330,17 @@ class Lingo2ClientContext(CommonContext): | |||
| 242 | return ui | 330 | return ui |
| 243 | 331 | ||
| 244 | async def server_auth(self, password_requested: bool = False): | 332 | async def server_auth(self, password_requested: bool = False): |
| 245 | self.auth = self.username | 333 | if password_requested and not self.password: |
| 246 | await self.send_connect() | 334 | self.manager.game_ctx.send_connection_refused("Invalid password.") |
| 335 | else: | ||
| 336 | self.auth = self.username | ||
| 337 | await self.send_connect() | ||
| 338 | |||
| 339 | def handle_connection_loss(self, msg: str): | ||
| 340 | super().handle_connection_loss(msg) | ||
| 341 | |||
| 342 | exc_info = sys.exc_info() | ||
| 343 | self.manager.game_ctx.send_connection_refused(str(exc_info[1])) | ||
| 247 | 344 | ||
| 248 | def on_package(self, cmd: str, args: dict): | 345 | def on_package(self, cmd: str, args: dict): |
| 249 | if cmd == "RoomInfo": | 346 | if cmd == "RoomInfo": |
| @@ -259,10 +356,12 @@ class Lingo2ClientContext(CommonContext): | |||
| 259 | self.manager.tracker.set_checked_locations(self.checked_locations) | 356 | self.manager.tracker.set_checked_locations(self.checked_locations) |
| 260 | self.manager.game_ctx.send_accessible_locations() | 357 | self.manager.game_ctx.send_accessible_locations() |
| 261 | 358 | ||
| 359 | self.hints_data_storage_key = f"_read_hints_{self.team}_{self.slot}" | ||
| 262 | 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}" |
| 263 | 361 | ||
| 264 | 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"), |
| 265 | self.victory_data_storage_key) | 363 | self.victory_data_storage_key, self.get_datastorage_key("latches"), |
| 364 | self.get_datastorage_key("ignored_locations")) | ||
| 266 | msg_batch = [{ | 365 | msg_batch = [{ |
| 267 | "cmd": "Set", | 366 | "cmd": "Set", |
| 268 | "key": self.get_datastorage_key("keyboard1"), | 367 | "key": self.get_datastorage_key("keyboard1"), |
| @@ -275,6 +374,18 @@ class Lingo2ClientContext(CommonContext): | |||
| 275 | "default": 0, | 374 | "default": 0, |
| 276 | "want_reply": True, | 375 | "want_reply": True, |
| 277 | "operations": [{"operation": "default", "value": 0}] | 376 | "operations": [{"operation": "default", "value": 0}] |
| 377 | }, { | ||
| 378 | "cmd": "Set", | ||
| 379 | "key": self.get_datastorage_key("latches"), | ||
| 380 | "default": [], | ||
| 381 | "want_reply": True, | ||
| 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": []}] | ||
| 278 | }] | 389 | }] |
| 279 | 390 | ||
| 280 | if self.slot_data.get("shuffle_worldports", False): | 391 | if self.slot_data.get("shuffle_worldports", False): |
| @@ -373,17 +484,29 @@ class Lingo2ClientContext(CommonContext): | |||
| 373 | for k, v in args["keys"].items(): | 484 | for k, v in args["keys"].items(): |
| 374 | if k == self.victory_data_storage_key: | 485 | if k == self.victory_data_storage_key: |
| 375 | self.handle_status_update(v) | 486 | self.handle_status_update(v) |
| 487 | elif k == self.hints_data_storage_key: | ||
| 488 | self.update_hints() | ||
| 376 | elif cmd == "SetReply": | 489 | elif cmd == "SetReply": |
| 377 | if args["key"] == self.get_datastorage_key("keyboard1"): | 490 | if args["key"] == self.get_datastorage_key("keyboard1"): |
| 378 | self.handle_keyboard_update(1, args) | 491 | self.handle_keyboard_update(1, args) |
| 379 | elif args["key"] == self.get_datastorage_key("keyboard2"): | 492 | elif args["key"] == self.get_datastorage_key("keyboard2"): |
| 380 | self.handle_keyboard_update(2, args) | 493 | self.handle_keyboard_update(2, args) |
| 381 | elif args["key"] == self.get_datastorage_key("worldports"): | 494 | elif args["key"] == self.get_datastorage_key("worldports"): |
| 382 | updates = self.manager.update_worldports(set(args["value"])) | 495 | port_ids = set(Lingo2World.static_logic.port_id_by_ap_id[ap_id] for ap_id in args["value"]) |
| 496 | updates = self.manager.update_worldports(port_ids) | ||
| 383 | if len(updates) > 0: | 497 | if len(updates) > 0: |
| 384 | self.manager.game_ctx.send_update_worldports(updates) | 498 | self.manager.game_ctx.send_update_worldports(updates) |
| 385 | elif args["key"] == self.victory_data_storage_key: | 499 | elif args["key"] == self.victory_data_storage_key: |
| 386 | self.handle_status_update(args["value"]) | 500 | self.handle_status_update(args["value"]) |
| 501 | elif args["key"] == self.get_datastorage_key("latches"): | ||
| 502 | door_ids = set(Lingo2World.static_logic.door_id_by_ap_id[ap_id] for ap_id in args["value"]) | ||
| 503 | updates = self.manager.update_latches(door_ids) | ||
| 504 | if len(updates) > 0: | ||
| 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() | ||
| 387 | 510 | ||
| 388 | def get_datastorage_key(self, name: str): | 511 | def get_datastorage_key(self, name: str): |
| 389 | return f"Lingo2_{self.slot}_{name}" | 512 | return f"Lingo2_{self.slot}_{name}" |
| @@ -449,14 +572,16 @@ class Lingo2ClientContext(CommonContext): | |||
| 449 | if len(updates) > 0: | 572 | if len(updates) > 0: |
| 450 | self.manager.game_ctx.send_update_keyboard(updates) | 573 | self.manager.game_ctx.send_update_keyboard(updates) |
| 451 | 574 | ||
| 575 | # Input should be real IDs, not AP IDs | ||
| 452 | async def update_worldports(self, updates: set[int]): | 576 | async def update_worldports(self, updates: set[int]): |
| 577 | port_ap_ids = [Lingo2World.static_logic.objects.ports[port_id].ap_id for port_id in updates] | ||
| 453 | await self.send_msgs([{ | 578 | await self.send_msgs([{ |
| 454 | "cmd": "Set", | 579 | "cmd": "Set", |
| 455 | "key": self.get_datastorage_key("worldports"), | 580 | "key": self.get_datastorage_key("worldports"), |
| 456 | "want_reply": True, | 581 | "want_reply": True, |
| 457 | "operations": [{ | 582 | "operations": [{ |
| 458 | "operation": "update", | 583 | "operation": "update", |
| 459 | "value": updates | 584 | "value": port_ap_ids |
| 460 | }] | 585 | }] |
| 461 | }]) | 586 | }]) |
| 462 | 587 | ||
| @@ -465,6 +590,48 @@ class Lingo2ClientContext(CommonContext): | |||
| 465 | self.manager.tracker.refresh_state() | 590 | self.manager.tracker.refresh_state() |
| 466 | self.manager.game_ctx.send_accessible_locations() | 591 | self.manager.game_ctx.send_accessible_locations() |
| 467 | 592 | ||
| 593 | async def update_latches(self, updates: set[int]): | ||
| 594 | door_ap_ids = [Lingo2World.static_logic.objects.doors[door_id].ap_id for door_id in updates] | ||
| 595 | await self.send_msgs([{ | ||
| 596 | "cmd": "Set", | ||
| 597 | "key": self.get_datastorage_key("latches"), | ||
| 598 | "want_reply": True, | ||
| 599 | "operations": [{ | ||
| 600 | "operation": "update", | ||
| 601 | "value": door_ap_ids | ||
| 602 | }] | ||
| 603 | }]) | ||
| 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 | |||
| 468 | 635 | ||
| 469 | async def pipe_loop(manager: Lingo2Manager): | 636 | async def pipe_loop(manager: Lingo2Manager): |
| 470 | while not manager.client_ctx.exit_event.is_set(): | 637 | while not manager.client_ctx.exit_event.is_set(): |
| @@ -489,6 +656,8 @@ async def process_game_cmd(manager: Lingo2Manager, args: dict): | |||
| 489 | cmd = args["cmd"] | 656 | cmd = args["cmd"] |
| 490 | 657 | ||
| 491 | if cmd == "Connect": | 658 | if cmd == "Connect": |
| 659 | manager.client_ctx.seed_name = None | ||
| 660 | |||
| 492 | server = args.get("server") | 661 | server = args.get("server") |
| 493 | player = args.get("player") | 662 | player = args.get("player") |
| 494 | password = args.get("password") | 663 | password = args.get("password") |
| @@ -500,6 +669,8 @@ async def process_game_cmd(manager: Lingo2Manager, args: dict): | |||
| 500 | 669 | ||
| 501 | async_start(manager.client_ctx.connect(server_address), name="client connect") | 670 | async_start(manager.client_ctx.connect(server_address), name="client connect") |
| 502 | elif cmd == "Disconnect": | 671 | elif cmd == "Disconnect": |
| 672 | manager.client_ctx.seed_name = None | ||
| 673 | |||
| 503 | async_start(manager.client_ctx.disconnect(), name="client disconnect") | 674 | async_start(manager.client_ctx.disconnect(), name="client disconnect") |
| 504 | elif cmd in ["Sync", "LocationChecks", "Say", "StatusUpdate", "LocationScouts"]: | 675 | elif cmd in ["Sync", "LocationChecks", "Say", "StatusUpdate", "LocationScouts"]: |
| 505 | async_start(manager.client_ctx.send_msgs([args]), name="client forward") | 676 | async_start(manager.client_ctx.send_msgs([args]), name="client forward") |
| @@ -509,14 +680,38 @@ async def process_game_cmd(manager: Lingo2Manager, args: dict): | |||
| 509 | async_start(manager.client_ctx.update_keyboard(updates), name="client update keyboard") | 680 | async_start(manager.client_ctx.update_keyboard(updates), name="client update keyboard") |
| 510 | elif cmd == "CheckWorldport": | 681 | elif cmd == "CheckWorldport": |
| 511 | port_id = args["port_id"] | 682 | port_id = args["port_id"] |
| 683 | port_ap_id = Lingo2World.static_logic.objects.ports[port_id].ap_id | ||
| 512 | worldports = {port_id} | 684 | worldports = {port_id} |
| 513 | if str(port_id) in manager.client_ctx.slot_data["port_pairings"]: | 685 | |
| 514 | worldports.add(manager.client_ctx.slot_data["port_pairings"][str(port_id)]) | 686 | # Also check the reverse port if it's a two-way connection. |
| 687 | port_pairings = manager.client_ctx.slot_data["port_pairings"] | ||
| 688 | if str(port_ap_id) in port_pairings and\ | ||
| 689 | port_pairings.get(str(port_pairings[str(port_ap_id)]), None) == port_ap_id: | ||
| 690 | worldports.add(Lingo2World.static_logic.port_id_by_ap_id[port_pairings[str(port_ap_id)]]) | ||
| 515 | 691 | ||
| 516 | updates = manager.update_worldports(worldports) | 692 | updates = manager.update_worldports(worldports) |
| 517 | if len(updates) > 0: | 693 | if len(updates) > 0: |
| 518 | async_start(manager.client_ctx.update_worldports(updates), name="client update worldports") | 694 | async_start(manager.client_ctx.update_worldports(updates), name="client update worldports") |
| 519 | manager.game_ctx.send_update_worldports(updates) | 695 | manager.game_ctx.send_update_worldports(updates) |
| 696 | elif cmd == "GetPath": | ||
| 697 | path = None | ||
| 698 | |||
| 699 | if args["type"] == "location": | ||
| 700 | path = manager.tracker.get_path_to_location(args["id"]) | ||
| 701 | elif args["type"] == "worldport": | ||
| 702 | path = manager.tracker.get_path_to_port(args["id"]) | ||
| 703 | elif args["type"] == "goal": | ||
| 704 | path = manager.tracker.get_path_to_goal() | ||
| 705 | |||
| 706 | manager.game_ctx.send_path_reply(args["type"], args.get("id", None), path) | ||
| 707 | elif cmd == "LatchDoor": | ||
| 708 | updates = manager.update_latches({args["door"]}) | ||
| 709 | if len(updates) > 0: | ||
| 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") | ||
| 520 | elif cmd == "Quit": | 715 | elif cmd == "Quit": |
| 521 | manager.client_ctx.exit_event.set() | 716 | manager.client_ctx.exit_event.set() |
| 522 | 717 | ||
| @@ -564,9 +759,12 @@ async def run_game(): | |||
| 564 | 759 | ||
| 565 | def client_main(*launch_args: str) -> None: | 760 | def client_main(*launch_args: str) -> None: |
| 566 | async def main(args): | 761 | async def main(args): |
| 567 | async_start(run_game()) | 762 | if settings.get_settings().lingo2_options.start_game: |
| 763 | async_start(run_game()) | ||
| 568 | 764 | ||
| 569 | client_ctx = Lingo2ClientContext(args.connect, args.password) | 765 | client_ctx = Lingo2ClientContext(args.connect, args.password) |
| 766 | client_ctx.auth = args.name | ||
| 767 | |||
| 570 | game_ctx = Lingo2GameContext() | 768 | game_ctx = Lingo2GameContext() |
| 571 | manager = Lingo2Manager(game_ctx, client_ctx) | 769 | manager = Lingo2Manager(game_ctx, client_ctx) |
| 572 | 770 | ||
