| 1 | /**************************************************************************/ |
| 2 | /* multiplayer_api.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 "multiplayer_api.h" |
| 32 | |
| 33 | #include "core/debugger/engine_debugger.h" |
| 34 | #include "core/io/marshalls.h" |
| 35 | |
| 36 | #include <stdint.h> |
| 37 | |
| 38 | #ifdef DEBUG_ENABLED |
| 39 | #include "core/os/os.h" |
| 40 | #endif |
| 41 | |
| 42 | StringName MultiplayerAPI::default_interface; |
| 43 | |
| 44 | void MultiplayerAPI::set_default_interface(const StringName &p_interface) { |
| 45 | ERR_FAIL_COND_MSG(!ClassDB::is_parent_class(p_interface, MultiplayerAPI::get_class_static()), vformat("Can't make %s the default multiplayer interface since it does not extend MultiplayerAPI." , p_interface)); |
| 46 | default_interface = StringName(p_interface, true); |
| 47 | } |
| 48 | |
| 49 | StringName MultiplayerAPI::get_default_interface() { |
| 50 | return default_interface; |
| 51 | } |
| 52 | |
| 53 | Ref<MultiplayerAPI> MultiplayerAPI::create_default_interface() { |
| 54 | if (default_interface != StringName()) { |
| 55 | return Ref<MultiplayerAPI>(Object::cast_to<MultiplayerAPI>(ClassDB::instantiate(default_interface))); |
| 56 | } |
| 57 | return Ref<MultiplayerAPI>(memnew(MultiplayerAPIExtension)); |
| 58 | } |
| 59 | |
| 60 | // The variant is compressed and encoded; The first byte contains all the meta |
| 61 | // information and the format is: |
| 62 | // - The first LSB 6 bits are used for the variant type. |
| 63 | // - The next two bits are used to store the encoding mode. |
| 64 | // - Boolean values uses the encoding mode to store the value. |
| 65 | #define VARIANT_META_TYPE_MASK 0x3F |
| 66 | #define VARIANT_META_EMODE_MASK 0xC0 |
| 67 | #define VARIANT_META_BOOL_MASK 0x80 |
| 68 | #define ENCODE_8 0 << 6 |
| 69 | #define ENCODE_16 1 << 6 |
| 70 | #define ENCODE_32 2 << 6 |
| 71 | #define ENCODE_64 3 << 6 |
| 72 | Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_allow_object_decoding) { |
| 73 | // Unreachable because `VARIANT_MAX` == 38 and `ENCODE_VARIANT_MASK` == 77 |
| 74 | CRASH_COND(p_variant.get_type() > VARIANT_META_TYPE_MASK); |
| 75 | |
| 76 | uint8_t *buf = r_buffer; |
| 77 | r_len = 0; |
| 78 | uint8_t encode_mode = 0; |
| 79 | |
| 80 | switch (p_variant.get_type()) { |
| 81 | case Variant::BOOL: { |
| 82 | if (buf) { |
| 83 | // We don't use encode_mode for booleans, so we can use it to store the value. |
| 84 | buf[0] = (p_variant.operator bool()) ? (1 << 7) : 0; |
| 85 | buf[0] |= p_variant.get_type(); |
| 86 | } |
| 87 | r_len += 1; |
| 88 | } break; |
| 89 | case Variant::INT: { |
| 90 | if (buf) { |
| 91 | // Reserve the first byte for the meta. |
| 92 | buf += 1; |
| 93 | } |
| 94 | r_len += 1; |
| 95 | int64_t val = p_variant; |
| 96 | if (val <= (int64_t)INT8_MAX && val >= (int64_t)INT8_MIN) { |
| 97 | // Use 8 bit |
| 98 | encode_mode = ENCODE_8; |
| 99 | if (buf) { |
| 100 | buf[0] = val; |
| 101 | } |
| 102 | r_len += 1; |
| 103 | } else if (val <= (int64_t)INT16_MAX && val >= (int64_t)INT16_MIN) { |
| 104 | // Use 16 bit |
| 105 | encode_mode = ENCODE_16; |
| 106 | if (buf) { |
| 107 | encode_uint16(val, buf); |
| 108 | } |
| 109 | r_len += 2; |
| 110 | } else if (val <= (int64_t)INT32_MAX && val >= (int64_t)INT32_MIN) { |
| 111 | // Use 32 bit |
| 112 | encode_mode = ENCODE_32; |
| 113 | if (buf) { |
| 114 | encode_uint32(val, buf); |
| 115 | } |
| 116 | r_len += 4; |
| 117 | } else { |
| 118 | // Use 64 bit |
| 119 | encode_mode = ENCODE_64; |
| 120 | if (buf) { |
| 121 | encode_uint64(val, buf); |
| 122 | } |
| 123 | r_len += 8; |
| 124 | } |
| 125 | // Store the meta |
| 126 | if (buf) { |
| 127 | buf -= 1; |
| 128 | buf[0] = encode_mode | p_variant.get_type(); |
| 129 | } |
| 130 | } break; |
| 131 | default: |
| 132 | // Any other case is not yet compressed. |
| 133 | Error err = encode_variant(p_variant, r_buffer, r_len, p_allow_object_decoding); |
| 134 | if (err != OK) { |
| 135 | return err; |
| 136 | } |
| 137 | if (r_buffer) { |
| 138 | // The first byte is not used by the marshaling, so store the type |
| 139 | // so we know how to decompress and decode this variant. |
| 140 | r_buffer[0] = p_variant.get_type(); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | return OK; |
| 145 | } |
| 146 | |
| 147 | Error MultiplayerAPI::decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len, bool p_allow_object_decoding) { |
| 148 | const uint8_t *buf = p_buffer; |
| 149 | int len = p_len; |
| 150 | |
| 151 | ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA); |
| 152 | uint8_t type = buf[0] & VARIANT_META_TYPE_MASK; |
| 153 | uint8_t encode_mode = buf[0] & VARIANT_META_EMODE_MASK; |
| 154 | |
| 155 | ERR_FAIL_COND_V(type >= Variant::VARIANT_MAX, ERR_INVALID_DATA); |
| 156 | |
| 157 | switch (type) { |
| 158 | case Variant::BOOL: { |
| 159 | bool val = (buf[0] & VARIANT_META_BOOL_MASK) > 0; |
| 160 | r_variant = val; |
| 161 | if (r_len) { |
| 162 | *r_len = 1; |
| 163 | } |
| 164 | } break; |
| 165 | case Variant::INT: { |
| 166 | buf += 1; |
| 167 | len -= 1; |
| 168 | if (r_len) { |
| 169 | *r_len = 1; |
| 170 | } |
| 171 | if (encode_mode == ENCODE_8) { |
| 172 | // 8 bits. |
| 173 | ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA); |
| 174 | int8_t val = buf[0]; |
| 175 | r_variant = val; |
| 176 | if (r_len) { |
| 177 | (*r_len) += 1; |
| 178 | } |
| 179 | } else if (encode_mode == ENCODE_16) { |
| 180 | // 16 bits. |
| 181 | ERR_FAIL_COND_V(len < 2, ERR_INVALID_DATA); |
| 182 | int16_t val = decode_uint16(buf); |
| 183 | r_variant = val; |
| 184 | if (r_len) { |
| 185 | (*r_len) += 2; |
| 186 | } |
| 187 | } else if (encode_mode == ENCODE_32) { |
| 188 | // 32 bits. |
| 189 | ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); |
| 190 | int32_t val = decode_uint32(buf); |
| 191 | r_variant = val; |
| 192 | if (r_len) { |
| 193 | (*r_len) += 4; |
| 194 | } |
| 195 | } else { |
| 196 | // 64 bits. |
| 197 | ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); |
| 198 | int64_t val = decode_uint64(buf); |
| 199 | r_variant = val; |
| 200 | if (r_len) { |
| 201 | (*r_len) += 8; |
| 202 | } |
| 203 | } |
| 204 | } break; |
| 205 | default: |
| 206 | Error err = decode_variant(r_variant, p_buffer, p_len, r_len, p_allow_object_decoding); |
| 207 | if (err != OK) { |
| 208 | return err; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | return OK; |
| 213 | } |
| 214 | |
| 215 | Error MultiplayerAPI::encode_and_compress_variants(const Variant **p_variants, int p_count, uint8_t *p_buffer, int &r_len, bool *r_raw, bool p_allow_object_decoding) { |
| 216 | r_len = 0; |
| 217 | int size = 0; |
| 218 | |
| 219 | if (p_count == 0) { |
| 220 | if (r_raw) { |
| 221 | *r_raw = true; |
| 222 | } |
| 223 | return OK; |
| 224 | } |
| 225 | |
| 226 | // Try raw encoding optimization. |
| 227 | if (r_raw && p_count == 1) { |
| 228 | *r_raw = false; |
| 229 | const Variant &v = *(p_variants[0]); |
| 230 | if (v.get_type() == Variant::PACKED_BYTE_ARRAY) { |
| 231 | *r_raw = true; |
| 232 | const PackedByteArray pba = v; |
| 233 | if (p_buffer) { |
| 234 | memcpy(p_buffer, pba.ptr(), pba.size()); |
| 235 | } |
| 236 | r_len += pba.size(); |
| 237 | } else { |
| 238 | encode_and_compress_variant(v, p_buffer, size, p_allow_object_decoding); |
| 239 | r_len += size; |
| 240 | } |
| 241 | return OK; |
| 242 | } |
| 243 | |
| 244 | // Regular encoding. |
| 245 | for (int i = 0; i < p_count; i++) { |
| 246 | const Variant &v = *(p_variants[i]); |
| 247 | encode_and_compress_variant(v, p_buffer ? p_buffer + r_len : nullptr, size, p_allow_object_decoding); |
| 248 | r_len += size; |
| 249 | } |
| 250 | return OK; |
| 251 | } |
| 252 | |
| 253 | Error MultiplayerAPI::decode_and_decompress_variants(Vector<Variant> &r_variants, const uint8_t *p_buffer, int p_len, int &r_len, bool p_raw, bool p_allow_object_decoding) { |
| 254 | r_len = 0; |
| 255 | int argc = r_variants.size(); |
| 256 | if (argc == 0 && p_raw) { |
| 257 | return OK; |
| 258 | } |
| 259 | ERR_FAIL_COND_V(p_raw && argc != 1, ERR_INVALID_DATA); |
| 260 | if (p_raw) { |
| 261 | r_len = p_len; |
| 262 | PackedByteArray pba; |
| 263 | pba.resize(p_len); |
| 264 | memcpy(pba.ptrw(), p_buffer, p_len); |
| 265 | r_variants.write[0] = pba; |
| 266 | return OK; |
| 267 | } |
| 268 | |
| 269 | Vector<Variant> args; |
| 270 | Vector<const Variant *> argp; |
| 271 | args.resize(argc); |
| 272 | |
| 273 | for (int i = 0; i < argc; i++) { |
| 274 | ERR_FAIL_COND_V_MSG(r_len >= p_len, ERR_INVALID_DATA, "Invalid packet received. Size too small." ); |
| 275 | |
| 276 | int vlen; |
| 277 | Error err = MultiplayerAPI::decode_and_decompress_variant(r_variants.write[i], &p_buffer[r_len], p_len - r_len, &vlen, p_allow_object_decoding); |
| 278 | ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid packet received. Unable to decode state variable." ); |
| 279 | r_len += vlen; |
| 280 | } |
| 281 | return OK; |
| 282 | } |
| 283 | |
| 284 | Error MultiplayerAPI::_rpc_bind(int p_peer, Object *p_object, const StringName &p_method, Array p_args) { |
| 285 | Vector<Variant> args; |
| 286 | Vector<const Variant *> argsp; |
| 287 | args.resize(p_args.size()); |
| 288 | argsp.resize(p_args.size()); |
| 289 | Variant *ptr = args.ptrw(); |
| 290 | const Variant **pptr = argsp.ptrw(); |
| 291 | for (int i = 0; i < p_args.size(); i++) { |
| 292 | ptr[i] = p_args[i]; |
| 293 | pptr[i] = &ptr[i]; |
| 294 | } |
| 295 | return rpcp(p_object, p_peer, p_method, argsp.size() ? argsp.ptrw() : nullptr, argsp.size()); |
| 296 | } |
| 297 | |
| 298 | void MultiplayerAPI::_bind_methods() { |
| 299 | ClassDB::bind_method(D_METHOD("has_multiplayer_peer" ), &MultiplayerAPI::has_multiplayer_peer); |
| 300 | ClassDB::bind_method(D_METHOD("get_multiplayer_peer" ), &MultiplayerAPI::get_multiplayer_peer); |
| 301 | ClassDB::bind_method(D_METHOD("set_multiplayer_peer" , "peer" ), &MultiplayerAPI::set_multiplayer_peer); |
| 302 | ClassDB::bind_method(D_METHOD("get_unique_id" ), &MultiplayerAPI::get_unique_id); |
| 303 | ClassDB::bind_method(D_METHOD("is_server" ), &MultiplayerAPI::is_server); |
| 304 | ClassDB::bind_method(D_METHOD("get_remote_sender_id" ), &MultiplayerAPI::get_remote_sender_id); |
| 305 | ClassDB::bind_method(D_METHOD("poll" ), &MultiplayerAPI::poll); |
| 306 | ClassDB::bind_method(D_METHOD("rpc" , "peer" , "object" , "method" , "arguments" ), &MultiplayerAPI::_rpc_bind, DEFVAL(Array())); |
| 307 | ClassDB::bind_method(D_METHOD("object_configuration_add" , "object" , "configuration" ), &MultiplayerAPI::object_configuration_add); |
| 308 | ClassDB::bind_method(D_METHOD("object_configuration_remove" , "object" , "configuration" ), &MultiplayerAPI::object_configuration_remove); |
| 309 | |
| 310 | ClassDB::bind_method(D_METHOD("get_peers" ), &MultiplayerAPI::get_peer_ids); |
| 311 | |
| 312 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer_peer" , PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerPeer" , PROPERTY_USAGE_NONE), "set_multiplayer_peer" , "get_multiplayer_peer" ); |
| 313 | |
| 314 | ClassDB::bind_static_method("MultiplayerAPI" , D_METHOD("set_default_interface" , "interface_name" ), &MultiplayerAPI::set_default_interface); |
| 315 | ClassDB::bind_static_method("MultiplayerAPI" , D_METHOD("get_default_interface" ), &MultiplayerAPI::get_default_interface); |
| 316 | ClassDB::bind_static_method("MultiplayerAPI" , D_METHOD("create_default_interface" ), &MultiplayerAPI::create_default_interface); |
| 317 | |
| 318 | ADD_SIGNAL(MethodInfo("peer_connected" , PropertyInfo(Variant::INT, "id" ))); |
| 319 | ADD_SIGNAL(MethodInfo("peer_disconnected" , PropertyInfo(Variant::INT, "id" ))); |
| 320 | ADD_SIGNAL(MethodInfo("connected_to_server" )); |
| 321 | ADD_SIGNAL(MethodInfo("connection_failed" )); |
| 322 | ADD_SIGNAL(MethodInfo("server_disconnected" )); |
| 323 | |
| 324 | BIND_ENUM_CONSTANT(RPC_MODE_DISABLED); |
| 325 | BIND_ENUM_CONSTANT(RPC_MODE_ANY_PEER); |
| 326 | BIND_ENUM_CONSTANT(RPC_MODE_AUTHORITY); |
| 327 | } |
| 328 | |
| 329 | /// MultiplayerAPIExtension |
| 330 | |
| 331 | Error MultiplayerAPIExtension::poll() { |
| 332 | Error err = OK; |
| 333 | GDVIRTUAL_CALL(_poll, err); |
| 334 | return err; |
| 335 | } |
| 336 | |
| 337 | void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) { |
| 338 | GDVIRTUAL_CALL(_set_multiplayer_peer, p_peer); |
| 339 | } |
| 340 | |
| 341 | Ref<MultiplayerPeer> MultiplayerAPIExtension::get_multiplayer_peer() { |
| 342 | Ref<MultiplayerPeer> peer; |
| 343 | GDVIRTUAL_CALL(_get_multiplayer_peer, peer); |
| 344 | return peer; |
| 345 | } |
| 346 | |
| 347 | int MultiplayerAPIExtension::get_unique_id() { |
| 348 | int id = 1; |
| 349 | GDVIRTUAL_CALL(_get_unique_id, id); |
| 350 | return id; |
| 351 | } |
| 352 | |
| 353 | Vector<int> MultiplayerAPIExtension::get_peer_ids() { |
| 354 | Vector<int> ids; |
| 355 | GDVIRTUAL_CALL(_get_peer_ids, ids); |
| 356 | return ids; |
| 357 | } |
| 358 | |
| 359 | Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { |
| 360 | if (!GDVIRTUAL_IS_OVERRIDDEN(_rpc)) { |
| 361 | return ERR_UNAVAILABLE; |
| 362 | } |
| 363 | Array args; |
| 364 | for (int i = 0; i < p_argcount; i++) { |
| 365 | args.push_back(*p_arg[i]); |
| 366 | } |
| 367 | Error ret = FAILED; |
| 368 | GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret); |
| 369 | return ret; |
| 370 | } |
| 371 | |
| 372 | int MultiplayerAPIExtension::get_remote_sender_id() { |
| 373 | int id = 0; |
| 374 | GDVIRTUAL_CALL(_get_remote_sender_id, id); |
| 375 | return id; |
| 376 | } |
| 377 | |
| 378 | Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) { |
| 379 | Error err = ERR_UNAVAILABLE; |
| 380 | GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err); |
| 381 | return err; |
| 382 | } |
| 383 | |
| 384 | Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) { |
| 385 | Error err = ERR_UNAVAILABLE; |
| 386 | GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err); |
| 387 | return err; |
| 388 | } |
| 389 | |
| 390 | void MultiplayerAPIExtension::_bind_methods() { |
| 391 | GDVIRTUAL_BIND(_poll); |
| 392 | GDVIRTUAL_BIND(_set_multiplayer_peer, "multiplayer_peer" ); |
| 393 | GDVIRTUAL_BIND(_get_multiplayer_peer); |
| 394 | GDVIRTUAL_BIND(_get_unique_id); |
| 395 | GDVIRTUAL_BIND(_get_peer_ids); |
| 396 | GDVIRTUAL_BIND(_rpc, "peer" , "object" , "method" , "args" ); |
| 397 | GDVIRTUAL_BIND(_get_remote_sender_id); |
| 398 | GDVIRTUAL_BIND(_object_configuration_add, "object" , "configuration" ); |
| 399 | GDVIRTUAL_BIND(_object_configuration_remove, "object" , "configuration" ); |
| 400 | } |
| 401 | |