diff options
Diffstat (limited to 'modules/multiplayer/scene_replication_interface.cpp')
-rw-r--r-- | modules/multiplayer/scene_replication_interface.cpp | 54 |
1 files changed, 46 insertions, 8 deletions
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index e1b7b0c346..68b6bc4a24 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -125,6 +125,20 @@ void SceneReplicationInterface::on_reset() { } void SceneReplicationInterface::on_network_process() { + // Prevent endless stalling in case of unforeseen spawn errors. + if (spawn_queue.size()) { + ERR_PRINT("An error happened during last spawn, this usually means the 'ready' signal was not emitted by the spawned node."); + for (const ObjectID &oid : spawn_queue) { + Node *node = get_id_as<Node>(oid); + ERR_CONTINUE(!node); + if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready))) { + node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready)); + } + } + spawn_queue.clear(); + } + + // Process timed syncs. uint64_t msec = OS::get_singleton()->get_ticks_msec(); for (KeyValue<int, PeerInfo> &E : peers_info) { const HashSet<ObjectID> to_sync = E.value.sync_nodes; @@ -144,17 +158,39 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) { // Track node. const ObjectID oid = node->get_instance_id(); TrackedNode &tobj = _track(oid); + + // Spawn state needs to be callected after "ready", but the spawn order follows "enter_tree". ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); tobj.spawner = spawner->get_instance_id(); - spawned_nodes.insert(oid); + spawn_queue.insert(oid); + node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready).bind(oid), Node::CONNECT_ONE_SHOT); + return OK; +} + +void SceneReplicationInterface::_node_ready(const ObjectID &p_oid) { + ERR_FAIL_COND(!spawn_queue.has(p_oid)); // Bug. - if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) { - if (tobj.net_id == 0) { - tobj.net_id = ++last_net_id; + // If we are a nested spawn, we need to wait until the parent is ready. + if (p_oid != *(spawn_queue.begin())) { + return; + } + + for (const ObjectID &oid : spawn_queue) { + ERR_CONTINUE(!tracked_nodes.has(oid)); + + TrackedNode &tobj = tracked_nodes[oid]; + MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tobj.spawner); + ERR_CONTINUE(!spawner); + + spawned_nodes.insert(oid); + if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) { + if (tobj.net_id == 0) { + tobj.net_id = ++last_net_id; + } + _update_spawn_visibility(0, oid); } - _update_spawn_visibility(0, oid); } - return OK; + spawn_queue.clear(); } Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) { @@ -706,6 +742,7 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu ofs += 4; uint32_t size = decode_uint32(&p_buffer[ofs]); ofs += 4; + ERR_FAIL_COND_V(size > uint32_t(p_buffer_len - ofs), ERR_INVALID_DATA); MultiplayerSynchronizer *sync = nullptr; if (net_id & 0x80000000) { sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer->get_path_cache()->get_cached_object(p_from, net_id & 0x7FFFFFFF)); @@ -720,14 +757,15 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu } Node *node = sync->get_root_node(); if (sync->get_multiplayer_authority() != p_from || !node) { - ERR_CONTINUE(true); + // Not valid for me. + ofs += size; + ERR_CONTINUE_MSG(true, "Ignoring sync data from non-authority or for missing node."); } if (!sync->update_inbound_sync_time(time)) { // State is too old. ofs += size; continue; } - ERR_FAIL_COND_V(size > uint32_t(p_buffer_len - ofs), ERR_BUG); const List<NodePath> props = sync->get_replication_config()->get_sync_properties(); Vector<Variant> vars; vars.resize(props.size()); |