Skip to content

Commit 6672565

Browse files
committed
Merge pull request godotengine#77829 from AThousandShips/mp_fix
Disallow nested custom multiplayers in `SceneTree`
2 parents 5381539 + da68f02 commit 6672565

3 files changed

Lines changed: 32 additions & 9 deletions

File tree

doc/classes/Node.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@
851851
</member>
852852
<member name="multiplayer" type="MultiplayerAPI" setter="" getter="get_multiplayer">
853853
The [MultiplayerAPI] instance associated with this node. See [method SceneTree.get_multiplayer].
854+
[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.
854855
</member>
855856
<member name="name" type="StringName" setter="set_name" getter="get_name">
856857
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.

doc/classes/SceneTree.xml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@
110110
<return type="MultiplayerAPI" />
111111
<param index="0" name="for_path" type="NodePath" default="NodePath(&quot;&quot;)" />
112112
<description>
113-
Return the [MultiplayerAPI] configured for the given path, or the default one if [param for_path] is empty.
114-
[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.
113+
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].
115114
</description>
116115
</method>
117116
<method name="get_node_count" qualifiers="const">
@@ -211,7 +210,7 @@
211210
<param index="1" name="root_path" type="NodePath" default="NodePath(&quot;&quot;)" />
212211
<description>
213212
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.
214-
[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].
213+
[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.
215214
</description>
216215
</method>
217216
<method name="unload_current_scene">

scene/main/scene_tree.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,15 +1483,18 @@ TypedArray<Tween> SceneTree::get_processed_tweens() {
14831483

14841484
Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const {
14851485
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), Ref<MultiplayerAPI>(), "Multiplayer can only be manipulated from the main thread.");
1486-
Ref<MultiplayerAPI> out = multiplayer;
1486+
if (p_for_path.is_empty()) {
1487+
return multiplayer;
1488+
}
1489+
1490+
const Vector<StringName> tnames = p_for_path.get_names();
1491+
const StringName *nptr = tnames.ptr();
14871492
for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
14881493
const Vector<StringName> snames = E.key.get_names();
1489-
const Vector<StringName> tnames = p_for_path.get_names();
14901494
if (tnames.size() < snames.size()) {
14911495
continue;
14921496
}
14931497
const StringName *sptr = snames.ptr();
1494-
const StringName *nptr = tnames.ptr();
14951498
bool valid = true;
14961499
for (int i = 0; i < snames.size(); i++) {
14971500
if (sptr[i] != nptr[i]) {
@@ -1500,11 +1503,11 @@ Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const
15001503
}
15011504
}
15021505
if (valid) {
1503-
out = E.value;
1504-
break;
1506+
return E.value;
15051507
}
15061508
}
1507-
return out;
1509+
1510+
return multiplayer;
15081511
}
15091512

15101513
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
15191522
} else {
15201523
if (custom_multiplayers.has(p_root_path)) {
15211524
custom_multiplayers[p_root_path]->object_configuration_remove(nullptr, p_root_path);
1525+
} else if (p_multiplayer.is_valid()) {
1526+
const Vector<StringName> tnames = p_root_path.get_names();
1527+
const StringName *nptr = tnames.ptr();
1528+
for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
1529+
const Vector<StringName> snames = E.key.get_names();
1530+
if (tnames.size() < snames.size()) {
1531+
continue;
1532+
}
1533+
const StringName *sptr = snames.ptr();
1534+
bool valid = true;
1535+
for (int i = 0; i < snames.size(); i++) {
1536+
if (sptr[i] != nptr[i]) {
1537+
valid = false;
1538+
break;
1539+
}
1540+
}
1541+
ERR_FAIL_COND_MSG(valid, "Multiplayer is already configured for a parent of this path: '" + p_root_path + "' in '" + E.key + "'.");
1542+
}
15221543
}
15231544
if (p_multiplayer.is_valid()) {
15241545
custom_multiplayers[p_root_path] = p_multiplayer;
15251546
p_multiplayer->object_configuration_add(nullptr, p_root_path);
1547+
} else {
1548+
custom_multiplayers.erase(p_root_path);
15261549
}
15271550
}
15281551
}

0 commit comments

Comments
 (0)