multiplayer_replicator.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*************************************************************************/
  2. /* multiplayer_replicator.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  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. #include "core/io/multiplayer_replicator.h"
  31. #include "core/io/marshalls.h"
  32. #include "scene/main/node.h"
  33. #include "scene/resources/packed_scene.h"
  34. #define MAKE_ROOM(m_amount) \
  35. if (packet_cache.size() < m_amount) \
  36. packet_cache.resize(m_amount);
  37. Error MultiplayerReplicator::_send_default_spawn_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, Object *p_obj, const NodePath &p_path, bool p_spawn) {
  38. ERR_FAIL_COND_V(p_spawn && !p_obj, ERR_INVALID_PARAMETER);
  39. ERR_FAIL_COND_V(!replications.has(p_scene_id), ERR_INVALID_PARAMETER);
  40. Error err;
  41. // Prepare state
  42. List<Variant> state_variants;
  43. int state_len = 0;
  44. const SceneConfig &cfg = replications[p_scene_id];
  45. if (p_spawn) {
  46. if ((err = _get_state(cfg.properties, p_obj, state_variants)) != OK) {
  47. return err;
  48. }
  49. }
  50. bool is_raw = false;
  51. if (state_variants.size() == 1 && state_variants[0].get_type() == Variant::PACKED_BYTE_ARRAY) {
  52. is_raw = true;
  53. } else if (state_variants.size()) {
  54. err = _encode_state(state_variants, nullptr, state_len);
  55. ERR_FAIL_COND_V(err, err);
  56. } else {
  57. is_raw = true;
  58. }
  59. int ofs = 0;
  60. // Prepare simplified path
  61. const Node *root_node = multiplayer->get_root_node();
  62. ERR_FAIL_COND_V(!root_node, ERR_UNCONFIGURED);
  63. NodePath rel_path = (root_node->get_path()).rel_path_to(p_path);
  64. const Vector<StringName> names = rel_path.get_names();
  65. ERR_FAIL_COND_V(names.size() < 2, ERR_INVALID_PARAMETER);
  66. NodePath parent = NodePath(names.subarray(0, names.size() - 2), false);
  67. ERR_FAIL_COND_V_MSG(!root_node->has_node(parent), ERR_INVALID_PARAMETER, "Path not found: " + parent);
  68. int path_id = 0;
  69. multiplayer->send_confirm_path(root_node->get_node(parent), parent, p_peer_id, path_id);
  70. // Encode name and parent ID.
  71. CharString cname = String(names[names.size() - 1]).utf8();
  72. int nlen = encode_cstring(cname.get_data(), nullptr);
  73. MAKE_ROOM(SPAWN_CMD_OFFSET + 4 + 4 + nlen + state_len);
  74. uint8_t *ptr = packet_cache.ptrw();
  75. ptr[0] = (p_spawn ? MultiplayerAPI::NETWORK_COMMAND_SPAWN : MultiplayerAPI::NETWORK_COMMAND_DESPAWN) + ((is_raw ? 1 : 0) << MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT);
  76. ofs = 1;
  77. ofs += encode_uint64(p_scene_id, &ptr[ofs]);
  78. ofs += encode_uint32(path_id, &ptr[ofs]);
  79. ofs += encode_uint32(nlen, &ptr[ofs]);
  80. ofs += encode_cstring(cname.get_data(), &ptr[ofs]);
  81. // Encode state.
  82. if (!is_raw) {
  83. _encode_state(state_variants, &ptr[ofs], state_len);
  84. } else if (state_len) {
  85. PackedByteArray pba = state_variants[0];
  86. memcpy(&ptr[ofs], pba.ptr(), state_len);
  87. }
  88. Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer();
  89. network_peer->set_target_peer(p_peer_id);
  90. network_peer->set_transfer_channel(0);
  91. network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
  92. return network_peer->put_packet(ptr, ofs + state_len);
  93. }
  94. void MultiplayerReplicator::_process_default_spawn_despawn(int p_from, const ResourceUID::ID &p_scene_id, const uint8_t *p_packet, int p_packet_len, bool p_spawn) {
  95. ERR_FAIL_COND_MSG(p_packet_len < SPAWN_CMD_OFFSET + 9, "Invalid spawn packet received");
  96. int ofs = SPAWN_CMD_OFFSET;
  97. uint32_t node_target = decode_uint32(&p_packet[ofs]);
  98. Node *parent = multiplayer->get_cached_node(p_from, node_target);
  99. ofs += 4;
  100. ERR_FAIL_COND_MSG(parent == nullptr, "Invalid packet received. Requested node was not found.");
  101. uint32_t name_len = decode_uint32(&p_packet[ofs]);
  102. ofs += 4;
  103. ERR_FAIL_COND_MSG(name_len > uint32_t(p_packet_len - ofs), vformat("Invalid spawn packet size: %d, wants: %d", p_packet_len, ofs + name_len));
  104. ERR_FAIL_COND_MSG(name_len < 1, "Zero spawn name size.");
  105. const String name = String::utf8((const char *)&p_packet[ofs], name_len);
  106. // We need to make sure no trickery happens here (e.g. despawning a subpath), but we want to allow autogenerated ("@") node names.
  107. ERR_FAIL_COND_MSG(name.validate_node_name() != name.replace("@", ""), vformat("Invalid node name received: '%s'", name));
  108. ofs += name_len;
  109. const SceneConfig &cfg = replications[p_scene_id];
  110. if (cfg.mode == REPLICATION_MODE_SERVER && p_from == 1) {
  111. String scene_path = ResourceUID::get_singleton()->get_id_path(p_scene_id);
  112. if (p_spawn) {
  113. const bool is_raw = ((p_packet[0] & 64) >> MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1;
  114. ERR_FAIL_COND_MSG(parent->has_node(name), vformat("Unable to spawn node. Node already exists: %s/%s", parent->get_path(), name));
  115. RES res = ResourceLoader::load(scene_path);
  116. ERR_FAIL_COND_MSG(!res.is_valid(), "Unable to load scene to spawn at path: " + scene_path);
  117. PackedScene *scene = Object::cast_to<PackedScene>(res.ptr());
  118. ERR_FAIL_COND(!scene);
  119. Node *node = scene->instantiate();
  120. ERR_FAIL_COND(!node);
  121. replicated_nodes[node->get_instance_id()] = p_scene_id;
  122. int size;
  123. _decode_state(cfg.properties, node, &p_packet[ofs], p_packet_len - ofs, size, is_raw);
  124. parent->_add_child_nocheck(node, name);
  125. emit_signal(SNAME("spawned"), p_scene_id, node);
  126. } else {
  127. ERR_FAIL_COND_MSG(!parent->has_node(name), vformat("Path not found: %s/%s", parent->get_path(), name));
  128. Node *node = parent->get_node(name);
  129. ERR_FAIL_COND_MSG(!replicated_nodes.has(node->get_instance_id()), vformat("Trying to despawn a Node that was not replicated: %s/%s", parent->get_path(), name));
  130. emit_signal(SNAME("despawned"), p_scene_id, node);
  131. replicated_nodes.erase(node->get_instance_id());
  132. node->queue_delete();
  133. }
  134. } else {
  135. PackedByteArray data;
  136. if (p_packet_len > ofs) {
  137. data.resize(p_packet_len - ofs);
  138. memcpy(data.ptrw(), &p_packet[ofs], data.size());
  139. }
  140. if (p_spawn) {
  141. emit_signal(SNAME("spawn_requested"), p_from, p_scene_id, parent, name, data);
  142. } else {
  143. emit_signal(SNAME("despawn_requested"), p_from, p_scene_id, parent, name, data);
  144. }
  145. }
  146. }
  147. void MultiplayerReplicator::process_spawn_despawn(int p_from, const uint8_t *p_packet, int p_packet_len, bool p_spawn) {
  148. ERR_FAIL_COND_MSG(p_packet_len < SPAWN_CMD_OFFSET, "Invalid spawn packet received");
  149. ResourceUID::ID id = decode_uint64(&p_packet[1]);
  150. ERR_FAIL_COND_MSG(!replications.has(id), "Invalid spawn ID received " + itos(id));
  151. const SceneConfig &cfg = replications[id];
  152. if (cfg.on_spawn_despawn_receive.is_valid()) {
  153. int ofs = SPAWN_CMD_OFFSET;
  154. bool is_raw = ((p_packet[0] & 64) >> MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1;
  155. Variant data;
  156. int left = p_packet_len - ofs;
  157. if (is_raw && left) {
  158. PackedByteArray pba;
  159. pba.resize(left);
  160. memcpy(pba.ptrw(), &p_packet[ofs], pba.size());
  161. data = pba;
  162. } else if (left) {
  163. ERR_FAIL_COND(decode_variant(data, &p_packet[ofs], left) != OK);
  164. }
  165. Variant args[4];
  166. args[0] = p_from;
  167. args[1] = id;
  168. args[2] = data;
  169. args[3] = p_spawn;
  170. const Variant *argp[] = { &args[0], &args[1], &args[2], &args[3] };
  171. Callable::CallError ce;
  172. Variant ret;
  173. cfg.on_spawn_despawn_receive.call(argp, 4, ret, ce);
  174. ERR_FAIL_COND_MSG(ce.error != Callable::CallError::CALL_OK, "Custom receive function failed");
  175. } else {
  176. _process_default_spawn_despawn(p_from, id, p_packet, p_packet_len, p_spawn);
  177. }
  178. }
  179. Error MultiplayerReplicator::_get_state(const List<StringName> &p_properties, const Object *p_obj, List<Variant> &r_variant) {
  180. ERR_FAIL_COND_V_MSG(!p_obj, ERR_INVALID_PARAMETER, "Cannot encode null object");
  181. for (const StringName &prop : p_properties) {
  182. bool valid = false;
  183. const Variant v = p_obj->get(prop, &valid);
  184. ERR_FAIL_COND_V_MSG(!valid, ERR_INVALID_DATA, vformat("Property '%s' not found.", prop));
  185. r_variant.push_back(v);
  186. }
  187. return OK;
  188. }
  189. Error MultiplayerReplicator::_encode_state(const List<Variant> &p_variants, uint8_t *p_buffer, int &r_len, bool *r_raw) {
  190. r_len = 0;
  191. int size = 0;
  192. // Try raw encoding optimization.
  193. if (r_raw && p_variants.size() == 1) {
  194. *r_raw = false;
  195. const Variant v = p_variants[0];
  196. if (v.get_type() == Variant::PACKED_BYTE_ARRAY) {
  197. *r_raw = true;
  198. const PackedByteArray pba = v;
  199. if (p_buffer) {
  200. memcpy(p_buffer, pba.ptr(), pba.size());
  201. }
  202. r_len += pba.size();
  203. } else {
  204. multiplayer->encode_and_compress_variant(v, p_buffer, size);
  205. r_len += size;
  206. }
  207. return OK;
  208. }
  209. // Regular encoding.
  210. for (const Variant &v : p_variants) {
  211. multiplayer->encode_and_compress_variant(v, p_buffer ? p_buffer + r_len : nullptr, size);
  212. r_len += size;
  213. }
  214. return OK;
  215. }
  216. Error MultiplayerReplicator::_decode_state(const List<StringName> &p_properties, Object *p_obj, const uint8_t *p_buffer, int p_len, int &r_len, bool p_raw) {
  217. r_len = 0;
  218. int argc = p_properties.size();
  219. if (argc == 0 && p_raw) {
  220. ERR_FAIL_COND_V_MSG(p_len != 0, ERR_INVALID_DATA, "Buffer has trailing bytes.");
  221. return OK;
  222. }
  223. ERR_FAIL_COND_V(p_raw && argc != 1, ERR_INVALID_DATA);
  224. if (p_raw) {
  225. r_len = p_len;
  226. PackedByteArray pba;
  227. pba.resize(p_len);
  228. memcpy(pba.ptrw(), p_buffer, p_len);
  229. p_obj->set(p_properties[0], pba);
  230. return OK;
  231. }
  232. Vector<Variant> args;
  233. Vector<const Variant *> argp;
  234. args.resize(argc);
  235. for (int i = 0; i < argc; i++) {
  236. ERR_FAIL_COND_V_MSG(r_len >= p_len, ERR_INVALID_DATA, "Invalid packet received. Size too small.");
  237. int vlen;
  238. Error err = multiplayer->decode_and_decompress_variant(args.write[i], &p_buffer[r_len], p_len - r_len, &vlen);
  239. ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid packet received. Unable to decode state variable.");
  240. r_len += vlen;
  241. }
  242. ERR_FAIL_COND_V_MSG(p_len - r_len != 0, ERR_INVALID_DATA, "Buffer has trailing bytes.");
  243. int i = 0;
  244. for (const StringName &prop : p_properties) {
  245. p_obj->set(prop, args[i]);
  246. i += 1;
  247. }
  248. return OK;
  249. }
  250. Error MultiplayerReplicator::spawn_config(const ResourceUID::ID &p_id, ReplicationMode p_mode, const TypedArray<StringName> &p_props, const Callable &p_on_send, const Callable &p_on_recv) {
  251. ERR_FAIL_COND_V(p_mode < REPLICATION_MODE_NONE || p_mode > REPLICATION_MODE_CUSTOM, ERR_INVALID_PARAMETER);
  252. ERR_FAIL_COND_V(!ResourceUID::get_singleton()->has_id(p_id), ERR_INVALID_PARAMETER);
  253. ERR_FAIL_COND_V_MSG(p_on_send.is_valid() != p_on_recv.is_valid(), ERR_INVALID_PARAMETER, "Send and receive custom callables must be both valid or both empty");
  254. #ifdef TOOLS_ENABLED
  255. if (!p_on_send.is_valid()) {
  256. // We allow non scene spawning with custom callables.
  257. String path = ResourceUID::get_singleton()->get_id_path(p_id);
  258. RES res = ResourceLoader::load(path);
  259. ERR_FAIL_COND_V(!res->is_class("PackedScene"), ERR_INVALID_PARAMETER);
  260. }
  261. #endif
  262. if (p_mode == REPLICATION_MODE_NONE) {
  263. if (replications.has(p_id)) {
  264. replications.erase(p_id);
  265. }
  266. } else {
  267. SceneConfig cfg;
  268. cfg.mode = p_mode;
  269. for (int i = 0; i < p_props.size(); i++) {
  270. cfg.properties.push_back(StringName(p_props[i]));
  271. }
  272. cfg.on_spawn_despawn_send = p_on_send;
  273. cfg.on_spawn_despawn_receive = p_on_recv;
  274. replications[p_id] = cfg;
  275. }
  276. return OK;
  277. }
  278. Error MultiplayerReplicator::_send_spawn_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const Variant &p_data, bool p_spawn) {
  279. int data_size = 0;
  280. int is_raw = false;
  281. if (p_data.get_type() == Variant::PACKED_BYTE_ARRAY) {
  282. const PackedByteArray pba = p_data;
  283. is_raw = true;
  284. data_size = p_data.operator PackedByteArray().size();
  285. } else if (p_data.get_type() == Variant::NIL) {
  286. is_raw = true;
  287. } else {
  288. Error err = encode_variant(p_data, nullptr, data_size);
  289. ERR_FAIL_COND_V(err, err);
  290. }
  291. MAKE_ROOM(SPAWN_CMD_OFFSET + data_size);
  292. uint8_t *ptr = packet_cache.ptrw();
  293. ptr[0] = (p_spawn ? MultiplayerAPI::NETWORK_COMMAND_SPAWN : MultiplayerAPI::NETWORK_COMMAND_DESPAWN) + ((is_raw ? 1 : 0) << MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT);
  294. encode_uint64(p_scene_id, &ptr[1]);
  295. if (p_data.get_type() == Variant::PACKED_BYTE_ARRAY) {
  296. const PackedByteArray pba = p_data;
  297. memcpy(&ptr[SPAWN_CMD_OFFSET], pba.ptr(), pba.size());
  298. } else if (data_size) {
  299. encode_variant(p_data, &ptr[SPAWN_CMD_OFFSET], data_size);
  300. }
  301. Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer();
  302. network_peer->set_target_peer(p_peer_id);
  303. network_peer->set_transfer_channel(0);
  304. network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
  305. return network_peer->put_packet(ptr, SPAWN_CMD_OFFSET + data_size);
  306. }
  307. Error MultiplayerReplicator::send_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const Variant &p_data, const NodePath &p_path) {
  308. ERR_FAIL_COND_V_MSG(!replications.has(p_scene_id), ERR_INVALID_PARAMETER, vformat("Spawnable not found: %d", p_scene_id));
  309. const SceneConfig &cfg = replications[p_scene_id];
  310. if (cfg.on_spawn_despawn_send.is_valid()) {
  311. return _send_spawn_despawn(p_peer_id, p_scene_id, p_data, true);
  312. } else {
  313. ERR_FAIL_COND_V_MSG(cfg.mode == REPLICATION_MODE_SERVER && multiplayer->is_network_server(), ERR_UNAVAILABLE, "Manual despawn is restricted in default server mode implementation. Use custom mode if you desire control over server spawn requests.");
  314. NodePath path = p_path;
  315. Object *obj = p_data.get_type() == Variant::OBJECT ? p_data.get_validated_object() : nullptr;
  316. if (path.is_empty() && obj) {
  317. Node *node = Object::cast_to<Node>(obj);
  318. if (node && node->is_inside_tree()) {
  319. path = node->get_path();
  320. }
  321. }
  322. ERR_FAIL_COND_V_MSG(path.is_empty(), ERR_INVALID_PARAMETER, "Despawn default implementation requires a despawn path, or the data to be a node inside the SceneTree");
  323. return _send_default_spawn_despawn(p_peer_id, p_scene_id, obj, path, false);
  324. }
  325. }
  326. Error MultiplayerReplicator::send_spawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const Variant &p_data, const NodePath &p_path) {
  327. ERR_FAIL_COND_V_MSG(!replications.has(p_scene_id), ERR_INVALID_PARAMETER, vformat("Spawnable not found: %d", p_scene_id));
  328. const SceneConfig &cfg = replications[p_scene_id];
  329. if (cfg.on_spawn_despawn_send.is_valid()) {
  330. return _send_spawn_despawn(p_peer_id, p_scene_id, p_data, false);
  331. } else {
  332. ERR_FAIL_COND_V_MSG(cfg.mode == REPLICATION_MODE_SERVER && multiplayer->is_network_server(), ERR_UNAVAILABLE, "Manual spawn is restricted in default server mode implementation. Use custom mode if you desire control over server spawn requests.");
  333. NodePath path = p_path;
  334. Object *obj = p_data.get_type() == Variant::OBJECT ? p_data.get_validated_object() : nullptr;
  335. ERR_FAIL_COND_V_MSG(!obj, ERR_INVALID_PARAMETER, "Spawn default implementation requires the data to be an object.");
  336. if (path.is_empty()) {
  337. Node *node = Object::cast_to<Node>(obj);
  338. if (node && node->is_inside_tree()) {
  339. path = node->get_path();
  340. }
  341. }
  342. ERR_FAIL_COND_V_MSG(path.is_empty(), ERR_INVALID_PARAMETER, "Spawn default implementation requires a spawn path, or the data to be a node inside the SceneTree");
  343. return _send_default_spawn_despawn(p_peer_id, p_scene_id, obj, path, true);
  344. }
  345. }
  346. Error MultiplayerReplicator::_spawn_despawn(ResourceUID::ID p_scene_id, Object *p_obj, int p_peer, bool p_spawn) {
  347. ERR_FAIL_COND_V_MSG(!replications.has(p_scene_id), ERR_INVALID_PARAMETER, vformat("Spawnable not found: %d", p_scene_id));
  348. const SceneConfig &cfg = replications[p_scene_id];
  349. if (cfg.on_spawn_despawn_send.is_valid()) {
  350. Variant args[4];
  351. args[0] = p_peer;
  352. args[1] = p_scene_id;
  353. args[2] = p_obj;
  354. args[3] = true;
  355. const Variant *argp[] = { &args[0], &args[1], &args[2], &args[3] };
  356. Callable::CallError ce;
  357. Variant ret;
  358. cfg.on_spawn_despawn_send.call(argp, 4, ret, ce);
  359. ERR_FAIL_COND_V_MSG(ce.error != Callable::CallError::CALL_OK, FAILED, "Custom send function failed");
  360. return OK;
  361. } else {
  362. Node *node = Object::cast_to<Node>(p_obj);
  363. ERR_FAIL_COND_V_MSG(!p_obj, ERR_INVALID_PARAMETER, "Only nodes can be replicated by the default implementation");
  364. return _send_default_spawn_despawn(p_peer, p_scene_id, node, node->get_path(), p_spawn);
  365. }
  366. }
  367. Error MultiplayerReplicator::spawn(ResourceUID::ID p_scene_id, Object *p_obj, int p_peer) {
  368. return _spawn_despawn(p_scene_id, p_obj, p_peer, true);
  369. }
  370. Error MultiplayerReplicator::despawn(ResourceUID::ID p_scene_id, Object *p_obj, int p_peer) {
  371. return _spawn_despawn(p_scene_id, p_obj, p_peer, false);
  372. }
  373. PackedByteArray MultiplayerReplicator::encode_state(const ResourceUID::ID &p_scene_id, const Object *p_obj) {
  374. PackedByteArray state;
  375. ERR_FAIL_COND_V_MSG(!replications.has(p_scene_id), state, vformat("Spawnable not found: %d", p_scene_id));
  376. const SceneConfig &cfg = replications[p_scene_id];
  377. int len = 0;
  378. List<Variant> state_vars;
  379. Error err = _get_state(cfg.properties, p_obj, state_vars);
  380. ERR_FAIL_COND_V_MSG(err != OK, state, "Unable to retrieve object state.");
  381. err = _encode_state(state_vars, nullptr, len);
  382. ERR_FAIL_COND_V_MSG(err != OK, state, "Unable to encode object state.");
  383. state.resize(len);
  384. _encode_state(state_vars, state.ptrw(), len);
  385. return state;
  386. }
  387. Error MultiplayerReplicator::decode_state(const ResourceUID::ID &p_scene_id, Object *p_obj, const PackedByteArray p_data) {
  388. ERR_FAIL_COND_V_MSG(!replications.has(p_scene_id), ERR_INVALID_PARAMETER, vformat("Spawnable not found: %d", p_scene_id));
  389. const SceneConfig &cfg = replications[p_scene_id];
  390. int size;
  391. return _decode_state(cfg.properties, p_obj, p_data.ptr(), p_data.size(), size);
  392. }
  393. void MultiplayerReplicator::scene_enter_exit_notify(const String &p_scene, Node *p_node, bool p_enter) {
  394. if (!multiplayer->has_network_peer()) {
  395. return;
  396. }
  397. Node *root_node = multiplayer->get_root_node();
  398. ERR_FAIL_COND(!p_node || !p_node->get_parent() || !root_node);
  399. NodePath path = (root_node->get_path()).rel_path_to(p_node->get_parent()->get_path());
  400. if (path.is_empty()) {
  401. return;
  402. }
  403. ResourceUID::ID id = ResourceLoader::get_resource_uid(p_scene);
  404. if (!replications.has(id)) {
  405. return;
  406. }
  407. const SceneConfig &cfg = replications[id];
  408. if (p_enter) {
  409. if (cfg.mode == REPLICATION_MODE_SERVER && multiplayer->is_network_server()) {
  410. replicated_nodes[p_node->get_instance_id()] = id;
  411. spawn(id, p_node, 0);
  412. }
  413. emit_signal(SNAME("replicated_instance_added"), id, p_node);
  414. } else {
  415. if (cfg.mode == REPLICATION_MODE_SERVER && multiplayer->is_network_server() && replicated_nodes.has(p_node->get_instance_id())) {
  416. replicated_nodes.erase(p_node->get_instance_id());
  417. despawn(id, p_node, 0);
  418. }
  419. emit_signal(SNAME("replicated_instance_removed"), id, p_node);
  420. }
  421. }
  422. void MultiplayerReplicator::spawn_all(int p_peer) {
  423. for (const KeyValue<ObjectID, ResourceUID::ID> &E : replicated_nodes) {
  424. // Only server mode adds to replicated_nodes, no need to check it.
  425. Object *obj = ObjectDB::get_instance(E.key);
  426. ERR_CONTINUE(!obj);
  427. Node *node = Object::cast_to<Node>(obj);
  428. ERR_CONTINUE(!node);
  429. spawn(E.value, node, p_peer);
  430. }
  431. }
  432. void MultiplayerReplicator::clear() {
  433. replicated_nodes.clear();
  434. }
  435. void MultiplayerReplicator::_bind_methods() {
  436. ClassDB::bind_method(D_METHOD("spawn_config", "scene_id", "spawn_mode", "properties", "custom_send", "custom_receive"), &MultiplayerReplicator::spawn_config, DEFVAL(TypedArray<StringName>()), DEFVAL(Callable()), DEFVAL(Callable()));
  437. ClassDB::bind_method(D_METHOD("despawn", "scene_id", "object", "peer_id"), &MultiplayerReplicator::despawn, DEFVAL(0));
  438. ClassDB::bind_method(D_METHOD("spawn", "scene_id", "object", "peer_id"), &MultiplayerReplicator::spawn, DEFVAL(0));
  439. ClassDB::bind_method(D_METHOD("send_despawn", "peer_id", "scene_id", "data", "path"), &MultiplayerReplicator::send_despawn, DEFVAL(Variant()), DEFVAL(NodePath()));
  440. ClassDB::bind_method(D_METHOD("send_spawn", "peer_id", "scene_id", "data", "path"), &MultiplayerReplicator::send_spawn, DEFVAL(Variant()), DEFVAL(NodePath()));
  441. ClassDB::bind_method(D_METHOD("encode_state", "scene_id", "object"), &MultiplayerReplicator::encode_state);
  442. ClassDB::bind_method(D_METHOD("decode_state", "scene_id", "object", "data"), &MultiplayerReplicator::decode_state);
  443. ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
  444. ADD_SIGNAL(MethodInfo("spawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
  445. ADD_SIGNAL(MethodInfo("despawn_requested", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data")));
  446. ADD_SIGNAL(MethodInfo("spawn_requested", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data")));
  447. ADD_SIGNAL(MethodInfo("replicated_instance_added", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
  448. ADD_SIGNAL(MethodInfo("replicated_instance_removed", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
  449. BIND_ENUM_CONSTANT(REPLICATION_MODE_NONE);
  450. BIND_ENUM_CONSTANT(REPLICATION_MODE_SERVER);
  451. BIND_ENUM_CONSTANT(REPLICATION_MODE_CUSTOM);
  452. }