[Net] Allow branch-specific MultiplayerAPIs.

Removes custom_multiplayer from Node.
MultiplayerAPI overrides are now set at SceneTree level, and apply to
whole branches.
Impact on performance when using only the default multiplayer or
overriding it is minimal, the use of branches can likely be further
optimized by caching nodes and relevant MultiplayerAPI IDs.
This commit is contained in:
Fabio Alessandrelli
2022-02-05 01:43:47 +01:00
parent 5c54770b7c
commit aee2240d5f
7 changed files with 73 additions and 40 deletions
+1 -15
View File
@@ -653,21 +653,10 @@ void Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg
}
Ref<MultiplayerAPI> Node::get_multiplayer() const {
if (multiplayer.is_valid()) {
return multiplayer;
}
if (!is_inside_tree()) {
return Ref<MultiplayerAPI>();
}
return get_tree()->get_multiplayer();
}
Ref<MultiplayerAPI> Node::get_custom_multiplayer() const {
return multiplayer;
}
void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
multiplayer = p_multiplayer;
return get_tree()->get_multiplayer(get_path());
}
Vector<Multiplayer::RPCConfig> Node::get_node_rpc_methods() const {
@@ -2892,8 +2881,6 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_multiplayer_authority"), &Node::is_multiplayer_authority);
ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer);
ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer);
ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer);
ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "call_local", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(false), DEFVAL(Multiplayer::TRANSFER_MODE_RELIABLE), DEFVAL(0));
ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description);
@@ -2999,7 +2986,6 @@ void Node::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "scene_file_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_scene_file_path", "get_scene_file_path");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_owner", "get_owner");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "", "get_multiplayer");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "set_custom_multiplayer", "get_custom_multiplayer");
ADD_GROUP("Process", "process_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,When Paused,Always,Disabled"), "set_process_mode", "get_process_mode");
-2
View File
@@ -515,8 +515,6 @@ public:
void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount);
Ref<MultiplayerAPI> get_multiplayer() const;
Ref<MultiplayerAPI> get_custom_multiplayer() const;
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
Node();
~Node();
+51 -12
View File
@@ -438,6 +438,10 @@ bool SceneTree::process(double p_time) {
if (multiplayer_poll) {
multiplayer->poll();
const NodePath *rpath = nullptr;
while ((rpath = custom_multiplayers.next(rpath))) {
custom_multiplayers[*rpath]->poll();
}
}
emit_signal(SNAME("process_frame"));
@@ -1133,8 +1137,51 @@ Array SceneTree::get_processed_tweens() {
return ret;
}
Ref<MultiplayerAPI> SceneTree::get_multiplayer() const {
return multiplayer;
Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const {
Ref<MultiplayerAPI> out = multiplayer;
const NodePath *spath = nullptr;
while ((spath = custom_multiplayers.next(spath))) {
const Vector<StringName> snames = (*spath).get_names();
const Vector<StringName> tnames = p_for_path.get_names();
if (tnames.size() < snames.size()) {
continue;
}
const StringName *sptr = snames.ptr();
const StringName *nptr = tnames.ptr();
bool valid = true;
for (int i = 0; i < snames.size(); i++) {
if (sptr[i] != nptr[i]) {
valid = false;
break;
}
}
if (valid) {
out = custom_multiplayers[*spath];
break;
}
}
return out;
}
void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer, const NodePath &p_root_path) {
if (p_root_path.is_empty()) {
ERR_FAIL_COND(!p_multiplayer.is_valid());
if (multiplayer.is_valid()) {
multiplayer->set_root_path(NodePath());
}
multiplayer = p_multiplayer;
multiplayer->set_root_path("/" + root->get_name());
} else {
if (p_multiplayer.is_valid()) {
custom_multiplayers[p_root_path] = p_multiplayer;
p_multiplayer->set_root_path(p_root_path);
} else {
if (custom_multiplayers.has(p_root_path)) {
custom_multiplayers[p_root_path]->set_root_path(NodePath());
custom_multiplayers.erase(p_root_path);
}
}
}
}
void SceneTree::set_multiplayer_poll_enabled(bool p_enabled) {
@@ -1145,13 +1192,6 @@ bool SceneTree::is_multiplayer_poll_enabled() const {
return multiplayer_poll;
}
void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
ERR_FAIL_COND(!p_multiplayer.is_valid());
multiplayer = p_multiplayer;
multiplayer->set_root_path("/" + root->get_name());
}
void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root"), &SceneTree::get_root);
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
@@ -1214,8 +1254,8 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene);
ClassDB::bind_method(D_METHOD("set_multiplayer", "multiplayer"), &SceneTree::set_multiplayer);
ClassDB::bind_method(D_METHOD("get_multiplayer"), &SceneTree::get_multiplayer);
ClassDB::bind_method(D_METHOD("set_multiplayer", "multiplayer", "root_path"), &SceneTree::set_multiplayer, DEFVAL(NodePath()));
ClassDB::bind_method(D_METHOD("get_multiplayer", "for_path"), &SceneTree::get_multiplayer, DEFVAL(NodePath()));
ClassDB::bind_method(D_METHOD("set_multiplayer_poll_enabled", "enabled"), &SceneTree::set_multiplayer_poll_enabled);
ClassDB::bind_method(D_METHOD("is_multiplayer_poll_enabled"), &SceneTree::is_multiplayer_poll_enabled);
@@ -1225,7 +1265,6 @@ void SceneTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_edited_scene_root", "get_edited_scene_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_current_scene", "get_current_scene");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "set_multiplayer", "get_multiplayer");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled");
ADD_SIGNAL(MethodInfo("tree_changed"));
+3 -2
View File
@@ -159,6 +159,7 @@ private:
///network///
Ref<MultiplayerAPI> multiplayer;
HashMap<NodePath, Ref<MultiplayerAPI>> custom_multiplayers;
bool multiplayer_poll = true;
static SceneTree *singleton;
@@ -351,10 +352,10 @@ public:
//network API
Ref<MultiplayerAPI> get_multiplayer() const;
Ref<MultiplayerAPI> get_multiplayer(const NodePath &p_for_path = NodePath()) const;
void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer, const NodePath &p_root_path = NodePath());
void set_multiplayer_poll_enabled(bool p_enabled);
bool is_multiplayer_poll_enabled() const;
void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
static void add_idle_callback(IdleCallback p_callback);