diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index c9c94eff36e..8da2f0b86bf 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -851,6 +851,7 @@
The [MultiplayerAPI] instance associated with this node. See [method SceneTree.get_multiplayer].
+ [b]Note:[/b] Renaming the node, or moving it in the tree, will not move the [MultiplayerAPI] to the new path, you will have to update this manually.
The name of the node. This name is unique among the siblings (other child nodes from the same parent). When set to an existing name, the node will be automatically renamed.
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 5086b68f24e..da23eadfd14 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -110,8 +110,7 @@
- Return the [MultiplayerAPI] configured for the given path, or the default one if [param for_path] is empty.
- [b]Note:[/b] Only one [MultiplayerAPI] may be configured for any subpath. If one is configured for [code]"/root/Foo"[/code] then calling this for [code]"/root/Foo/Bar"[/code] will return the one configured for [code]"/root/Foo"[/code], regardless if one is configured for that path.
+ Searches for the [MultiplayerAPI] configured for the given path, if one does not exist it searches the parent paths until one is found. If the path is empty, or none is found, the default one is returned. See [method set_multiplayer].
@@ -211,7 +210,7 @@
Sets a custom [MultiplayerAPI] with the given [param root_path] (controlling also the relative subpaths), or override the default one if [param root_path] is empty.
- [b]Note:[/b] Only one [MultiplayerAPI] may be configured for any subpath. If one is configured for [code]"/root/Foo"[/code] setting one for [code]"/root/Foo/Bar"[/code] will be ignored. See [method get_multiplayer].
+ [b]Note:[/b] No [MultiplayerAPI] must be configured for the subpath containing [param root_path], nested custom multiplayers are not allowed. I.e. if one is configured for [code]"/root/Foo"[/code] setting one for [code]"/root/Foo/Bar"[/code] will cause an error.
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index ba11084d3bf..d357e35c1d5 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1483,15 +1483,18 @@ TypedArray SceneTree::get_processed_tweens() {
Ref SceneTree::get_multiplayer(const NodePath &p_for_path) const {
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), Ref(), "Multiplayer can only be manipulated from the main thread.");
- Ref out = multiplayer;
+ if (p_for_path.is_empty()) {
+ return multiplayer;
+ }
+
+ const Vector tnames = p_for_path.get_names();
+ const StringName *nptr = tnames.ptr();
for (const KeyValue> &E : custom_multiplayers) {
const Vector snames = E.key.get_names();
- const Vector 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]) {
@@ -1500,11 +1503,11 @@ Ref SceneTree::get_multiplayer(const NodePath &p_for_path) const
}
}
if (valid) {
- out = E.value;
- break;
+ return E.value;
}
}
- return out;
+
+ return multiplayer;
}
void SceneTree::set_multiplayer(Ref p_multiplayer, const NodePath &p_root_path) {
@@ -1519,10 +1522,30 @@ void SceneTree::set_multiplayer(Ref p_multiplayer, const NodePat
} else {
if (custom_multiplayers.has(p_root_path)) {
custom_multiplayers[p_root_path]->object_configuration_remove(nullptr, p_root_path);
+ } else if (p_multiplayer.is_valid()) {
+ const Vector tnames = p_root_path.get_names();
+ const StringName *nptr = tnames.ptr();
+ for (const KeyValue> &E : custom_multiplayers) {
+ const Vector snames = E.key.get_names();
+ if (tnames.size() < snames.size()) {
+ continue;
+ }
+ const StringName *sptr = snames.ptr();
+ bool valid = true;
+ for (int i = 0; i < snames.size(); i++) {
+ if (sptr[i] != nptr[i]) {
+ valid = false;
+ break;
+ }
+ }
+ ERR_FAIL_COND_MSG(valid, "Multiplayer is already configured for a parent of this path: '" + p_root_path + "' in '" + E.key + "'.");
+ }
}
if (p_multiplayer.is_valid()) {
custom_multiplayers[p_root_path] = p_multiplayer;
p_multiplayer->object_configuration_add(nullptr, p_root_path);
+ } else {
+ custom_multiplayers.erase(p_root_path);
}
}
}