feat: updated engine

This commit is contained in:
Sara Gerretsen 2026-07-10 17:04:34 +02:00
parent cbe99774ff
commit f4cf6b3999
6607 changed files with 910135 additions and 430025 deletions

View file

@ -15,8 +15,4 @@ if env.editor_build:
env.modules_sources += module_obj
if env["tests"]:
env_mp.Append(CPPDEFINES=["TESTS_ENABLED"])
env_mp.add_source_files(env.modules_sources, "./tests/*.cpp")
if env["disable_exceptions"]:
env_mp.Append(CPPDEFINES=["DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS"])

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MultiplayerSpawner" inherits="Node" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="MultiplayerSpawner" inherits="Node" api_type="core" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Automatically replicates spawnable nodes from the authority to other multiplayer peers.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MultiplayerSynchronizer" inherits="Node" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="MultiplayerSynchronizer" inherits="Node" api_type="core" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Synchronizes properties from the multiplayer authority to the remote peers.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OfflineMultiplayerPeer" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="OfflineMultiplayerPeer" inherits="MultiplayerPeer" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A [MultiplayerPeer] which is always connected and acts as a server.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SceneMultiplayer" inherits="MultiplayerAPI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="SceneMultiplayer" inherits="MultiplayerAPI" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
High-level multiplayer API implementation.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SceneReplicationConfig" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<class name="SceneReplicationConfig" inherits="Resource" api_type="core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Configuration for properties to synchronize with a [MultiplayerSynchronizer].
</brief_description>

View file

@ -30,6 +30,8 @@
#include "editor_network_profiler.h"
#include "core/io/resource_loader.h"
#include "core/object/callable_mp.h"
#include "editor/editor_string_names.h"
#include "editor/run/editor_run_bar.h"
#include "editor/settings/editor_settings.h"
@ -37,6 +39,7 @@
#include "scene/gui/check_box.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/split_container.h"
#include "scene/main/timer.h"
void EditorNetworkProfiler::_bind_methods() {

View file

@ -36,7 +36,6 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
#include "scene/gui/split_container.h"
#include "scene/gui/tree.h"
class Timer;

View file

@ -34,10 +34,11 @@
#include "editor_network_profiler.h"
#include "replication_editor.h"
#include "core/object/callable_mp.h"
#include "editor/docks/editor_dock_manager.h"
#include "editor/editor_interface.h"
#include "editor/editor_node.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/settings/editor_command_palette.h"
#include "scene/main/scene_tree.h"
void MultiplayerEditorDebugger::_bind_methods() {
ADD_SIGNAL(MethodInfo("open_request", PropertyInfo(Variant::STRING, "path")));
@ -116,8 +117,8 @@ void MultiplayerEditorDebugger::setup_session(int p_session_id) {
MultiplayerEditorPlugin::MultiplayerEditorPlugin() {
repl_editor = memnew(ReplicationEditor);
button = EditorNode::get_bottom_panel()->add_item(TTRC("Replication"), repl_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_replication_bottom_panel", TTRC("Toggle Replication Bottom Panel")));
button->hide();
EditorDockManager::get_singleton()->add_dock(repl_editor);
repl_editor->close();
repl_editor->get_pin()->connect(SceneStringName(pressed), callable_mp(this, &MultiplayerEditorPlugin::_pinned));
debugger.instantiate();
debugger->connect("open_request", callable_mp(this, &MultiplayerEditorPlugin::_open_request));
@ -142,20 +143,14 @@ void MultiplayerEditorPlugin::_notification(int p_what) {
void MultiplayerEditorPlugin::_node_removed(Node *p_node) {
if (p_node && p_node == repl_editor->get_current()) {
repl_editor->edit(nullptr);
if (repl_editor->is_visible_in_tree()) {
EditorNode::get_bottom_panel()->hide_bottom_panel();
}
button->hide();
repl_editor->close();
repl_editor->get_pin()->set_pressed(false);
}
}
void MultiplayerEditorPlugin::_pinned() {
if (!repl_editor->get_pin()->is_pressed() && repl_editor->get_current() == nullptr) {
if (repl_editor->is_visible_in_tree()) {
EditorNode::get_bottom_panel()->hide_bottom_panel();
}
button->hide();
repl_editor->close();
}
}
@ -169,12 +164,8 @@ bool MultiplayerEditorPlugin::handles(Object *p_object) const {
void MultiplayerEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
EditorNode::get_bottom_panel()->make_item_visible(repl_editor);
repl_editor->make_visible();
} else if (!repl_editor->get_pin()->is_pressed()) {
if (repl_editor->is_visible_in_tree()) {
EditorNode::get_bottom_panel()->hide_bottom_panel();
}
button->hide();
repl_editor->close();
}
}

View file

@ -58,7 +58,6 @@ class MultiplayerEditorPlugin : public EditorPlugin {
GDCLASS(MultiplayerEditorPlugin, EditorPlugin);
private:
Button *button = nullptr;
ReplicationEditor *repl_editor = nullptr;
Ref<MultiplayerEditorDebugger> debugger;

View file

@ -32,11 +32,14 @@
#include "../multiplayer_synchronizer.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/inspector/property_selector.h"
#include "editor/scene/scene_tree_editor.h"
#include "editor/settings/editor_command_palette.h"
#include "editor/settings/editor_settings.h"
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
@ -152,10 +155,18 @@ void ReplicationEditor::_pick_node_property_selected(String p_name) {
/// ReplicationEditor
ReplicationEditor::ReplicationEditor() {
set_name(TTRC("Replication"));
set_icon_name("ReplicationDock");
set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_replication_bottom_panel", TTRC("Toggle Replication Dock")));
set_default_slot(EditorDock::DOCK_SLOT_BOTTOM);
set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);
set_global(false);
set_transient(true);
set_v_size_flags(SIZE_EXPAND_FILL);
set_custom_minimum_size(Size2(0, 200) * EDSCALE);
delete_dialog = memnew(ConfirmationDialog);
delete_dialog->set_flag(Window::FLAG_RESIZE_DISABLED, true);
delete_dialog->connect("canceled", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(false));
delete_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ReplicationEditor::_dialog_closed).bind(true));
add_child(delete_dialog);
@ -253,6 +264,11 @@ ReplicationEditor::ReplicationEditor() {
pin->set_tooltip_text(TTRC("Pin replication editor"));
hb->add_child(pin);
tree_mc = memnew(MarginContainer);
tree_mc->set_theme_type_variation("NoBorderHorizontal");
tree_mc->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_child(tree_mc);
tree = memnew(Tree);
tree->set_hide_root(true);
tree->set_columns(4);
@ -269,8 +285,8 @@ ReplicationEditor::ReplicationEditor() {
tree->create_item();
tree->connect("button_clicked", callable_mp(this, &ReplicationEditor::_tree_button_pressed));
tree->connect("item_edited", callable_mp(this, &ReplicationEditor::_tree_item_edited));
tree->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_child(tree);
tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTTOM);
tree_mc->add_child(tree);
drop_label = memnew(Label(TTRC("Add properties using the options above, or\ndrag them from the inspector and drop them here.")));
drop_label->set_focus_mode(FOCUS_ACCESSIBILITY);
@ -516,6 +532,16 @@ void ReplicationEditor::_update_config() {
}
}
void ReplicationEditor::update_layout(EditorDock::DockLayout p_layout, int p_slot) {
if (p_slot != EditorDock::DOCK_SLOT_BOTTOM) {
tree_mc->set_theme_type_variation("NoBorderHorizontalBottom");
tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_DISABLED);
} else {
tree_mc->set_theme_type_variation("NoBorderHorizontal");
tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTTOM);
}
}
void ReplicationEditor::edit(MultiplayerSynchronizer *p_sync) {
if (current == p_sync) {
return;

View file

@ -32,8 +32,8 @@
#include "../scene_replication_config.h"
#include "editor/docks/editor_dock.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/gui/box_container.h"
class ConfirmationDialog;
class MultiplayerSynchronizer;
@ -44,8 +44,8 @@ class TreeItem;
class PropertySelector;
class SceneTreeDialog;
class ReplicationEditor : public VBoxContainer {
GDCLASS(ReplicationEditor, VBoxContainer);
class ReplicationEditor : public EditorDock {
GDCLASS(ReplicationEditor, EditorDock);
private:
MultiplayerSynchronizer *current = nullptr;
@ -59,6 +59,8 @@ private:
Ref<SceneReplicationConfig> config;
NodePath deleting;
MarginContainer *tree_mc = nullptr;
Tree *tree = nullptr;
PropertySelector *prop_selector = nullptr;
@ -91,9 +93,10 @@ private:
void _add_sync_property(String p_path);
protected:
void _notification(int p_what);
static void _bind_methods();
void _notification(int p_what);
virtual void update_layout(EditorDock::DockLayout p_layout, int p_slot) override;
public:
void edit(MultiplayerSynchronizer *p_object);

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m8 10-2 4-2-4ZM12 14l-2-4-2 4Z"/><path fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" d="M4.936 7.429a4 4 0 0 1 6.128 0M1.872 4.858a8 8 0 0 1 12.256 0"/></svg>

After

Width:  |  Height:  |  Size: 269 B

View file

@ -30,7 +30,10 @@
#include "multiplayer_spawner.h"
#include "core/config/engine.h"
#include "core/io/resource_loader.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "scene/main/multiplayer_api.h"
#ifdef TOOLS_ENABLED
@ -175,8 +178,8 @@ void MultiplayerSpawner::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_spawn_function", "spawn_function"), &MultiplayerSpawner::set_spawn_function);
ADD_PROPERTY(PropertyInfo(Variant::CALLABLE, "spawn_function", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_spawn_function", "get_spawn_function");
ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("spawned", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, Node::get_class_static())));
ADD_SIGNAL(MethodInfo("spawned", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, Node::get_class_static())));
}
void MultiplayerSpawner::_update_spawn_node() {

View file

@ -31,6 +31,7 @@
#include "multiplayer_synchronizer.h"
#include "core/config/engine.h"
#include "core/object/class_db.h"
#include "scene/main/multiplayer_api.h"
Object *MultiplayerSynchronizer::_get_prop_target(Object *p_obj, const NodePath &p_path) {
@ -270,7 +271,7 @@ void MultiplayerSynchronizer::_bind_methods() {
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::FLOAT, "delta_interval", PROPERTY_HINT_RANGE, "0,5,0.001,suffix:s"), "set_delta_interval", "get_delta_interval");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_replication_config", "get_replication_config");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, SceneReplicationConfig::get_class_static(), PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "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");
@ -372,7 +373,7 @@ void MultiplayerSynchronizer::set_multiplayer_authority(int p_peer_id, bool p_re
Error MultiplayerSynchronizer::_watch_changes(uint64_t p_usec) {
ERR_FAIL_COND_V(replication_config.is_null(), FAILED);
const List<NodePath> props = replication_config->get_watch_properties();
const List<NodePath> props(replication_config->get_watch_properties());
if (props.size() != watchers.size()) {
watchers.resize(props.size());
}
@ -436,7 +437,7 @@ List<Variant> MultiplayerSynchronizer::get_delta_state(uint64_t p_cur_usec, uint
List<NodePath> MultiplayerSynchronizer::get_delta_properties(uint64_t p_indexes) {
List<NodePath> out;
ERR_FAIL_COND_V(replication_config.is_null(), out);
const List<NodePath> watch_props = replication_config->get_watch_properties();
const List<NodePath> watch_props(replication_config->get_watch_properties());
int idx = 0;
for (const NodePath &prop : watch_props) {
if ((p_indexes & (1ULL << idx++)) == 0) {

View file

@ -37,6 +37,8 @@
#include "scene_replication_interface.h"
#include "scene_rpc_interface.h"
#include "core/object/class_db.h"
#ifdef TOOLS_ENABLED
#include "editor/multiplayer_editor_plugin.h"
#endif

View file

@ -33,7 +33,9 @@
#include "scene_multiplayer.h"
#include "core/io/marshalls.h"
#include "core/object/callable_mp.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
SceneCacheInterface::NodeCache &SceneCacheInterface::_track(Node *p_node) {

View file

@ -32,6 +32,8 @@
#include "core/debugger/engine_debugger.h"
#include "core/io/marshalls.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#ifdef DEBUG_ENABLED

View file

@ -182,7 +182,7 @@ public:
Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE, int p_channel = 0);
String get_rpc_md5(const Object *p_obj);
const HashSet<int> get_connected_peers() const { return connected_peers; }
const HashSet<int> get_connected_peers() const { return HashSet<int>(connected_peers); }
void set_remote_sender_override(int p_id) { remote_sender_override = p_id; }
void set_refuse_new_connections(bool p_refuse);

View file

@ -30,6 +30,8 @@
#include "scene_replication_config.h"
#include "core/object/class_db.h"
bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_value) {
String prop_name = p_name;

View file

@ -34,10 +34,11 @@
#include "core/debugger/engine_debugger.h"
#include "core/io/marshalls.h"
#include "core/object/callable_mp.h"
#include "core/os/os.h"
#include "scene/main/node.h"
#define MAKE_ROOM(m_amount) \
#define MAKE_ROOM(m_amount) \
if (packet_cache.size() < m_amount) \
packet_cache.resize(m_amount);
@ -142,7 +143,7 @@ void SceneReplicationInterface::on_network_process() {
// Process syncs.
uint64_t usec = OS::get_singleton()->get_ticks_usec();
for (KeyValue<int, PeerInfo> &E : peers_info) {
const HashSet<ObjectID> to_sync = E.value.sync_nodes;
const HashSet<ObjectID> to_sync(E.value.sync_nodes);
if (to_sync.is_empty()) {
continue; // Nothing to sync
}
@ -249,7 +250,7 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c
if (pending_buffer_size > 0) {
ERR_FAIL_COND_V(!node || !sync->get_replication_config_ptr(), ERR_UNCONFIGURED);
int consumed = 0;
const List<NodePath> props = sync->get_replication_config_ptr()->get_spawn_properties();
const List<NodePath> props(sync->get_replication_config_ptr()->get_spawn_properties());
Vector<Variant> vars;
vars.resize(props.size());
Error err = MultiplayerAPI::decode_and_decompress_variants(vars, pending_buffer, pending_buffer_size, consumed);
@ -281,7 +282,7 @@ Error SceneReplicationInterface::on_replication_stop(Object *p_obj, Variant p_co
for (KeyValue<int, PeerInfo> &E : peers_info) {
E.value.sync_nodes.erase(sid);
E.value.last_watch_usecs.erase(sid);
if (sync->get_net_id()) {
if (sync->get_net_id() && uint32_t(E.key) == tobj.remote_peer) {
E.value.recv_sync_ids.erase(sync->get_net_id());
}
}
@ -386,7 +387,7 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje
ERR_FAIL_NULL_V(spawner, ERR_BUG);
ERR_FAIL_COND_V(!_has_authority(spawner), ERR_BUG);
ERR_FAIL_COND_V(!tracked_nodes.has(p_oid), ERR_BUG);
const HashSet<ObjectID> synchronizers = tracked_nodes[p_oid].synchronizers;
const HashSet<ObjectID> synchronizers(tracked_nodes[p_oid].synchronizers);
bool is_visible = true;
for (const ObjectID &sid : synchronizers) {
MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid);
@ -490,7 +491,7 @@ Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, MultiplayerSpa
// Prepare spawn state.
List<NodePath> state_props;
List<uint32_t> sync_ids;
const HashSet<ObjectID> synchronizers = tnode->synchronizers;
const HashSet<ObjectID> synchronizers(tnode->synchronizers);
for (const ObjectID &sid : synchronizers) {
MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid);
if (!_has_authority(sync)) {
@ -519,7 +520,7 @@ Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, MultiplayerSpa
// Encode scene ID, path ID, net ID, node name.
int path_id = multiplayer_cache->make_object_cache(p_spawner);
CharString cname = p_node->get_name().operator String().utf8();
CharString cname = p_node->get_name().string().utf8();
int nlen = encode_cstring(cname.get_data(), nullptr);
MAKE_ROOM(1 + 1 + 4 + 4 + 4 + 4 * sync_ids.size() + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size);
uint8_t *ptr = packet_cache.ptrw();
@ -823,7 +824,7 @@ void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> &
int size;
Vector<Variant> vars;
Vector<const Variant *> varp;
const List<NodePath> props = sync->get_replication_config_ptr()->get_sync_properties();
const List<NodePath> props(sync->get_replication_config_ptr()->get_sync_properties());
Error err = MultiplayerSynchronizer::get_state(props, node, vars, varp);
ERR_CONTINUE_MSG(err != OK, "Unable to retrieve sync state.");
err = MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), nullptr, size);
@ -882,7 +883,7 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu
ofs += size;
continue;
}
const List<NodePath> props = sync->get_replication_config_ptr()->get_sync_properties();
const List<NodePath> props(sync->get_replication_config_ptr()->get_sync_properties());
Vector<Variant> vars;
vars.resize(props.size());
int consumed;

View file

@ -34,8 +34,10 @@
#include "core/debugger/engine_debugger.h"
#include "core/io/marshalls.h"
#include "core/object/callable_mp.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
// The RPC meta is composed by a single byte that contains (starting from the least significant bit):
@ -346,7 +348,7 @@ void SceneRPCInterface::_send_rpc(Node *p_node, int p_to, uint16_t p_rpc_id, con
// Create base packet, lots of hardcode because it must be tight.
int ofs = 0;
#define MAKE_ROOM(m_amount) \
#define MAKE_ROOM(m_amount) \
if (packet_cache.size() < m_amount) \
packet_cache.resize(m_amount);

View file

@ -30,11 +30,14 @@
#pragma once
#include "../multiplayer_spawner.h"
#include "core/object/class_db.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "tests/test_macros.h"
#include "tests/test_utils.h"
#include "../multiplayer_spawner.h"
namespace TestMultiplayerSpawner {
class Wasp : public Node {
GDCLASS(Wasp, Node);

View file

@ -30,11 +30,16 @@
#pragma once
#include "../scene_multiplayer.h"
#include "core/object/callable_mp.h"
#include "core/os/os.h"
#include "scene/2d/node_2d.h"
#include "scene/main/scene_tree.h"
#include "tests/signal_watcher.h"
#include "tests/test_macros.h"
#include "tests/test_utils.h"
#include "../scene_multiplayer.h"
namespace TestSceneMultiplayer {
TEST_CASE("[Multiplayer][SceneMultiplayer] Defaults") {
Ref<SceneMultiplayer> scene_multiplayer;