Skip to content

Commit

Permalink
Merge pull request #62961 from Faless/mp/4.x_interest
Browse files Browse the repository at this point in the history
Add peer visibility to MultiplayerSynchronizer.
  • Loading branch information
Faless authored Jul 20, 2022
2 parents e1c5015 + ddee5f6 commit 1cf7ebd
Show file tree
Hide file tree
Showing 15 changed files with 482 additions and 128 deletions.
8 changes: 6 additions & 2 deletions core/multiplayer/multiplayer_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,12 @@ bool MultiplayerAPI::is_cache_confirmed(NodePath p_path, int 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) {
return cache->send_object_cache(p_obj, p_path, p_peer_id, 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_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) {
Expand Down
6 changes: 4 additions & 2 deletions core/multiplayer/multiplayer_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ class MultiplayerCacheInterface : public RefCounted {
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.
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 bool is_cache_confirmed(NodePath p_path, int p_peer) { return false; }

Expand Down Expand Up @@ -160,7 +161,8 @@ class MultiplayerAPI : public RefCounted {
Error replication_start(Object *p_object, Variant p_config);
Error replication_stop(Object *p_object, Variant p_config);
// 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);
bool is_cache_confirmed(NodePath p_path, int p_peer);

Expand Down
2 changes: 0 additions & 2 deletions doc/classes/MultiplayerSpawner.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@
</method>
</methods>
<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>
<member name="spawn_path" type="NodePath" setter="set_spawn_path" getter="get_spawn_path" default="NodePath(&quot;&quot;)">
Expand Down
52 changes: 52 additions & 0 deletions doc/classes/MultiplayerSynchronizer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,64 @@
</description>
<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>
<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>
<member name="replication_interval" type="float" setter="set_replication_interval" getter="get_replication_interval" default="0.0">
</member>
<member name="root_path" type="NodePath" setter="set_root_path" getter="get_root_path" default="NodePath(&quot;..&quot;)">
</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>
<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>
17 changes: 2 additions & 15 deletions scene/multiplayer/multiplayer_spawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
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;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &exts);
String ext_hint;
Expand Down Expand Up @@ -144,10 +144,6 @@ void MultiplayerSpawner::_bind_methods() {
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");

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");

ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
Expand All @@ -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);
if (node) {
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));
}
} else {
Expand Down Expand Up @@ -221,15 +217,6 @@ void MultiplayerSpawner::_node_added(Node *p_node) {
_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 {
return spawn_path;
}
Expand Down
3 changes: 0 additions & 3 deletions scene/multiplayer/multiplayer_spawner.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ class MultiplayerSpawner : public Node {

ObjectID spawn_node;
HashMap<ObjectID, SpawnInfo> tracked_nodes;
bool auto_spawn = false;
uint32_t spawn_limit = 0;

void _update_spawn_node();
Expand Down Expand Up @@ -102,8 +101,6 @@ class MultiplayerSpawner : public Node {
void set_spawn_path(const NodePath &p_path);
uint32_t get_spawn_limit() const { return spawn_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;
int find_spawnable_scene_index_from_object(const ObjectID &p_id) const;
Expand Down
142 changes: 141 additions & 1 deletion scene/multiplayer/multiplayer_synchronizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,54 @@ Object *MultiplayerSynchronizer::_get_prop_target(Object *p_obj, const NodePath
}

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;
if (node) {
get_multiplayer()->replication_stop(node, this);
}
}

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;
if (node) {
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;
}
}

Expand Down Expand Up @@ -85,6 +123,66 @@ Error MultiplayerSynchronizer::set_state(const List<NodePath> &p_properties, Obj
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() {
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);
Expand All @@ -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("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::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) {
Expand All @@ -118,6 +236,11 @@ void MultiplayerSynchronizer::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
_stop();
} break;

case NOTIFICATION_INTERNAL_PROCESS:
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
update_visibility(0);
} break;
}
}

Expand All @@ -142,6 +265,18 @@ Ref<SceneReplicationConfig> MultiplayerSynchronizer::get_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) {
_stop();
root_path = p_path;
Expand All @@ -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);
get_multiplayer()->replication_start(node, this);
}

MultiplayerSynchronizer::MultiplayerSynchronizer() {
// Publicly visible by default.
peer_visibility.insert(0);
}
Loading

0 comments on commit 1cf7ebd

Please sign in to comment.