about summary refs log tree commit diff stats
path: root/apworld
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-11-02 12:29:29 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2025-11-02 12:29:29 -0500
commitadfc639965b2bda776ceb0a20840438e31f82d58 (patch)
treeb31b6896dee65b66595e648139ba4e047258847b /apworld
parenta5dc6b35da0a790b59940992d2cb175c35946f19 (diff)
downloadlingo2-archipelago-adfc639965b2bda776ceb0a20840438e31f82d58.tar.gz
lingo2-archipelago-adfc639965b2bda776ceb0a20840438e31f82d58.tar.bz2
lingo2-archipelago-adfc639965b2bda776ceb0a20840438e31f82d58.zip
Allow ignoring locations in tracker
Diffstat (limited to 'apworld')
-rw-r--r--apworld/client/client.gd16
-rw-r--r--apworld/client/manager.gd17
-rw-r--r--apworld/client/textclient.gd82
-rw-r--r--apworld/context.py50
4 files changed, 146 insertions, 19 deletions
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)
38signal door_latched(id) 38signal door_latched(id)
39signal accessible_locations_updated 39signal accessible_locations_updated
40signal checked_locations_updated 40signal checked_locations_updated
41signal ignored_locations_updated(locations)
41signal checked_worldports_updated 42signal checked_worldports_updated
42signal keyboard_update_received 43signal keyboard_update_received
43 44
@@ -199,6 +200,13 @@ func _on_web_socket_server_message_received(_peer_id: int, packet: String) -> vo
199 200
200 door_latched.emit(iid) 201 door_latched.emit(iid)
201 202
203 elif cmd == "SetIgnoredLocations":
204 var locs = []
205 for id in message["locations"]:
206 locs.append(int(id))
207
208 ignored_locations_updated.emit(locs)
209
202 210
203func connectToServer(server, un, pw): 211func connectToServer(server, un, pw):
204 sendMessage([{"cmd": "Connect", "server": server, "player": un, "password": pw}]) 212 sendMessage([{"cmd": "Connect", "server": server, "player": un, "password": pw}])
@@ -280,6 +288,14 @@ func getLogicalPath(object_type, object_id):
280 sendMessage([msg]) 288 sendMessage([msg])
281 289
282 290
291func addIgnoredLocation(loc_id):
292 sendMessage([{"cmd": "IgnoreLocation", "id": loc_id}])
293
294
295func removeIgnoredLocation(loc_id):
296 sendMessage([{"cmd": "UnignoreLocation", "id": loc_id}])
297
298
283func sendQuit(): 299func sendQuit():
284 sendMessage([{"cmd": "Quit"}]) 300 sendMessage([{"cmd": "Quit"}])
285 301
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 = {}
29var _held_letters = {} 29var _held_letters = {}
30var _letters_setup = false 30var _letters_setup = false
31var _already_connected = false 31var _already_connected = false
32var _ignored_locations = []
32 33
33const kSHUFFLE_LETTERS_VANILLA = 0 34const kSHUFFLE_LETTERS_VANILLA = 0
34const kSHUFFLE_LETTERS_UNLOCKED = 1 35const kSHUFFLE_LETTERS_UNLOCKED = 1
@@ -144,6 +145,7 @@ func _ready():
144 client.hint_received.connect(_process_hint_received) 145 client.hint_received.connect(_process_hint_received)
145 client.accessible_locations_updated.connect(_on_accessible_locations_updated) 146 client.accessible_locations_updated.connect(_on_accessible_locations_updated)
146 client.checked_locations_updated.connect(_on_checked_locations_updated) 147 client.checked_locations_updated.connect(_on_checked_locations_updated)
148 client.ignored_locations_updated.connect(_on_ignored_locations_updated)
147 client.checked_worldports_updated.connect(_on_checked_worldports_updated) 149 client.checked_worldports_updated.connect(_on_checked_worldports_updated)
148 client.door_latched.connect(_on_door_latched) 150 client.door_latched.connect(_on_door_latched)
149 151
@@ -384,6 +386,14 @@ func _on_checked_worldports_updated():
384 textclient_node.update_worldports() 386 textclient_node.update_worldports()
385 387
386 388
389func _on_ignored_locations_updated(locations):
390 _ignored_locations = locations
391
392 var textclient_node = global.get_node("Textclient")
393 if textclient_node != null:
394 textclient_node.update_locations()
395
396
387func _on_door_latched(door_id): 397func _on_door_latched(door_id):
388 var gamedata = global.get_node("Gamedata") 398 var gamedata = global.get_node("Gamedata")
389 if gamedata.get_door_map_name(door_id) != global.map: 399 if gamedata.get_door_map_name(door_id) != global.map:
@@ -677,3 +687,10 @@ func update_job_well_done_sign():
677 687
678 sign2.get_node("MeshInstance3D").mesh.text = sign2.text 688 sign2.get_node("MeshInstance3D").mesh.text = sign2.text
679 sign3.get_node("MeshInstance3D").mesh.text = sign3.text 689 sign3.get_node("MeshInstance3D").mesh.text = sign3.text
690
691
692func toggle_ignored_location(loc_id):
693 if loc_id in _ignored_locations:
694 client.removeIgnoredLocation(loc_id)
695 else:
696 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 = {}
16var tracker_port_tree_item_by_id = {} 16var tracker_port_tree_item_by_id = {}
17var tracker_goal_tree_item = null 17var tracker_goal_tree_item = null
18var tracker_object_by_index = {} 18var tracker_object_by_index = {}
19var tracker_object_by_ignored_index = {}
19 20
20var worldports_tab 21var worldports_tab
21var worldports_tree 22var worldports_tree
@@ -99,7 +100,7 @@ func _ready():
99 tabs.add_child(tracker_margins) 100 tabs.add_child(tracker_margins)
100 101
101 tracker_tree = Tree.new() 102 tracker_tree = Tree.new()
102 tracker_tree.columns = 3 103 tracker_tree.columns = 4
103 tracker_tree.hide_root = true 104 tracker_tree.hide_root = true
104 tracker_tree.add_theme_font_size_override("font_size", 24) 105 tracker_tree.add_theme_font_size_override("font_size", 24)
105 tracker_tree.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1)) 106 tracker_tree.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1))
@@ -108,7 +109,9 @@ func _ready():
108 tracker_tree.set_column_expand(0, false) 109 tracker_tree.set_column_expand(0, false)
109 tracker_tree.set_column_expand(1, true) 110 tracker_tree.set_column_expand(1, true)
110 tracker_tree.set_column_expand(2, false) 111 tracker_tree.set_column_expand(2, false)
112 tracker_tree.set_column_expand(3, false)
111 tracker_tree.set_column_custom_minimum_width(2, 200) 113 tracker_tree.set_column_custom_minimum_width(2, 200)
114 tracker_tree.set_column_custom_minimum_width(3, 200)
112 tracker_margins.add_child(tracker_tree) 115 tracker_margins.add_child(tracker_tree)
113 116
114 worldports_tab = MarginContainer.new() 117 worldports_tab = MarginContainer.new()
@@ -208,6 +211,7 @@ func update_locations(reset_locations = true):
208 "name": location_name, 211 "name": location_name,
209 "type": kLocation, 212 "type": kLocation,
210 "id": location_id, 213 "id": location_id,
214 "ignored": ap._ignored_locations.has(location_id),
211 } 215 }
212 ) 216 )
213 ) 217 )
@@ -222,11 +226,14 @@ func update_locations(reset_locations = true):
222 "name": port_name, 226 "name": port_name,
223 "type": kWorldport, 227 "type": kWorldport,
224 "id": port_id, 228 "id": port_id,
229 "ignored": false,
225 } 230 }
226 ) 231 )
227 ) 232 )
228 233
229 locations.sort_custom(func(a, b): return a["name"] < b["name"]) 234 locations.sort_custom(
235 func(a, b): return a["name"] < b["name"] if a["ignored"] == b["ignored"] else !a["ignored"]
236 )
230 237
231 if ap.client._goal_accessible: 238 if ap.client._goal_accessible:
232 var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[ 239 var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[
@@ -238,13 +245,14 @@ func update_locations(reset_locations = true):
238 { 245 {
239 "name": location_name, 246 "name": location_name,
240 "type": kGoal, 247 "type": kGoal,
248 "ignored": false,
241 } 249 }
242 ) 250 )
243 ) 251 )
244 252
245 var count = 0 253 var count = 0
246 for location in locations: 254 for location in locations:
247 if count < 18: 255 if count < 18 and not location["ignored"]:
248 locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT) 256 locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT)
249 locations_overlay.append_text(location["name"]) 257 locations_overlay.append_text(location["name"])
250 locations_overlay.append_text(" ") 258 locations_overlay.append_text(" ")
@@ -264,9 +272,24 @@ func update_locations(reset_locations = true):
264 reset_tracker_tab() 272 reset_tracker_tab()
265 273
266 var root_ti = tracker_tree.create_item(null) 274 var root_ti = tracker_tree.create_item(null)
275 var ignored_loc_header = null
267 276
268 for location in locations: 277 for location in locations:
269 var loc_row = root_ti.create_child() 278 var loc_row
279
280 if location["ignored"]:
281 if ignored_loc_header == null:
282 ignored_loc_header = root_ti.create_child()
283 ignored_loc_header.set_text(1, "Ignored Locations")
284 ignored_loc_header.set_selectable(0, false)
285 ignored_loc_header.set_selectable(1, false)
286 ignored_loc_header.set_selectable(2, false)
287 ignored_loc_header.set_selectable(3, false)
288
289 loc_row = ignored_loc_header.create_child()
290 else:
291 loc_row = root_ti.create_child()
292
270 loc_row.set_cell_mode(0, TreeItem.CELL_MODE_ICON) 293 loc_row.set_cell_mode(0, TreeItem.CELL_MODE_ICON)
271 loc_row.set_selectable(0, false) 294 loc_row.set_selectable(0, false)
272 loc_row.set_text(1, location["name"]) 295 loc_row.set_text(1, location["name"])
@@ -277,6 +300,16 @@ func update_locations(reset_locations = true):
277 loc_row.set_editable(2, true) 300 loc_row.set_editable(2, true)
278 loc_row.set_selectable(2, false) 301 loc_row.set_selectable(2, false)
279 loc_row.set_text_alignment(2, HORIZONTAL_ALIGNMENT_CENTER) 302 loc_row.set_text_alignment(2, HORIZONTAL_ALIGNMENT_CENTER)
303 loc_row.set_selectable(3, false)
304 if location["type"] == kLocation:
305 loc_row.set_cell_mode(3, TreeItem.CELL_MODE_CUSTOM)
306 if location["ignored"]:
307 loc_row.set_text(3, "Unignore")
308 else:
309 loc_row.set_text(3, "Ignore")
310 loc_row.set_custom_as_button(3, true)
311 loc_row.set_editable(3, true)
312 loc_row.set_text_alignment(3, HORIZONTAL_ALIGNMENT_CENTER)
280 313
281 if location["type"] == kLocation: 314 if location["type"] == kLocation:
282 loc_row.set_icon(0, location_texture) 315 loc_row.set_icon(0, location_texture)
@@ -288,7 +321,10 @@ func update_locations(reset_locations = true):
288 loc_row.set_icon(0, goal_texture) 321 loc_row.set_icon(0, goal_texture)
289 tracker_goal_tree_item = loc_row 322 tracker_goal_tree_item = loc_row
290 323
291 tracker_object_by_index[loc_row.get_index()] = location 324 if location["ignored"]:
325 tracker_object_by_ignored_index[loc_row.get_index()] = location
326 else:
327 tracker_object_by_index[loc_row.get_index()] = location
292 else: 328 else:
293 for loc_row in tracker_tree.get_root().get_children(): 329 for loc_row in tracker_tree.get_root().get_children():
294 loc_row.visible = false 330 loc_row.visible = false
@@ -317,20 +353,33 @@ func update_locations_visibility():
317 353
318 354
319func _on_tracker_button_clicked(): 355func _on_tracker_button_clicked():
356 var ap = global.get_node("Archipelago")
357
320 var edited_item = tracker_tree.get_edited() 358 var edited_item = tracker_tree.get_edited()
321 var edited_index = edited_item.get_index() 359 var edited_index = edited_item.get_index()
322 360
323 if tracker_object_by_index.has(edited_index): 361 if edited_item.get_parent() == tracker_tree.get_root():
324 var tracker_object = tracker_object_by_index[edited_index] 362 if tracker_object_by_index.has(edited_index):
325 var ap = global.get_node("Archipelago") 363 var tracker_object = tracker_object_by_index[edited_index]
326 var type_str = "" 364 if tracker_tree.get_edited_column() == 2:
327 if tracker_object["type"] == kLocation: 365 var type_str = ""
328 type_str = "location" 366 if tracker_object["type"] == kLocation:
329 elif tracker_object["type"] == kWorldport: 367 type_str = "location"
330 type_str = "worldport" 368 elif tracker_object["type"] == kWorldport:
331 elif tracker_object["type"] == kGoal: 369 type_str = "worldport"
332 type_str = "goal" 370 elif tracker_object["type"] == kGoal:
333 ap.client.getLogicalPath(type_str, tracker_object.get("id", null)) 371 type_str = "goal"
372 ap.client.getLogicalPath(type_str, tracker_object.get("id", null))
373 elif tracker_tree.get_edited_column() == 3:
374 ap.toggle_ignored_location(tracker_object["id"])
375 else:
376 # This is the ignored locations group.
377 if (
378 tracker_object_by_ignored_index.has(edited_index)
379 and tracker_tree.get_edited_column() == 3
380 ):
381 var tracker_object = tracker_object_by_ignored_index[edited_index]
382 ap.toggle_ignored_location(tracker_object["id"])
334 383
335 384
336func display_logical_path(object_type, object_id, paths): 385func display_logical_path(object_type, object_id, paths):
@@ -435,4 +484,5 @@ func reset_tracker_tab():
435 tracker_port_tree_item_by_id.clear() 484 tracker_port_tree_item_by_id.clear()
436 tracker_goal_tree_item = null 485 tracker_goal_tree_item = null
437 tracker_object_by_index.clear() 486 tracker_object_by_index.clear()
487 tracker_object_by_ignored_index.clear()
438 tracker_tree.clear() 488 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:
57 self.client_ctx.manager = self 57 self.client_ctx.manager = self
58 self.tracker = Tracker(self) 58 self.tracker = Tracker(self)
59 self.keyboard = {} 59 self.keyboard = {}
60 self.worldports = set()
61 self.latches = set()
62 60
63 self.reset() 61 self.reset()
64 62
@@ -276,6 +274,17 @@ class Lingo2GameContext:
276 274
277 async_start(self.send_msgs([msg]), name="update latches") 275 async_start(self.send_msgs([msg]), name="update latches")
278 276
277 def send_ignored_locations(self, ignored_locations):
278 if self.server is None:
279 return
280
281 msg = {
282 "cmd": "SetIgnoredLocations",
283 "locations": ignored_locations,
284 }
285
286 async_start(self.send_msgs([msg]), name="set ignored locations")
287
279 async def send_msgs(self, msgs: list[Any]) -> None: 288 async def send_msgs(self, msgs: list[Any]) -> None:
280 """ `msgs` JSON serializable """ 289 """ `msgs` JSON serializable """
281 if not self.server or not self.server.socket.open or self.server.socket.closed: 290 if not self.server or not self.server.socket.open or self.server.socket.closed:
@@ -330,7 +339,8 @@ class Lingo2ClientContext(CommonContext):
330 self.victory_data_storage_key = f"_read_client_status_{self.team}_{self.slot}" 339 self.victory_data_storage_key = f"_read_client_status_{self.team}_{self.slot}"
331 340
332 self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2"), 341 self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2"),
333 self.victory_data_storage_key, self.get_datastorage_key("latches")) 342 self.victory_data_storage_key, self.get_datastorage_key("latches"),
343 self.get_datastorage_key("ignored_locations"))
334 msg_batch = [{ 344 msg_batch = [{
335 "cmd": "Set", 345 "cmd": "Set",
336 "key": self.get_datastorage_key("keyboard1"), 346 "key": self.get_datastorage_key("keyboard1"),
@@ -349,6 +359,12 @@ class Lingo2ClientContext(CommonContext):
349 "default": [], 359 "default": [],
350 "want_reply": True, 360 "want_reply": True,
351 "operations": [{"operation": "default", "value": []}] 361 "operations": [{"operation": "default", "value": []}]
362 }, {
363 "cmd": "Set",
364 "key": self.get_datastorage_key("ignored_locations"),
365 "default": [],
366 "want_reply": True,
367 "operations": [{"operation": "default", "value": []}]
352 }] 368 }]
353 369
354 if self.slot_data.get("shuffle_worldports", False): 370 if self.slot_data.get("shuffle_worldports", False):
@@ -464,6 +480,8 @@ class Lingo2ClientContext(CommonContext):
464 updates = self.manager.update_latches(door_ids) 480 updates = self.manager.update_latches(door_ids)
465 if len(updates) > 0: 481 if len(updates) > 0:
466 self.manager.game_ctx.send_update_latches(updates) 482 self.manager.game_ctx.send_update_latches(updates)
483 elif args["key"] == self.get_datastorage_key("ignored_locations"):
484 self.manager.game_ctx.send_ignored_locations(args["value"])
467 485
468 def get_datastorage_key(self, name: str): 486 def get_datastorage_key(self, name: str):
469 return f"Lingo2_{self.slot}_{name}" 487 return f"Lingo2_{self.slot}_{name}"
@@ -559,6 +577,28 @@ class Lingo2ClientContext(CommonContext):
559 }] 577 }]
560 }]) 578 }])
561 579
580 async def add_ignored_location(self, loc_id: int):
581 await self.send_msgs([{
582 "cmd": "Set",
583 "key": self.get_datastorage_key("ignored_locations"),
584 "want_reply": True,
585 "operations": [{
586 "operation": "update",
587 "value": [loc_id]
588 }]
589 }])
590
591 async def remove_ignored_location(self, loc_id: int):
592 await self.send_msgs([{
593 "cmd": "Set",
594 "key": self.get_datastorage_key("ignored_locations"),
595 "want_reply": True,
596 "operations": [{
597 "operation": "remove",
598 "value": loc_id
599 }]
600 }])
601
562 602
563async def pipe_loop(manager: Lingo2Manager): 603async def pipe_loop(manager: Lingo2Manager):
564 while not manager.client_ctx.exit_event.is_set(): 604 while not manager.client_ctx.exit_event.is_set():
@@ -635,6 +675,10 @@ async def process_game_cmd(manager: Lingo2Manager, args: dict):
635 updates = manager.update_latches({args["door"]}) 675 updates = manager.update_latches({args["door"]})
636 if len(updates) > 0: 676 if len(updates) > 0:
637 async_start(manager.client_ctx.update_latches(updates), name="client update latches") 677 async_start(manager.client_ctx.update_latches(updates), name="client update latches")
678 elif cmd == "IgnoreLocation":
679 async_start(manager.client_ctx.add_ignored_location(args["id"]), name="client ignore loc")
680 elif cmd == "UnignoreLocation":
681 async_start(manager.client_ctx.remove_ignored_location(args["id"]), name="client unignore loc")
638 elif cmd == "Quit": 682 elif cmd == "Quit":
639 manager.client_ctx.exit_event.set() 683 manager.client_ctx.exit_event.set()
640 684