mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
[MP] Fix nested spawning during "ready".
We want our spawns to be notified after ready, but we need to notify them in the order they entered tree, so that nested spawners can be used during "ready" (instead of having to await a frame).
This commit is contained in:
parent
629796c333
commit
ad3a4214c5
4 changed files with 52 additions and 17 deletions
|
@ -125,6 +125,20 @@ void SceneReplicationInterface::on_reset() {
|
|||
}
|
||||
|
||||
void SceneReplicationInterface::on_network_process() {
|
||||
// Prevent endless stalling in case of unforseen 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,19 +158,41 @@ 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);
|
||||
|
||||
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);
|
||||
}
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
spawn_queue.clear();
|
||||
}
|
||||
|
||||
Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) {
|
||||
Node *node = Object::cast_to<Node>(p_obj);
|
||||
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue