1 | /**************************************************************************/ |
2 | /* scene_multiplayer.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "scene_multiplayer.h" |
32 | |
33 | #include "core/debugger/engine_debugger.h" |
34 | #include "core/io/marshalls.h" |
35 | |
36 | #ifdef DEBUG_ENABLED |
37 | #include "core/os/os.h" |
38 | #endif |
39 | |
40 | #include <stdint.h> |
41 | |
42 | #ifdef DEBUG_ENABLED |
43 | _FORCE_INLINE_ void SceneMultiplayer::_profile_bandwidth(const String &p_what, int p_value) { |
44 | if (EngineDebugger::is_profiling("multiplayer:bandwidth" )) { |
45 | Array values; |
46 | values.push_back(p_what); |
47 | values.push_back(OS::get_singleton()->get_ticks_msec()); |
48 | values.push_back(p_value); |
49 | EngineDebugger::profiler_add_frame_data("multiplayer:bandwidth" , values); |
50 | } |
51 | } |
52 | #endif |
53 | |
54 | void SceneMultiplayer::_update_status() { |
55 | MultiplayerPeer::ConnectionStatus status = multiplayer_peer.is_valid() ? multiplayer_peer->get_connection_status() : MultiplayerPeer::CONNECTION_DISCONNECTED; |
56 | if (last_connection_status != status) { |
57 | if (status == MultiplayerPeer::CONNECTION_DISCONNECTED) { |
58 | if (last_connection_status == MultiplayerPeer::CONNECTION_CONNECTING) { |
59 | emit_signal(SNAME("connection_failed" )); |
60 | } else { |
61 | emit_signal(SNAME("server_disconnected" )); |
62 | } |
63 | clear(); |
64 | } |
65 | last_connection_status = status; |
66 | } |
67 | } |
68 | |
69 | Error SceneMultiplayer::poll() { |
70 | _update_status(); |
71 | if (last_connection_status == MultiplayerPeer::CONNECTION_DISCONNECTED) { |
72 | return OK; |
73 | } |
74 | |
75 | multiplayer_peer->poll(); |
76 | |
77 | _update_status(); |
78 | if (last_connection_status != MultiplayerPeer::CONNECTION_CONNECTED) { |
79 | // We might be still connecting, or polling might have resulted in a disconnection. |
80 | return OK; |
81 | } |
82 | |
83 | while (multiplayer_peer->get_available_packet_count()) { |
84 | int sender = multiplayer_peer->get_packet_peer(); |
85 | const uint8_t *packet; |
86 | int len; |
87 | |
88 | int channel = multiplayer_peer->get_packet_channel(); |
89 | MultiplayerPeer::TransferMode mode = multiplayer_peer->get_packet_mode(); |
90 | |
91 | Error err = multiplayer_peer->get_packet(&packet, len); |
92 | ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Error getting packet! %d" , err)); |
93 | |
94 | #ifdef DEBUG_ENABLED |
95 | _profile_bandwidth("in" , len); |
96 | #endif |
97 | |
98 | if (pending_peers.has(sender)) { |
99 | if (pending_peers[sender].local) { |
100 | // If the auth is over, admit the peer at the first packet. |
101 | pending_peers.erase(sender); |
102 | _admit_peer(sender); |
103 | } else { |
104 | ERR_CONTINUE(len < 2 || (packet[0] & CMD_MASK) != NETWORK_COMMAND_SYS || packet[1] != SYS_COMMAND_AUTH); |
105 | // Auth message. |
106 | PackedByteArray pba; |
107 | pba.resize(len - 2); |
108 | if (pba.size()) { |
109 | memcpy(pba.ptrw(), &packet[2], len - 2); |
110 | // User callback |
111 | const Variant sv = sender; |
112 | const Variant pbav = pba; |
113 | const Variant *argv[2] = { &sv, &pbav }; |
114 | Variant ret; |
115 | Callable::CallError ce; |
116 | auth_callback.callp(argv, 2, ret, ce); |
117 | ERR_CONTINUE_MSG(ce.error != Callable::CallError::CALL_OK, "Failed to call authentication callback" ); |
118 | } else { |
119 | // Remote complete notification. |
120 | pending_peers[sender].remote = true; |
121 | if (pending_peers[sender].local) { |
122 | pending_peers.erase(sender); |
123 | _admit_peer(sender); |
124 | } |
125 | } |
126 | continue; // Auth in progress. |
127 | } |
128 | } |
129 | |
130 | ERR_CONTINUE(!connected_peers.has(sender)); |
131 | |
132 | if (len && (packet[0] & CMD_MASK) == NETWORK_COMMAND_SYS) { |
133 | // Sys messages are processed separately since they might call _process_packet themselves. |
134 | if (len > 1 && packet[1] == SYS_COMMAND_AUTH) { |
135 | ERR_CONTINUE(len != 2); |
136 | // If we are here, we already admitted the peer locally, and this is just a confirmation packet. |
137 | continue; |
138 | } |
139 | |
140 | _process_sys(sender, packet, len, mode, channel); |
141 | } else { |
142 | remote_sender_id = sender; |
143 | _process_packet(sender, packet, len); |
144 | remote_sender_id = 0; |
145 | } |
146 | |
147 | _update_status(); |
148 | if (last_connection_status != MultiplayerPeer::CONNECTION_CONNECTED) { // It's possible that processing a packet might have resulted in a disconnection, so check here. |
149 | return OK; |
150 | } |
151 | } |
152 | if (pending_peers.size() && auth_timeout) { |
153 | HashSet<int> to_drop; |
154 | uint64_t time = OS::get_singleton()->get_ticks_msec(); |
155 | for (const KeyValue<int, PendingPeer> &pending : pending_peers) { |
156 | if (pending.value.time + auth_timeout <= time) { |
157 | multiplayer_peer->disconnect_peer(pending.key); |
158 | to_drop.insert(pending.key); |
159 | } |
160 | } |
161 | for (const int &P : to_drop) { |
162 | // Each signal might trigger a disconnection. |
163 | pending_peers.erase(P); |
164 | emit_signal(SNAME("peer_authentication_failed" ), P); |
165 | } |
166 | } |
167 | |
168 | _update_status(); |
169 | if (last_connection_status != MultiplayerPeer::CONNECTION_CONNECTED) { // Signals might have triggered disconnection. |
170 | return OK; |
171 | } |
172 | |
173 | replicator->on_network_process(); |
174 | return OK; |
175 | } |
176 | |
177 | void SceneMultiplayer::clear() { |
178 | last_connection_status = MultiplayerPeer::CONNECTION_DISCONNECTED; |
179 | pending_peers.clear(); |
180 | connected_peers.clear(); |
181 | packet_cache.clear(); |
182 | replicator->on_reset(); |
183 | cache->clear(); |
184 | relay_buffer->clear(); |
185 | } |
186 | |
187 | void SceneMultiplayer::set_root_path(const NodePath &p_path) { |
188 | ERR_FAIL_COND_MSG(!p_path.is_absolute() && !p_path.is_empty(), "SceneMultiplayer root path must be absolute." ); |
189 | root_path = p_path; |
190 | } |
191 | |
192 | NodePath SceneMultiplayer::get_root_path() const { |
193 | return root_path; |
194 | } |
195 | |
196 | void SceneMultiplayer::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) { |
197 | if (p_peer == multiplayer_peer) { |
198 | return; // Nothing to do |
199 | } |
200 | |
201 | ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, |
202 | "Supplied MultiplayerPeer must be connecting or connected." ); |
203 | |
204 | if (multiplayer_peer.is_valid()) { |
205 | multiplayer_peer->disconnect("peer_connected" , callable_mp(this, &SceneMultiplayer::_add_peer)); |
206 | multiplayer_peer->disconnect("peer_disconnected" , callable_mp(this, &SceneMultiplayer::_del_peer)); |
207 | clear(); |
208 | } |
209 | |
210 | multiplayer_peer = p_peer; |
211 | |
212 | if (multiplayer_peer.is_valid()) { |
213 | multiplayer_peer->connect("peer_connected" , callable_mp(this, &SceneMultiplayer::_add_peer)); |
214 | multiplayer_peer->connect("peer_disconnected" , callable_mp(this, &SceneMultiplayer::_del_peer)); |
215 | } |
216 | _update_status(); |
217 | } |
218 | |
219 | Ref<MultiplayerPeer> SceneMultiplayer::get_multiplayer_peer() { |
220 | return multiplayer_peer; |
221 | } |
222 | |
223 | void SceneMultiplayer::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { |
224 | ERR_FAIL_COND_MSG(root_path.is_empty(), "Multiplayer root was not initialized. If you are using custom multiplayer, remember to set the root path via SceneMultiplayer.set_root_path before using it." ); |
225 | ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small." ); |
226 | |
227 | // Extract the `packet_type` from the LSB three bits: |
228 | uint8_t packet_type = p_packet[0] & CMD_MASK; |
229 | |
230 | switch (packet_type) { |
231 | case NETWORK_COMMAND_SIMPLIFY_PATH: { |
232 | cache->process_simplify_path(p_from, p_packet, p_packet_len); |
233 | } break; |
234 | |
235 | case NETWORK_COMMAND_CONFIRM_PATH: { |
236 | cache->process_confirm_path(p_from, p_packet, p_packet_len); |
237 | } break; |
238 | |
239 | case NETWORK_COMMAND_REMOTE_CALL: { |
240 | rpc->process_rpc(p_from, p_packet, p_packet_len); |
241 | } break; |
242 | |
243 | case NETWORK_COMMAND_RAW: { |
244 | _process_raw(p_from, p_packet, p_packet_len); |
245 | } break; |
246 | case NETWORK_COMMAND_SPAWN: { |
247 | replicator->on_spawn_receive(p_from, p_packet, p_packet_len); |
248 | } break; |
249 | case NETWORK_COMMAND_DESPAWN: { |
250 | replicator->on_despawn_receive(p_from, p_packet, p_packet_len); |
251 | } break; |
252 | case NETWORK_COMMAND_SYNC: { |
253 | replicator->on_sync_receive(p_from, p_packet, p_packet_len); |
254 | } break; |
255 | default: { |
256 | ERR_FAIL_MSG("Invalid network command from " + itos(p_from)); |
257 | } break; |
258 | } |
259 | } |
260 | |
261 | #ifdef DEBUG_ENABLED |
262 | _FORCE_INLINE_ Error SceneMultiplayer::_send(const uint8_t *p_packet, int p_packet_len) { |
263 | _profile_bandwidth("out" , p_packet_len); |
264 | return multiplayer_peer->put_packet(p_packet, p_packet_len); |
265 | } |
266 | #endif |
267 | |
268 | Error SceneMultiplayer::send_command(int p_to, const uint8_t *p_packet, int p_packet_len) { |
269 | if (server_relay && get_unique_id() != 1 && p_to != 1 && multiplayer_peer->is_server_relay_supported()) { |
270 | // Send relay packet. |
271 | relay_buffer->seek(0); |
272 | relay_buffer->put_u8(NETWORK_COMMAND_SYS); |
273 | relay_buffer->put_u8(SYS_COMMAND_RELAY); |
274 | relay_buffer->put_32(p_to); // Set the destination. |
275 | relay_buffer->put_data(p_packet, p_packet_len); |
276 | multiplayer_peer->set_target_peer(1); |
277 | const Vector<uint8_t> data = relay_buffer->get_data_array(); |
278 | return _send(data.ptr(), relay_buffer->get_position()); |
279 | } |
280 | if (p_to > 0) { |
281 | ERR_FAIL_COND_V(!connected_peers.has(p_to), ERR_BUG); |
282 | multiplayer_peer->set_target_peer(p_to); |
283 | return _send(p_packet, p_packet_len); |
284 | } else { |
285 | for (const int &pid : connected_peers) { |
286 | if (p_to && pid == -p_to) { |
287 | continue; |
288 | } |
289 | multiplayer_peer->set_target_peer(pid); |
290 | _send(p_packet, p_packet_len); |
291 | } |
292 | return OK; |
293 | } |
294 | } |
295 | |
296 | void SceneMultiplayer::_process_sys(int p_from, const uint8_t *p_packet, int p_packet_len, MultiplayerPeer::TransferMode p_mode, int p_channel) { |
297 | ERR_FAIL_COND_MSG(p_packet_len < SYS_CMD_SIZE, "Invalid packet received. Size too small." ); |
298 | uint8_t sys_cmd_type = p_packet[1]; |
299 | int32_t peer = int32_t(decode_uint32(&p_packet[2])); |
300 | switch (sys_cmd_type) { |
301 | case SYS_COMMAND_ADD_PEER: { |
302 | ERR_FAIL_COND(!server_relay || !multiplayer_peer->is_server_relay_supported() || get_unique_id() == 1 || p_from != 1); |
303 | _admit_peer(peer); // Relayed peers are automatically accepted. |
304 | } break; |
305 | case SYS_COMMAND_DEL_PEER: { |
306 | ERR_FAIL_COND(!server_relay || !multiplayer_peer->is_server_relay_supported() || get_unique_id() == 1 || p_from != 1); |
307 | _del_peer(peer); |
308 | } break; |
309 | case SYS_COMMAND_RELAY: { |
310 | ERR_FAIL_COND(!server_relay || !multiplayer_peer->is_server_relay_supported()); |
311 | ERR_FAIL_COND(p_packet_len < SYS_CMD_SIZE + 1); |
312 | const uint8_t *packet = p_packet + SYS_CMD_SIZE; |
313 | int len = p_packet_len - SYS_CMD_SIZE; |
314 | bool should_process = false; |
315 | if (get_unique_id() == 1) { // I am the server. |
316 | // Direct messages to server should not go through relay. |
317 | ERR_FAIL_COND(peer > 0 && !connected_peers.has(peer)); |
318 | // Send relay packet. |
319 | relay_buffer->seek(0); |
320 | relay_buffer->put_u8(NETWORK_COMMAND_SYS); |
321 | relay_buffer->put_u8(SYS_COMMAND_RELAY); |
322 | relay_buffer->put_32(p_from); // Set the source. |
323 | relay_buffer->put_data(packet, len); |
324 | const Vector<uint8_t> data = relay_buffer->get_data_array(); |
325 | multiplayer_peer->set_transfer_mode(p_mode); |
326 | multiplayer_peer->set_transfer_channel(p_channel); |
327 | if (peer > 0) { |
328 | multiplayer_peer->set_target_peer(peer); |
329 | _send(data.ptr(), relay_buffer->get_position()); |
330 | } else { |
331 | for (const int &P : connected_peers) { |
332 | // Not to sender, nor excluded. |
333 | if (P == p_from || (peer < 0 && P != -peer)) { |
334 | continue; |
335 | } |
336 | multiplayer_peer->set_target_peer(P); |
337 | _send(data.ptr(), relay_buffer->get_position()); |
338 | } |
339 | } |
340 | if (peer == 0 || peer == -1) { |
341 | should_process = true; |
342 | peer = p_from; // Process as the source. |
343 | } |
344 | } else { |
345 | ERR_FAIL_COND(p_from != 1); // Bug. |
346 | should_process = true; |
347 | } |
348 | if (should_process) { |
349 | remote_sender_id = peer; |
350 | _process_packet(peer, packet, len); |
351 | remote_sender_id = 0; |
352 | } |
353 | } break; |
354 | default: { |
355 | ERR_FAIL(); |
356 | } |
357 | } |
358 | } |
359 | |
360 | void SceneMultiplayer::_add_peer(int p_id) { |
361 | if (auth_callback.is_valid()) { |
362 | pending_peers[p_id] = PendingPeer(); |
363 | pending_peers[p_id].time = OS::get_singleton()->get_ticks_msec(); |
364 | emit_signal(SNAME("peer_authenticating" ), p_id); |
365 | return; |
366 | } else { |
367 | _admit_peer(p_id); |
368 | } |
369 | } |
370 | |
371 | void SceneMultiplayer::_admit_peer(int p_id) { |
372 | if (server_relay && get_unique_id() == 1 && multiplayer_peer->is_server_relay_supported()) { |
373 | // Notify others of connection, and send connected peers to newly connected one. |
374 | uint8_t buf[SYS_CMD_SIZE]; |
375 | buf[0] = NETWORK_COMMAND_SYS; |
376 | buf[1] = SYS_COMMAND_ADD_PEER; |
377 | multiplayer_peer->set_transfer_channel(0); |
378 | multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); |
379 | for (const int &P : connected_peers) { |
380 | // Send new peer to already connected. |
381 | encode_uint32(p_id, &buf[2]); |
382 | multiplayer_peer->set_target_peer(P); |
383 | _send(buf, sizeof(buf)); |
384 | // Send already connected to new peer. |
385 | encode_uint32(P, &buf[2]); |
386 | multiplayer_peer->set_target_peer(p_id); |
387 | _send(buf, sizeof(buf)); |
388 | } |
389 | } |
390 | |
391 | connected_peers.insert(p_id); |
392 | cache->on_peer_change(p_id, true); |
393 | replicator->on_peer_change(p_id, true); |
394 | if (p_id == 1) { |
395 | emit_signal(SNAME("connected_to_server" )); |
396 | } |
397 | emit_signal(SNAME("peer_connected" ), p_id); |
398 | } |
399 | |
400 | void SceneMultiplayer::_del_peer(int p_id) { |
401 | if (pending_peers.has(p_id)) { |
402 | pending_peers.erase(p_id); |
403 | emit_signal(SNAME("peer_authentication_failed" ), p_id); |
404 | return; |
405 | } else if (!connected_peers.has(p_id)) { |
406 | return; |
407 | } |
408 | |
409 | if (server_relay && get_unique_id() == 1 && multiplayer_peer->is_server_relay_supported()) { |
410 | // Notify others of disconnection. |
411 | uint8_t buf[SYS_CMD_SIZE]; |
412 | buf[0] = NETWORK_COMMAND_SYS; |
413 | buf[1] = SYS_COMMAND_DEL_PEER; |
414 | multiplayer_peer->set_transfer_channel(0); |
415 | multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); |
416 | encode_uint32(p_id, &buf[2]); |
417 | for (const int &P : connected_peers) { |
418 | if (P == p_id) { |
419 | continue; |
420 | } |
421 | multiplayer_peer->set_target_peer(P); |
422 | _send(buf, sizeof(buf)); |
423 | } |
424 | } |
425 | |
426 | replicator->on_peer_change(p_id, false); |
427 | cache->on_peer_change(p_id, false); |
428 | connected_peers.erase(p_id); |
429 | emit_signal(SNAME("peer_disconnected" ), p_id); |
430 | } |
431 | |
432 | void SceneMultiplayer::disconnect_peer(int p_id) { |
433 | ERR_FAIL_COND(multiplayer_peer.is_null() || multiplayer_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED); |
434 | if (pending_peers.has(p_id)) { |
435 | pending_peers.erase(p_id); |
436 | } else if (connected_peers.has(p_id)) { |
437 | connected_peers.has(p_id); |
438 | } |
439 | multiplayer_peer->disconnect_peer(p_id); |
440 | } |
441 | |
442 | Error SceneMultiplayer::send_bytes(Vector<uint8_t> p_data, int p_to, MultiplayerPeer::TransferMode p_mode, int p_channel) { |
443 | ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet." ); |
444 | ERR_FAIL_COND_V_MSG(!multiplayer_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no multiplayer peer is active." ); |
445 | ERR_FAIL_COND_V_MSG(multiplayer_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a multiplayer peer which is not connected." ); |
446 | |
447 | if (packet_cache.size() < p_data.size() + 1) { |
448 | packet_cache.resize(p_data.size() + 1); |
449 | } |
450 | |
451 | const uint8_t *r = p_data.ptr(); |
452 | packet_cache.write[0] = NETWORK_COMMAND_RAW; |
453 | memcpy(&packet_cache.write[1], &r[0], p_data.size()); |
454 | |
455 | multiplayer_peer->set_transfer_channel(p_channel); |
456 | multiplayer_peer->set_transfer_mode(p_mode); |
457 | return send_command(p_to, packet_cache.ptr(), p_data.size() + 1); |
458 | } |
459 | |
460 | Error SceneMultiplayer::send_auth(int p_to, Vector<uint8_t> p_data) { |
461 | ERR_FAIL_COND_V(multiplayer_peer.is_null() || multiplayer_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED); |
462 | ERR_FAIL_COND_V(!pending_peers.has(p_to), ERR_INVALID_PARAMETER); |
463 | ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_PARAMETER); |
464 | ERR_FAIL_COND_V_MSG(pending_peers[p_to].local, ERR_FILE_CANT_WRITE, "The authentication session was previously marked as completed, no more authentication data can be sent." ); |
465 | ERR_FAIL_COND_V_MSG(pending_peers[p_to].remote, ERR_FILE_CANT_WRITE, "The remote peer notified that the authentication session was completed, no more authentication data can be sent." ); |
466 | |
467 | if (packet_cache.size() < p_data.size() + 2) { |
468 | packet_cache.resize(p_data.size() + 2); |
469 | } |
470 | |
471 | packet_cache.write[0] = NETWORK_COMMAND_SYS; |
472 | packet_cache.write[1] = SYS_COMMAND_AUTH; |
473 | memcpy(&packet_cache.write[2], p_data.ptr(), p_data.size()); |
474 | |
475 | multiplayer_peer->set_target_peer(p_to); |
476 | multiplayer_peer->set_transfer_channel(0); |
477 | multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); |
478 | return _send(packet_cache.ptr(), p_data.size() + 2); |
479 | } |
480 | |
481 | Error SceneMultiplayer::complete_auth(int p_peer) { |
482 | ERR_FAIL_COND_V(multiplayer_peer.is_null() || multiplayer_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED); |
483 | ERR_FAIL_COND_V(!pending_peers.has(p_peer), ERR_INVALID_PARAMETER); |
484 | ERR_FAIL_COND_V_MSG(pending_peers[p_peer].local, ERR_FILE_CANT_WRITE, "The authentication session was already marked as completed." ); |
485 | pending_peers[p_peer].local = true; |
486 | // Notify the remote peer that the authentication has completed. |
487 | uint8_t buf[2] = { NETWORK_COMMAND_SYS, SYS_COMMAND_AUTH }; |
488 | Error err = _send(buf, 2); |
489 | // The remote peer already reported the authentication as completed, so admit the peer. |
490 | // May generate new packets, so it must happen after sending confirmation. |
491 | if (pending_peers[p_peer].remote) { |
492 | pending_peers.erase(p_peer); |
493 | _admit_peer(p_peer); |
494 | } |
495 | return err; |
496 | } |
497 | |
498 | void SceneMultiplayer::set_auth_callback(Callable p_callback) { |
499 | auth_callback = p_callback; |
500 | } |
501 | |
502 | Callable SceneMultiplayer::get_auth_callback() const { |
503 | return auth_callback; |
504 | } |
505 | |
506 | void SceneMultiplayer::set_auth_timeout(double p_timeout) { |
507 | ERR_FAIL_COND_MSG(p_timeout < 0, "Timeout must be greater or equal to 0 (where 0 means no timeout)" ); |
508 | auth_timeout = uint64_t(p_timeout * 1000); |
509 | } |
510 | |
511 | double SceneMultiplayer::get_auth_timeout() const { |
512 | return double(auth_timeout) / 1000.0; |
513 | } |
514 | |
515 | void SceneMultiplayer::_process_raw(int p_from, const uint8_t *p_packet, int p_packet_len) { |
516 | ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small." ); |
517 | |
518 | Vector<uint8_t> out; |
519 | int len = p_packet_len - 1; |
520 | out.resize(len); |
521 | { |
522 | uint8_t *w = out.ptrw(); |
523 | memcpy(&w[0], &p_packet[1], len); |
524 | } |
525 | emit_signal(SNAME("peer_packet" ), p_from, out); |
526 | } |
527 | |
528 | int SceneMultiplayer::get_unique_id() { |
529 | ERR_FAIL_COND_V_MSG(!multiplayer_peer.is_valid(), 0, "No multiplayer peer is assigned. Unable to get unique ID." ); |
530 | return multiplayer_peer->get_unique_id(); |
531 | } |
532 | |
533 | void SceneMultiplayer::set_refuse_new_connections(bool p_refuse) { |
534 | ERR_FAIL_COND_MSG(!multiplayer_peer.is_valid(), "No multiplayer peer is assigned. Unable to set 'refuse_new_connections'." ); |
535 | multiplayer_peer->set_refuse_new_connections(p_refuse); |
536 | } |
537 | |
538 | bool SceneMultiplayer::is_refusing_new_connections() const { |
539 | ERR_FAIL_COND_V_MSG(!multiplayer_peer.is_valid(), false, "No multiplayer peer is assigned. Unable to get 'refuse_new_connections'." ); |
540 | return multiplayer_peer->is_refusing_new_connections(); |
541 | } |
542 | |
543 | Vector<int> SceneMultiplayer::get_peer_ids() { |
544 | ERR_FAIL_COND_V_MSG(!multiplayer_peer.is_valid(), Vector<int>(), "No multiplayer peer is assigned. Assume no peers are connected." ); |
545 | |
546 | Vector<int> ret; |
547 | for (const int &E : connected_peers) { |
548 | ret.push_back(E); |
549 | } |
550 | |
551 | return ret; |
552 | } |
553 | |
554 | Vector<int> SceneMultiplayer::get_authenticating_peer_ids() { |
555 | Vector<int> out; |
556 | out.resize(pending_peers.size()); |
557 | int idx = 0; |
558 | for (const KeyValue<int, PendingPeer> &E : pending_peers) { |
559 | out.write[idx++] = E.key; |
560 | } |
561 | return out; |
562 | } |
563 | |
564 | void SceneMultiplayer::set_allow_object_decoding(bool p_enable) { |
565 | allow_object_decoding = p_enable; |
566 | } |
567 | |
568 | bool SceneMultiplayer::is_object_decoding_allowed() const { |
569 | return allow_object_decoding; |
570 | } |
571 | |
572 | String SceneMultiplayer::get_rpc_md5(const Object *p_obj) { |
573 | return rpc->get_rpc_md5(p_obj); |
574 | } |
575 | |
576 | Error SceneMultiplayer::rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { |
577 | return rpc->rpcp(p_obj, p_peer_id, p_method, p_arg, p_argcount); |
578 | } |
579 | |
580 | Error SceneMultiplayer::object_configuration_add(Object *p_obj, Variant p_config) { |
581 | if (p_obj == nullptr && p_config.get_type() == Variant::NODE_PATH) { |
582 | set_root_path(p_config); |
583 | return OK; |
584 | } |
585 | MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object()); |
586 | MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); |
587 | if (spawner) { |
588 | return replicator->on_spawn(p_obj, p_config); |
589 | } else if (sync) { |
590 | return replicator->on_replication_start(p_obj, p_config); |
591 | } |
592 | return ERR_INVALID_PARAMETER; |
593 | } |
594 | |
595 | Error SceneMultiplayer::object_configuration_remove(Object *p_obj, Variant p_config) { |
596 | if (p_obj == nullptr && p_config.get_type() == Variant::NODE_PATH) { |
597 | ERR_FAIL_COND_V(root_path != p_config.operator NodePath(), ERR_INVALID_PARAMETER); |
598 | set_root_path(NodePath()); |
599 | return OK; |
600 | } |
601 | MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object()); |
602 | MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); |
603 | if (spawner) { |
604 | return replicator->on_despawn(p_obj, p_config); |
605 | } |
606 | if (sync) { |
607 | return replicator->on_replication_stop(p_obj, p_config); |
608 | } |
609 | return ERR_INVALID_PARAMETER; |
610 | } |
611 | |
612 | void SceneMultiplayer::set_server_relay_enabled(bool p_enabled) { |
613 | server_relay = p_enabled; |
614 | } |
615 | |
616 | bool SceneMultiplayer::is_server_relay_enabled() const { |
617 | return server_relay; |
618 | } |
619 | |
620 | void SceneMultiplayer::set_max_sync_packet_size(int p_size) { |
621 | replicator->set_max_sync_packet_size(p_size); |
622 | } |
623 | |
624 | int SceneMultiplayer::get_max_sync_packet_size() const { |
625 | return replicator->get_max_sync_packet_size(); |
626 | } |
627 | |
628 | void SceneMultiplayer::set_max_delta_packet_size(int p_size) { |
629 | replicator->set_max_delta_packet_size(p_size); |
630 | } |
631 | |
632 | int SceneMultiplayer::get_max_delta_packet_size() const { |
633 | return replicator->get_max_delta_packet_size(); |
634 | } |
635 | |
636 | void SceneMultiplayer::_bind_methods() { |
637 | ClassDB::bind_method(D_METHOD("set_root_path" , "path" ), &SceneMultiplayer::set_root_path); |
638 | ClassDB::bind_method(D_METHOD("get_root_path" ), &SceneMultiplayer::get_root_path); |
639 | ClassDB::bind_method(D_METHOD("clear" ), &SceneMultiplayer::clear); |
640 | |
641 | ClassDB::bind_method(D_METHOD("disconnect_peer" , "id" ), &SceneMultiplayer::disconnect_peer); |
642 | |
643 | ClassDB::bind_method(D_METHOD("get_authenticating_peers" ), &SceneMultiplayer::get_authenticating_peer_ids); |
644 | ClassDB::bind_method(D_METHOD("send_auth" , "id" , "data" ), &SceneMultiplayer::send_auth); |
645 | ClassDB::bind_method(D_METHOD("complete_auth" , "id" ), &SceneMultiplayer::complete_auth); |
646 | |
647 | ClassDB::bind_method(D_METHOD("set_auth_callback" , "callback" ), &SceneMultiplayer::set_auth_callback); |
648 | ClassDB::bind_method(D_METHOD("get_auth_callback" ), &SceneMultiplayer::get_auth_callback); |
649 | ClassDB::bind_method(D_METHOD("set_auth_timeout" , "timeout" ), &SceneMultiplayer::set_auth_timeout); |
650 | ClassDB::bind_method(D_METHOD("get_auth_timeout" ), &SceneMultiplayer::get_auth_timeout); |
651 | |
652 | ClassDB::bind_method(D_METHOD("set_refuse_new_connections" , "refuse" ), &SceneMultiplayer::set_refuse_new_connections); |
653 | ClassDB::bind_method(D_METHOD("is_refusing_new_connections" ), &SceneMultiplayer::is_refusing_new_connections); |
654 | ClassDB::bind_method(D_METHOD("set_allow_object_decoding" , "enable" ), &SceneMultiplayer::set_allow_object_decoding); |
655 | ClassDB::bind_method(D_METHOD("is_object_decoding_allowed" ), &SceneMultiplayer::is_object_decoding_allowed); |
656 | ClassDB::bind_method(D_METHOD("set_server_relay_enabled" , "enabled" ), &SceneMultiplayer::set_server_relay_enabled); |
657 | ClassDB::bind_method(D_METHOD("is_server_relay_enabled" ), &SceneMultiplayer::is_server_relay_enabled); |
658 | ClassDB::bind_method(D_METHOD("send_bytes" , "bytes" , "id" , "mode" , "channel" ), &SceneMultiplayer::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); |
659 | |
660 | ClassDB::bind_method(D_METHOD("get_max_sync_packet_size" ), &SceneMultiplayer::get_max_sync_packet_size); |
661 | ClassDB::bind_method(D_METHOD("set_max_sync_packet_size" , "size" ), &SceneMultiplayer::set_max_sync_packet_size); |
662 | ClassDB::bind_method(D_METHOD("get_max_delta_packet_size" ), &SceneMultiplayer::get_max_delta_packet_size); |
663 | ClassDB::bind_method(D_METHOD("set_max_delta_packet_size" , "size" ), &SceneMultiplayer::set_max_delta_packet_size); |
664 | |
665 | ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_path" ), "set_root_path" , "get_root_path" ); |
666 | ADD_PROPERTY(PropertyInfo(Variant::CALLABLE, "auth_callback" ), "set_auth_callback" , "get_auth_callback" ); |
667 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auth_timeout" , PROPERTY_HINT_RANGE, "0,30,0.1,or_greater,suffix:s" ), "set_auth_timeout" , "get_auth_timeout" ); |
668 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding" ), "set_allow_object_decoding" , "is_object_decoding_allowed" ); |
669 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections" ), "set_refuse_new_connections" , "is_refusing_new_connections" ); |
670 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay" ), "set_server_relay_enabled" , "is_server_relay_enabled" ); |
671 | ADD_PROPERTY(PropertyInfo(Variant::INT, "max_sync_packet_size" ), "set_max_sync_packet_size" , "get_max_sync_packet_size" ); |
672 | ADD_PROPERTY(PropertyInfo(Variant::INT, "max_delta_packet_size" ), "set_max_delta_packet_size" , "get_max_delta_packet_size" ); |
673 | |
674 | ADD_PROPERTY_DEFAULT("refuse_new_connections" , false); |
675 | |
676 | ADD_SIGNAL(MethodInfo("peer_authenticating" , PropertyInfo(Variant::INT, "id" ))); |
677 | ADD_SIGNAL(MethodInfo("peer_authentication_failed" , PropertyInfo(Variant::INT, "id" ))); |
678 | ADD_SIGNAL(MethodInfo("peer_packet" , PropertyInfo(Variant::INT, "id" ), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "packet" ))); |
679 | } |
680 | |
681 | SceneMultiplayer::SceneMultiplayer() { |
682 | relay_buffer.instantiate(); |
683 | replicator = Ref<SceneReplicationInterface>(memnew(SceneReplicationInterface(this))); |
684 | rpc = Ref<SceneRPCInterface>(memnew(SceneRPCInterface(this))); |
685 | cache = Ref<SceneCacheInterface>(memnew(SceneCacheInterface(this))); |
686 | set_multiplayer_peer(Ref<OfflineMultiplayerPeer>(memnew(OfflineMultiplayerPeer))); |
687 | } |
688 | |
689 | SceneMultiplayer::~SceneMultiplayer() { |
690 | clear(); |
691 | } |
692 | |