1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-07 12:30:27 +00:00

[MP] Allow multiple synchronizers per node.

The same node can now be controlled by multiple synchronizers at once.
Spawn visibility is composed in OR across multiple synchronizers (i.e.
if any synchronizer is visible to the peer, the object will be spawned).

Synchronizers controlling spawned nodes can now have a different
authority then the one spawning the node, in that case, the spawn
variables for that specific synchronizer are simply ignored (other
synchronizers with the same authority of the spawner will correctly
synchronize variables on spawn).

The SceneReplicationState class has been completly removed, since it was
bloating the implementation, the state is now simply stored in the
SceneReplicationInterface.
This commit is contained in:
Fabio Alessandrelli
2022-09-30 22:35:56 +02:00
parent 04a28763c0
commit 32a62af648
6 changed files with 409 additions and 565 deletions

View File

@@ -31,9 +31,10 @@
#ifndef SCENE_REPLICATION_INTERFACE_H
#define SCENE_REPLICATION_INTERFACE_H
#include "scene/main/multiplayer_api.h"
#include "core/object/ref_counted.h"
#include "scene_replication_state.h"
#include "multiplayer_spawner.h"
#include "multiplayer_synchronizer.h"
class SceneMultiplayer;
@@ -41,25 +42,68 @@ class SceneReplicationInterface : public RefCounted {
GDCLASS(SceneReplicationInterface, RefCounted);
private:
void _send_sync(int p_peer, uint64_t p_msec);
Error _make_spawn_packet(Node *p_node, int &r_len);
Error _make_despawn_packet(Node *p_node, int &r_len);
Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable);
struct TrackedNode {
ObjectID id;
uint32_t net_id = 0;
uint32_t remote_peer = 0;
ObjectID spawner;
HashSet<ObjectID> synchronizers;
void _visibility_changed(int p_peer, ObjectID p_oid);
Error _update_sync_visibility(int p_peer, const ObjectID &p_oid);
Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid);
void _free_remotes(int p_peer);
bool operator==(const ObjectID &p_other) { return id == p_other; }
Ref<SceneReplicationState> rep_state;
_FORCE_INLINE_ MultiplayerSpawner *get_spawner() const { return spawner.is_valid() ? Object::cast_to<MultiplayerSpawner>(ObjectDB::get_instance(spawner)) : nullptr; }
TrackedNode() {}
TrackedNode(const ObjectID &p_id) { id = p_id; }
TrackedNode(const ObjectID &p_id, uint32_t p_net_id) {
id = p_id;
net_id = p_net_id;
}
};
struct PeerInfo {
HashSet<ObjectID> sync_nodes;
HashSet<ObjectID> spawn_nodes;
HashMap<uint32_t, ObjectID> recv_sync_ids;
HashMap<uint32_t, ObjectID> recv_nodes;
uint16_t last_sent_sync = 0;
};
// Replication state.
HashMap<int, PeerInfo> peers_info;
uint32_t last_net_id = 0;
HashMap<ObjectID, TrackedNode> tracked_nodes;
HashSet<ObjectID> spawned_nodes;
HashSet<ObjectID> sync_nodes;
// Pending spawn informations.
ObjectID pending_spawn;
int pending_spawn_remote = 0;
const uint8_t *pending_buffer = nullptr;
int pending_buffer_size = 0;
List<uint32_t> pending_sync_net_ids;
// Replicator config.
SceneMultiplayer *multiplayer = nullptr;
PackedByteArray packet_cache;
int sync_mtu = 1350; // Highly dependent on underlying protocol.
// An hack to apply the initial state before ready.
ObjectID pending_spawn;
const uint8_t *pending_buffer = nullptr;
int pending_buffer_size = 0;
TrackedNode &_track(const ObjectID &p_id);
void _untrack(const ObjectID &p_id);
void _send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_msec);
Error _make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len);
Error _make_despawn_packet(Node *p_node, int &r_len);
Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable);
void _visibility_changed(int p_peer, ObjectID p_oid);
Error _update_sync_visibility(int p_peer, MultiplayerSynchronizer *p_sync);
Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid);
void _free_remotes(const PeerInfo &p_info);
template <class T>
static T *get_id_as(const ObjectID &p_id) {
return p_id.is_valid() ? Object::cast_to<T>(ObjectDB::get_instance(p_id)) : nullptr;
}
public:
static void make_default();
@@ -78,7 +122,6 @@ public:
Error on_sync_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len);
SceneReplicationInterface(SceneMultiplayer *p_multiplayer) {
rep_state.instantiate();
multiplayer = p_multiplayer;
}
};