summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/core_bind.cpp3
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/extension/gdnative_interface.cpp6
-rw-r--r--core/extension/gdnative_interface.h11
-rw-r--r--core/input/input_event.cpp18
-rw-r--r--core/io/compression.cpp8
-rw-r--r--core/io/http_client_tcp.cpp1
-rw-r--r--core/io/multiplayer_api.cpp30
-rw-r--r--core/io/multiplayer_api.h12
-rw-r--r--core/io/multiplayer_peer.cpp (renamed from core/io/networked_multiplayer_peer.cpp)24
-rw-r--r--core/io/multiplayer_peer.h (renamed from core/io/networked_multiplayer_peer.h)12
-rw-r--r--core/object/class_db.h11
-rw-r--r--core/object/object.cpp61
-rw-r--r--core/object/object.h36
-rw-r--r--core/object/ref_counted.cpp19
-rw-r--r--core/os/memory.h2
-rw-r--r--core/os/os.h2
-rw-r--r--core/register_core_types.cpp160
-rw-r--r--core/string/ustring.cpp19
-rw-r--r--core/templates/list.h77
-rw-r--r--core/templates/map.h133
-rw-r--r--core/templates/pair.h35
-rw-r--r--core/templates/rid_owner.h2
-rw-r--r--core/templates/set.h79
-rw-r--r--core/templates/vector.h64
-rw-r--r--core/typedefs.h7
-rw-r--r--core/variant/variant_op.h12
-rw-r--r--core/variant/variant_parser.cpp32
29 files changed, 643 insertions, 236 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 25506e8db3..ac4e0db5b7 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1114,6 +1114,8 @@ ProjectSettings::ProjectSettings() {
// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor");
+ // Keep the enum values in sync with the `DisplayServer::VSyncMode` enum.
+ custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox");
custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
GLOBAL_DEF("physics/2d/run_on_thread", false);
GLOBAL_DEF("physics/3d/run_on_thread", false);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index a3349444c4..9a58528bd7 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -1729,10 +1729,11 @@ void _Thread::_start_func(void *ud) {
memdelete(tud);
Callable::CallError ce;
const Variant *arg[1] = { &t->userdata };
+ int argc = (int)(arg[0]->get_type() != Variant::NIL);
Thread::set_name(t->target_method);
- t->ret = t->target_instance->call(t->target_method, arg, 1, ce);
+ t->ret = t->target_instance->call(t->target_method, arg, argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
String reason;
switch (ce.error) {
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 0aad21276a..de15cfd14a 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -509,6 +509,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 324933d7b7..8f68b8d848 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -520,6 +520,11 @@ static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
}
+static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_instance, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks) {
+ Object *o = (Object *)p_instance;
+ return o->get_instance_binding(p_token, p_callbacks);
+}
+
static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
}
@@ -665,6 +670,7 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.object_method_bind_ptrcall = gdnative_object_method_bind_ptrcall;
gdni.object_destroy = gdnative_object_destroy;
gdni.global_get_singleton = gdnative_global_get_singleton;
+ gdni.object_get_instance_binding = gdnative_object_get_instance_binding;
gdni.object_cast_to = gdnative_object_cast_to;
gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 318912e889..c1ebb3e76a 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -171,6 +171,16 @@ typedef void (*GDNativePtrUtilityFunction)(GDNativeTypePtr r_return, const GDNat
typedef GDNativeObjectPtr (*GDNativeClassConstructor)();
+typedef void *(*GDNativeInstanceBindingCreateCallback)(void *p_token, void *p_instance);
+typedef void (*GDNativeInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding);
+typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_instance, GDNativeBool p_reference);
+
+struct GDNativeInstanceBindingCallbacks {
+ GDNativeInstanceBindingCreateCallback create_callback;
+ GDNativeInstanceBindingFreeCallback free_callback;
+ GDNativeInstanceBindingReferenceCallback reference_callback;
+};
+
/* EXTENSION CLASSES */
typedef void *GDExtensionClassInstancePtr;
@@ -373,6 +383,7 @@ typedef struct {
void (*object_method_bind_ptrcall)(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
void (*object_destroy)(GDNativeObjectPtr p_o);
GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
+ void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks);
GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 52a6c5d64f..4a2abffae8 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -38,6 +38,7 @@ const int InputEvent::DEVICE_ID_INTERNAL = -2;
void InputEvent::set_device(int p_device) {
device = p_device;
+ emit_changed();
}
int InputEvent::get_device() const {
@@ -131,6 +132,7 @@ void InputEventFromWindow::_bind_methods() {
void InputEventFromWindow::set_window_id(int64_t p_id) {
window_id = p_id;
+ emit_changed();
}
int64_t InputEventFromWindow::get_window_id() const {
@@ -141,6 +143,7 @@ int64_t InputEventFromWindow::get_window_id() const {
void InputEventWithModifiers::set_store_command(bool p_enabled) {
store_command = p_enabled;
+ emit_changed();
}
bool InputEventWithModifiers::is_storing_command() const {
@@ -149,6 +152,7 @@ bool InputEventWithModifiers::is_storing_command() const {
void InputEventWithModifiers::set_shift_pressed(bool p_enabled) {
shift_pressed = p_enabled;
+ emit_changed();
}
bool InputEventWithModifiers::is_shift_pressed() const {
@@ -157,6 +161,7 @@ bool InputEventWithModifiers::is_shift_pressed() const {
void InputEventWithModifiers::set_alt_pressed(bool p_enabled) {
alt_pressed = p_enabled;
+ emit_changed();
}
bool InputEventWithModifiers::is_alt_pressed() const {
@@ -165,6 +170,7 @@ bool InputEventWithModifiers::is_alt_pressed() const {
void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) {
ctrl_pressed = p_enabled;
+ emit_changed();
}
bool InputEventWithModifiers::is_ctrl_pressed() const {
@@ -173,6 +179,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const {
void InputEventWithModifiers::set_meta_pressed(bool p_enabled) {
meta_pressed = p_enabled;
+ emit_changed();
}
bool InputEventWithModifiers::is_meta_pressed() const {
@@ -181,6 +188,7 @@ bool InputEventWithModifiers::is_meta_pressed() const {
void InputEventWithModifiers::set_command_pressed(bool p_enabled) {
command_pressed = p_enabled;
+ emit_changed();
}
bool InputEventWithModifiers::is_command_pressed() const {
@@ -291,6 +299,7 @@ void InputEventWithModifiers::_validate_property(PropertyInfo &property) const {
void InputEventKey::set_pressed(bool p_pressed) {
pressed = p_pressed;
+ emit_changed();
}
bool InputEventKey::is_pressed() const {
@@ -299,6 +308,7 @@ bool InputEventKey::is_pressed() const {
void InputEventKey::set_keycode(uint32_t p_keycode) {
keycode = p_keycode;
+ emit_changed();
}
uint32_t InputEventKey::get_keycode() const {
@@ -307,6 +317,7 @@ uint32_t InputEventKey::get_keycode() const {
void InputEventKey::set_physical_keycode(uint32_t p_keycode) {
physical_keycode = p_keycode;
+ emit_changed();
}
uint32_t InputEventKey::get_physical_keycode() const {
@@ -315,6 +326,7 @@ uint32_t InputEventKey::get_physical_keycode() const {
void InputEventKey::set_unicode(uint32_t p_unicode) {
unicode = p_unicode;
+ emit_changed();
}
uint32_t InputEventKey::get_unicode() const {
@@ -323,6 +335,7 @@ uint32_t InputEventKey::get_unicode() const {
void InputEventKey::set_echo(bool p_enable) {
echo = p_enable;
+ emit_changed();
}
bool InputEventKey::is_echo() const {
@@ -469,6 +482,7 @@ void InputEventKey::_bind_methods() {
void InputEventMouse::set_button_mask(int p_mask) {
button_mask = p_mask;
+ emit_changed();
}
int InputEventMouse::get_button_mask() const {
@@ -518,6 +532,7 @@ float InputEventMouseButton::get_factor() const {
void InputEventMouseButton::set_button_index(MouseButton p_index) {
button_index = p_index;
+ emit_changed();
}
MouseButton InputEventMouseButton::get_button_index() const {
@@ -847,6 +862,7 @@ void InputEventMouseMotion::_bind_methods() {
void InputEventJoypadMotion::set_axis(JoyAxis p_axis) {
axis = p_axis;
+ emit_changed();
}
JoyAxis InputEventJoypadMotion::get_axis() const {
@@ -855,6 +871,7 @@ JoyAxis InputEventJoypadMotion::get_axis() const {
void InputEventJoypadMotion::set_axis_value(float p_value) {
axis_value = p_value;
+ emit_changed();
}
float InputEventJoypadMotion::get_axis_value() const {
@@ -949,6 +966,7 @@ void InputEventJoypadMotion::_bind_methods() {
void InputEventJoypadButton::set_button_index(JoyButton p_index) {
button_index = p_index;
+ emit_changed();
}
JoyButton InputEventJoypadButton::get_button_index() const {
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 6de626db99..790b6febc0 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -134,8 +134,9 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
if (p_dst_max_size < 16) {
uint8_t dst[16];
- ret_size = fastlz_decompress(p_src, p_src_size, dst, 16);
+ fastlz_decompress(p_src, p_src_size, dst, 16);
memcpy(p_dst, dst, p_dst_max_size);
+ ret_size = p_dst_max_size;
} else {
ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
}
@@ -238,7 +239,10 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
- WARN_PRINT(strm.msg);
+ case Z_BUF_ERROR:
+ if (strm.msg) {
+ WARN_PRINT(strm.msg);
+ }
(void)inflateEnd(&strm);
p_dst_vect->resize(0);
return ret;
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index f9b3165a07..f291086808 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -590,6 +590,7 @@ PackedByteArray HTTPClientTCP::read_response_body_chunk() {
}
}
if (err != OK) {
+ ret.resize(_offset);
break;
}
}
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 51ba8800e4..564397c88c 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -85,7 +85,7 @@ const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_i
if (id & (1 << 15)) {
id = id & ~(1 << 15);
config = p_node->get_node_rpc_methods();
- } else {
+ } else if (p_node->get_script_instance()) {
config = p_node->get_script_instance()->get_rpc_methods();
}
if (id < config.size()) {
@@ -149,7 +149,7 @@ _FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, i
}
void MultiplayerAPI::poll() {
- if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) {
+ if (!network_peer.is_valid() || network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED) {
return;
}
@@ -196,13 +196,13 @@ Node *MultiplayerAPI::get_root_node() {
return root_node;
}
-void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) {
+void MultiplayerAPI::set_network_peer(const Ref<MultiplayerPeer> &p_peer) {
if (p_peer == network_peer) {
return; // Nothing to do
}
- ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED,
- "Supplied NetworkedMultiplayerPeer must be connecting or connected.");
+ ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED,
+ "Supplied MultiplayerPeer must be connecting or connected.");
if (network_peer.is_valid()) {
network_peer->disconnect("peer_connected", callable_mp(this, &MultiplayerAPI::_add_peer));
@@ -224,7 +224,7 @@ void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_pee
}
}
-Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const {
+Ref<MultiplayerPeer> MultiplayerAPI::get_network_peer() const {
return network_peer;
}
@@ -513,7 +513,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
packet.write[1] = valid_rpc_checksum;
encode_cstring(pname.get_data(), &packet.write[2]);
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
network_peer->set_target_peer(p_from);
network_peer->put_packet(packet.ptr(), packet.size());
}
@@ -592,7 +592,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC
for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
network_peer->set_target_peer(E->get()); // To all of you.
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
network_peer->put_packet(packet.ptr(), packet.size());
psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed.
@@ -760,9 +760,9 @@ Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const u
void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree.");
- ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree.");
+ ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree.");
- ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected.");
+ ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected.");
ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255.");
@@ -974,7 +974,7 @@ void MultiplayerAPI::_server_disconnected() {
void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active.");
ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree.");
- ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected.");
+ ERR_FAIL_COND_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected.");
int node_id = network_peer->get_unique_id();
bool skip_rpc = node_id == p_peer_id;
@@ -1033,10 +1033,10 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode.");
}
-Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) {
+Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, MultiplayerPeer::TransferMode p_mode) {
ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet.");
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active.");
- ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected.");
+ ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected.");
MAKE_ROOM(p_data.size() + 1);
const uint8_t *r = p_data.ptr();
@@ -1105,7 +1105,7 @@ bool MultiplayerAPI::is_object_decoding_allowed() const {
void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node);
- ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
+ ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE));
ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer);
ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer);
ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id);
@@ -1123,7 +1123,7 @@ void MultiplayerAPI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", PROPERTY_USAGE_NONE), "set_network_peer", "get_network_peer");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerPeer", PROPERTY_USAGE_NONE), "set_network_peer", "get_network_peer");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_root_node", "get_root_node");
ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false);
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index 43804a20ec..e9f96383c9 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -31,7 +31,7 @@
#ifndef MULTIPLAYER_API_H
#define MULTIPLAYER_API_H
-#include "core/io/networked_multiplayer_peer.h"
+#include "core/io/multiplayer_peer.h"
#include "core/object/ref_counted.h"
class MultiplayerAPI : public RefCounted {
@@ -51,7 +51,7 @@ public:
struct RPCConfig {
StringName name;
RPCMode rpc_mode = RPC_MODE_DISABLED;
- NetworkedMultiplayerPeer::TransferMode transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
+ MultiplayerPeer::TransferMode transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
int channel = 0;
bool operator==(RPCConfig const &p_other) const {
@@ -83,7 +83,7 @@ private:
Map<int, NodeInfo> nodes;
};
- Ref<NetworkedMultiplayerPeer> network_peer;
+ Ref<MultiplayerPeer> network_peer;
int rpc_sender_id = 0;
Set<int> connected_peers;
HashMap<NodePath, PathSentCache> path_send_cache;
@@ -132,9 +132,9 @@ public:
void clear();
void set_root_node(Node *p_node);
Node *get_root_node();
- void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer);
- Ref<NetworkedMultiplayerPeer> get_network_peer() const;
- Error send_bytes(Vector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ void set_network_peer(const Ref<MultiplayerPeer> &p_peer);
+ Ref<MultiplayerPeer> get_network_peer() const;
+ Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE);
// Called by Node.rpc
void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/multiplayer_peer.cpp
index b6af046e77..8126b4cea3 100644
--- a/core/io/networked_multiplayer_peer.cpp
+++ b/core/io/multiplayer_peer.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* networked_multiplayer_peer.cpp */
+/* multiplayer_peer.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,22 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "networked_multiplayer_peer.h"
+#include "multiplayer_peer.h"
-void NetworkedMultiplayerPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &NetworkedMultiplayerPeer::set_transfer_mode);
- ClassDB::bind_method(D_METHOD("get_transfer_mode"), &NetworkedMultiplayerPeer::get_transfer_mode);
- ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &NetworkedMultiplayerPeer::set_target_peer);
+void MultiplayerPeer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &MultiplayerPeer::set_transfer_mode);
+ ClassDB::bind_method(D_METHOD("get_transfer_mode"), &MultiplayerPeer::get_transfer_mode);
+ ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer);
- ClassDB::bind_method(D_METHOD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer);
+ ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer);
- ClassDB::bind_method(D_METHOD("poll"), &NetworkedMultiplayerPeer::poll);
+ ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll);
- ClassDB::bind_method(D_METHOD("get_connection_status"), &NetworkedMultiplayerPeer::get_connection_status);
- ClassDB::bind_method(D_METHOD("get_unique_id"), &NetworkedMultiplayerPeer::get_unique_id);
+ ClassDB::bind_method(D_METHOD("get_connection_status"), &MultiplayerPeer::get_connection_status);
+ ClassDB::bind_method(D_METHOD("get_unique_id"), &MultiplayerPeer::get_unique_id);
- ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &NetworkedMultiplayerPeer::set_refuse_new_connections);
- ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &NetworkedMultiplayerPeer::is_refusing_new_connections);
+ ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections);
+ ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode");
diff --git a/core/io/networked_multiplayer_peer.h b/core/io/multiplayer_peer.h
index 7c90f97d88..432f47280f 100644
--- a/core/io/networked_multiplayer_peer.h
+++ b/core/io/multiplayer_peer.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* networked_multiplayer_peer.h */
+/* multiplayer_peer.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -33,8 +33,8 @@
#include "core/io/packet_peer.h"
-class NetworkedMultiplayerPeer : public PacketPeer {
- GDCLASS(NetworkedMultiplayerPeer, PacketPeer);
+class MultiplayerPeer : public PacketPeer {
+ GDCLASS(MultiplayerPeer, PacketPeer);
protected:
static void _bind_methods();
@@ -73,10 +73,10 @@ public:
virtual ConnectionStatus get_connection_status() const = 0;
- NetworkedMultiplayerPeer() {}
+ MultiplayerPeer() {}
};
-VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::TransferMode)
-VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::ConnectionStatus)
+VARIANT_ENUM_CAST(MultiplayerPeer::TransferMode)
+VARIANT_ENUM_CAST(MultiplayerPeer::ConnectionStatus)
#endif // NETWORKED_MULTIPLAYER_PEER_H
diff --git a/core/object/class_db.h b/core/object/class_db.h
index af528bfde7..e0cba1b8b5 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -434,4 +434,15 @@ public:
#endif
+#define GDREGISTER_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ClassDB::register_class<m_class>(); \
+ }
+#define GDREGISTER_VIRTUAL_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ClassDB::register_virtual_class<m_class>(); \
+ }
+
+#include "core/disabled_classes.gen.h"
+
#endif // CLASS_DB_H
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 1c8db89e5e..296d876701 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1769,42 +1769,41 @@ uint32_t Object::get_edited_version() const {
}
#endif
-void *Object::get_script_instance_binding(int p_script_language_index) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr);
-#endif
-
- //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync
- //just return the same pointer.
- //if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it
- //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards
-
- if (!_script_instance_bindings[p_script_language_index]) {
- void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
- if (script_data) {
- instance_binding_count.increment();
- _script_instance_bindings[p_script_language_index] = script_data;
+void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
+ void *binding = nullptr;
+ _instance_binding_mutex.lock();
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].token == p_token) {
+ binding = _instance_bindings[i].binding;
+ break;
}
}
+ if (unlikely(!binding)) {
+ uint32_t current_size = next_power_of_2(_instance_binding_count);
+ uint32_t new_size = next_power_of_2(_instance_binding_count + 1);
- return _script_instance_bindings[p_script_language_index];
-}
+ if (current_size == 0 || new_size > current_size) {
+ _instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding));
+ }
-bool Object::has_script_instance_binding(int p_script_language_index) {
- return _script_instance_bindings[p_script_language_index] != nullptr;
-}
+ _instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback;
+ _instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback;
+ _instance_bindings[_instance_binding_count].token = p_token;
-void Object::set_script_instance_binding(int p_script_language_index, void *p_data) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(_script_instance_bindings[p_script_language_index] != nullptr);
-#endif
- _script_instance_bindings[p_script_language_index] = p_data;
+ binding = p_callbacks->create_callback(p_token, this);
+ _instance_bindings[_instance_binding_count].binding = binding;
+
+ _instance_binding_count++;
+ }
+
+ _instance_binding_mutex.unlock();
+
+ return binding;
}
void Object::_construct_object(bool p_reference) {
type_is_reference = p_reference;
_instance_id = ObjectDB::add_instance(this);
- memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance);
@@ -1864,12 +1863,13 @@ Object::~Object() {
_instance_id = ObjectID();
_predelete_ok = 2;
- if (!ScriptServer::are_languages_finished()) {
- for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
- if (_script_instance_bindings[i]) {
- ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]);
+ if (_instance_bindings != nullptr) {
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].free_callback) {
+ _instance_bindings[i].free_callback(_instance_bindings[i].token, _instance_bindings[i].binding, this);
}
}
+ memfree(_instance_bindings);
}
}
@@ -1887,7 +1887,6 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
if (object_slots[i].validator) {
p_func(object_slots[i].object);
-
count--;
}
}
diff --git a/core/object/object.h b/core/object/object.h
index e6eb6d1aaf..33d9b627f6 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -60,6 +60,7 @@ enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
+ PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
@@ -480,10 +481,6 @@ public:
};
private:
- enum {
- MAX_SCRIPT_INSTANCE_BINDINGS = 8
- };
-
#ifdef DEBUG_ENABLED
friend struct _ObjectDebugLock;
#endif
@@ -542,12 +539,35 @@ private:
friend class RefCounted;
bool type_is_reference = false;
- SafeNumeric<uint32_t> instance_binding_count;
- void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
+
+ std::mutex _instance_binding_mutex;
+ struct InstanceBinding {
+ void *binding;
+ void *token;
+ GDNativeInstanceBindingFreeCallback free_callback = nullptr;
+ GDNativeInstanceBindingReferenceCallback reference_callback = nullptr;
+ };
+ InstanceBinding *_instance_bindings = nullptr;
+ uint32_t _instance_binding_count = 0;
Object(bool p_reference);
protected:
+ _FORCE_INLINE_ bool _instance_binding_reference(bool p_reference) {
+ bool can_die = true;
+ if (_instance_bindings) {
+ _instance_binding_mutex.lock();
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].reference_callback) {
+ if (!_instance_bindings[i].reference_callback(_instance_bindings[i].token, _instance_bindings[i].binding, p_reference)) {
+ can_die = false;
+ }
+ }
+ }
+ _instance_binding_mutex.unlock();
+ }
+ return can_die;
+ }
friend class NativeExtensionMethodBind;
_ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; }
_ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; }
@@ -785,9 +805,7 @@ public:
#endif
//used by script languages to store binding data
- void *get_script_instance_binding(int p_script_language_index);
- bool has_script_instance_binding(int p_script_language_index);
- void set_script_instance_binding(int p_script_language_index, void *p_data);
+ void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
void clear_internal_resource_paths();
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index 9862624972..2833f774dc 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -65,13 +65,8 @@ bool RefCounted::reference() {
if (_get_extension() && _get_extension()->reference) {
_get_extension()->reference(_get_extension_instance());
}
- if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
- for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
- if (_script_instance_bindings[i]) {
- ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
- }
- }
- }
+
+ _instance_binding_reference(true);
}
return success;
@@ -89,14 +84,8 @@ bool RefCounted::unreference() {
if (_get_extension() && _get_extension()->unreference) {
_get_extension()->unreference(_get_extension_instance());
}
- if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
- for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
- if (_script_instance_bindings[i]) {
- bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
- die = die && script_ret;
- }
- }
- }
+
+ die = die && _instance_binding_reference(false);
}
return die;
diff --git a/core/os/memory.h b/core/os/memory.h
index 10e678103d..9d09626b8c 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -80,7 +80,7 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
#define memalloc(m_size) Memory::alloc_static(m_size)
#define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size)
-#define memfree(m_size) Memory::free_static(m_size)
+#define memfree(m_mem) Memory::free_static(m_mem)
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
diff --git a/core/os/os.h b/core/os/os.h
index 444f67431f..301718a8b3 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -58,8 +58,6 @@ class OS {
int _orientation;
bool _allow_hidpi = false;
bool _allow_layered = false;
- bool _use_vsync;
- bool _vsync_via_compositor;
bool _stdout_enabled = true;
bool _stderr_enabled = true;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 1cbb0bb597..eb37267546 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -48,7 +48,7 @@
#include "core/io/json.h"
#include "core/io/marshalls.h"
#include "core/io/multiplayer_api.h"
-#include "core/io/networked_multiplayer_peer.h"
+#include "core/io/multiplayer_peer.h"
#include "core/io/packed_data_container.h"
#include "core/io/packet_peer.h"
#include "core/io/packet_peer_dtls.h"
@@ -131,50 +131,50 @@ void register_core_types() {
resource_format_image.instantiate();
ResourceLoader::add_resource_format_loader(resource_format_image);
- ClassDB::register_class<Object>();
-
- ClassDB::register_virtual_class<Script>();
-
- ClassDB::register_class<RefCounted>();
- ClassDB::register_class<WeakRef>();
- ClassDB::register_class<Resource>();
- ClassDB::register_class<Image>();
-
- ClassDB::register_virtual_class<InputEvent>();
- ClassDB::register_virtual_class<InputEventWithModifiers>();
- ClassDB::register_virtual_class<InputEventFromWindow>();
- ClassDB::register_class<InputEventKey>();
- ClassDB::register_virtual_class<InputEventMouse>();
- ClassDB::register_class<InputEventMouseButton>();
- ClassDB::register_class<InputEventMouseMotion>();
- ClassDB::register_class<InputEventJoypadButton>();
- ClassDB::register_class<InputEventJoypadMotion>();
- ClassDB::register_class<InputEventScreenDrag>();
- ClassDB::register_class<InputEventScreenTouch>();
- ClassDB::register_class<InputEventAction>();
- ClassDB::register_virtual_class<InputEventGesture>();
- ClassDB::register_class<InputEventMagnifyGesture>();
- ClassDB::register_class<InputEventPanGesture>();
- ClassDB::register_class<InputEventMIDI>();
+ GDREGISTER_CLASS(Object);
+
+ GDREGISTER_VIRTUAL_CLASS(Script);
+
+ GDREGISTER_CLASS(RefCounted);
+ GDREGISTER_CLASS(WeakRef);
+ GDREGISTER_CLASS(Resource);
+ GDREGISTER_CLASS(Image);
+
+ GDREGISTER_VIRTUAL_CLASS(InputEvent);
+ GDREGISTER_VIRTUAL_CLASS(InputEventWithModifiers);
+ GDREGISTER_VIRTUAL_CLASS(InputEventFromWindow);
+ GDREGISTER_CLASS(InputEventKey);
+ GDREGISTER_VIRTUAL_CLASS(InputEventMouse);
+ GDREGISTER_CLASS(InputEventMouseButton);
+ GDREGISTER_CLASS(InputEventMouseMotion);
+ GDREGISTER_CLASS(InputEventJoypadButton);
+ GDREGISTER_CLASS(InputEventJoypadMotion);
+ GDREGISTER_CLASS(InputEventScreenDrag);
+ GDREGISTER_CLASS(InputEventScreenTouch);
+ GDREGISTER_CLASS(InputEventAction);
+ GDREGISTER_VIRTUAL_CLASS(InputEventGesture);
+ GDREGISTER_CLASS(InputEventMagnifyGesture);
+ GDREGISTER_CLASS(InputEventPanGesture);
+ GDREGISTER_CLASS(InputEventMIDI);
// Network
- ClassDB::register_virtual_class<IP>();
+ GDREGISTER_VIRTUAL_CLASS(IP);
- ClassDB::register_virtual_class<StreamPeer>();
- ClassDB::register_class<StreamPeerBuffer>();
- ClassDB::register_class<StreamPeerTCP>();
- ClassDB::register_class<TCPServer>();
+ GDREGISTER_VIRTUAL_CLASS(StreamPeer);
+ GDREGISTER_CLASS(StreamPeerBuffer);
+ GDREGISTER_CLASS(StreamPeerTCP);
+ GDREGISTER_CLASS(TCPServer);
- ClassDB::register_virtual_class<PacketPeer>();
- ClassDB::register_class<PacketPeerStream>();
- ClassDB::register_class<PacketPeerUDP>();
- ClassDB::register_class<UDPServer>();
+ GDREGISTER_VIRTUAL_CLASS(PacketPeer);
+ GDREGISTER_CLASS(PacketPeerStream);
+ GDREGISTER_CLASS(PacketPeerUDP);
+ GDREGISTER_CLASS(UDPServer);
ClassDB::register_custom_instance_class<HTTPClient>();
// Crypto
- ClassDB::register_class<HashingContext>();
- ClassDB::register_class<AESContext>();
+ GDREGISTER_CLASS(HashingContext);
+ GDREGISTER_CLASS(AESContext);
ClassDB::register_custom_instance_class<X509Certificate>();
ClassDB::register_custom_instance_class<CryptoKey>();
ClassDB::register_custom_instance_class<HMACContext>();
@@ -188,42 +188,42 @@ void register_core_types() {
resource_format_loader_crypto.instantiate();
ResourceLoader::add_resource_format_loader(resource_format_loader_crypto);
- ClassDB::register_virtual_class<NetworkedMultiplayerPeer>();
- ClassDB::register_class<MultiplayerAPI>();
- ClassDB::register_class<MainLoop>();
- ClassDB::register_class<Translation>();
- ClassDB::register_class<OptimizedTranslation>();
- ClassDB::register_class<UndoRedo>();
- ClassDB::register_class<TriangleMesh>();
+ GDREGISTER_VIRTUAL_CLASS(MultiplayerPeer);
+ GDREGISTER_CLASS(MultiplayerAPI);
+ GDREGISTER_CLASS(MainLoop);
+ GDREGISTER_CLASS(Translation);
+ GDREGISTER_CLASS(OptimizedTranslation);
+ GDREGISTER_CLASS(UndoRedo);
+ GDREGISTER_CLASS(TriangleMesh);
- ClassDB::register_class<ResourceFormatLoader>();
- ClassDB::register_class<ResourceFormatSaver>();
+ GDREGISTER_CLASS(ResourceFormatLoader);
+ GDREGISTER_CLASS(ResourceFormatSaver);
- ClassDB::register_class<_File>();
- ClassDB::register_class<_Directory>();
- ClassDB::register_class<_Thread>();
- ClassDB::register_class<_Mutex>();
- ClassDB::register_class<_Semaphore>();
+ GDREGISTER_CLASS(_File);
+ GDREGISTER_CLASS(_Directory);
+ GDREGISTER_CLASS(_Thread);
+ GDREGISTER_CLASS(_Mutex);
+ GDREGISTER_CLASS(_Semaphore);
- ClassDB::register_class<XMLParser>();
- ClassDB::register_class<JSON>();
+ GDREGISTER_CLASS(XMLParser);
+ GDREGISTER_CLASS(JSON);
- ClassDB::register_class<ConfigFile>();
+ GDREGISTER_CLASS(ConfigFile);
- ClassDB::register_class<PCKPacker>();
+ GDREGISTER_CLASS(PCKPacker);
- ClassDB::register_class<PackedDataContainer>();
- ClassDB::register_virtual_class<PackedDataContainerRef>();
- ClassDB::register_class<AStar>();
- ClassDB::register_class<AStar2D>();
- ClassDB::register_class<EncodedObjectAsID>();
- ClassDB::register_class<RandomNumberGenerator>();
+ GDREGISTER_CLASS(PackedDataContainer);
+ GDREGISTER_VIRTUAL_CLASS(PackedDataContainerRef);
+ GDREGISTER_CLASS(AStar);
+ GDREGISTER_CLASS(AStar2D);
+ GDREGISTER_CLASS(EncodedObjectAsID);
+ GDREGISTER_CLASS(RandomNumberGenerator);
- ClassDB::register_virtual_class<ResourceImporter>();
+ GDREGISTER_VIRTUAL_CLASS(ResourceImporter);
- ClassDB::register_class<NativeExtension>();
+ GDREGISTER_CLASS(NativeExtension);
- ClassDB::register_virtual_class<NativeExtensionManager>();
+ GDREGISTER_VIRTUAL_CLASS(NativeExtensionManager);
native_extension_manager = memnew(NativeExtensionManager);
@@ -253,22 +253,22 @@ void register_core_settings() {
}
void register_core_singletons() {
- ClassDB::register_class<ProjectSettings>();
- ClassDB::register_virtual_class<IP>();
- ClassDB::register_class<_Geometry2D>();
- ClassDB::register_class<_Geometry3D>();
- ClassDB::register_class<_ResourceLoader>();
- ClassDB::register_class<_ResourceSaver>();
- ClassDB::register_class<_OS>();
- ClassDB::register_class<_Engine>();
- ClassDB::register_class<_ClassDB>();
- ClassDB::register_class<_Marshalls>();
- ClassDB::register_class<TranslationServer>();
- ClassDB::register_virtual_class<Input>();
- ClassDB::register_class<InputMap>();
- ClassDB::register_class<Expression>();
- ClassDB::register_class<_EngineDebugger>();
- ClassDB::register_class<Time>();
+ GDREGISTER_CLASS(ProjectSettings);
+ GDREGISTER_VIRTUAL_CLASS(IP);
+ GDREGISTER_CLASS(_Geometry2D);
+ GDREGISTER_CLASS(_Geometry3D);
+ GDREGISTER_CLASS(_ResourceLoader);
+ GDREGISTER_CLASS(_ResourceSaver);
+ GDREGISTER_CLASS(_OS);
+ GDREGISTER_CLASS(_Engine);
+ GDREGISTER_CLASS(_ClassDB);
+ GDREGISTER_CLASS(_Marshalls);
+ GDREGISTER_CLASS(TranslationServer);
+ GDREGISTER_VIRTUAL_CLASS(Input);
+ GDREGISTER_CLASS(InputMap);
+ GDREGISTER_CLASS(Expression);
+ GDREGISTER_CLASS(_EngineDebugger);
+ GDREGISTER_CLASS(Time);
Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton(), "IP"));
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 16ecd2b985..4cd2915ffa 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -3397,17 +3397,10 @@ String String::format(const Variant &values, String placeholder) const {
if (value_arr.size() == 2) {
Variant v_key = value_arr[0];
String key = v_key;
- if (key.left(1) == "\"" && key.right(1) == "\"") {
- key = key.substr(1, key.length() - 2);
- }
Variant v_val = value_arr[1];
String val = v_val;
- if (val.left(1) == "\"" && val.right(1) == "\"") {
- val = val.substr(1, val.length() - 2);
- }
-
new_string = new_string.replace(placeholder.replace("_", key), val);
} else {
ERR_PRINT(String("STRING.format Inner Array size != 2 ").ascii().get_data());
@@ -3416,10 +3409,6 @@ String String::format(const Variant &values, String placeholder) const {
Variant v_val = values_arr[i];
String val = v_val;
- if (val.left(1) == "\"" && val.right(1) == "\"") {
- val = val.substr(1, val.length() - 2);
- }
-
if (placeholder.find("_") > -1) {
new_string = new_string.replace(placeholder.replace("_", i_as_str), val);
} else {
@@ -3436,14 +3425,6 @@ String String::format(const Variant &values, String placeholder) const {
String key = E->get();
String val = d[E->get()];
- if (key.left(1) == "\"" && key.right(1) == "\"") {
- key = key.substr(1, key.length() - 2);
- }
-
- if (val.left(1) == "\"" && val.right(1) == "\"") {
- val = val.substr(1, val.length() - 2);
- }
-
new_string = new_string.replace(placeholder.replace("_", key), val);
}
} else {
diff --git a/core/templates/list.h b/core/templates/list.h
index 010e35eed8..6047b89670 100644
--- a/core/templates/list.h
+++ b/core/templates/list.h
@@ -135,6 +135,83 @@ public:
_FORCE_INLINE_ Element() {}
};
+ typedef T ValueType;
+
+ struct Iterator {
+ _FORCE_INLINE_ T &operator*() const {
+ return E->get();
+ }
+ _FORCE_INLINE_ T *operator->() const { return &E->get(); }
+ _FORCE_INLINE_ Iterator &operator++() {
+ E = E->next();
+ return *this;
+ }
+ _FORCE_INLINE_ Iterator &operator--() {
+ E = E->prev();
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+ Iterator(Element *p_E) { E = p_E; }
+ Iterator() {}
+ Iterator(const Iterator &p_it) { E = p_it.E; }
+
+ private:
+ Element *E = nullptr;
+ };
+
+ struct ConstIterator {
+ _FORCE_INLINE_ const T &operator*() const {
+ return E->get();
+ }
+ _FORCE_INLINE_ const T *operator->() const { return &E->get(); }
+ _FORCE_INLINE_ ConstIterator &operator++() {
+ E = E->next();
+ return *this;
+ }
+ _FORCE_INLINE_ ConstIterator &operator--() {
+ E = E->prev();
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+ _FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
+ _FORCE_INLINE_ ConstIterator() {}
+ _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+
+ private:
+ const Element *E = nullptr;
+ };
+
+ _FORCE_INLINE_ Iterator begin() {
+ return Iterator(front());
+ }
+ _FORCE_INLINE_ Iterator end() {
+ return Iterator(nullptr);
+ }
+
+#if 0
+ //to use when replacing find()
+ _FORCE_INLINE_ Iterator find(const K &p_key) {
+ return Iterator(find(p_key));
+ }
+#endif
+ _FORCE_INLINE_ ConstIterator begin() const {
+ return ConstIterator(front());
+ }
+ _FORCE_INLINE_ ConstIterator end() const {
+ return ConstIterator(nullptr);
+ }
+#if 0
+ //to use when replacing find()
+ _FORCE_INLINE_ ConstIterator find(const K &p_key) const {
+ return ConstIterator(find(p_key));
+ }
+#endif
private:
struct _Data {
Element *first = nullptr;
diff --git a/core/templates/map.h b/core/templates/map.h
index 7dfee13d2c..a47547d355 100644
--- a/core/templates/map.h
+++ b/core/templates/map.h
@@ -33,6 +33,7 @@
#include "core/error/error_macros.h"
#include "core/os/memory.h"
+#include "core/templates/pair.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
@@ -55,11 +56,12 @@ public:
Element *parent = nullptr;
Element *_next = nullptr;
Element *_prev = nullptr;
- K _key;
- V _value;
- //_Data *data;
+ KeyValue<K, V> _data;
public:
+ KeyValue<K, V> &key_value() { return _data; }
+ const KeyValue<K, V> &key_value() const { return _data; }
+
const Element *next() const {
return _next;
}
@@ -73,23 +75,106 @@ public:
return _prev;
}
const K &key() const {
- return _key;
+ return _data.key;
}
V &value() {
- return _value;
+ return _data.value;
}
const V &value() const {
- return _value;
+ return _data.value;
}
V &get() {
- return _value;
+ return _data.value;
}
const V &get() const {
- return _value;
+ return _data.value;
}
- Element() {}
+ Element(const KeyValue<K, V> &p_data) :
+ _data(p_data) {}
};
+ typedef KeyValue<K, V> ValueType;
+
+ struct Iterator {
+ _FORCE_INLINE_ KeyValue<K, V> &operator*() const {
+ return E->key_value();
+ }
+ _FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); }
+ _FORCE_INLINE_ Iterator &operator++() {
+ E = E->next();
+ return *this;
+ }
+ _FORCE_INLINE_ Iterator &operator--() {
+ E = E->prev();
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+ Iterator(Element *p_E) { E = p_E; }
+ Iterator() {}
+ Iterator(const Iterator &p_it) { E = p_it.E; }
+
+ private:
+ Element *E = nullptr;
+ };
+
+ struct ConstIterator {
+ _FORCE_INLINE_ const KeyValue<K, V> &operator*() const {
+ return E->key_value();
+ }
+ _FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); }
+ _FORCE_INLINE_ ConstIterator &operator++() {
+ E = E->next();
+ return *this;
+ }
+ _FORCE_INLINE_ ConstIterator &operator--() {
+ E = E->prev();
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
+ _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
+
+ ConstIterator(const Element *p_E) { E = p_E; }
+ ConstIterator() {}
+ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+
+ private:
+ const Element *E = nullptr;
+ };
+
+ _FORCE_INLINE_ Iterator begin() {
+ return Iterator(front());
+ }
+ _FORCE_INLINE_ Iterator end() {
+ return Iterator(nullptr);
+ }
+
+#if 0
+ //to use when replacing find()
+ _FORCE_INLINE_ Iterator find(const K &p_key) {
+ return Iterator(find(p_key));
+ }
+#endif
+ _FORCE_INLINE_ void remove(const Iterator &p_iter) {
+ return erase(p_iter.E);
+ }
+
+ _FORCE_INLINE_ ConstIterator begin() const {
+ return ConstIterator(front());
+ }
+ _FORCE_INLINE_ ConstIterator end() const {
+ return ConstIterator(nullptr);
+ }
+
+#if 0
+ //to use when replacing find()
+ _FORCE_INLINE_ ConstIterator find(const K &p_key) const {
+ return ConstIterator(find(p_key));
+ }
+#endif
private:
struct _Data {
Element *_root = nullptr;
@@ -107,7 +192,7 @@ private:
}
void _create_root() {
- _root = memnew_allocator(Element, A);
+ _root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A);
_root->parent = _root->left = _root->right = _nil;
_root->color = BLACK;
}
@@ -216,9 +301,9 @@ private:
C less;
while (node != _data._nil) {
- if (less(p_key, node->_key)) {
+ if (less(p_key, node->_data.key)) {
node = node->left;
- } else if (less(node->_key, p_key)) {
+ } else if (less(node->_data.key, p_key)) {
node = node->right;
} else {
return node; // found
@@ -236,9 +321,9 @@ private:
while (node != _data._nil) {
prev = node;
- if (less(p_key, node->_key)) {
+ if (less(p_key, node->_data.key)) {
node = node->left;
- } else if (less(node->_key, p_key)) {
+ } else if (less(node->_data.key, p_key)) {
node = node->right;
} else {
return node; // found
@@ -249,7 +334,7 @@ private:
return nullptr; // tree empty
}
- if (less(p_key, prev->_key)) {
+ if (less(p_key, prev->_data.key)) {
prev = prev->_prev;
}
@@ -312,25 +397,25 @@ private:
while (node != _data._nil) {
new_parent = node;
- if (less(p_key, node->_key)) {
+ if (less(p_key, node->_data.key)) {
node = node->left;
- } else if (less(node->_key, p_key)) {
+ } else if (less(node->_data.key, p_key)) {
node = node->right;
} else {
- node->_value = p_value;
+ node->_data.value = p_value;
return node; // Return existing node with new value
}
}
- Element *new_node = memnew_allocator(Element, A);
+ typedef KeyValue<K, V> KV;
+ Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A);
new_node->parent = new_parent;
new_node->right = _data._nil;
new_node->left = _data._nil;
- new_node->_key = p_key;
- new_node->_value = p_value;
+
//new_node->data=_data;
- if (new_parent == _data._root || less(p_key, new_parent->_key)) {
+ if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
new_parent->left = new_node;
} else {
new_parent->right = new_node;
@@ -575,7 +660,7 @@ public:
CRASH_COND(!_data._root);
const Element *e = find(p_key);
CRASH_COND(!e);
- return e->_value;
+ return e->_data.value;
}
V &operator[](const K &p_key) {
@@ -588,7 +673,7 @@ public:
e = insert(p_key, V());
}
- return e->_value;
+ return e->_data.value;
}
Element *front() const {
diff --git a/core/templates/pair.h b/core/templates/pair.h
index bc1a764694..31706b6ecb 100644
--- a/core/templates/pair.h
+++ b/core/templates/pair.h
@@ -31,6 +31,8 @@
#ifndef PAIR_H
#define PAIR_H
+#include "core/typedefs.h"
+
template <class F, class S>
struct Pair {
F first;
@@ -64,4 +66,37 @@ struct PairSort {
}
};
+template <class K, class V>
+struct KeyValue {
+ const K key;
+ V value;
+
+ void operator=(const KeyValue &p_kv) = delete;
+ _FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
+ key(p_kv.key),
+ value(p_kv.value) {
+ }
+ _FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
+ key(p_key),
+ value(p_value) {
+ }
+};
+
+template <class K, class V>
+bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
+ return (pair.key == other.key) && (pair.value == other.value);
+}
+
+template <class K, class V>
+bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
+ return (pair.key != other.key) || (pair.value != other.value);
+}
+
+template <class K, class V>
+struct KeyValueSort {
+ bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
+ return A.key < B.key;
+ }
+};
+
#endif // PAIR_H
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index e4964f744e..4f5c74ca46 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -193,7 +193,7 @@ public:
if (THREAD_SAFE) {
spin_lock.unlock();
}
- if (validator_chunks[idx_chunk][idx_element] & 0x80000000) {
+ if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) {
ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
}
return nullptr;
diff --git a/core/templates/set.h b/core/templates/set.h
index 3036ecf27d..245c174862 100644
--- a/core/templates/set.h
+++ b/core/templates/set.h
@@ -77,6 +77,85 @@ public:
Element() {}
};
+ typedef T ValueType;
+
+ struct Iterator {
+ _FORCE_INLINE_ T &operator*() const {
+ return E->get();
+ }
+ _FORCE_INLINE_ T *operator->() const { return &E->get(); }
+ _FORCE_INLINE_ Iterator &operator++() {
+ E = E->next();
+ return *this;
+ }
+ _FORCE_INLINE_ Iterator &operator--() {
+ E = E->prev();
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+ Iterator(Element *p_E) { E = p_E; }
+ Iterator() {}
+ Iterator(const Iterator &p_it) { E = p_it.E; }
+
+ private:
+ Element *E = nullptr;
+ };
+
+ struct ConstIterator {
+ _FORCE_INLINE_ const T &operator*() const {
+ return E->get();
+ }
+ _FORCE_INLINE_ const T *operator->() const { return &E->get(); }
+ _FORCE_INLINE_ ConstIterator &operator++() {
+ E = E->next();
+ return *this;
+ }
+ _FORCE_INLINE_ ConstIterator &operator--() {
+ E = E->prev();
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+ _FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
+ _FORCE_INLINE_ ConstIterator() {}
+ _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+
+ private:
+ const Element *E = nullptr;
+ };
+
+ _FORCE_INLINE_ Iterator begin() {
+ return Iterator(front());
+ }
+ _FORCE_INLINE_ Iterator end() {
+ return Iterator(nullptr);
+ }
+
+#if 0
+ //to use when replacing find()
+ _FORCE_INLINE_ Iterator find(const K &p_key) {
+ return Iterator(find(p_key));
+ }
+#endif
+
+ _FORCE_INLINE_ ConstIterator begin() const {
+ return ConstIterator(front());
+ }
+ _FORCE_INLINE_ ConstIterator end() const {
+ return ConstIterator(nullptr);
+ }
+
+#if 0
+ //to use when replacing find()
+ _FORCE_INLINE_ ConstIterator find(const K &p_key) const {
+ return ConstIterator(find(p_key));
+ }
+#endif
private:
struct _Data {
Element *_root = nullptr;
diff --git a/core/templates/vector.h b/core/templates/vector.h
index dae8874a87..08cbef6ba4 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -187,6 +187,70 @@ public:
return false;
}
+ struct Iterator {
+ _FORCE_INLINE_ T &operator*() const {
+ return *elem_ptr;
+ }
+ _FORCE_INLINE_ T *operator->() const { return elem_ptr; }
+ _FORCE_INLINE_ Iterator &operator++() {
+ elem_ptr++;
+ return *this;
+ }
+ _FORCE_INLINE_ Iterator &operator--() {
+ elem_ptr--;
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
+
+ Iterator(T *p_ptr) { elem_ptr = p_ptr; }
+ Iterator() {}
+ Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
+
+ private:
+ T *elem_ptr = nullptr;
+ };
+
+ struct ConstIterator {
+ _FORCE_INLINE_ const T &operator*() const {
+ return *elem_ptr;
+ }
+ _FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
+ _FORCE_INLINE_ ConstIterator &operator++() {
+ elem_ptr++;
+ return *this;
+ }
+ _FORCE_INLINE_ ConstIterator &operator--() {
+ elem_ptr--;
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
+ _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
+
+ ConstIterator(T *p_ptr) { elem_ptr = p_ptr; }
+ ConstIterator() {}
+ ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
+
+ private:
+ const T *elem_ptr = nullptr;
+ };
+
+ _FORCE_INLINE_ Iterator begin() {
+ return Iterator(ptrw());
+ }
+ _FORCE_INLINE_ Iterator end() {
+ return Iterator(ptrw() + size());
+ }
+
+ _FORCE_INLINE_ ConstIterator begin() const {
+ return ConstIterator(ptr());
+ }
+ _FORCE_INLINE_ ConstIterator end() const {
+ return ConstIterator(ptr() + size());
+ }
+
_FORCE_INLINE_ Vector() {}
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
diff --git a/core/typedefs.h b/core/typedefs.h
index cdbfb34e56..dde254af23 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -281,4 +281,11 @@ struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
#define DEBUG_METHODS_ENABLED
#endif
+// Macro GD_IS_DEFINED() allows to check if a macro is defined. It needs to be defined to anything (say 1) to work.
+#define __GDARG_PLACEHOLDER_1 0,
+#define __gd_take_second_arg(__ignored, val, ...) val
+#define ____gd_is_defined(arg1_or_junk) __gd_take_second_arg(arg1_or_junk 1, 0)
+#define ___gd_is_defined(val) ____gd_is_defined(__GDARG_PLACEHOLDER_##val)
+#define GD_IS_DEFINED(x) ___gd_is_defined(x)
+
#endif // TYPEDEFS_H
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index e744e76ea3..cbdd60f404 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -1261,8 +1261,10 @@ public:
const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
- b->get(a, &r_valid);
- *r_ret = r_valid;
+ bool exist;
+ b->get(a, &exist);
+ *r_ret = exist;
+ r_valid = true;
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
Object *l = right->get_validated_object();
@@ -1293,8 +1295,10 @@ public:
const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left);
- b->get(a, &r_valid);
- *r_ret = r_valid;
+ bool exist;
+ b->get(a, &exist);
+ *r_ret = exist;
+ r_valid = true;
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
Object *l = right->get_validated_object();
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index e61ce1eeaa..86d5ae7f38 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1204,16 +1204,32 @@ Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, Strin
r_tag.name = "";
r_tag.fields.clear();
- while (true) {
- char32_t c = p_stream->get_char();
- if (p_stream->is_eof()) {
- r_err_str = "Unexpected EOF while parsing simple tag";
- return ERR_PARSE_ERROR;
+ if (p_stream->is_utf8()) {
+ CharString cs;
+ while (true) {
+ char c = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected EOF while parsing simple tag";
+ return ERR_PARSE_ERROR;
+ }
+ if (c == ']') {
+ break;
+ }
+ cs += c;
}
- if (c == ']') {
- break;
+ r_tag.name.parse_utf8(cs.get_data(), cs.length());
+ } else {
+ while (true) {
+ char32_t c = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_err_str = "Unexpected EOF while parsing simple tag";
+ return ERR_PARSE_ERROR;
+ }
+ if (c == ']') {
+ break;
+ }
+ r_tag.name += String::chr(c);
}
- r_tag.name += String::chr(c);
}
r_tag.name = r_tag.name.strip_edges();