From adfc639965b2bda776ceb0a20840438e31f82d58 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sun, 2 Nov 2025 12:29:29 -0500 Subject: Allow ignoring locations in tracker --- apworld/client/client.gd | 16 +++++++++ apworld/client/manager.gd | 17 +++++++++ apworld/client/textclient.gd | 82 +++++++++++++++++++++++++++++++++++--------- apworld/context.py | 50 +++++++++++++++++++++++++-- 4 files changed, 146 insertions(+), 19 deletions(-) (limited to 'apworld') diff --git a/apworld/client/client.gd b/apworld/client/client.gd index ce5ac7e..54d3d67 100644 --- a/apworld/client/client.gd +++ b/apworld/client/client.gd @@ -38,6 +38,7 @@ signal hint_received(message) signal door_latched(id) signal accessible_locations_updated signal checked_locations_updated +signal ignored_locations_updated(locations) signal checked_worldports_updated signal keyboard_update_received @@ -199,6 +200,13 @@ func _on_web_socket_server_message_received(_peer_id: int, packet: String) -> vo door_latched.emit(iid) + elif cmd == "SetIgnoredLocations": + var locs = [] + for id in message["locations"]: + locs.append(int(id)) + + ignored_locations_updated.emit(locs) + func connectToServer(server, un, pw): sendMessage([{"cmd": "Connect", "server": server, "player": un, "password": pw}]) @@ -280,6 +288,14 @@ func getLogicalPath(object_type, object_id): sendMessage([msg]) +func addIgnoredLocation(loc_id): + sendMessage([{"cmd": "IgnoreLocation", "id": loc_id}]) + + +func removeIgnoredLocation(loc_id): + sendMessage([{"cmd": "UnignoreLocation", "id": loc_id}]) + + func sendQuit(): sendMessage([{"cmd": "Quit"}]) diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index 727d17a..b7bb5fd 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd @@ -29,6 +29,7 @@ var _inverse_item_locks = {} var _held_letters = {} var _letters_setup = false var _already_connected = false +var _ignored_locations = [] const kSHUFFLE_LETTERS_VANILLA = 0 const kSHUFFLE_LETTERS_UNLOCKED = 1 @@ -144,6 +145,7 @@ func _ready(): client.hint_received.connect(_process_hint_received) client.accessible_locations_updated.connect(_on_accessible_locations_updated) client.checked_locations_updated.connect(_on_checked_locations_updated) + client.ignored_locations_updated.connect(_on_ignored_locations_updated) client.checked_worldports_updated.connect(_on_checked_worldports_updated) client.door_latched.connect(_on_door_latched) @@ -384,6 +386,14 @@ func _on_checked_worldports_updated(): textclient_node.update_worldports() +func _on_ignored_locations_updated(locations): + _ignored_locations = locations + + var textclient_node = global.get_node("Textclient") + if textclient_node != null: + textclient_node.update_locations() + + func _on_door_latched(door_id): var gamedata = global.get_node("Gamedata") if gamedata.get_door_map_name(door_id) != global.map: @@ -677,3 +687,10 @@ func update_job_well_done_sign(): sign2.get_node("MeshInstance3D").mesh.text = sign2.text sign3.get_node("MeshInstance3D").mesh.text = sign3.text + + +func toggle_ignored_location(loc_id): + if loc_id in _ignored_locations: + client.removeIgnoredLocation(loc_id) + else: + client.addIgnoredLocation(loc_id) diff --git a/apworld/client/textclient.gd b/apworld/client/textclient.gd index f785a03..8356f92 100644 --- a/apworld/client/textclient.gd +++ b/apworld/client/textclient.gd @@ -16,6 +16,7 @@ var tracker_loc_tree_item_by_id = {} var tracker_port_tree_item_by_id = {} var tracker_goal_tree_item = null var tracker_object_by_index = {} +var tracker_object_by_ignored_index = {} var worldports_tab var worldports_tree @@ -99,7 +100,7 @@ func _ready(): tabs.add_child(tracker_margins) tracker_tree = Tree.new() - tracker_tree.columns = 3 + tracker_tree.columns = 4 tracker_tree.hide_root = true tracker_tree.add_theme_font_size_override("font_size", 24) tracker_tree.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1)) @@ -108,7 +109,9 @@ func _ready(): tracker_tree.set_column_expand(0, false) tracker_tree.set_column_expand(1, true) tracker_tree.set_column_expand(2, false) + tracker_tree.set_column_expand(3, false) tracker_tree.set_column_custom_minimum_width(2, 200) + tracker_tree.set_column_custom_minimum_width(3, 200) tracker_margins.add_child(tracker_tree) worldports_tab = MarginContainer.new() @@ -208,6 +211,7 @@ func update_locations(reset_locations = true): "name": location_name, "type": kLocation, "id": location_id, + "ignored": ap._ignored_locations.has(location_id), } ) ) @@ -222,11 +226,14 @@ func update_locations(reset_locations = true): "name": port_name, "type": kWorldport, "id": port_id, + "ignored": false, } ) ) - locations.sort_custom(func(a, b): return a["name"] < b["name"]) + locations.sort_custom( + func(a, b): return a["name"] < b["name"] if a["ignored"] == b["ignored"] else !a["ignored"] + ) if ap.client._goal_accessible: var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[ @@ -238,13 +245,14 @@ func update_locations(reset_locations = true): { "name": location_name, "type": kGoal, + "ignored": false, } ) ) var count = 0 for location in locations: - if count < 18: + if count < 18 and not location["ignored"]: locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT) locations_overlay.append_text(location["name"]) locations_overlay.append_text(" ") @@ -264,9 +272,24 @@ func update_locations(reset_locations = true): reset_tracker_tab() var root_ti = tracker_tree.create_item(null) + var ignored_loc_header = null for location in locations: - var loc_row = root_ti.create_child() + var loc_row + + if location["ignored"]: + if ignored_loc_header == null: + ignored_loc_header = root_ti.create_child() + ignored_loc_header.set_text(1, "Ignored Locations") + ignored_loc_header.set_selectable(0, false) + ignored_loc_header.set_selectable(1, false) + ignored_loc_header.set_selectable(2, false) + ignored_loc_header.set_selectable(3, false) + + loc_row = ignored_loc_header.create_child() + else: + loc_row = root_ti.create_child() + loc_row.set_cell_mode(0, TreeItem.CELL_MODE_ICON) loc_row.set_selectable(0, false) loc_row.set_text(1, location["name"]) @@ -277,6 +300,16 @@ func update_locations(reset_locations = true): loc_row.set_editable(2, true) loc_row.set_selectable(2, false) loc_row.set_text_alignment(2, HORIZONTAL_ALIGNMENT_CENTER) + loc_row.set_selectable(3, false) + if location["type"] == kLocation: + loc_row.set_cell_mode(3, TreeItem.CELL_MODE_CUSTOM) + if location["ignored"]: + loc_row.set_text(3, "Unignore") + else: + loc_row.set_text(3, "Ignore") + loc_row.set_custom_as_button(3, true) + loc_row.set_editable(3, true) + loc_row.set_text_alignment(3, HORIZONTAL_ALIGNMENT_CENTER) if location["type"] == kLocation: loc_row.set_icon(0, location_texture) @@ -288,7 +321,10 @@ func update_locations(reset_locations = true): loc_row.set_icon(0, goal_texture) tracker_goal_tree_item = loc_row - tracker_object_by_index[loc_row.get_index()] = location + if location["ignored"]: + tracker_object_by_ignored_index[loc_row.get_index()] = location + else: + tracker_object_by_index[loc_row.get_index()] = location else: for loc_row in tracker_tree.get_root().get_children(): loc_row.visible = false @@ -317,20 +353,33 @@ func update_locations_visibility(): func _on_tracker_button_clicked(): + var ap = global.get_node("Archipelago") + var edited_item = tracker_tree.get_edited() var edited_index = edited_item.get_index() - if tracker_object_by_index.has(edited_index): - var tracker_object = tracker_object_by_index[edited_index] - var ap = global.get_node("Archipelago") - var type_str = "" - if tracker_object["type"] == kLocation: - type_str = "location" - elif tracker_object["type"] == kWorldport: - type_str = "worldport" - elif tracker_object["type"] == kGoal: - type_str = "goal" - ap.client.getLogicalPath(type_str, tracker_object.get("id", null)) + if edited_item.get_parent() == tracker_tree.get_root(): + if tracker_object_by_index.has(edited_index): + var tracker_object = tracker_object_by_index[edited_index] + if tracker_tree.get_edited_column() == 2: + var type_str = "" + if tracker_object["type"] == kLocation: + type_str = "location" + elif tracker_object["type"] == kWorldport: + type_str = "worldport" + elif tracker_object["type"] == kGoal: + type_str = "goal" + ap.client.getLogicalPath(type_str, tracker_object.get("id", null)) + elif tracker_tree.get_edited_column() == 3: + ap.toggle_ignored_location(tracker_object["id"]) + else: + # This is the ignored locations group. + if ( + tracker_object_by_ignored_index.has(edited_index) + and tracker_tree.get_edited_column() == 3 + ): + var tracker_object = tracker_object_by_ignored_index[edited_index] + ap.toggle_ignored_location(tracker_object["id"]) func display_logical_path(object_type, object_id, paths): @@ -435,4 +484,5 @@ func reset_tracker_tab(): tracker_port_tree_item_by_id.clear() tracker_goal_tree_item = null tracker_object_by_index.clear() + tracker_object_by_ignored_index.clear() tracker_tree.clear() diff --git a/apworld/context.py b/apworld/context.py index 52b04ae..e5ba3cf 100644 --- a/apworld/context.py +++ b/apworld/context.py @@ -57,8 +57,6 @@ class Lingo2Manager: self.client_ctx.manager = self self.tracker = Tracker(self) self.keyboard = {} - self.worldports = set() - self.latches = set() self.reset() @@ -276,6 +274,17 @@ class Lingo2GameContext: async_start(self.send_msgs([msg]), name="update latches") + def send_ignored_locations(self, ignored_locations): + if self.server is None: + return + + msg = { + "cmd": "SetIgnoredLocations", + "locations": ignored_locations, + } + + async_start(self.send_msgs([msg]), name="set ignored locations") + async def send_msgs(self, msgs: list[Any]) -> None: """ `msgs` JSON serializable """ if not self.server or not self.server.socket.open or self.server.socket.closed: @@ -330,7 +339,8 @@ class Lingo2ClientContext(CommonContext): self.victory_data_storage_key = f"_read_client_status_{self.team}_{self.slot}" self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2"), - self.victory_data_storage_key, self.get_datastorage_key("latches")) + self.victory_data_storage_key, self.get_datastorage_key("latches"), + self.get_datastorage_key("ignored_locations")) msg_batch = [{ "cmd": "Set", "key": self.get_datastorage_key("keyboard1"), @@ -349,6 +359,12 @@ class Lingo2ClientContext(CommonContext): "default": [], "want_reply": True, "operations": [{"operation": "default", "value": []}] + }, { + "cmd": "Set", + "key": self.get_datastorage_key("ignored_locations"), + "default": [], + "want_reply": True, + "operations": [{"operation": "default", "value": []}] }] if self.slot_data.get("shuffle_worldports", False): @@ -464,6 +480,8 @@ class Lingo2ClientContext(CommonContext): updates = self.manager.update_latches(door_ids) if len(updates) > 0: self.manager.game_ctx.send_update_latches(updates) + elif args["key"] == self.get_datastorage_key("ignored_locations"): + self.manager.game_ctx.send_ignored_locations(args["value"]) def get_datastorage_key(self, name: str): return f"Lingo2_{self.slot}_{name}" @@ -559,6 +577,28 @@ class Lingo2ClientContext(CommonContext): }] }]) + async def add_ignored_location(self, loc_id: int): + await self.send_msgs([{ + "cmd": "Set", + "key": self.get_datastorage_key("ignored_locations"), + "want_reply": True, + "operations": [{ + "operation": "update", + "value": [loc_id] + }] + }]) + + async def remove_ignored_location(self, loc_id: int): + await self.send_msgs([{ + "cmd": "Set", + "key": self.get_datastorage_key("ignored_locations"), + "want_reply": True, + "operations": [{ + "operation": "remove", + "value": loc_id + }] + }]) + async def pipe_loop(manager: Lingo2Manager): while not manager.client_ctx.exit_event.is_set(): @@ -635,6 +675,10 @@ async def process_game_cmd(manager: Lingo2Manager, args: dict): updates = manager.update_latches({args["door"]}) if len(updates) > 0: async_start(manager.client_ctx.update_latches(updates), name="client update latches") + elif cmd == "IgnoreLocation": + async_start(manager.client_ctx.add_ignored_location(args["id"]), name="client ignore loc") + elif cmd == "UnignoreLocation": + async_start(manager.client_ctx.remove_ignored_location(args["id"]), name="client unignore loc") elif cmd == "Quit": manager.client_ctx.exit_event.set() -- cgit 1.4.1