summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorA Thousand Ships <96648715+AThousandShips@users.noreply.github.com>2023-08-16 14:00:29 +0200
committerA Thousand Ships <96648715+AThousandShips@users.noreply.github.com>2023-09-25 14:59:05 +0200
commita5fe392b7812f62309e228959e8b7ea8c93013d8 (patch)
tree8854c20b1b9d3c5b388ff5a7604562b888cee435
parentdf0a822323a79e1a645f0c6a17d51c7602f23166 (diff)
downloadredot-engine-a5fe392b7812f62309e228959e8b7ea8c93013d8.tar.gz
Disallow nested custom multiplayers in `SceneTree`
Enables clearing the custom multiplayer
-rw-r--r--doc/classes/Node.xml1
-rw-r--r--doc/classes/SceneTree.xml5
-rw-r--r--scene/main/scene_tree.cpp35
3 files changed, 32 insertions, 9 deletions
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index c9c94eff36..8da2f0b86b 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -851,6 +851,7 @@
</member>
<member name="multiplayer" type="MultiplayerAPI" setter="" getter="get_multiplayer">
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.
</member>
<member name="name" type="StringName" setter="set_name" getter="get_name">
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 5086b68f24..da23eadfd1 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -110,8 +110,7 @@
<return type="MultiplayerAPI" />
<param index="0" name="for_path" type="NodePath" default="NodePath(&quot;&quot;)" />
<description>
- 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].
</description>
</method>
<method name="get_node_count" qualifiers="const">
@@ -211,7 +210,7 @@
<param index="1" name="root_path" type="NodePath" default="NodePath(&quot;&quot;)" />
<description>
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.
</description>
</method>
<method name="unload_current_scene">
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index ba11084d3b..d357e35c1d 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1483,15 +1483,18 @@ TypedArray<Tween> SceneTree::get_processed_tweens() {
Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const {
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), Ref<MultiplayerAPI>(), "Multiplayer can only be manipulated from the main thread.");
- Ref<MultiplayerAPI> out = multiplayer;
+ if (p_for_path.is_empty()) {
+ return multiplayer;
+ }
+
+ const Vector<StringName> tnames = p_for_path.get_names();
+ const StringName *nptr = tnames.ptr();
for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
const Vector<StringName> snames = E.key.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]) {
@@ -1500,11 +1503,11 @@ Ref<MultiplayerAPI> 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<MultiplayerAPI> p_multiplayer, const NodePath &p_root_path) {
@@ -1519,10 +1522,30 @@ void SceneTree::set_multiplayer(Ref<MultiplayerAPI> 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<StringName> tnames = p_root_path.get_names();
+ const StringName *nptr = tnames.ptr();
+ for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
+ const Vector<StringName> 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);
}
}
}