| 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 | |