From 617e31fce21eb18d1ffccdc9c377d25535157351 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Thu, 13 Apr 2023 18:09:30 -0400 Subject: It WORKS! You can send checks and receive door items! --- Archipelago/client.gd | 70 ++++++++++++++++++++++++++++++++++++++++++ Archipelago/doorControl.gd | 15 +++++++++ Archipelago/load.gd | 36 ++++++++++++++++++++++ Archipelago/location.gd | 17 ++++++++++ Archipelago/painting_eye.gd | 12 ++++++++ Archipelago/settings_screen.gd | 26 ++++++++++++++++ 6 files changed, 176 insertions(+) create mode 100644 Archipelago/doorControl.gd create mode 100644 Archipelago/load.gd create mode 100644 Archipelago/location.gd create mode 100644 Archipelago/painting_eye.gd diff --git a/Archipelago/client.gd b/Archipelago/client.gd index 74fe6e9..cbddf89 100644 --- a/Archipelago/client.gd +++ b/Archipelago/client.gd @@ -16,12 +16,21 @@ var _location_name_to_id = {} const uuid_util = preload("user://maps/Archipelago/vendor/uuid.gd") +# TODO: caching per MW/slot, reset between connections var _authenticated = false var _team = 0 var _slot = 0 var _players = [] var _checked_locations = [] var _slot_data = {} +var _door_ids_by_item = {} +var _mentioned_doors = [] +var _painting_ids_by_item = {} +var _mentioned_paintings = [] +var _panel_ids_by_location = {} + +var _map_loaded = false +var _held_items = [] signal client_connected @@ -104,12 +113,36 @@ func _on_data(): _checked_locations = message["checked_locations"] _slot_data = message["slot_data"] + if _slot_data.has("door_ids_by_item_id"): + _door_ids_by_item = _slot_data["door_ids_by_item_id"] + + _mentioned_doors = [] + for item in _door_ids_by_item.values(): + for door in item: + _mentioned_doors.append(door) + if _slot_data.has("painting_ids_by_item_id"): + _painting_ids_by_item = _slot_data["painting_ids_by_item_id"] + + _mentioned_paintings = [] + for item in _painting_ids_by_item.values(): + for painting in item: + _mentioned_paintings.append(painting) + if _slot_data.has("panel_ids_by_location_id"): + _panel_ids_by_location = _slot_data["panel_ids_by_location_id"] + emit_signal("client_connected") elif cmd == "ConnectionRefused": global._print("Connection to AP refused") global._print(message) + elif cmd == "ReceivedItems": + for item in message["items"]: + if _map_loaded: + processItem(item["item"]) + else: + _held_items.append(item["item"]) + func _process(_delta): if _should_process: @@ -170,3 +203,40 @@ func connectToRoom(): } ] ) + + +func sendLocation(loc_id): + sendMessage([{"cmd": "LocationChecks", "locations": [loc_id]}]) + + +func mapFinishedLoading(): + if !_map_loaded: + _map_loaded = true + + for item in _held_items: + processItem(item) + + _held_items = [] + + +func processItem(item): + global._print(item) + + var stringified = String(item) + if _door_ids_by_item.has(stringified): + var doorsNode = get_tree().get_root().get_node("Spatial/Doors") + for door_id in _door_ids_by_item[stringified]: + doorsNode.get_node(door_id).openDoor() + + if _painting_ids_by_item.has(stringified): + var paintingsNode = get_tree().get_root().get_node("Spatial/Decorations/Paintings") + for painting_id in _painting_ids_by_item[stringified]: + paintingsNode.get_node(painting_id).movePainting() + + +func doorIsVanilla(door): + return !_mentioned_doors.has(door) + + +func paintingIsVanilla(painting): + return !_mentioned_paintings.has(painting) diff --git a/Archipelago/doorControl.gd b/Archipelago/doorControl.gd new file mode 100644 index 0000000..011b0e0 --- /dev/null +++ b/Archipelago/doorControl.gd @@ -0,0 +1,15 @@ +extends "res://scripts/doorControl.gd" + + +func handle_correct(): + # TODO: Right now we are just assuming that door shuffle is on. + var apclient = global.get_node("Archipelago") + if apclient.doorIsVanilla(self.get_parent().name + "/" + self.name): + .handle_correct() + + +func openDoor(): + if !ran: + # Basically do the same thing that the base game does. + ran = true + $AnimationPlayer.play("Open") diff --git a/Archipelago/load.gd b/Archipelago/load.gd new file mode 100644 index 0000000..b0ccafc --- /dev/null +++ b/Archipelago/load.gd @@ -0,0 +1,36 @@ +extends "res://scripts/load.gd" + + +func _load(): + global._print("Hooked Load Start") + + var apclient = global.get_node("Archipelago") + + # TODO: Override the YOU panel with the AP slot name + + # This is the best time to create the location nodes, since the map is now + # loaded but the panels haven't been solved from the save file yet. + var panels_parent = self.get_node("Panels") + var location_script = ResourceLoader.load("user://maps/Archipelago/location.gd") + for location_name in apclient._location_name_to_id: + var location = location_script.new() + location.ap_name = location_name + location.ap_id = apclient._location_name_to_id[location_name] + location.name = "AP_location_" + location.ap_id + self.add_child(location) + + var panels = apclient._panel_ids_by_location[String(location.ap_id)] + location.total = panels.size() + + for panel in panels: + var that_panel = panels_parent.get_node(panel) + that_panel.get_node("Viewport/GUI/Panel/TextEdit").connect( + "answer_correct", location, "handle_correct" + ) + + # Process any items received while the map was loading. + apclient.mapFinishedLoading() + + # Proceed with the rest of the load. + global._print("Hooked Load End") + ._load() diff --git a/Archipelago/location.gd b/Archipelago/location.gd new file mode 100644 index 0000000..b85b5c4 --- /dev/null +++ b/Archipelago/location.gd @@ -0,0 +1,17 @@ +extends Node + +var ap_name = "" +var ap_id = 0 +var total = 0 +var solved = 0 +var ran = false + + +func handle_correct(): + solved += 1 + + if solved >= total && !ran: + ran = true + + var apclient = global.get_node("Archipelago") + apclient.sendLocation(ap_id) diff --git a/Archipelago/painting_eye.gd b/Archipelago/painting_eye.gd new file mode 100644 index 0000000..86e0ce9 --- /dev/null +++ b/Archipelago/painting_eye.gd @@ -0,0 +1,12 @@ +extends "res://scripts/painting_eye.gd" + + +func _answer_correct(): + # TODO: Right now we are just assuming that door shuffle is on. + var apclient = global.get_node("Archipelago") + if apclient.paintingIsVanilla(self.name): + ._answer_correct() + + +func movePainting(): + ._answer_correct() diff --git a/Archipelago/settings_screen.gd b/Archipelago/settings_screen.gd index 0854a8b..9624693 100644 --- a/Archipelago/settings_screen.gd +++ b/Archipelago/settings_screen.gd @@ -13,6 +13,11 @@ func _ready(): apclient_instance.name = "Archipelago" global.add_child(apclient_instance) + # Let's also inject any scripts we need to inject now. + installScriptExtension("user://maps/Archipelago/doorControl.gd") + installScriptExtension("user://maps/Archipelago/load.gd") + installScriptExtension("user://maps/Archipelago/painting_eye.gd") + global.get_node("Archipelago").connect("client_connected", self, "connectionSuccessful") # Populate textboxes with AP settings. @@ -21,6 +26,27 @@ func _ready(): self.get_node("Panel/password_box").text = global.get_node("Archipelago").ap_pass +# Adapted from https://gitlab.com/Delta-V-Modding/Mods/-/blob/main/game/ModLoader.gd +func installScriptExtension(childScriptPath: String): + var childScript = ResourceLoader.load(childScriptPath) + + # Force Godot to compile the script now. + # We need to do this here to ensure that the inheritance chain is + # properly set up, and multiple mods can chain-extend the same + # class multiple times. + # This is also needed to make Godot instantiate the extended class + # when creating singletons. + # The actual instance is thrown away. + childScript.new() + + var parentScript = childScript.get_base_script() + var parentScriptPath = parentScript.resource_path + global._print( + "ModLoader: Installing script extension: %s <- %s" % [parentScriptPath, childScriptPath] + ) + childScript.take_over_path(parentScriptPath) + + func connectionSuccessful(): # Switch to LL1 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) -- cgit 1.4.1