about summary refs log tree commit diff stats
path: root/apworld/client/main.gd
diff options
context:
space:
mode:
Diffstat (limited to 'apworld/client/main.gd')
-rw-r--r--apworld/client/main.gd296
1 files changed, 296 insertions, 0 deletions
diff --git a/apworld/client/main.gd b/apworld/client/main.gd new file mode 100644 index 0000000..e1f9610 --- /dev/null +++ b/apworld/client/main.gd
@@ -0,0 +1,296 @@
1extends Node
2
3
4func _ready():
5 var runtime = global.get_node("Runtime")
6
7 # Some helpful logging.
8 if Steam.isSubscribed():
9 global._print("Provisioning successful! Build ID: %d" % Steam.getAppBuildId())
10 else:
11 global._print("Provisioning failed.")
12
13 # Undo the load screen removing our cursor
14 get_tree().get_root().set_disable_input(false)
15 Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
16
17 # Increase the WebSocket input buffer size so that we can download large
18 # data packages.
19 ProjectSettings.set_setting("network/limits/websocket_client/max_in_buffer_kb", 8192)
20
21 switcher.layer = 4
22
23 # Create the global AP manager, if it doesn't already exist.
24 if not global.has_node("Archipelago"):
25 var ap_script = runtime.load_script("manager.gd")
26 var ap_instance = ap_script.new()
27 ap_instance.name = "Archipelago"
28
29 ap_instance.SCRIPT_client = runtime.load_script("client.gd")
30 ap_instance.SCRIPT_keyboard = runtime.load_script("keyboard.gd")
31 ap_instance.SCRIPT_locationListener = runtime.load_script("locationListener.gd")
32 ap_instance.SCRIPT_minimap = runtime.load_script("minimap.gd")
33 ap_instance.SCRIPT_victoryListener = runtime.load_script("victoryListener.gd")
34 ap_instance.SCRIPT_websocketserver = runtime.load_script("vendor/WebSocketServer.gd")
35
36 global.add_child(ap_instance)
37
38 # Let's also inject any scripts we need to inject now.
39 installScriptExtension(runtime.load_script("animationListener.gd"))
40 installScriptExtension(runtime.load_script("collectable.gd"))
41 installScriptExtension(runtime.load_script("door.gd"))
42 installScriptExtension(runtime.load_script("keyHolder.gd"))
43 installScriptExtension(runtime.load_script("keyHolderChecker.gd"))
44 installScriptExtension(runtime.load_script("keyHolderResetterListener.gd"))
45 installScriptExtension(runtime.load_script("painting.gd"))
46 installScriptExtension(runtime.load_script("panel.gd"))
47 installScriptExtension(runtime.load_script("pauseMenu.gd"))
48 installScriptExtension(runtime.load_script("player.gd"))
49 installScriptExtension(runtime.load_script("saver.gd"))
50 installScriptExtension(runtime.load_script("teleport.gd"))
51 installScriptExtension(runtime.load_script("teleportListener.gd"))
52 installScriptExtension(runtime.load_script("visibilityListener.gd"))
53 installScriptExtension(runtime.load_script("worldport.gd"))
54 installScriptExtension(runtime.load_script("worldportListener.gd"))
55
56 var proto_script = runtime.load_script("../generated/proto.gd")
57 var gamedata_script = runtime.load_script("gamedata.gd")
58 var gamedata_instance = gamedata_script.new(proto_script)
59 gamedata_instance.load(runtime.read_path("../generated/data.binpb"))
60 gamedata_instance.name = "Gamedata"
61 global.add_child(gamedata_instance)
62
63 var messages_script = runtime.load_script("messages.gd")
64 var messages_instance = messages_script.new()
65 messages_instance.name = "Messages"
66 messages_instance.SCRIPT_rainbowText = runtime.load_script("rainbowText.gd")
67 global.add_child(messages_instance)
68
69 var effects_script = runtime.load_script("effects.gd")
70 var effects_instance = effects_script.new()
71 effects_instance.name = "Effects"
72 global.add_child(effects_instance)
73
74 var textclient_script = runtime.load_script("textclient.gd")
75 var textclient_instance = textclient_script.new()
76 textclient_instance.name = "Textclient"
77 global.add_child(textclient_instance)
78
79 var compass_overlay_script = runtime.load_script("compass_overlay.gd")
80 var compass_overlay_instance = compass_overlay_script.new()
81 compass_overlay_instance.name = "Compass"
82 compass_overlay_instance.SCRIPT_compass = runtime.load_script("compass.gd")
83 global.add_child(compass_overlay_instance)
84
85 var ap = global.get_node("Archipelago")
86 var gamedata = global.get_node("Gamedata")
87 ap.ap_connected.connect(connectionSuccessful)
88 ap.could_not_connect.connect(connectionUnsuccessful)
89 ap.connect_status.connect(connectionStatus)
90
91 # Populate textboxes with AP settings.
92 get_node("../Panel/server_box").text = ap.ap_server
93 get_node("../Panel/player_box").text = ap.ap_user
94 get_node("../Panel/password_box").text = ap.ap_pass
95
96 var history_box = get_node("../Panel/connection_history")
97 if ap.connection_history.is_empty():
98 history_box.disabled = true
99 else:
100 history_box.disabled = false
101
102 var i = 0
103 for details in ap.connection_history:
104 history_box.get_popup().add_item("%s (%s)" % [details[1], details[0]], i)
105 i += 1
106
107 history_box.get_popup().id_pressed.connect(historySelected)
108
109 # Show client version.
110 var version = gamedata.objects.get_version()
111 get_node("../Panel/title").text = (
112 "ARCHIPELAGO (%d.%d.%d)" % [version.get_major(), version.get_minor(), version.get_patch()]
113 )
114
115 # Increase font size in text boxes.
116 get_node("../Panel/server_box").add_theme_font_size_override("font_size", 36)
117 get_node("../Panel/player_box").add_theme_font_size_override("font_size", 36)
118 get_node("../Panel/password_box").add_theme_font_size_override("font_size", 36)
119
120 # Set up version mismatch dialog.
121 get_node("../Panel/VersionMismatch").confirmed.connect(startGame)
122 get_node("../Panel/VersionMismatch").get_cancel_button().pressed.connect(
123 versionMismatchDeclined
124 )
125
126 # Set up buttons.
127 get_node("../Panel/connect_button").pressed.connect(_connect_pressed)
128 get_node("../Panel/quit_button").pressed.connect(_back_pressed)
129
130
131func _connect_pressed():
132 get_node("../Panel/connect_button").disabled = true
133
134 var ap = global.get_node("Archipelago")
135 ap.ap_server = get_node("../Panel/server_box").text
136 ap.ap_user = get_node("../Panel/player_box").text
137 ap.ap_pass = get_node("../Panel/password_box").text
138 ap.saveSettings()
139
140 ap.connectToServer()
141
142
143func _back_pressed():
144 var ap = global.get_node("Archipelago")
145 ap.disconnect_from_ap()
146 ap.client.sendQuit()
147
148 get_tree().quit()
149
150
151# Adapted from https://gitlab.com/Delta-V-Modding/Mods/-/blob/main/game/ModLoader.gd
152func installScriptExtension(childScript: Resource):
153 # Force Godot to compile the script now.
154 # We need to do this here to ensure that the inheritance chain is
155 # properly set up, and multiple mods can chain-extend the same
156 # class multiple times.
157 # This is also needed to make Godot instantiate the extended class
158 # when creating singletons.
159 # The actual instance is thrown away.
160 childScript.new()
161
162 var parentScript = childScript.get_base_script()
163 var parentScriptPath = parentScript.resource_path
164 global._print("ModLoader: Installing script extension over %s" % parentScriptPath)
165 childScript.take_over_path(parentScriptPath)
166
167
168func connectionStatus(message):
169 var popup = get_node("../Panel/AcceptDialog")
170 popup.title = "Connecting to Archipelago"
171 popup.dialog_text = message
172 popup.exclusive = true
173 popup.get_ok_button().visible = false
174 popup.popup_centered()
175
176
177func connectionSuccessful():
178 var ap = global.get_node("Archipelago")
179 var gamedata = global.get_node("Gamedata")
180
181 # Check for major version mismatch.
182 if ap.apworld_version[0] != gamedata.objects.get_version().get_major():
183 get_node("../Panel/AcceptDialog").exclusive = false
184
185 var popup = get_node("../Panel/VersionMismatch")
186 popup.title = "Version Mismatch!"
187 popup.dialog_text = (
188 "This slot was generated using v%d.%d.%d of the Lingo 2 apworld,\nwhich has a different major version than this client (v%d.%d.%d).\nIt is highly recommended to play using the correct version of the client.\nYou may experience bugs or logic issues if you continue."
189 % [
190 ap.apworld_version[0],
191 ap.apworld_version[1],
192 ap.apworld_version[2],
193 gamedata.objects.get_version().get_major(),
194 gamedata.objects.get_version().get_minor(),
195 gamedata.objects.get_version().get_patch()
196 ]
197 )
198 popup.exclusive = true
199 popup.popup_centered()
200
201 return
202
203 startGame()
204
205
206func startGame():
207 var ap = global.get_node("Archipelago")
208
209 # Save connection details
210 var connection_details = [ap.ap_server, ap.ap_user, ap.ap_pass]
211 if ap.connection_history.has(connection_details):
212 ap.connection_history.erase(connection_details)
213 ap.connection_history.push_front(connection_details)
214 if ap.connection_history.size() > 10:
215 ap.connection_history.resize(10)
216 ap.saveSettings()
217
218 # Switch to the_entry
219 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
220 global.user = ap.getSaveFileName()
221 global.universe = "lingo"
222 global.map = "the_entry"
223
224 unlocks.resetCollectables()
225 unlocks.resetData()
226
227 ap.setup_keys()
228
229 unlocks.loadCollectables()
230 unlocks.loadData()
231 unlocks.unlockKey("capslock", 1)
232
233 if ap.shuffle_worldports:
234 settings.worldport_fades = "default"
235 else:
236 settings.worldport_fades = "never"
237
238 clearResourceCache("res://objects/meshes/gridDoor.tscn")
239 clearResourceCache("res://objects/nodes/collectable.tscn")
240 clearResourceCache("res://objects/nodes/door.tscn")
241 clearResourceCache("res://objects/nodes/keyHolder.tscn")
242 clearResourceCache("res://objects/nodes/listeners/animationListener.tscn")
243 clearResourceCache("res://objects/nodes/listeners/keyHolderChecker.tscn")
244 clearResourceCache("res://objects/nodes/listeners/keyHolderResetterListener.tscn")
245 clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn")
246 clearResourceCache("res://objects/nodes/listeners/visibilityListener.tscn")
247 clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn")
248 clearResourceCache("res://objects/nodes/panel.tscn")
249 clearResourceCache("res://objects/nodes/player.tscn")
250 clearResourceCache("res://objects/nodes/saver.tscn")
251 clearResourceCache("res://objects/nodes/teleport.tscn")
252 clearResourceCache("res://objects/nodes/worldport.tscn")
253 clearResourceCache("res://objects/scenes/menus/pause_menu.tscn")
254
255 var paintings_dir = DirAccess.open("res://objects/meshes/paintings")
256 if paintings_dir:
257 paintings_dir.list_dir_begin()
258 var file_name = paintings_dir.get_next()
259 while file_name != "":
260 if not paintings_dir.current_is_dir() and file_name.ends_with(".tscn"):
261 clearResourceCache("res://objects/meshes/paintings/" + file_name)
262 file_name = paintings_dir.get_next()
263
264 switcher.switch_map.call_deferred("res://objects/scenes/the_entry.tscn")
265
266
267func connectionUnsuccessful(error_message):
268 get_node("../Panel/connect_button").disabled = false
269
270 var popup = get_node("../Panel/AcceptDialog")
271 popup.title = "Could not connect to Archipelago"
272 popup.dialog_text = error_message
273 popup.exclusive = true
274 popup.get_ok_button().visible = true
275 popup.popup_centered()
276
277
278func versionMismatchDeclined():
279 get_node("../Panel/AcceptDialog").hide()
280 get_node("../Panel/connect_button").disabled = false
281
282 var ap = global.get_node("Archipelago")
283 ap.disconnect_from_ap()
284
285
286func historySelected(index):
287 var ap = global.get_node("Archipelago")
288 var details = ap.connection_history[index]
289
290 get_node("../Panel/server_box").text = details[0]
291 get_node("../Panel/player_box").text = details[1]
292 get_node("../Panel/password_box").text = details[2]
293
294
295func clearResourceCache(path):
296 ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_REPLACE)