Merge pull request #62961 from Faless/mp/4.x_interest
Add peer visibility to MultiplayerSynchronizer.
This commit is contained in:
commit
1cf7ebda50
|
@ -463,8 +463,12 @@ bool MultiplayerAPI::is_cache_confirmed(NodePath p_path, int p_peer) {
|
||||||
return cache->is_cache_confirmed(p_path, p_peer);
|
return cache->is_cache_confirmed(p_path, p_peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MultiplayerAPI::send_object_cache(Object *p_obj, NodePath p_path, int p_peer_id, int &r_id) {
|
bool MultiplayerAPI::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) {
|
||||||
return cache->send_object_cache(p_obj, p_path, p_peer_id, r_id);
|
return cache->send_object_cache(p_obj, p_peer_id, r_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MultiplayerAPI::make_object_cache(Object *p_obj) {
|
||||||
|
return cache->make_object_cache(p_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *MultiplayerAPI::get_cached_object(int p_from, uint32_t p_cache_id) {
|
Object *MultiplayerAPI::get_cached_object(int p_from, uint32_t p_cache_id) {
|
||||||
|
|
|
@ -77,7 +77,8 @@ public:
|
||||||
virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {}
|
virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {}
|
||||||
|
|
||||||
// Returns true if all peers have cached path.
|
// Returns true if all peers have cached path.
|
||||||
virtual bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id) { return false; }
|
virtual bool send_object_cache(Object *p_obj, int p_target, int &r_id) { return false; }
|
||||||
|
virtual int make_object_cache(Object *p_obj) { return false; }
|
||||||
virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) { return nullptr; }
|
virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) { return nullptr; }
|
||||||
virtual bool is_cache_confirmed(NodePath p_path, int p_peer) { return false; }
|
virtual bool is_cache_confirmed(NodePath p_path, int p_peer) { return false; }
|
||||||
|
|
||||||
|
@ -160,7 +161,8 @@ public:
|
||||||
Error replication_start(Object *p_object, Variant p_config);
|
Error replication_start(Object *p_object, Variant p_config);
|
||||||
Error replication_stop(Object *p_object, Variant p_config);
|
Error replication_stop(Object *p_object, Variant p_config);
|
||||||
// Cache API
|
// Cache API
|
||||||
bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id);
|
bool send_object_cache(Object *p_obj, int p_target, int &r_id);
|
||||||
|
int make_object_cache(Object *p_obj);
|
||||||
Object *get_cached_object(int p_from, uint32_t p_cache_id);
|
Object *get_cached_object(int p_from, uint32_t p_cache_id);
|
||||||
bool is_cache_confirmed(NodePath p_path, int p_peer);
|
bool is_cache_confirmed(NodePath p_path, int p_peer);
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,6 @@
|
||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="auto_spawn" type="bool" setter="set_auto_spawning" getter="is_auto_spawning" default="false">
|
|
||||||
</member>
|
|
||||||
<member name="spawn_limit" type="int" setter="set_spawn_limit" getter="get_spawn_limit" default="0">
|
<member name="spawn_limit" type="int" setter="set_spawn_limit" getter="get_spawn_limit" default="0">
|
||||||
</member>
|
</member>
|
||||||
<member name="spawn_path" type="NodePath" setter="set_spawn_path" getter="get_spawn_path" default="NodePath("")">
|
<member name="spawn_path" type="NodePath" setter="set_spawn_path" getter="get_spawn_path" default="NodePath("")">
|
||||||
|
|
|
@ -6,12 +6,64 @@
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="add_visibility_filter">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="filter" type="Callable" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_visibility_for" qualifiers="const">
|
||||||
|
<return type="bool" />
|
||||||
|
<argument index="0" name="peer" type="int" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="remove_visibility_filter">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="filter" type="Callable" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="set_visibility_for">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="peer" type="int" />
|
||||||
|
<argument index="1" name="visible" type="bool" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="update_visibility">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="for_peer" type="int" default="0" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="public_visibility" type="bool" setter="set_visibility_public" getter="is_visibility_public" default="true">
|
||||||
|
</member>
|
||||||
<member name="replication_config" type="SceneReplicationConfig" setter="set_replication_config" getter="get_replication_config">
|
<member name="replication_config" type="SceneReplicationConfig" setter="set_replication_config" getter="get_replication_config">
|
||||||
</member>
|
</member>
|
||||||
<member name="replication_interval" type="float" setter="set_replication_interval" getter="get_replication_interval" default="0.0">
|
<member name="replication_interval" type="float" setter="set_replication_interval" getter="get_replication_interval" default="0.0">
|
||||||
</member>
|
</member>
|
||||||
<member name="root_path" type="NodePath" setter="set_root_path" getter="get_root_path" default="NodePath("..")">
|
<member name="root_path" type="NodePath" setter="set_root_path" getter="get_root_path" default="NodePath("..")">
|
||||||
</member>
|
</member>
|
||||||
|
<member name="visibility_update_mode" type="int" setter="set_visibility_update_mode" getter="get_visibility_update_mode" enum="MultiplayerSynchronizer.VisibilityUpdateMode" default="0">
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
<signals>
|
||||||
|
<signal name="visibility_changed">
|
||||||
|
<argument index="0" name="for_peer" type="int" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
|
<constants>
|
||||||
|
<constant name="VISIBILITY_PROCESS_IDLE" value="0" enum="VisibilityUpdateMode">
|
||||||
|
</constant>
|
||||||
|
<constant name="VISIBILITY_PROCESS_PHYSICS" value="1" enum="VisibilityUpdateMode">
|
||||||
|
</constant>
|
||||||
|
<constant name="VISIBILITY_PROCESS_NONE" value="2" enum="VisibilityUpdateMode">
|
||||||
|
</constant>
|
||||||
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -71,7 +71,7 @@ bool MultiplayerSpawner::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const {
|
void MultiplayerSpawner::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
p_list->push_back(PropertyInfo(Variant::INT, "_spawnable_scene_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Scenes,scenes/"));
|
p_list->push_back(PropertyInfo(Variant::INT, "_spawnable_scene_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Auto Spawn List,scenes/"));
|
||||||
List<String> exts;
|
List<String> exts;
|
||||||
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &exts);
|
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &exts);
|
||||||
String ext_hint;
|
String ext_hint;
|
||||||
|
@ -144,10 +144,6 @@ void MultiplayerSpawner::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_spawn_limit", "limit"), &MultiplayerSpawner::set_spawn_limit);
|
ClassDB::bind_method(D_METHOD("set_spawn_limit", "limit"), &MultiplayerSpawner::set_spawn_limit);
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "spawn_limit", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_spawn_limit", "get_spawn_limit");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "spawn_limit", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_spawn_limit", "get_spawn_limit");
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_auto_spawning", "enabled"), &MultiplayerSpawner::set_auto_spawning);
|
|
||||||
ClassDB::bind_method(D_METHOD("is_auto_spawning"), &MultiplayerSpawner::is_auto_spawning);
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_spawn"), "set_auto_spawning", "is_auto_spawning");
|
|
||||||
|
|
||||||
GDVIRTUAL_BIND(_spawn_custom, "data");
|
GDVIRTUAL_BIND(_spawn_custom, "data");
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
||||||
|
@ -169,7 +165,7 @@ void MultiplayerSpawner::_update_spawn_node() {
|
||||||
Node *node = spawn_path.is_empty() && is_inside_tree() ? nullptr : get_node_or_null(spawn_path);
|
Node *node = spawn_path.is_empty() && is_inside_tree() ? nullptr : get_node_or_null(spawn_path);
|
||||||
if (node) {
|
if (node) {
|
||||||
spawn_node = node->get_instance_id();
|
spawn_node = node->get_instance_id();
|
||||||
if (auto_spawn) {
|
if (get_spawnable_scene_count() && !GDVIRTUAL_IS_OVERRIDDEN(_spawn_custom)) {
|
||||||
node->connect("child_entered_tree", callable_mp(this, &MultiplayerSpawner::_node_added));
|
node->connect("child_entered_tree", callable_mp(this, &MultiplayerSpawner::_node_added));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -221,15 +217,6 @@ void MultiplayerSpawner::_node_added(Node *p_node) {
|
||||||
_track(p_node, Variant(), id);
|
_track(p_node, Variant(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiplayerSpawner::set_auto_spawning(bool p_enabled) {
|
|
||||||
auto_spawn = p_enabled;
|
|
||||||
_update_spawn_node();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MultiplayerSpawner::is_auto_spawning() const {
|
|
||||||
return auto_spawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodePath MultiplayerSpawner::get_spawn_path() const {
|
NodePath MultiplayerSpawner::get_spawn_path() const {
|
||||||
return spawn_path;
|
return spawn_path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,6 @@ private:
|
||||||
|
|
||||||
ObjectID spawn_node;
|
ObjectID spawn_node;
|
||||||
HashMap<ObjectID, SpawnInfo> tracked_nodes;
|
HashMap<ObjectID, SpawnInfo> tracked_nodes;
|
||||||
bool auto_spawn = false;
|
|
||||||
uint32_t spawn_limit = 0;
|
uint32_t spawn_limit = 0;
|
||||||
|
|
||||||
void _update_spawn_node();
|
void _update_spawn_node();
|
||||||
|
@ -102,8 +101,6 @@ public:
|
||||||
void set_spawn_path(const NodePath &p_path);
|
void set_spawn_path(const NodePath &p_path);
|
||||||
uint32_t get_spawn_limit() const { return spawn_limit; }
|
uint32_t get_spawn_limit() const { return spawn_limit; }
|
||||||
void set_spawn_limit(uint32_t p_limit) { spawn_limit = p_limit; }
|
void set_spawn_limit(uint32_t p_limit) { spawn_limit = p_limit; }
|
||||||
bool is_auto_spawning() const;
|
|
||||||
void set_auto_spawning(bool p_enabled);
|
|
||||||
|
|
||||||
const Variant get_spawn_argument(const ObjectID &p_id) const;
|
const Variant get_spawn_argument(const ObjectID &p_id) const;
|
||||||
int find_spawnable_scene_index_from_object(const ObjectID &p_id) const;
|
int find_spawnable_scene_index_from_object(const ObjectID &p_id) const;
|
||||||
|
|
|
@ -43,6 +43,11 @@ Object *MultiplayerSynchronizer::_get_prop_target(Object *p_obj, const NodePath
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiplayerSynchronizer::_stop() {
|
void MultiplayerSynchronizer::_stop() {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr;
|
Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr;
|
||||||
if (node) {
|
if (node) {
|
||||||
get_multiplayer()->replication_stop(node, this);
|
get_multiplayer()->replication_stop(node, this);
|
||||||
|
@ -50,9 +55,42 @@ void MultiplayerSynchronizer::_stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiplayerSynchronizer::_start() {
|
void MultiplayerSynchronizer::_start() {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr;
|
Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr;
|
||||||
if (node) {
|
if (node) {
|
||||||
get_multiplayer()->replication_start(node, this);
|
get_multiplayer()->replication_start(node, this);
|
||||||
|
_update_process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::_update_process() {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr;
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set_process_internal(false);
|
||||||
|
set_physics_process_internal(false);
|
||||||
|
if (!visibility_filters.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (visibility_update_mode) {
|
||||||
|
case VISIBILITY_PROCESS_IDLE:
|
||||||
|
set_process_internal(true);
|
||||||
|
break;
|
||||||
|
case VISIBILITY_PROCESS_PHYSICS:
|
||||||
|
set_physics_process_internal(true);
|
||||||
|
break;
|
||||||
|
case VISIBILITY_PROCESS_NONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +123,66 @@ Error MultiplayerSynchronizer::set_state(const List<NodePath> &p_properties, Obj
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MultiplayerSynchronizer::is_visibility_public() const {
|
||||||
|
return peer_visibility.has(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::set_visibility_public(bool p_visible) {
|
||||||
|
set_visibility_for(0, p_visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MultiplayerSynchronizer::is_visible_to(int p_peer) {
|
||||||
|
if (visibility_filters.size()) {
|
||||||
|
Variant arg = p_peer;
|
||||||
|
const Variant *argv[1] = { &arg };
|
||||||
|
for (Callable filter : visibility_filters) {
|
||||||
|
Variant ret;
|
||||||
|
Callable::CallError err;
|
||||||
|
filter.call(argv, 1, ret, err);
|
||||||
|
ERR_FAIL_COND_V(err.error != Callable::CallError::CALL_OK || ret.get_type() != Variant::BOOL, false);
|
||||||
|
if (!ret.operator bool()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return peer_visibility.has(0) || peer_visibility.has(p_peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::add_visibility_filter(Callable p_callback) {
|
||||||
|
visibility_filters.insert(p_callback);
|
||||||
|
_update_process();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::remove_visibility_filter(Callable p_callback) {
|
||||||
|
visibility_filters.erase(p_callback);
|
||||||
|
_update_process();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::set_visibility_for(int p_peer, bool p_visible) {
|
||||||
|
if (peer_visibility.has(p_peer) == p_visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (p_visible) {
|
||||||
|
peer_visibility.insert(p_peer);
|
||||||
|
} else {
|
||||||
|
peer_visibility.erase(p_peer);
|
||||||
|
}
|
||||||
|
update_visibility(p_peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MultiplayerSynchronizer::get_visibility_for(int p_peer) const {
|
||||||
|
return peer_visibility.has(p_peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::set_visibility_update_mode(VisibilityUpdateMode p_mode) {
|
||||||
|
visibility_update_mode = p_mode;
|
||||||
|
_update_process();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerSynchronizer::VisibilityUpdateMode MultiplayerSynchronizer::get_visibility_update_mode() const {
|
||||||
|
return visibility_update_mode;
|
||||||
|
}
|
||||||
|
|
||||||
void MultiplayerSynchronizer::_bind_methods() {
|
void MultiplayerSynchronizer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_root_path", "path"), &MultiplayerSynchronizer::set_root_path);
|
ClassDB::bind_method(D_METHOD("set_root_path", "path"), &MultiplayerSynchronizer::set_root_path);
|
||||||
ClassDB::bind_method(D_METHOD("get_root_path"), &MultiplayerSynchronizer::get_root_path);
|
ClassDB::bind_method(D_METHOD("get_root_path"), &MultiplayerSynchronizer::get_root_path);
|
||||||
|
@ -95,9 +193,29 @@ void MultiplayerSynchronizer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config);
|
ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config);
|
||||||
ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config);
|
ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_visibility_update_mode", "mode"), &MultiplayerSynchronizer::set_visibility_update_mode);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_visibility_update_mode"), &MultiplayerSynchronizer::get_visibility_update_mode);
|
||||||
|
ClassDB::bind_method(D_METHOD("update_visibility", "for_peer"), &MultiplayerSynchronizer::update_visibility, DEFVAL(0));
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_visibility_public", "visible"), &MultiplayerSynchronizer::set_visibility_public);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_visibility_public"), &MultiplayerSynchronizer::is_visibility_public);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("add_visibility_filter", "filter"), &MultiplayerSynchronizer::add_visibility_filter);
|
||||||
|
ClassDB::bind_method(D_METHOD("remove_visibility_filter", "filter"), &MultiplayerSynchronizer::remove_visibility_filter);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_visibility_for", "peer", "visible"), &MultiplayerSynchronizer::set_visibility_for);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_visibility_for", "peer"), &MultiplayerSynchronizer::get_visibility_for);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_path"), "set_root_path", "get_root_path");
|
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_path"), "set_root_path", "get_root_path");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "replication_interval", PROPERTY_HINT_RANGE, "0,5,0.001,suffix:s"), "set_replication_interval", "get_replication_interval");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "replication_interval", PROPERTY_HINT_RANGE, "0,5,0.001,suffix:s"), "set_replication_interval", "get_replication_interval");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig", PROPERTY_USAGE_NO_EDITOR), "set_replication_config", "get_replication_config");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,None"), "set_visibility_update_mode", "get_visibility_update_mode");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "public_visibility"), "set_visibility_public", "is_visibility_public");
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(VISIBILITY_PROCESS_IDLE);
|
||||||
|
BIND_ENUM_CONSTANT(VISIBILITY_PROCESS_PHYSICS);
|
||||||
|
BIND_ENUM_CONSTANT(VISIBILITY_PROCESS_NONE);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("visibility_changed", PropertyInfo(Variant::INT, "for_peer")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiplayerSynchronizer::_notification(int p_what) {
|
void MultiplayerSynchronizer::_notification(int p_what) {
|
||||||
|
@ -118,6 +236,11 @@ void MultiplayerSynchronizer::_notification(int p_what) {
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
_stop();
|
_stop();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NOTIFICATION_INTERNAL_PROCESS:
|
||||||
|
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||||
|
update_visibility(0);
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +265,18 @@ Ref<SceneReplicationConfig> MultiplayerSynchronizer::get_replication_config() {
|
||||||
return replication_config;
|
return replication_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiplayerSynchronizer::update_visibility(int p_for_peer) {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr;
|
||||||
|
if (node && get_multiplayer()->has_multiplayer_peer() && is_multiplayer_authority()) {
|
||||||
|
emit_signal(SNAME("visibility_changed"), p_for_peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MultiplayerSynchronizer::set_root_path(const NodePath &p_path) {
|
void MultiplayerSynchronizer::set_root_path(const NodePath &p_path) {
|
||||||
_stop();
|
_stop();
|
||||||
root_path = p_path;
|
root_path = p_path;
|
||||||
|
@ -162,3 +297,8 @@ void MultiplayerSynchronizer::set_multiplayer_authority(int p_peer_id, bool p_re
|
||||||
Node::set_multiplayer_authority(p_peer_id, p_recursive);
|
Node::set_multiplayer_authority(p_peer_id, p_recursive);
|
||||||
get_multiplayer()->replication_start(node, this);
|
get_multiplayer()->replication_start(node, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MultiplayerSynchronizer::MultiplayerSynchronizer() {
|
||||||
|
// Publicly visible by default.
|
||||||
|
peer_visibility.insert(0);
|
||||||
|
}
|
||||||
|
|
|
@ -38,14 +38,25 @@
|
||||||
class MultiplayerSynchronizer : public Node {
|
class MultiplayerSynchronizer : public Node {
|
||||||
GDCLASS(MultiplayerSynchronizer, Node);
|
GDCLASS(MultiplayerSynchronizer, Node);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum VisibilityUpdateMode {
|
||||||
|
VISIBILITY_PROCESS_IDLE,
|
||||||
|
VISIBILITY_PROCESS_PHYSICS,
|
||||||
|
VISIBILITY_PROCESS_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ref<SceneReplicationConfig> replication_config;
|
Ref<SceneReplicationConfig> replication_config;
|
||||||
NodePath root_path = NodePath(".."); // Start with parent, like with AnimationPlayer.
|
NodePath root_path = NodePath(".."); // Start with parent, like with AnimationPlayer.
|
||||||
uint64_t interval_msec = 0;
|
uint64_t interval_msec = 0;
|
||||||
|
VisibilityUpdateMode visibility_update_mode = VISIBILITY_PROCESS_IDLE;
|
||||||
|
HashSet<Callable> visibility_filters;
|
||||||
|
HashSet<int> peer_visibility;
|
||||||
|
|
||||||
static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop);
|
static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop);
|
||||||
void _start();
|
void _start();
|
||||||
void _stop();
|
void _stop();
|
||||||
|
void _update_process();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
@ -66,7 +77,19 @@ public:
|
||||||
NodePath get_root_path() const;
|
NodePath get_root_path() const;
|
||||||
virtual void set_multiplayer_authority(int p_peer_id, bool p_recursive = true) override;
|
virtual void set_multiplayer_authority(int p_peer_id, bool p_recursive = true) override;
|
||||||
|
|
||||||
MultiplayerSynchronizer() {}
|
bool is_visibility_public() const;
|
||||||
|
void set_visibility_public(bool p_public);
|
||||||
|
bool is_visible_to(int p_peer);
|
||||||
|
void set_visibility_for(int p_peer, bool p_visible);
|
||||||
|
bool get_visibility_for(int p_peer) const;
|
||||||
|
void update_visibility(int p_for_peer);
|
||||||
|
void set_visibility_update_mode(VisibilityUpdateMode p_mode);
|
||||||
|
void add_visibility_filter(Callable p_callback);
|
||||||
|
void remove_visibility_filter(Callable p_callback);
|
||||||
|
VisibilityUpdateMode get_visibility_update_mode() const;
|
||||||
|
|
||||||
|
MultiplayerSynchronizer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(MultiplayerSynchronizer::VisibilityUpdateMode);
|
||||||
#endif // MULTIPLAYER_SYNCHRONIZER_H
|
#endif // MULTIPLAYER_SYNCHRONIZER_H
|
||||||
|
|
|
@ -187,18 +187,29 @@ bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) {
|
||||||
return F->value;
|
return F->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int p_peer_id, int &r_id) {
|
int SceneCacheInterface::make_object_cache(Object *p_obj) {
|
||||||
Node *node = Object::cast_to<Node>(p_obj);
|
Node *node = Object::cast_to<Node>(p_obj);
|
||||||
ERR_FAIL_COND_V(!node, false);
|
ERR_FAIL_COND_V(!node, -1);
|
||||||
|
NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path());
|
||||||
// See if the path is cached.
|
// See if the path is cached.
|
||||||
PathSentCache *psc = path_send_cache.getptr(p_path);
|
PathSentCache *psc = path_send_cache.getptr(for_path);
|
||||||
if (!psc) {
|
if (!psc) {
|
||||||
// Path is not cached, create.
|
// Path is not cached, create.
|
||||||
path_send_cache[p_path] = PathSentCache();
|
path_send_cache[for_path] = PathSentCache();
|
||||||
psc = path_send_cache.getptr(p_path);
|
psc = path_send_cache.getptr(for_path);
|
||||||
psc->id = last_send_cache_id++;
|
psc->id = last_send_cache_id++;
|
||||||
}
|
}
|
||||||
r_id = psc->id;
|
return psc->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) {
|
||||||
|
Node *node = Object::cast_to<Node>(p_obj);
|
||||||
|
ERR_FAIL_COND_V(!node, false);
|
||||||
|
|
||||||
|
r_id = make_object_cache(p_obj);
|
||||||
|
ERR_FAIL_COND_V(r_id < 0, false);
|
||||||
|
NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path());
|
||||||
|
PathSentCache *psc = path_send_cache.getptr(for_path);
|
||||||
|
|
||||||
bool has_all_peers = true;
|
bool has_all_peers = true;
|
||||||
List<int> peers_to_add; // If one is missing, take note to add it.
|
List<int> peers_to_add; // If one is missing, take note to add it.
|
||||||
|
@ -233,7 +244,7 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peers_to_add.size()) {
|
if (peers_to_add.size()) {
|
||||||
_send_confirm_path(node, p_path, psc, peers_to_add);
|
_send_confirm_path(node, for_path, psc, peers_to_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
return has_all_peers;
|
return has_all_peers;
|
||||||
|
|
|
@ -72,7 +72,8 @@ public:
|
||||||
virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) override;
|
virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) override;
|
||||||
|
|
||||||
// Returns true if all peers have cached path.
|
// Returns true if all peers have cached path.
|
||||||
virtual bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id) override;
|
virtual bool send_object_cache(Object *p_obj, int p_target, int &p_id) override;
|
||||||
|
virtual int make_object_cache(Object *p_obj) override;
|
||||||
virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) override;
|
virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) override;
|
||||||
virtual bool is_cache_confirmed(NodePath p_path, int p_peer) override;
|
virtual bool is_cache_confirmed(NodePath p_path, int p_peer) override;
|
||||||
|
|
||||||
|
|
|
@ -60,14 +60,13 @@ void SceneReplicationInterface::on_peer_change(int p_id, bool p_connected) {
|
||||||
if (p_connected) {
|
if (p_connected) {
|
||||||
rep_state->on_peer_change(p_id, p_connected);
|
rep_state->on_peer_change(p_id, p_connected);
|
||||||
for (const ObjectID &oid : rep_state->get_spawned_nodes()) {
|
for (const ObjectID &oid : rep_state->get_spawned_nodes()) {
|
||||||
_send_spawn(rep_state->get_node(oid), rep_state->get_spawner(oid), p_id);
|
_update_spawn_visibility(p_id, oid);
|
||||||
}
|
}
|
||||||
for (const ObjectID &oid : rep_state->get_path_only_nodes()) {
|
for (const ObjectID &oid : rep_state->get_synced_nodes()) {
|
||||||
Node *node = rep_state->get_node(oid);
|
|
||||||
MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid);
|
MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid);
|
||||||
ERR_CONTINUE(!node || !sync);
|
ERR_CONTINUE(!sync); // ERR_BUG
|
||||||
if (sync->is_multiplayer_authority()) {
|
if (sync->is_multiplayer_authority()) {
|
||||||
rep_state->peer_add_node(p_id, oid);
|
_update_sync_visibility(p_id, oid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,7 +96,13 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) {
|
||||||
ERR_FAIL_COND_V(!spawner, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!spawner, ERR_INVALID_PARAMETER);
|
||||||
Error err = rep_state->config_add_spawn(node, spawner);
|
Error err = rep_state->config_add_spawn(node, spawner);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
ERR_FAIL_COND_V(err != OK, err);
|
||||||
return _send_spawn(node, spawner, 0);
|
const ObjectID oid = node->get_instance_id();
|
||||||
|
if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) {
|
||||||
|
rep_state->ensure_net_id(oid);
|
||||||
|
_update_spawn_visibility(0, oid);
|
||||||
|
}
|
||||||
|
ERR_FAIL_COND_V(err != OK, err);
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) {
|
Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) {
|
||||||
|
@ -105,9 +110,19 @@ Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) {
|
||||||
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
||||||
MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object());
|
MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object());
|
||||||
ERR_FAIL_COND_V(!p_obj || !spawner, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!p_obj || !spawner, ERR_INVALID_PARAMETER);
|
||||||
Error err = rep_state->config_del_spawn(node, spawner);
|
// Forcibly despawn to all peers that knowns me.
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
int len = 0;
|
||||||
return _send_despawn(node, 0);
|
Error err = _make_despawn_packet(node, len);
|
||||||
|
ERR_FAIL_COND_V(err != OK, ERR_BUG);
|
||||||
|
const ObjectID oid = p_obj->get_instance_id();
|
||||||
|
for (int pid : rep_state->get_peers()) {
|
||||||
|
if (!rep_state->is_peer_spawn(pid, oid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_send_raw(packet_cache.ptr(), len, pid, true);
|
||||||
|
}
|
||||||
|
// Also remove spawner tracking from the replication state.
|
||||||
|
return rep_state->config_del_spawn(node, spawner);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_config) {
|
Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_config) {
|
||||||
|
@ -115,7 +130,15 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c
|
||||||
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
||||||
MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object());
|
MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object());
|
||||||
ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER);
|
||||||
|
|
||||||
|
// Add to synchronizer list and setup visibility.
|
||||||
rep_state->config_add_sync(node, sync);
|
rep_state->config_add_sync(node, sync);
|
||||||
|
const ObjectID oid = node->get_instance_id();
|
||||||
|
sync->connect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed), varray(oid));
|
||||||
|
if (multiplayer->has_multiplayer_peer() && sync->is_multiplayer_authority()) {
|
||||||
|
_update_sync_visibility(0, oid);
|
||||||
|
}
|
||||||
|
|
||||||
// Try to apply initial state if spawning (hack to apply if before ready).
|
// Try to apply initial state if spawning (hack to apply if before ready).
|
||||||
if (pending_spawn == p_obj->get_instance_id()) {
|
if (pending_spawn == p_obj->get_instance_id()) {
|
||||||
pending_spawn = ObjectID(); // Make sure this only happens once.
|
pending_spawn = ObjectID(); // Make sure this only happens once.
|
||||||
|
@ -127,9 +150,6 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c
|
||||||
ERR_FAIL_COND_V(err, err);
|
ERR_FAIL_COND_V(err, err);
|
||||||
err = MultiplayerSynchronizer::set_state(props, node, vars);
|
err = MultiplayerSynchronizer::set_state(props, node, vars);
|
||||||
ERR_FAIL_COND_V(err, err);
|
ERR_FAIL_COND_V(err, err);
|
||||||
} else if (multiplayer->has_multiplayer_peer() && sync->is_multiplayer_authority()) {
|
|
||||||
// Either it's a spawn or a static sync, in any case add it to the list of known nodes.
|
|
||||||
rep_state->peer_add_node(0, p_obj->get_instance_id());
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -138,10 +158,103 @@ Error SceneReplicationInterface::on_replication_stop(Object *p_obj, Variant p_co
|
||||||
Node *node = Object::cast_to<Node>(p_obj);
|
Node *node = Object::cast_to<Node>(p_obj);
|
||||||
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER);
|
||||||
MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object());
|
MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object());
|
||||||
ERR_FAIL_COND_V(!p_obj || !sync, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER);
|
||||||
|
sync->disconnect("visibility_changed", callable_mp(this, &SceneReplicationInterface::_visibility_changed));
|
||||||
return rep_state->config_del_sync(node, sync);
|
return rep_state->config_del_sync(node, sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SceneReplicationInterface::_visibility_changed(int p_peer, ObjectID p_oid) {
|
||||||
|
if (rep_state->is_spawned_node(p_oid)) {
|
||||||
|
_update_spawn_visibility(p_peer, p_oid);
|
||||||
|
}
|
||||||
|
if (rep_state->is_synced_node(p_oid)) {
|
||||||
|
_update_sync_visibility(p_peer, p_oid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error SceneReplicationInterface::_update_sync_visibility(int p_peer, const ObjectID &p_oid) {
|
||||||
|
MultiplayerSynchronizer *sync = rep_state->get_synchronizer(p_oid);
|
||||||
|
ERR_FAIL_COND_V(!sync || !sync->is_multiplayer_authority(), ERR_BUG);
|
||||||
|
bool is_visible = sync->is_visible_to(p_peer);
|
||||||
|
if (p_peer == 0) {
|
||||||
|
for (int pid : rep_state->get_peers()) {
|
||||||
|
// Might be visible to this specific peer.
|
||||||
|
is_visible = is_visible || sync->is_visible_to(pid);
|
||||||
|
if (rep_state->is_peer_sync(pid, p_oid) == is_visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_visible) {
|
||||||
|
rep_state->peer_add_sync(pid, p_oid);
|
||||||
|
} else {
|
||||||
|
rep_state->peer_del_sync(pid, p_oid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
} else {
|
||||||
|
if (is_visible == rep_state->is_peer_sync(p_peer, p_oid)) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (is_visible) {
|
||||||
|
return rep_state->peer_add_sync(p_peer, p_oid);
|
||||||
|
} else {
|
||||||
|
return rep_state->peer_del_sync(p_peer, p_oid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const ObjectID &p_oid) {
|
||||||
|
MultiplayerSpawner *spawner = rep_state->get_spawner(p_oid);
|
||||||
|
MultiplayerSynchronizer *sync = rep_state->get_synchronizer(p_oid);
|
||||||
|
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_oid));
|
||||||
|
ERR_FAIL_COND_V(!node || !spawner || !spawner->is_multiplayer_authority(), ERR_BUG);
|
||||||
|
bool is_visible = !sync || sync->is_visible_to(p_peer);
|
||||||
|
// Spawn (and despawn) when needed.
|
||||||
|
HashSet<int> to_spawn;
|
||||||
|
HashSet<int> to_despawn;
|
||||||
|
if (p_peer) {
|
||||||
|
if (is_visible == rep_state->is_peer_spawn(p_peer, p_oid)) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (is_visible) {
|
||||||
|
to_spawn.insert(p_peer);
|
||||||
|
} else {
|
||||||
|
to_despawn.insert(p_peer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check visibility for each peers.
|
||||||
|
for (int pid : rep_state->get_peers()) {
|
||||||
|
bool peer_visible = is_visible || sync->is_visible_to(pid);
|
||||||
|
if (peer_visible == rep_state->is_peer_spawn(pid, p_oid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (peer_visible) {
|
||||||
|
to_spawn.insert(pid);
|
||||||
|
} else {
|
||||||
|
to_despawn.insert(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to_spawn.size()) {
|
||||||
|
int len = 0;
|
||||||
|
_make_spawn_packet(node, len);
|
||||||
|
for (int pid : to_spawn) {
|
||||||
|
int path_id;
|
||||||
|
multiplayer->send_object_cache(spawner, pid, path_id);
|
||||||
|
_send_raw(packet_cache.ptr(), len, pid, true);
|
||||||
|
rep_state->peer_add_spawn(pid, p_oid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to_despawn.size()) {
|
||||||
|
int len = 0;
|
||||||
|
_make_despawn_packet(node, len);
|
||||||
|
for (int pid : to_despawn) {
|
||||||
|
rep_state->peer_del_spawn(pid, p_oid);
|
||||||
|
_send_raw(packet_cache.ptr(), len, pid, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) {
|
Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) {
|
||||||
ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER);
|
||||||
ERR_FAIL_COND_V(!multiplayer, ERR_UNCONFIGURED);
|
ERR_FAIL_COND_V(!multiplayer, ERR_UNCONFIGURED);
|
||||||
|
@ -158,18 +271,20 @@ Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size,
|
||||||
return peer->put_packet(p_buffer, p_size);
|
return peer->put_packet(p_buffer, p_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p_spawner, int p_peer) {
|
Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, int &r_len) {
|
||||||
ERR_FAIL_COND_V(p_peer < 0, ERR_BUG);
|
|
||||||
ERR_FAIL_COND_V(!multiplayer, ERR_BUG);
|
ERR_FAIL_COND_V(!multiplayer, ERR_BUG);
|
||||||
ERR_FAIL_COND_V(!p_spawner || !p_node, ERR_BUG);
|
|
||||||
|
|
||||||
const ObjectID oid = p_node->get_instance_id();
|
const ObjectID oid = p_node->get_instance_id();
|
||||||
uint32_t nid = rep_state->ensure_net_id(oid);
|
MultiplayerSpawner *spawner = rep_state->get_spawner(oid);
|
||||||
|
ERR_FAIL_COND_V(!spawner || !p_node, ERR_BUG);
|
||||||
|
|
||||||
|
uint32_t nid = rep_state->get_net_id(oid);
|
||||||
|
ERR_FAIL_COND_V(!nid, ERR_UNCONFIGURED);
|
||||||
|
|
||||||
// Prepare custom arg and scene_id
|
// Prepare custom arg and scene_id
|
||||||
uint8_t scene_id = p_spawner->find_spawnable_scene_index_from_object(oid);
|
uint8_t scene_id = spawner->find_spawnable_scene_index_from_object(oid);
|
||||||
bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID;
|
bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID;
|
||||||
Variant spawn_arg = p_spawner->get_spawn_argument(oid);
|
Variant spawn_arg = spawner->get_spawn_argument(oid);
|
||||||
int spawn_arg_size = 0;
|
int spawn_arg_size = 0;
|
||||||
if (is_custom) {
|
if (is_custom) {
|
||||||
Error err = MultiplayerAPI::encode_and_compress_variant(spawn_arg, nullptr, spawn_arg_size, false);
|
Error err = MultiplayerAPI::encode_and_compress_variant(spawn_arg, nullptr, spawn_arg_size, false);
|
||||||
|
@ -181,7 +296,8 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p
|
||||||
Vector<Variant> state_vars;
|
Vector<Variant> state_vars;
|
||||||
Vector<const Variant *> state_varp;
|
Vector<const Variant *> state_varp;
|
||||||
MultiplayerSynchronizer *synchronizer = rep_state->get_synchronizer(oid);
|
MultiplayerSynchronizer *synchronizer = rep_state->get_synchronizer(oid);
|
||||||
if (synchronizer && synchronizer->get_replication_config().is_valid()) {
|
if (synchronizer) {
|
||||||
|
ERR_FAIL_COND_V(synchronizer->get_replication_config().is_null(), ERR_BUG);
|
||||||
const List<NodePath> props = synchronizer->get_replication_config()->get_spawn_properties();
|
const List<NodePath> props = synchronizer->get_replication_config()->get_spawn_properties();
|
||||||
Error err = MultiplayerSynchronizer::get_state(props, p_node, state_vars, state_varp);
|
Error err = MultiplayerSynchronizer::get_state(props, p_node, state_vars, state_varp);
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to retrieve spawn state.");
|
ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to retrieve spawn state.");
|
||||||
|
@ -189,13 +305,8 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to encode spawn state.");
|
ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to encode spawn state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare simplified path.
|
// Encode scene ID, path ID, net ID, node name.
|
||||||
NodePath rel_path = multiplayer->get_root_path().rel_path_to(p_spawner->get_path());
|
int path_id = multiplayer->make_object_cache(spawner);
|
||||||
|
|
||||||
int path_id = 0;
|
|
||||||
multiplayer->send_object_cache(p_spawner, rel_path, p_peer, path_id);
|
|
||||||
|
|
||||||
// Encode name and parent ID.
|
|
||||||
CharString cname = p_node->get_name().operator String().utf8();
|
CharString cname = p_node->get_name().operator String().utf8();
|
||||||
int nlen = encode_cstring(cname.get_data(), nullptr);
|
int nlen = encode_cstring(cname.get_data(), nullptr);
|
||||||
MAKE_ROOM(1 + 1 + 4 + 4 + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size);
|
MAKE_ROOM(1 + 1 + 4 + 4 + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size);
|
||||||
|
@ -220,12 +331,11 @@ Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p
|
||||||
ERR_FAIL_COND_V(err, err);
|
ERR_FAIL_COND_V(err, err);
|
||||||
ofs += state_size;
|
ofs += state_size;
|
||||||
}
|
}
|
||||||
Error err = _send_raw(ptr, ofs, p_peer, true);
|
r_len = ofs;
|
||||||
ERR_FAIL_COND_V(err, err);
|
return OK;
|
||||||
return rep_state->peer_add_node(p_peer, oid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationInterface::_send_despawn(Node *p_node, int p_peer) {
|
Error SceneReplicationInterface::_make_despawn_packet(Node *p_node, int &r_len) {
|
||||||
const ObjectID oid = p_node->get_instance_id();
|
const ObjectID oid = p_node->get_instance_id();
|
||||||
MAKE_ROOM(5);
|
MAKE_ROOM(5);
|
||||||
uint8_t *ptr = packet_cache.ptrw();
|
uint8_t *ptr = packet_cache.ptrw();
|
||||||
|
@ -233,9 +343,8 @@ Error SceneReplicationInterface::_send_despawn(Node *p_node, int p_peer) {
|
||||||
int ofs = 1;
|
int ofs = 1;
|
||||||
uint32_t nid = rep_state->get_net_id(oid);
|
uint32_t nid = rep_state->get_net_id(oid);
|
||||||
ofs += encode_uint32(nid, &ptr[ofs]);
|
ofs += encode_uint32(nid, &ptr[ofs]);
|
||||||
Error err = _send_raw(ptr, ofs, p_peer, true);
|
r_len = ofs;
|
||||||
ERR_FAIL_COND_V(err, err);
|
return OK;
|
||||||
return rep_state->peer_del_node(p_peer, oid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) {
|
Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) {
|
||||||
|
@ -316,8 +425,8 @@ Error SceneReplicationInterface::on_despawn_receive(int p_from, const uint8_t *p
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) {
|
void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) {
|
||||||
const HashSet<ObjectID> &known = rep_state->get_known_nodes(p_peer);
|
const HashSet<ObjectID> &to_sync = rep_state->get_peer_sync_nodes(p_peer);
|
||||||
if (known.is_empty()) {
|
if (to_sync.is_empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MAKE_ROOM(sync_mtu);
|
MAKE_ROOM(sync_mtu);
|
||||||
|
@ -327,14 +436,29 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) {
|
||||||
ofs += encode_uint16(rep_state->peer_sync_next(p_peer), &ptr[1]);
|
ofs += encode_uint16(rep_state->peer_sync_next(p_peer), &ptr[1]);
|
||||||
// Can only send updates for already notified nodes.
|
// Can only send updates for already notified nodes.
|
||||||
// This is a lazy implementation, we could optimize much more here with by grouping by replication config.
|
// This is a lazy implementation, we could optimize much more here with by grouping by replication config.
|
||||||
for (const ObjectID &oid : known) {
|
for (const ObjectID &oid : to_sync) {
|
||||||
if (!rep_state->update_sync_time(oid, p_msec)) {
|
if (!rep_state->update_sync_time(oid, p_msec)) {
|
||||||
continue; // nothing to sync.
|
continue; // nothing to sync.
|
||||||
}
|
}
|
||||||
MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid);
|
MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid);
|
||||||
ERR_CONTINUE(!sync);
|
ERR_CONTINUE(!sync || !sync->get_replication_config().is_valid());
|
||||||
Node *node = rep_state->get_node(oid);
|
Node *node = rep_state->get_node(oid);
|
||||||
ERR_CONTINUE(!node);
|
ERR_CONTINUE(!node);
|
||||||
|
uint32_t net_id = rep_state->get_net_id(oid);
|
||||||
|
if (net_id == 0 || (net_id & 0x80000000)) {
|
||||||
|
int path_id = 0;
|
||||||
|
bool verified = multiplayer->send_object_cache(sync, p_peer, path_id);
|
||||||
|
ERR_CONTINUE_MSG(path_id < 0, "This should never happen!");
|
||||||
|
if (net_id == 0) {
|
||||||
|
// First time path based ID.
|
||||||
|
net_id = path_id | 0x80000000;
|
||||||
|
rep_state->set_net_id(oid, net_id | 0x80000000);
|
||||||
|
}
|
||||||
|
if (!verified) {
|
||||||
|
// The path based sync is not yet confirmed, skipping.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
int size;
|
int size;
|
||||||
Vector<Variant> vars;
|
Vector<Variant> vars;
|
||||||
Vector<const Variant *> varp;
|
Vector<const Variant *> varp;
|
||||||
|
@ -351,16 +475,6 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) {
|
||||||
ofs = 3;
|
ofs = 3;
|
||||||
}
|
}
|
||||||
if (size) {
|
if (size) {
|
||||||
uint32_t net_id = rep_state->get_net_id(oid);
|
|
||||||
if (net_id == 0 || (net_id & 0x80000000)) {
|
|
||||||
// First time path based ID.
|
|
||||||
NodePath rel_path = multiplayer->get_root_path().rel_path_to(sync->get_path());
|
|
||||||
int path_id = 0;
|
|
||||||
multiplayer->send_object_cache(sync, rel_path, p_peer, path_id);
|
|
||||||
ERR_CONTINUE_MSG(net_id && net_id != (uint32_t(path_id) | 0x80000000), "This should never happen!");
|
|
||||||
net_id = path_id;
|
|
||||||
rep_state->set_net_id(oid, net_id | 0x80000000);
|
|
||||||
}
|
|
||||||
ofs += encode_uint32(rep_state->get_net_id(oid), &ptr[ofs]);
|
ofs += encode_uint32(rep_state->get_net_id(oid), &ptr[ofs]);
|
||||||
ofs += encode_uint32(size, &ptr[ofs]);
|
ofs += encode_uint32(size, &ptr[ofs]);
|
||||||
MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), &ptr[ofs], size);
|
MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), &ptr[ofs], size);
|
||||||
|
|
|
@ -40,10 +40,13 @@ class SceneReplicationInterface : public MultiplayerReplicationInterface {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _send_sync(int p_peer, uint64_t p_msec);
|
void _send_sync(int p_peer, uint64_t p_msec);
|
||||||
Error _send_spawn(Node *p_node, MultiplayerSpawner *p_spawner, int p_peer);
|
Error _make_spawn_packet(Node *p_node, int &r_len);
|
||||||
Error _send_despawn(Node *p_node, int p_peer);
|
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);
|
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, const ObjectID &p_oid);
|
||||||
|
Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid);
|
||||||
void _free_remotes(int p_peer);
|
void _free_remotes(int p_peer);
|
||||||
|
|
||||||
Ref<SceneReplicationState> rep_state;
|
Ref<SceneReplicationState> rep_state;
|
||||||
|
|
|
@ -56,7 +56,8 @@ void SceneReplicationState::_untrack(const ObjectID &p_id) {
|
||||||
// If we spawned or synced it, we need to remove it from any peer it was sent to.
|
// If we spawned or synced it, we need to remove it from any peer it was sent to.
|
||||||
if (net_id || peer == 0) {
|
if (net_id || peer == 0) {
|
||||||
for (KeyValue<int, PeerInfo> &E : peers_info) {
|
for (KeyValue<int, PeerInfo> &E : peers_info) {
|
||||||
E.value.known_nodes.erase(p_id);
|
E.value.sync_nodes.erase(p_id);
|
||||||
|
E.value.spawn_nodes.erase(p_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,11 +94,6 @@ bool SceneReplicationState::update_sync_time(const ObjectID &p_id, uint64_t p_ms
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HashSet<ObjectID> SceneReplicationState::get_known_nodes(int p_peer) {
|
|
||||||
ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>());
|
|
||||||
return peers_info[p_peer].known_nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t SceneReplicationState::get_net_id(const ObjectID &p_id) const {
|
uint32_t SceneReplicationState::get_net_id(const ObjectID &p_id) const {
|
||||||
const TrackedNode *tnode = tracked_nodes.getptr(p_id);
|
const TrackedNode *tnode = tracked_nodes.getptr(p_id);
|
||||||
ERR_FAIL_COND_V(!tnode, 0);
|
ERR_FAIL_COND_V(!tnode, 0);
|
||||||
|
@ -147,8 +143,6 @@ Error SceneReplicationState::config_add_spawn(Node *p_node, MultiplayerSpawner *
|
||||||
ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE);
|
ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE);
|
||||||
tobj.spawner = p_spawner->get_instance_id();
|
tobj.spawner = p_spawner->get_instance_id();
|
||||||
spawned_nodes.insert(oid);
|
spawned_nodes.insert(oid);
|
||||||
// The spawner may be notified after the synchronizer.
|
|
||||||
path_only_nodes.erase(oid);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +153,9 @@ Error SceneReplicationState::config_del_spawn(Node *p_node, MultiplayerSpawner *
|
||||||
ERR_FAIL_COND_V(tobj.spawner != p_spawner->get_instance_id(), ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(tobj.spawner != p_spawner->get_instance_id(), ERR_INVALID_PARAMETER);
|
||||||
tobj.spawner = ObjectID();
|
tobj.spawner = ObjectID();
|
||||||
spawned_nodes.erase(oid);
|
spawned_nodes.erase(oid);
|
||||||
|
for (KeyValue<int, PeerInfo> &E : peers_info) {
|
||||||
|
E.value.spawn_nodes.erase(oid);
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,10 +164,7 @@ Error SceneReplicationState::config_add_sync(Node *p_node, MultiplayerSynchroniz
|
||||||
TrackedNode &tobj = _track(oid);
|
TrackedNode &tobj = _track(oid);
|
||||||
ERR_FAIL_COND_V(tobj.synchronizer != ObjectID(), ERR_ALREADY_IN_USE);
|
ERR_FAIL_COND_V(tobj.synchronizer != ObjectID(), ERR_ALREADY_IN_USE);
|
||||||
tobj.synchronizer = p_sync->get_instance_id();
|
tobj.synchronizer = p_sync->get_instance_id();
|
||||||
// If it doesn't have a spawner, we might need to assign ID for this node using it's path.
|
synced_nodes.insert(oid);
|
||||||
if (tobj.spawner.is_null()) {
|
|
||||||
path_only_nodes.insert(oid);
|
|
||||||
}
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,38 +174,57 @@ Error SceneReplicationState::config_del_sync(Node *p_node, MultiplayerSynchroniz
|
||||||
TrackedNode &tobj = _track(oid);
|
TrackedNode &tobj = _track(oid);
|
||||||
ERR_FAIL_COND_V(tobj.synchronizer != p_sync->get_instance_id(), ERR_INVALID_PARAMETER);
|
ERR_FAIL_COND_V(tobj.synchronizer != p_sync->get_instance_id(), ERR_INVALID_PARAMETER);
|
||||||
tobj.synchronizer = ObjectID();
|
tobj.synchronizer = ObjectID();
|
||||||
if (path_only_nodes.has(oid)) {
|
synced_nodes.erase(oid);
|
||||||
p_node->disconnect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack));
|
for (KeyValue<int, PeerInfo> &E : peers_info) {
|
||||||
_untrack(oid);
|
E.value.sync_nodes.erase(oid);
|
||||||
path_only_nodes.erase(oid);
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationState::peer_add_node(int p_peer, const ObjectID &p_id) {
|
Error SceneReplicationState::peer_add_sync(int p_peer, const ObjectID &p_id) {
|
||||||
if (p_peer) {
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
|
||||||
ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
|
peers_info[p_peer].sync_nodes.insert(p_id);
|
||||||
peers_info[p_peer].known_nodes.insert(p_id);
|
|
||||||
} else {
|
|
||||||
for (KeyValue<int, PeerInfo> &E : peers_info) {
|
|
||||||
E.value.known_nodes.insert(p_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error SceneReplicationState::peer_del_node(int p_peer, const ObjectID &p_id) {
|
Error SceneReplicationState::peer_del_sync(int p_peer, const ObjectID &p_id) {
|
||||||
if (p_peer) {
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
|
||||||
ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
|
peers_info[p_peer].sync_nodes.erase(p_id);
|
||||||
peers_info[p_peer].known_nodes.erase(p_id);
|
|
||||||
} else {
|
|
||||||
for (KeyValue<int, PeerInfo> &E : peers_info) {
|
|
||||||
E.value.known_nodes.erase(p_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HashSet<ObjectID> SceneReplicationState::get_peer_sync_nodes(int p_peer) {
|
||||||
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>());
|
||||||
|
return peers_info[p_peer].sync_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneReplicationState::is_peer_sync(int p_peer, const ObjectID &p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), false);
|
||||||
|
return peers_info[p_peer].sync_nodes.has(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error SceneReplicationState::peer_add_spawn(int p_peer, const ObjectID &p_id) {
|
||||||
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
|
||||||
|
peers_info[p_peer].spawn_nodes.insert(p_id);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error SceneReplicationState::peer_del_spawn(int p_peer, const ObjectID &p_id) {
|
||||||
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
|
||||||
|
peers_info[p_peer].spawn_nodes.erase(p_id);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HashSet<ObjectID> SceneReplicationState::get_peer_spawn_nodes(int p_peer) {
|
||||||
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), HashSet<ObjectID>());
|
||||||
|
return peers_info[p_peer].spawn_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneReplicationState::is_peer_spawn(int p_peer, const ObjectID &p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!peers_info.has(p_peer), false);
|
||||||
|
return peers_info[p_peer].spawn_nodes.has(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
Node *SceneReplicationState::peer_get_remote(int p_peer, uint32_t p_net_id) {
|
Node *SceneReplicationState::peer_get_remote(int p_peer, uint32_t p_net_id) {
|
||||||
PeerInfo *info = peers_info.getptr(p_peer);
|
PeerInfo *info = peers_info.getptr(p_peer);
|
||||||
return info && info->recv_nodes.has(p_net_id) ? Object::cast_to<Node>(ObjectDB::get_instance(info->recv_nodes[p_net_id])) : nullptr;
|
return info && info->recv_nodes.has(p_net_id) ? Object::cast_to<Node>(ObjectDB::get_instance(info->recv_nodes[p_net_id])) : nullptr;
|
||||||
|
|
|
@ -62,7 +62,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PeerInfo {
|
struct PeerInfo {
|
||||||
HashSet<ObjectID> known_nodes;
|
HashSet<ObjectID> sync_nodes;
|
||||||
|
HashSet<ObjectID> spawn_nodes;
|
||||||
HashMap<uint32_t, ObjectID> recv_nodes;
|
HashMap<uint32_t, ObjectID> recv_nodes;
|
||||||
uint16_t last_sent_sync = 0;
|
uint16_t last_sent_sync = 0;
|
||||||
uint16_t last_recv_sync = 0;
|
uint16_t last_recv_sync = 0;
|
||||||
|
@ -73,7 +74,7 @@ private:
|
||||||
HashMap<ObjectID, TrackedNode> tracked_nodes;
|
HashMap<ObjectID, TrackedNode> tracked_nodes;
|
||||||
HashMap<int, PeerInfo> peers_info;
|
HashMap<int, PeerInfo> peers_info;
|
||||||
HashSet<ObjectID> spawned_nodes;
|
HashSet<ObjectID> spawned_nodes;
|
||||||
HashSet<ObjectID> path_only_nodes;
|
HashSet<ObjectID> synced_nodes;
|
||||||
|
|
||||||
TrackedNode &_track(const ObjectID &p_id);
|
TrackedNode &_track(const ObjectID &p_id);
|
||||||
void _untrack(const ObjectID &p_id);
|
void _untrack(const ObjectID &p_id);
|
||||||
|
@ -82,7 +83,9 @@ private:
|
||||||
public:
|
public:
|
||||||
const HashSet<int> get_peers() const { return known_peers; }
|
const HashSet<int> get_peers() const { return known_peers; }
|
||||||
const HashSet<ObjectID> &get_spawned_nodes() const { return spawned_nodes; }
|
const HashSet<ObjectID> &get_spawned_nodes() const { return spawned_nodes; }
|
||||||
const HashSet<ObjectID> &get_path_only_nodes() const { return path_only_nodes; }
|
bool is_spawned_node(const ObjectID &p_id) const { return spawned_nodes.has(p_id); }
|
||||||
|
const HashSet<ObjectID> &get_synced_nodes() const { return synced_nodes; }
|
||||||
|
bool is_synced_node(const ObjectID &p_id) const { return synced_nodes.has(p_id); }
|
||||||
|
|
||||||
MultiplayerSynchronizer *get_synchronizer(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_synchronizer() : nullptr; }
|
MultiplayerSynchronizer *get_synchronizer(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_synchronizer() : nullptr; }
|
||||||
MultiplayerSpawner *get_spawner(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_spawner() : nullptr; }
|
MultiplayerSpawner *get_spawner(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_spawner() : nullptr; }
|
||||||
|
@ -90,7 +93,6 @@ public:
|
||||||
bool update_last_node_sync(const ObjectID &p_id, uint16_t p_time);
|
bool update_last_node_sync(const ObjectID &p_id, uint16_t p_time);
|
||||||
bool update_sync_time(const ObjectID &p_id, uint64_t p_msec);
|
bool update_sync_time(const ObjectID &p_id, uint64_t p_msec);
|
||||||
|
|
||||||
const HashSet<ObjectID> get_known_nodes(int p_peer);
|
|
||||||
uint32_t get_net_id(const ObjectID &p_id) const;
|
uint32_t get_net_id(const ObjectID &p_id) const;
|
||||||
void set_net_id(const ObjectID &p_id, uint32_t p_net_id);
|
void set_net_id(const ObjectID &p_id, uint32_t p_net_id);
|
||||||
uint32_t ensure_net_id(const ObjectID &p_id);
|
uint32_t ensure_net_id(const ObjectID &p_id);
|
||||||
|
@ -104,8 +106,17 @@ public:
|
||||||
Error config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync);
|
Error config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync);
|
||||||
Error config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync);
|
Error config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync);
|
||||||
|
|
||||||
Error peer_add_node(int p_peer, const ObjectID &p_id);
|
Error peer_add_sync(int p_peer, const ObjectID &p_id);
|
||||||
Error peer_del_node(int p_peer, const ObjectID &p_id);
|
Error peer_del_sync(int p_peer, const ObjectID &p_id);
|
||||||
|
|
||||||
|
const HashSet<ObjectID> get_peer_sync_nodes(int p_peer);
|
||||||
|
bool is_peer_sync(int p_peer, const ObjectID &p_id) const;
|
||||||
|
|
||||||
|
Error peer_add_spawn(int p_peer, const ObjectID &p_id);
|
||||||
|
Error peer_del_spawn(int p_peer, const ObjectID &p_id);
|
||||||
|
|
||||||
|
const HashSet<ObjectID> get_peer_spawn_nodes(int p_peer);
|
||||||
|
bool is_peer_spawn(int p_peer, const ObjectID &p_id) const;
|
||||||
|
|
||||||
const HashMap<uint32_t, ObjectID> peer_get_remotes(int p_peer) const;
|
const HashMap<uint32_t, ObjectID> peer_get_remotes(int p_peer) const;
|
||||||
Node *peer_get_remote(int p_peer, uint32_t p_net_id);
|
Node *peer_get_remote(int p_peer, uint32_t p_net_id);
|
||||||
|
|
|
@ -302,12 +302,9 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
|
||||||
ERR_FAIL_MSG("Attempt to call RPC with unknown peer ID: " + itos(p_to) + ".");
|
ERR_FAIL_MSG("Attempt to call RPC with unknown peer ID: " + itos(p_to) + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path());
|
|
||||||
ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!");
|
|
||||||
|
|
||||||
// See if all peers have cached path (if so, call can be fast).
|
// See if all peers have cached path (if so, call can be fast).
|
||||||
int psc_id;
|
int psc_id;
|
||||||
const bool has_all_peers = multiplayer->send_object_cache(p_from, from_path, p_to, psc_id);
|
const bool has_all_peers = multiplayer->send_object_cache(p_from, p_to, psc_id);
|
||||||
|
|
||||||
// Create base packet, lots of hardcode because it must be tight.
|
// Create base packet, lots of hardcode because it must be tight.
|
||||||
|
|
||||||
|
@ -414,6 +411,7 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
|
||||||
// Not all verified path, so send one by one.
|
// Not all verified path, so send one by one.
|
||||||
|
|
||||||
// Append path at the end, since we will need it for some packets.
|
// Append path at the end, since we will need it for some packets.
|
||||||
|
NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path());
|
||||||
CharString pname = String(from_path).utf8();
|
CharString pname = String(from_path).utf8();
|
||||||
int path_len = encode_cstring(pname.get_data(), nullptr);
|
int path_len = encode_cstring(pname.get_data(), nullptr);
|
||||||
MAKE_ROOM(ofs + path_len);
|
MAKE_ROOM(ofs + path_len);
|
||||||
|
|
Loading…
Reference in New Issue