about summary refs log tree commit diff stats
path: root/apworld/client/client.gd
diff options
context:
space:
mode:
Diffstat (limited to 'apworld/client/client.gd')
-rw-r--r--apworld/client/client.gd275
1 files changed, 275 insertions, 0 deletions
diff --git a/apworld/client/client.gd b/apworld/client/client.gd new file mode 100644 index 0000000..9a4b402 --- /dev/null +++ b/apworld/client/client.gd
@@ -0,0 +1,275 @@
1extends Node
2
3const ap_version = {"major": 0, "minor": 6, "build": 3, "class": "Version"}
4
5var SCRIPT_websocketserver
6
7var _server
8var _should_process = false
9
10var _remote_version = {"major": 0, "minor": 0, "build": 0}
11var _gen_version = {"major": 0, "minor": 0, "build": 0}
12
13var ap_server = ""
14var ap_user = ""
15var ap_pass = ""
16
17var _seed = ""
18var _team = 0
19var _slot = 0
20var _checked_locations = []
21var _checked_worldports = []
22var _received_indexes = []
23var _received_items = {}
24var _slot_data = {}
25var _accessible_locations = []
26var _accessible_worldports = []
27var _goal_accessible = false
28
29signal could_not_connect
30signal connect_status
31signal client_connected(slot_data)
32signal item_received(item, amount)
33signal location_scout_received(location_id, item_name, player_name, flags, for_self)
34signal text_message_received(message)
35signal item_sent_notification(message)
36signal hint_received(message)
37signal accessible_locations_updated
38signal checked_locations_updated
39signal checked_worldports_updated
40signal keyboard_update_received
41
42
43func _init():
44 set_process_mode(Node.PROCESS_MODE_ALWAYS)
45
46 global._print("Instantiated APClient")
47
48
49func _ready():
50 _server = SCRIPT_websocketserver.new()
51 _server.client_connected.connect(_on_web_socket_server_client_connected)
52 _server.client_disconnected.connect(_on_web_socket_server_client_disconnected)
53 _server.message_received.connect(_on_web_socket_server_message_received)
54 add_child(_server)
55 _server.listen(43182)
56
57
58func _reset_state():
59 _should_process = false
60 _received_items = {}
61 _received_indexes = []
62 _checked_worldports = []
63 _accessible_locations = []
64 _accessible_worldports = []
65 _goal_accessible = false
66
67
68func disconnect_from_ap():
69 sendMessage([{"cmd": "Disconnect"}])
70
71
72func _on_web_socket_server_client_connected(peer_id: int) -> void:
73 var peer: WebSocketPeer = _server.peers[peer_id]
74 print("Remote client connected: %d. Protocol: %s" % [peer_id, peer.get_selected_protocol()])
75 _server.send(-peer_id, "[%d] connected" % peer_id)
76
77
78func _on_web_socket_server_client_disconnected(peer_id: int) -> void:
79 var peer: WebSocketPeer = _server.peers[peer_id]
80 print(
81 (
82 "Remote client disconnected: %d. Code: %d, Reason: %s"
83 % [peer_id, peer.get_close_code(), peer.get_close_reason()]
84 )
85 )
86 _server.send(-peer_id, "[%d] disconnected" % peer_id)
87
88
89func _on_web_socket_server_message_received(_peer_id: int, packet: String) -> void:
90 global._print("Got data from server: " + packet)
91 var json = JSON.new()
92 var jserror = json.parse(packet)
93 if jserror != OK:
94 global._print("Error parsing packet from AP: " + jserror.error_string)
95 return
96
97 for message in json.data:
98 var cmd = message["cmd"]
99 global._print("Received command: " + cmd)
100
101 if cmd == "Connected":
102 _seed = message["seed_name"]
103 _remote_version = message["version"]
104 _gen_version = message["generator_version"]
105 _team = message["team"]
106 _slot = message["slot"]
107 _slot_data = message["slot_data"]
108
109 _checked_locations = []
110 for location in message["checked_locations"]:
111 _checked_locations.append(int(location))
112
113 client_connected.emit(_slot_data)
114
115 elif cmd == "ConnectionRefused":
116 could_not_connect.emit(message["text"])
117 global._print("Connection to AP refused")
118
119 elif cmd == "UpdateLocations":
120 for location in message["locations"]:
121 var lint = int(location)
122 if not _checked_locations.has(lint):
123 _checked_locations.append(lint)
124
125 checked_locations_updated.emit()
126
127 elif cmd == "UpdateWorldports":
128 for port_id in message["worldports"]:
129 var lint = int(port_id)
130 if not _checked_worldports.has(lint):
131 _checked_worldports.append(lint)
132
133 checked_worldports_updated.emit()
134
135 elif cmd == "ItemReceived":
136 for item in message["items"]:
137 var index = int(item["index"])
138 if _received_indexes.has(index):
139 # Do not re-process items.
140 continue
141
142 _received_indexes.append(index)
143
144 var item_id = int(item["id"])
145 _received_items[item_id] = _received_items.get(item_id, 0) + 1
146
147 item_received.emit(item, _received_items[item_id])
148
149 elif cmd == "TextMessage":
150 text_message_received.emit(message["data"])
151
152 elif cmd == "ItemSentNotif":
153 item_sent_notification.emit(message)
154
155 elif cmd == "HintReceived":
156 hint_received.emit(message)
157
158 elif cmd == "LocationInfo":
159 for loc in message["locations"]:
160 location_scout_received.emit(
161 int(loc["id"]), loc["item"], loc["player"], int(loc["flags"]), int(loc["self"])
162 )
163
164 elif cmd == "AccessibleLocations":
165 _accessible_locations.clear()
166 _accessible_worldports.clear()
167
168 for loc in message["locations"]:
169 _accessible_locations.append(int(loc))
170
171 if "worldports" in message:
172 for port_id in message["worldports"]:
173 _accessible_worldports.append(int(port_id))
174
175 _goal_accessible = bool(message.get("goal", false))
176
177 accessible_locations_updated.emit()
178
179 elif cmd == "UpdateKeyboard":
180 var updates = {}
181 for k in message["updates"]:
182 updates[k] = int(message["updates"][k])
183
184 keyboard_update_received.emit(updates)
185
186 elif cmd == "PathReply":
187 var textclient = global.get_node("Textclient")
188 textclient.display_logical_path(
189 message["type"], int(message.get("id", null)), message["path"]
190 )
191
192
193func connectToServer(server, un, pw):
194 sendMessage([{"cmd": "Connect", "server": server, "player": un, "password": pw}])
195
196 ap_server = server
197 ap_user = un
198 ap_pass = pw
199
200 _should_process = true
201
202 connect_status.emit("Connecting...")
203
204
205func sendMessage(msg):
206 var payload = JSON.stringify(msg)
207 _server.send(0, payload)
208
209
210func connectToRoom():
211 connect_status.emit("Authenticating...")
212
213 sendMessage(
214 [
215 {
216 "cmd": "Connect",
217 "password": ap_pass,
218 "game": "Lingo 2",
219 "name": ap_user,
220 }
221 ]
222 )
223
224
225func requestSync():
226 sendMessage([{"cmd": "Sync"}])
227
228
229func sendLocation(loc_id):
230 sendMessage([{"cmd": "LocationChecks", "locations": [loc_id]}])
231
232
233func sendLocations(loc_ids):
234 sendMessage([{"cmd": "LocationChecks", "locations": loc_ids}])
235
236
237func say(textdata):
238 sendMessage([{"cmd": "Say", "text": textdata}])
239
240
241func completedGoal():
242 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL
243
244
245func scoutLocations(loc_ids):
246 sendMessage([{"cmd": "LocationScouts", "locations": loc_ids}])
247
248
249func updateKeyboard(updates):
250 sendMessage([{"cmd": "UpdateKeyboard", "keyboard": updates}])
251
252
253func checkWorldport(port_id):
254 if not _checked_worldports.has(port_id):
255 sendMessage([{"cmd": "CheckWorldport", "port_id": port_id}])
256
257
258func getLogicalPath(object_type, object_id):
259 var msg = {"cmd": "GetPath", "type": object_type}
260 if object_id != null:
261 msg["id"] = object_id
262
263 sendMessage([msg])
264
265
266func sendQuit():
267 sendMessage([{"cmd": "Quit"}])
268
269
270func hasItem(item_id):
271 return _received_items.has(item_id)
272
273
274func getItemAmount(item_id):
275 return _received_items.get(item_id, 0)