summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub14
-rw-r--r--core/config/project_settings.cpp9
-rw-r--r--core/core_bind.cpp91
-rw-r--r--core/core_bind.h19
-rw-r--r--core/core_builders.py12
-rw-r--r--core/core_string_names.cpp7
-rw-r--r--core/core_string_names.h5
-rw-r--r--core/crypto/crypto.cpp18
-rw-r--r--core/crypto/crypto.h20
-rw-r--r--core/extension/SCsub2
-rw-r--r--core/extension/gdextension.compat.inc49
-rw-r--r--core/extension/gdextension.cpp2
-rw-r--r--core/extension/gdextension.h9
-rw-r--r--core/extension/gdextension_interface.cpp26
-rw-r--r--core/extension/gdextension_interface.h61
-rw-r--r--core/extension/make_wrappers.py2
-rw-r--r--core/input/SCsub1
-rw-r--r--core/input/input.cpp11
-rw-r--r--core/input/input.h3
-rw-r--r--core/input/input_event.cpp12
-rw-r--r--core/input/input_event.h4
-rw-r--r--core/input/input_map.cpp7
-rw-r--r--core/io/dir_access.cpp2
-rw-r--r--core/io/image.cpp6
-rw-r--r--core/io/image.h2
-rw-r--r--core/io/marshalls.cpp1
-rw-r--r--core/io/packed_data_container.cpp1
-rw-r--r--core/io/resource.cpp33
-rw-r--r--core/io/resource_format_binary.cpp68
-rw-r--r--core/io/resource_importer.cpp15
-rw-r--r--core/io/resource_loader.cpp145
-rw-r--r--core/io/resource_loader.h8
-rw-r--r--core/math/aabb.h2
-rw-r--r--core/math/basis.h2
-rw-r--r--core/math/color.cpp25
-rw-r--r--core/math/color.h2
-rw-r--r--core/math/color_names.inc1
-rw-r--r--core/math/face3.h2
-rw-r--r--core/math/geometry_2d.h2
-rw-r--r--core/math/plane.h2
-rw-r--r--core/math/projection.h2
-rw-r--r--core/math/quaternion.h2
-rw-r--r--core/math/rect2.h2
-rw-r--r--core/math/rect2i.h2
-rw-r--r--core/math/transform_2d.h2
-rw-r--r--core/math/transform_3d.h2
-rw-r--r--core/math/vector2.h2
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3.h2
-rw-r--r--core/math/vector3i.h2
-rw-r--r--core/math/vector4.h2
-rw-r--r--core/math/vector4i.h2
-rw-r--r--core/object/class_db.cpp9
-rw-r--r--core/object/message_queue.cpp7
-rw-r--r--core/object/message_queue.h1
-rw-r--r--core/object/object.cpp43
-rw-r--r--core/object/script_language.cpp9
-rw-r--r--core/object/script_language_extension.cpp1
-rw-r--r--core/object/script_language_extension.h2
-rw-r--r--core/object/worker_thread_pool.cpp3
-rw-r--r--core/os/midi_driver.cpp199
-rw-r--r--core/os/midi_driver.h68
-rw-r--r--core/os/os.cpp9
-rw-r--r--core/register_core_types.cpp3
-rw-r--r--core/string/translation.cpp8
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/translation_po.cpp90
-rw-r--r--core/string/translation_po.h14
-rw-r--r--core/typedefs.h7
-rw-r--r--core/variant/callable.cpp2
-rw-r--r--core/variant/typed_array.h22
-rw-r--r--core/variant/variant.cpp1
-rw-r--r--core/variant/variant.h9
-rw-r--r--core/variant/variant_call.cpp18
-rw-r--r--core/variant/variant_construct.h1
-rw-r--r--core/variant/variant_op.h1
-rw-r--r--core/variant/variant_setget.h1
-rw-r--r--core/variant/variant_utility.cpp1
78 files changed, 896 insertions, 362 deletions
diff --git a/core/SCsub b/core/SCsub
index a61c0b5fc2..1bd4eae16c 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -2,9 +2,11 @@
Import("env")
+import os
+
import core_builders
+
import methods
-import os
env.core_sources = []
@@ -188,13 +190,11 @@ def version_info_builder(target, source, env):
#define VERSION_WEBSITE "{website}"
#define VERSION_DOCS_BRANCH "{docs_branch}"
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
-""".format(
- **env.version_info
- )
+""".format(**env.version_info)
)
-env.CommandNoCache("version_generated.gen.h", "#version.py", env.Run(version_info_builder))
+env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder))
# Generate version hash
@@ -206,9 +206,7 @@ def version_hash_builder(target, source, env):
const char *const VERSION_HASH = "{git_hash}";
const uint64_t VERSION_TIMESTAMP = {git_timestamp};
-""".format(
- **env.version_info
- )
+""".format(**env.version_info)
)
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index a116c9c270..768540a0fa 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -31,7 +31,6 @@
#include "project_settings.h"
#include "core/core_bind.h" // For Compression enum.
-#include "core/core_string_names.h"
#include "core/input/input_map.h"
#include "core/io/config_file.h"
#include "core/io/dir_access.h"
@@ -1481,6 +1480,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"), "res://default_bus_layout.tres");
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/default_playback_type", PROPERTY_HINT_ENUM, "Stream,Sample"), 0);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/default_playback_type.web", PROPERTY_HINT_ENUM, "Stream,Sample"), 1);
GLOBAL_DEF_RST("audio/general/text_to_speech", false);
GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f);
GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f);
@@ -1557,7 +1558,11 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", 512);
custom_prop_info["rendering/rendering_device/d3d12/max_misc_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", PROPERTY_HINT_RANGE, "32,4096");
- GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version"), 610);
+ // The default value must match the minor part of the Agility SDK version
+ // installed by the scripts provided in the repository
+ // (check `misc/scripts/install_d3d12_sdk_windows.py`).
+ // For example, if the script installs 1.613.3, the default value must be 613.
+ GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version"), 613);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 0996db9d89..a1b7b81111 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
#include "core/debugger/engine_debugger.h"
+#include "core/debugger/script_debugger.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/marshalls.h"
@@ -193,6 +194,18 @@ void ResourceSaver::_bind_methods() {
////// OS //////
+PackedByteArray OS::get_entropy(int p_bytes) {
+ PackedByteArray pba;
+ pba.resize(p_bytes);
+ Error err = ::OS::get_singleton()->get_entropy(pba.ptrw(), p_bytes);
+ ERR_FAIL_COND_V(err != OK, PackedByteArray());
+ return pba;
+}
+
+String OS::get_system_ca_certificates() {
+ return ::OS::get_singleton()->get_system_ca_certificates();
+}
+
PackedStringArray OS::get_connected_midi_inputs() {
return ::OS::get_singleton()->get_connected_midi_inputs();
}
@@ -572,6 +585,8 @@ String OS::get_unique_id() const {
OS *OS::singleton = nullptr;
void OS::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_entropy", "size"), &OS::get_entropy);
+ ClassDB::bind_method(D_METHOD("get_system_ca_certificates"), &OS::get_system_ca_certificates);
ClassDB::bind_method(D_METHOD("get_connected_midi_inputs"), &OS::get_connected_midi_inputs);
ClassDB::bind_method(D_METHOD("open_midi_inputs"), &OS::open_midi_inputs);
ClassDB::bind_method(D_METHOD("close_midi_inputs"), &OS::close_midi_inputs);
@@ -1919,6 +1934,16 @@ void EngineDebugger::send_message(const String &p_msg, const Array &p_data) {
::EngineDebugger::get_singleton()->send_message(p_msg, p_data);
}
+void EngineDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::is_active(), "Can't send debug. No active debugger");
+ ::EngineDebugger::get_singleton()->debug(p_can_continue, p_is_error_breakpoint);
+}
+
+void EngineDebugger::script_debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::get_script_debugger(), "Can't send debug. No active debugger");
+ ::EngineDebugger::get_script_debugger()->debug(p_lang, p_can_continue, p_is_error_breakpoint);
+}
+
Error EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
Callable &capture = *(Callable *)p_user;
if (!capture.is_valid()) {
@@ -1935,6 +1960,56 @@ Error EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Arra
return OK;
}
+void EngineDebugger::line_poll() {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::is_active(), "Can't poll. No active debugger");
+ ::EngineDebugger::get_singleton()->line_poll();
+}
+
+void EngineDebugger::set_lines_left(int p_lines) {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::get_script_debugger(), "Can't set lines left. No active debugger");
+ ::EngineDebugger::get_script_debugger()->set_lines_left(p_lines);
+}
+
+int EngineDebugger::get_lines_left() const {
+ ERR_FAIL_COND_V_MSG(!::EngineDebugger::get_script_debugger(), 0, "Can't get lines left. No active debugger");
+ return ::EngineDebugger::get_script_debugger()->get_lines_left();
+}
+
+void EngineDebugger::set_depth(int p_depth) {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::get_script_debugger(), "Can't set depth. No active debugger");
+ ::EngineDebugger::get_script_debugger()->set_depth(p_depth);
+}
+
+int EngineDebugger::get_depth() const {
+ ERR_FAIL_COND_V_MSG(!::EngineDebugger::get_script_debugger(), 0, "Can't get depth. No active debugger");
+ return ::EngineDebugger::get_script_debugger()->get_depth();
+}
+
+bool EngineDebugger::is_breakpoint(int p_line, const StringName &p_source) const {
+ ERR_FAIL_COND_V_MSG(!::EngineDebugger::get_script_debugger(), false, "Can't check breakpoint. No active debugger");
+ return ::EngineDebugger::get_script_debugger()->is_breakpoint(p_line, p_source);
+}
+
+bool EngineDebugger::is_skipping_breakpoints() const {
+ ERR_FAIL_COND_V_MSG(!::EngineDebugger::get_script_debugger(), false, "Can't check skipping breakpoint. No active debugger");
+ return ::EngineDebugger::get_script_debugger()->is_skipping_breakpoints();
+}
+
+void EngineDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::get_script_debugger(), "Can't insert breakpoint. No active debugger");
+ ::EngineDebugger::get_script_debugger()->insert_breakpoint(p_line, p_source);
+}
+
+void EngineDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::get_script_debugger(), "Can't remove breakpoint. No active debugger");
+ ::EngineDebugger::get_script_debugger()->remove_breakpoint(p_line, p_source);
+}
+
+void EngineDebugger::clear_breakpoints() {
+ ERR_FAIL_COND_MSG(!::EngineDebugger::get_script_debugger(), "Can't clear breakpoints. No active debugger");
+ ::EngineDebugger::get_script_debugger()->clear_breakpoints();
+}
+
EngineDebugger::~EngineDebugger() {
for (const KeyValue<StringName, Callable> &E : captures) {
::EngineDebugger::unregister_message_capture(E.key);
@@ -1960,7 +2035,23 @@ void EngineDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &EngineDebugger::unregister_message_capture);
ClassDB::bind_method(D_METHOD("has_capture", "name"), &EngineDebugger::has_capture);
+ ClassDB::bind_method(D_METHOD("line_poll"), &EngineDebugger::line_poll);
+
ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &EngineDebugger::send_message);
+ ClassDB::bind_method(D_METHOD("debug", "can_continue", "is_error_breakpoint"), &EngineDebugger::debug, DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("script_debug", "language", "can_continue", "is_error_breakpoint"), &EngineDebugger::script_debug, DEFVAL(true), DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("set_lines_left", "lines"), &EngineDebugger::set_lines_left);
+ ClassDB::bind_method(D_METHOD("get_lines_left"), &EngineDebugger::get_lines_left);
+
+ ClassDB::bind_method(D_METHOD("set_depth", "depth"), &EngineDebugger::set_depth);
+ ClassDB::bind_method(D_METHOD("get_depth"), &EngineDebugger::get_depth);
+
+ ClassDB::bind_method(D_METHOD("is_breakpoint", "line", "source"), &EngineDebugger::is_breakpoint);
+ ClassDB::bind_method(D_METHOD("is_skipping_breakpoints"), &EngineDebugger::is_skipping_breakpoints);
+ ClassDB::bind_method(D_METHOD("insert_breakpoint", "line", "source"), &EngineDebugger::insert_breakpoint);
+ ClassDB::bind_method(D_METHOD("remove_breakpoint", "line", "source"), &EngineDebugger::remove_breakpoint);
+ ClassDB::bind_method(D_METHOD("clear_breakpoints"), &EngineDebugger::clear_breakpoints);
}
} // namespace core_bind
diff --git a/core/core_bind.h b/core/core_bind.h
index 148e0ad83e..b142a2fbbd 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -134,6 +134,9 @@ public:
RENDERING_DRIVER_D3D12,
};
+ PackedByteArray get_entropy(int p_bytes);
+ String get_system_ca_certificates();
+
virtual PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs();
virtual void close_midi_inputs();
@@ -576,9 +579,25 @@ public:
bool has_capture(const StringName &p_name);
void send_message(const String &p_msg, const Array &p_data);
+ void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false);
+ void script_debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
+ void line_poll();
+
+ void set_lines_left(int p_lines);
+ int get_lines_left() const;
+
+ void set_depth(int p_depth);
+ int get_depth() const;
+
+ bool is_breakpoint(int p_line, const StringName &p_source) const;
+ bool is_skipping_breakpoints() const;
+ void insert_breakpoint(int p_line, const StringName &p_source);
+ void remove_breakpoint(int p_line, const StringName &p_source);
+ void clear_breakpoints();
+
EngineDebugger() { singleton = this; }
~EngineDebugger();
};
diff --git a/core/core_builders.py b/core/core_builders.py
index a401f03693..a3dc935b79 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -180,7 +180,7 @@ def make_license_header(target, source, env):
return line
def next_tag(self):
- if not ":" in self.current:
+ if ":" not in self.current:
return ("", [])
tag, line = self.current.split(":", 1)
lines = [line.strip()]
@@ -206,7 +206,7 @@ def make_license_header(target, source, env):
if not tag or not reader.current:
# end of a paragraph start a new part
- if "License" in part and not "Files" in part:
+ if "License" in part and "Files" not in part:
# no Files tag in this one, so assume standalone license
license_list.append(part["License"])
part = {}
@@ -298,13 +298,13 @@ def make_license_header(target, source, env):
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
f.write("const char *const LICENSE_NAMES[] = {\n")
- for l in license_list:
- f.write('\t"' + escape_string(l[0]) + '",\n')
+ for license in license_list:
+ f.write('\t"' + escape_string(license[0]) + '",\n')
f.write("};\n\n")
f.write("const char *const LICENSE_BODIES[] = {\n\n")
- for l in license_list:
- for line in l[1:]:
+ for license in license_list:
+ for line in license[1:]:
if line == ".":
f.write('\t"\\n"\n')
else:
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 1ffe76495d..9bf625cc15 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -42,10 +42,8 @@ CoreStringNames::CoreStringNames() :
_iter_get(StaticCString::create("_iter_get")),
get_rid(StaticCString::create("get_rid")),
_to_string(StaticCString::create("_to_string")),
-#ifdef TOOLS_ENABLED
- _sections_unfolded(StaticCString::create("_sections_unfolded")),
-#endif
_custom_features(StaticCString::create("_custom_features")),
+
x(StaticCString::create("x")),
y(StaticCString::create("y")),
z(StaticCString::create("z")),
@@ -68,11 +66,10 @@ CoreStringNames::CoreStringNames() :
g8(StaticCString::create("g8")),
b8(StaticCString::create("b8")),
a8(StaticCString::create("a8")),
+
call(StaticCString::create("call")),
call_deferred(StaticCString::create("call_deferred")),
bind(StaticCString::create("bind")),
- unbind(StaticCString::create("unbind")),
- emit(StaticCString::create("emit")),
notification(StaticCString::create("notification")),
property_list_changed(StaticCString::create("property_list_changed")) {
}
diff --git a/core/core_string_names.h b/core/core_string_names.h
index d7ddc39f5e..d4ba9110c3 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -59,9 +59,6 @@ public:
StringName _iter_get;
StringName get_rid;
StringName _to_string;
-#ifdef TOOLS_ENABLED
- StringName _sections_unfolded;
-#endif
StringName _custom_features;
StringName x;
@@ -90,8 +87,6 @@ public:
StringName call;
StringName call_deferred;
StringName bind;
- StringName unbind;
- StringName emit;
StringName notification;
StringName property_list_changed;
};
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 7fef819159..d3d0079410 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -72,31 +72,26 @@ void X509Certificate::_bind_methods() {
Ref<TLSOptions> TLSOptions::client(Ref<X509Certificate> p_trusted_chain, const String &p_common_name_override) {
Ref<TLSOptions> opts;
opts.instantiate();
+ opts->mode = MODE_CLIENT;
opts->trusted_ca_chain = p_trusted_chain;
opts->common_name = p_common_name_override;
- opts->verify_mode = TLS_VERIFY_FULL;
return opts;
}
Ref<TLSOptions> TLSOptions::client_unsafe(Ref<X509Certificate> p_trusted_chain) {
Ref<TLSOptions> opts;
opts.instantiate();
+ opts->mode = MODE_CLIENT_UNSAFE;
opts->trusted_ca_chain = p_trusted_chain;
- if (p_trusted_chain.is_null()) {
- opts->verify_mode = TLS_VERIFY_NONE;
- } else {
- opts->verify_mode = TLS_VERIFY_CERT;
- }
return opts;
}
Ref<TLSOptions> TLSOptions::server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate) {
Ref<TLSOptions> opts;
opts.instantiate();
- opts->server_mode = true;
+ opts->mode = MODE_SERVER;
opts->own_certificate = p_own_certificate;
opts->private_key = p_own_key;
- opts->verify_mode = TLS_VERIFY_NONE;
return opts;
}
@@ -104,6 +99,13 @@ void TLSOptions::_bind_methods() {
ClassDB::bind_static_method("TLSOptions", D_METHOD("client", "trusted_chain", "common_name_override"), &TLSOptions::client, DEFVAL(Ref<X509Certificate>()), DEFVAL(String()));
ClassDB::bind_static_method("TLSOptions", D_METHOD("client_unsafe", "trusted_chain"), &TLSOptions::client_unsafe, DEFVAL(Ref<X509Certificate>()));
ClassDB::bind_static_method("TLSOptions", D_METHOD("server", "key", "certificate"), &TLSOptions::server);
+
+ ClassDB::bind_method(D_METHOD("is_server"), &TLSOptions::is_server);
+ ClassDB::bind_method(D_METHOD("is_unsafe_client"), &TLSOptions::is_unsafe_client);
+ ClassDB::bind_method(D_METHOD("get_common_name_override"), &TLSOptions::get_common_name_override);
+ ClassDB::bind_method(D_METHOD("get_trusted_ca_chain"), &TLSOptions::get_trusted_ca_chain);
+ ClassDB::bind_method(D_METHOD("get_private_key"), &TLSOptions::get_private_key);
+ ClassDB::bind_method(D_METHOD("get_own_certificate"), &TLSOptions::get_own_certificate);
}
/// HMACContext
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index fbd01be86d..16649422cf 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -72,17 +72,15 @@ public:
class TLSOptions : public RefCounted {
GDCLASS(TLSOptions, RefCounted);
-public:
- enum TLSVerifyMode {
- TLS_VERIFY_NONE = 0,
- TLS_VERIFY_CERT = 1,
- TLS_VERIFY_FULL = 2,
+private:
+ enum Mode {
+ MODE_CLIENT = 0,
+ MODE_CLIENT_UNSAFE = 1,
+ MODE_SERVER = 2,
};
-private:
- bool server_mode = false;
+ Mode mode = MODE_CLIENT;
String common_name;
- TLSVerifyMode verify_mode = TLS_VERIFY_FULL;
Ref<X509Certificate> trusted_ca_chain;
Ref<X509Certificate> own_certificate;
Ref<CryptoKey> private_key;
@@ -95,12 +93,12 @@ public:
static Ref<TLSOptions> client_unsafe(Ref<X509Certificate> p_trusted_chain);
static Ref<TLSOptions> server(Ref<CryptoKey> p_own_key, Ref<X509Certificate> p_own_certificate);
- TLSVerifyMode get_verify_mode() const { return verify_mode; }
- String get_common_name() const { return common_name; }
+ String get_common_name_override() const { return common_name; }
Ref<X509Certificate> get_trusted_ca_chain() const { return trusted_ca_chain; }
Ref<X509Certificate> get_own_certificate() const { return own_certificate; }
Ref<CryptoKey> get_private_key() const { return private_key; }
- bool is_server() const { return server_mode; }
+ bool is_server() const { return mode == MODE_SERVER; }
+ bool is_unsafe_client() const { return mode == MODE_CLIENT_UNSAFE; }
};
class HMACContext : public RefCounted {
diff --git a/core/extension/SCsub b/core/extension/SCsub
index 901ceec1e8..6ab2d2b0a6 100644
--- a/core/extension/SCsub
+++ b/core/extension/SCsub
@@ -2,8 +2,8 @@
Import("env")
-import make_wrappers
import make_interface_dumper
+import make_wrappers
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", env.Run(make_wrappers.run))
env.CommandNoCache(
diff --git a/core/extension/gdextension.compat.inc b/core/extension/gdextension.compat.inc
new file mode 100644
index 0000000000..9dea865dbd
--- /dev/null
+++ b/core/extension/gdextension.compat.inc
@@ -0,0 +1,49 @@
+/**************************************************************************/
+/* gdextension.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+Error GDExtension::_open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol) {
+ return ERR_UNAVAILABLE;
+}
+
+void GDExtension::_close_library_bind_compat_88418() {
+}
+
+void GDExtension::_initialize_library_bind_compat_88418(InitializationLevel p_level) {
+}
+
+void GDExtension::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::_open_library_bind_compat_88418);
+ ClassDB::bind_compatibility_method(D_METHOD("close_library"), &GDExtension::_close_library_bind_compat_88418);
+ ClassDB::bind_compatibility_method(D_METHOD("initialize_library", "level"), &GDExtension::_initialize_library_bind_compat_88418);
+}
+
+#endif
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index a26bb3e8f3..47628e4ea0 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -29,6 +29,8 @@
/**************************************************************************/
#include "gdextension.h"
+#include "gdextension.compat.inc"
+
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/object/class_db.h"
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index 3b15639890..9393e7399b 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -137,6 +137,15 @@ public:
INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
};
+protected:
+#ifndef DISABLE_DEPRECATED
+ Error _open_library_bind_compat_88418(const String &p_path, const String &p_entry_symbol);
+ void _close_library_bind_compat_88418();
+ void _initialize_library_bind_compat_88418(InitializationLevel p_level);
+ static void _bind_compatibility_methods();
+#endif
+
+public:
bool is_library_open() const;
#ifdef TOOLS_ENABLED
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 98f5cb4d02..85f83eecfd 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -805,12 +805,24 @@ static void gdextension_string_new_with_utf8_chars_and_len(GDExtensionUninitiali
dest->parse_utf8(p_contents, p_size);
}
+static GDExtensionInt gdextension_string_new_with_utf8_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) {
+ memnew_placement(r_dest, String);
+ String *dest = reinterpret_cast<String *>(r_dest);
+ return (GDExtensionInt)dest->parse_utf8(p_contents, p_size);
+}
+
static void gdextension_string_new_with_utf16_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count) {
memnew_placement(r_dest, String);
String *dest = reinterpret_cast<String *>(r_dest);
dest->parse_utf16(p_contents, p_char_count);
}
+static GDExtensionInt gdextension_string_new_with_utf16_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count, GDExtensionBool p_default_little_endian) {
+ memnew_placement(r_dest, String);
+ String *dest = reinterpret_cast<String *>(r_dest);
+ return (GDExtensionInt)dest->parse_utf16(p_contents, p_char_count, p_default_little_endian);
+}
+
static void gdextension_string_new_with_utf32_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_char_count) {
memnew_placement(r_dest, String((const char32_t *)p_contents, p_char_count));
}
@@ -962,6 +974,16 @@ static uint64_t gdextension_file_access_get_buffer(GDExtensionConstObjectPtr p_i
return fa->get_buffer(p_dst, p_length);
}
+static uint8_t *gdextension_image_ptrw(GDExtensionObjectPtr p_instance) {
+ Image *img = (Image *)p_instance;
+ return img->ptrw();
+}
+
+static const uint8_t *gdextension_image_ptr(GDExtensionObjectPtr p_instance) {
+ Image *img = (Image *)p_instance;
+ return img->ptr();
+}
+
static int64_t gdextension_worker_thread_pool_add_native_group_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) {
WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
const String *description = (const String *)p_description;
@@ -1598,7 +1620,9 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(string_new_with_wide_chars);
REGISTER_INTERFACE_FUNC(string_new_with_latin1_chars_and_len);
REGISTER_INTERFACE_FUNC(string_new_with_utf8_chars_and_len);
+ REGISTER_INTERFACE_FUNC(string_new_with_utf8_chars_and_len2);
REGISTER_INTERFACE_FUNC(string_new_with_utf16_chars_and_len);
+ REGISTER_INTERFACE_FUNC(string_new_with_utf16_chars_and_len2);
REGISTER_INTERFACE_FUNC(string_new_with_utf32_chars_and_len);
REGISTER_INTERFACE_FUNC(string_new_with_wide_chars_and_len);
REGISTER_INTERFACE_FUNC(string_to_latin1_chars);
@@ -1684,6 +1708,8 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(editor_remove_plugin);
REGISTER_INTERFACE_FUNC(editor_help_load_xml_from_utf8_chars);
REGISTER_INTERFACE_FUNC(editor_help_load_xml_from_utf8_chars_and_len);
+ REGISTER_INTERFACE_FUNC(image_ptrw);
+ REGISTER_INTERFACE_FUNC(image_ptr);
}
#undef REGISTER_INTERFACE_FUNCTION
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 6fe6b8df20..d6c1df9c00 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -1582,6 +1582,7 @@ typedef void (*GDExtensionInterfaceStringNewWithLatin1CharsAndLen)(GDExtensionUn
/**
* @name string_new_with_utf8_chars_and_len
* @since 4.1
+ * @deprecated in Godot 4.3. Use `string_new_with_utf8_chars_and_len2` instead.
*
* Creates a String from a UTF-8 encoded C string with the given length.
*
@@ -1592,8 +1593,23 @@ typedef void (*GDExtensionInterfaceStringNewWithLatin1CharsAndLen)(GDExtensionUn
typedef void (*GDExtensionInterfaceStringNewWithUtf8CharsAndLen)(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size);
/**
+ * @name string_new_with_utf8_chars_and_len2
+ * @since 4.3
+ *
+ * Creates a String from a UTF-8 encoded C string with the given length.
+ *
+ * @param r_dest A pointer to a Variant to hold the newly created String.
+ * @param p_contents A pointer to a UTF-8 encoded C string.
+ * @param p_size The number of bytes (not code units).
+ *
+ * @return Error code signifying if the operation successful.
+ */
+typedef GDExtensionInt (*GDExtensionInterfaceStringNewWithUtf8CharsAndLen2)(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size);
+
+/**
* @name string_new_with_utf16_chars_and_len
* @since 4.1
+ * @deprecated in Godot 4.3. Use `string_new_with_utf16_chars_and_len2` instead.
*
* Creates a String from a UTF-16 encoded C string with the given length.
*
@@ -1604,6 +1620,21 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf8CharsAndLen)(GDExtensionUnin
typedef void (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen)(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count);
/**
+ * @name string_new_with_utf16_chars_and_len2
+ * @since 4.3
+ *
+ * Creates a String from a UTF-16 encoded C string with the given length.
+ *
+ * @param r_dest A pointer to a Variant to hold the newly created String.
+ * @param p_contents A pointer to a UTF-16 encoded C string.
+ * @param p_size The number of characters (not bytes).
+ * @param p_default_little_endian If true, UTF-16 use little endian.
+ *
+ * @return Error code signifying if the operation successful.
+ */
+typedef GDExtensionInt (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen2)(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count, GDExtensionBool p_default_little_endian);
+
+/**
* @name string_new_with_utf32_chars_and_len
* @since 4.1
*
@@ -1899,6 +1930,36 @@ typedef void (*GDExtensionInterfaceFileAccessStoreBuffer)(GDExtensionObjectPtr p
*/
typedef uint64_t (*GDExtensionInterfaceFileAccessGetBuffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length);
+/* INTERFACE: Image Utilities */
+
+/**
+ * @name image_ptrw
+ * @since 4.3
+ *
+ * Returns writable pointer to internal Image buffer.
+ *
+ * @param p_instance A pointer to a Image object.
+ *
+ * @return Pointer to internal Image buffer.
+ *
+ * @see Image::ptrw()
+ */
+typedef uint8_t *(*GDExtensionInterfaceImagePtrw)(GDExtensionObjectPtr p_instance);
+
+/**
+ * @name image_ptr
+ * @since 4.3
+ *
+ * Returns read only pointer to internal Image buffer.
+ *
+ * @param p_instance A pointer to a Image object.
+ *
+ * @return Pointer to internal Image buffer.
+ *
+ * @see Image::ptr()
+ */
+typedef const uint8_t *(*GDExtensionInterfaceImagePtr)(GDExtensionObjectPtr p_instance);
+
/* INTERFACE: WorkerThreadPool Utilities */
/**
diff --git a/core/extension/make_wrappers.py b/core/extension/make_wrappers.py
index 655b90d2b1..54f4fd5579 100644
--- a/core/extension/make_wrappers.py
+++ b/core/extension/make_wrappers.py
@@ -10,7 +10,6 @@ _FORCE_INLINE_ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
def generate_mod_version(argcount, const=False, returns=False):
s = proto_mod
sproto = str(argcount)
- method_info = ""
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
@@ -68,7 +67,6 @@ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
def generate_ex_version(argcount, const=False, returns=False):
s = proto_ex
sproto = str(argcount)
- method_info = ""
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
diff --git a/core/input/SCsub b/core/input/SCsub
index da29637135..d8e6f33156 100644
--- a/core/input/SCsub
+++ b/core/input/SCsub
@@ -4,7 +4,6 @@ Import("env")
import input_builders
-
# Order matters here. Higher index controller database files write on top of lower index database files.
controller_databases = [
"gamecontrollerdb.txt",
diff --git a/core/input/input.cpp b/core/input/input.cpp
index a8409cc06d..56f616fac4 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -1029,6 +1029,14 @@ void Input::parse_input_event(const Ref<InputEvent> &p_event) {
}
}
+#ifdef DEBUG_ENABLED
+void Input::flush_frame_parsed_events() {
+ _THREAD_SAFE_METHOD_
+
+ frame_parsed_events.clear();
+}
+#endif
+
void Input::flush_buffered_events() {
_THREAD_SAFE_METHOD_
@@ -1244,7 +1252,7 @@ void Input::_update_action_cache(const StringName &p_action_name, ActionState &r
r_action_state.cache.strength = 0.0;
r_action_state.cache.raw_strength = 0.0;
- int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size();
+ int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size() + 1; // +1 comes from InputEventAction.
for (const KeyValue<int, ActionState::DeviceState> &kv : r_action_state.device_states) {
const ActionState::DeviceState &device_state = kv.value;
for (int i = 0; i < max_event; i++) {
@@ -1496,6 +1504,7 @@ void Input::parse_mapping(const String &p_mapping) {
JoyAxis output_axis = _get_output_axis(output);
if (output_button == JoyButton::INVALID && output_axis == JoyAxis::INVALID) {
print_verbose(vformat("Unrecognized output string \"%s\" in mapping:\n%s", output, p_mapping));
+ continue;
}
ERR_CONTINUE_MSG(output_button != JoyButton::INVALID && output_axis != JoyAxis::INVALID,
vformat("Output string \"%s\" matched both button and axis in mapping:\n%s", output, p_mapping));
diff --git a/core/input/input.h b/core/input/input.h
index 6e7ab43082..4daea0c9e8 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -363,6 +363,9 @@ public:
Dictionary get_joy_info(int p_device) const;
void set_fallback_mapping(const String &p_guid);
+#ifdef DEBUG_ENABLED
+ void flush_frame_parsed_events();
+#endif
void flush_buffered_events();
bool is_using_input_buffering();
void set_use_input_buffering(bool p_enable);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index bf1de8d3b2..de3efa7a3a 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1585,6 +1585,14 @@ float InputEventAction::get_strength() const {
return strength;
}
+void InputEventAction::set_event_index(int p_index) {
+ event_index = p_index;
+}
+
+int InputEventAction::get_event_index() const {
+ return event_index;
+}
+
bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const {
if (p_event.is_null()) {
return false;
@@ -1649,9 +1657,13 @@ void InputEventAction::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_strength", "strength"), &InputEventAction::set_strength);
ClassDB::bind_method(D_METHOD("get_strength"), &InputEventAction::get_strength);
+ ClassDB::bind_method(D_METHOD("set_event_index", "index"), &InputEventAction::set_event_index);
+ ClassDB::bind_method(D_METHOD("get_event_index"), &InputEventAction::get_event_index);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action"), "set_action", "get_action");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_strength", "get_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "event_index", PROPERTY_HINT_RANGE, "-1,31,1"), "set_event_index", "get_event_index"); // The max value equals to Input::MAX_EVENT - 1.
}
///////////////////////////////////
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 21b61f3bc2..19176f748e 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -453,6 +453,7 @@ class InputEventAction : public InputEvent {
StringName action;
float strength = 1.0f;
+ int event_index = -1;
protected:
static void _bind_methods();
@@ -466,6 +467,9 @@ public:
void set_strength(float p_strength);
float get_strength() const;
+ void set_event_index(int p_index);
+ int get_event_index() const;
+
virtual bool is_action(const StringName &p_action) const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 7fd1806b31..178d02b987 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -274,6 +274,13 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
if (r_raw_strength != nullptr) {
*r_raw_strength = strength;
}
+ if (r_event_index) {
+ if (input_event_action->get_event_index() >= 0) {
+ *r_event_index = input_event_action->get_event_index();
+ } else {
+ *r_event_index = E->value.inputs.size();
+ }
+ }
return input_event_action->get_action() == p_action;
}
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index 5df67b1103..2f3fe4deeb 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -339,6 +339,8 @@ String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
}
Error DirAccess::copy(const String &p_from, const String &p_to, int p_chmod_flags) {
+ ERR_FAIL_COND_V_MSG(p_from == p_to, ERR_INVALID_PARAMETER, "Source and destination path are equal.");
+
//printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data());
Error err;
{
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 5498b448d7..4b1188ad47 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -3312,7 +3312,7 @@ uint8_t *Image::ptrw() {
return data.ptrw();
}
-int64_t Image::data_size() const {
+int64_t Image::get_data_size() const {
return data.size();
}
@@ -3427,6 +3427,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_mipmaps"), &Image::has_mipmaps);
ClassDB::bind_method(D_METHOD("get_format"), &Image::get_format);
ClassDB::bind_method(D_METHOD("get_data"), &Image::get_data);
+ ClassDB::bind_method(D_METHOD("get_data_size"), &Image::get_data_size);
ClassDB::bind_method(D_METHOD("convert", "format"), &Image::convert);
@@ -3443,7 +3444,10 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_static_method("Image", D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
+#endif
+ ClassDB::bind_static_method("Image", D_METHOD("create_empty", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
ClassDB::bind_static_method("Image", D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
ClassDB::bind_method(D_METHOD("set_data", "width", "height", "use_mipmaps", "format", "data"), &Image::set_data);
diff --git a/core/io/image.h b/core/io/image.h
index daddfac59d..d3ae99954f 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -429,7 +429,7 @@ public:
const uint8_t *ptr() const;
uint8_t *ptrw();
- int64_t data_size() const;
+ int64_t get_data_size() const;
void adjust_bcs(float p_brightness, float p_contrast, float p_saturation);
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 1928f86d6a..c0d18d0120 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -30,7 +30,6 @@
#include "marshalls.h"
-#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index b20279c9ac..ca236ce05c 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -30,7 +30,6 @@
#include "packed_data_container.h"
-#include "core/core_string_names.h"
#include "core/io/marshalls.h"
Variant PackedDataContainer::getvar(const Variant &p_key, bool *r_valid) const {
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 24ff0e83d2..c045c0fc74 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -30,7 +30,6 @@
#include "resource.h"
-#include "core/core_string_names.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/math/math_funcs.h"
@@ -41,12 +40,7 @@
#include <stdio.h>
void Resource::emit_changed() {
- if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) {
- // Let the connection happen on the main thread, later, since signals are not thread-safe.
- call_deferred("emit_signal", CoreStringName(changed));
- } else {
- emit_signal(CoreStringName(changed));
- }
+ emit_signal(CoreStringName(changed));
}
void Resource::_resource_path_changed() {
@@ -167,22 +161,12 @@ bool Resource::editor_can_reload_from_file() {
}
void Resource::connect_changed(const Callable &p_callable, uint32_t p_flags) {
- if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) {
- // Let the check and connection happen on the main thread, later, since signals are not thread-safe.
- callable_mp(this, &Resource::connect_changed).call_deferred(p_callable, p_flags);
- return;
- }
if (!is_connected(CoreStringName(changed), p_callable) || p_flags & CONNECT_REFERENCE_COUNTED) {
connect(CoreStringName(changed), p_callable, p_flags);
}
}
void Resource::disconnect_changed(const Callable &p_callable) {
- if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) {
- // Let the check and disconnection happen on the main thread, later, since signals are not thread-safe.
- callable_mp(this, &Resource::disconnect_changed).call_deferred(p_callable);
- return;
- }
if (is_connected(CoreStringName(changed), p_callable)) {
disconnect(CoreStringName(changed), p_callable);
}
@@ -570,11 +554,18 @@ Resource::Resource() :
remapped_list(this) {}
Resource::~Resource() {
- if (!path_cache.is_empty()) {
- ResourceCache::lock.lock();
- ResourceCache::resources.erase(path_cache);
- ResourceCache::lock.unlock();
+ if (unlikely(path_cache.is_empty())) {
+ return;
+ }
+
+ ResourceCache::lock.lock();
+ // Only unregister from the cache if this is the actual resource listed there.
+ // (Other resources can have the same value in `path_cache` if loaded with `CACHE_IGNORE`.)
+ HashMap<String, Resource *>::Iterator E = ResourceCache::resources.find(path_cache);
+ if (likely(E && E->value == this)) {
+ ResourceCache::resources.remove(E);
}
+ ResourceCache::lock.unlock();
}
HashMap<String, Resource *> ResourceCache::resources;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index ab460c5f4c..f71257fa76 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -749,44 +749,54 @@ Error ResourceLoaderBinary::load() {
String t = get_unicode_string();
Ref<Resource> res;
+ Resource *r = nullptr;
- if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
- //use the existing one
- Ref<Resource> cached = ResourceCache::get_ref(path);
- if (cached->get_class() == t) {
- cached->reset_state();
- res = cached;
- }
+ MissingResource *missing_resource = nullptr;
+
+ if (main) {
+ res = ResourceLoader::get_resource_ref_override(local_path);
+ r = res.ptr();
}
+ if (!r) {
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
+ //use the existing one
+ Ref<Resource> cached = ResourceCache::get_ref(path);
+ if (cached->get_class() == t) {
+ cached->reset_state();
+ res = cached;
+ }
+ }
- MissingResource *missing_resource = nullptr;
+ if (res.is_null()) {
+ //did not replace
+
+ Object *obj = ClassDB::instantiate(t);
+ if (!obj) {
+ if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
+ //create a missing resource
+ missing_resource = memnew(MissingResource);
+ missing_resource->set_original_class(t);
+ missing_resource->set_recording_properties(true);
+ obj = missing_resource;
+ } else {
+ error = ERR_FILE_CORRUPT;
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
+ }
+ }
- if (res.is_null()) {
- //did not replace
-
- Object *obj = ClassDB::instantiate(t);
- if (!obj) {
- if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
- //create a missing resource
- missing_resource = memnew(MissingResource);
- missing_resource->set_original_class(t);
- missing_resource->set_recording_properties(true);
- obj = missing_resource;
- } else {
+ r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ String obj_class = obj->get_class();
error = ERR_FILE_CORRUPT;
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
+ memdelete(obj); //bye
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
}
- }
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- String obj_class = obj->get_class();
- error = ERR_FILE_CORRUPT;
- memdelete(obj); //bye
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ res = Ref<Resource>(r);
}
+ }
- res = Ref<Resource>(r);
+ if (r) {
if (!path.is_empty()) {
if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); // If got here because the resource with same path has different type, replace it.
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index fcf4a727ca..9e6f3ba314 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -118,9 +118,21 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
}
#endif
- if (r_path_and_type.path.is_empty() || r_path_and_type.type.is_empty()) {
+ if (r_path_and_type.type.is_empty()) {
return ERR_FILE_CORRUPT;
}
+ if (r_path_and_type.path.is_empty()) {
+ // Some importers may not write files to the .godot folder, so the path can be empty.
+ if (r_path_and_type.importer.is_empty()) {
+ return ERR_FILE_CORRUPT;
+ }
+
+ // It's only invalid if the extension for the importer is not empty.
+ Ref<ResourceImporter> importer = get_importer_by_name(r_path_and_type.importer);
+ if (importer.is_null() || !importer->get_save_extension().is_empty()) {
+ return ERR_FILE_CORRUPT;
+ }
+ }
return OK;
}
@@ -410,6 +422,7 @@ void ResourceFormatImporter::get_importers_for_extension(const String &p_extensi
for (const String &F : local_exts) {
if (p_extension.to_lower() == F) {
r_importers->push_back(importers[i]);
+ break;
}
}
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index c3c37aa89d..ed5e482296 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -272,6 +272,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
}
load_paths_stack->resize(load_paths_stack->size() - 1);
+ res_ref_overrides.erase(load_nesting);
load_nesting--;
if (!res.is_null()) {
@@ -302,7 +303,8 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex.unlock();
// Thread-safe either if it's the current thread or a brand new one.
- CallQueue *mq_override = nullptr;
+ bool mq_override_present = false;
+ CallQueue *own_mq_override = nullptr;
if (load_nesting == 0) {
load_paths_stack = memnew(Vector<String>);
@@ -310,8 +312,12 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
load_paths_stack->push_back(load_task.dependent_path);
}
if (!Thread::is_main_thread()) {
- mq_override = memnew(CallQueue);
- MessageQueue::set_thread_singleton_override(mq_override);
+ // Let the caller thread use its own, for added flexibility. Provide one otherwise.
+ if (MessageQueue::get_singleton() == MessageQueue::get_main_singleton()) {
+ own_mq_override = memnew(CallQueue);
+ MessageQueue::set_thread_singleton_override(own_mq_override);
+ }
+ mq_override_present = true;
set_current_thread_safe_for_nodes(true);
}
} else {
@@ -324,8 +330,8 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
}
Ref<Resource> res = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
- if (mq_override) {
- mq_override->flush();
+ if (mq_override_present) {
+ MessageQueue::get_singleton()->flush();
}
thread_load_mutex.lock();
@@ -394,8 +400,9 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex.unlock();
if (load_nesting == 0) {
- if (mq_override) {
- memdelete(mq_override);
+ if (own_mq_override) {
+ MessageQueue::set_thread_singleton_override(nullptr);
+ memdelete(own_mq_override);
}
memdelete(load_paths_stack);
}
@@ -457,25 +464,23 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, ResourceFormatLoader::CacheMode p_cache_mode) {
String local_path = _validate_local_path(p_path);
+ bool ignoring_cache = p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP;
+
Ref<LoadToken> load_token;
- bool must_not_register = false;
ThreadLoadTask unregistered_load_task; // Once set, must be valid up to the call to do the load.
ThreadLoadTask *load_task_ptr = nullptr;
bool run_on_current_thread = false;
{
MutexLock thread_load_lock(thread_load_mutex);
- if (thread_load_tasks.has(local_path)) {
+ if (!ignoring_cache && thread_load_tasks.has(local_path)) {
load_token = Ref<LoadToken>(thread_load_tasks[local_path].load_token);
if (!load_token.is_valid()) {
// The token is dying (reached 0 on another thread).
// Ensure it's killed now so the path can be safely reused right away.
thread_load_tasks[local_path].load_token->clear();
- } else {
- if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
- return load_token;
- }
}
+ return load_token;
}
load_token.instantiate();
@@ -503,19 +508,19 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
}
}
- // If we want to ignore cache, but there's another task loading it, we can't add this one to the map and we also have to finish unconditionally synchronously.
- must_not_register = thread_load_tasks.has(local_path) && p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE;
- if (must_not_register) {
+ // Cache-ignoring tasks aren't registered in the map and so must finish within scope.
+ if (ignoring_cache) {
load_token->local_path.clear();
unregistered_load_task = load_task;
+ load_task_ptr = &unregistered_load_task;
} else {
- thread_load_tasks[local_path] = load_task;
+ DEV_ASSERT(!thread_load_tasks.has(local_path));
+ HashMap<String, ResourceLoader::ThreadLoadTask>::Iterator E = thread_load_tasks.insert(local_path, load_task);
+ load_task_ptr = &E->value;
}
-
- load_task_ptr = must_not_register ? &unregistered_load_task : &thread_load_tasks[local_path];
}
- run_on_current_thread = must_not_register || p_thread_mode == LOAD_THREAD_FROM_CURRENT;
+ run_on_current_thread = ignoring_cache || p_thread_mode == LOAD_THREAD_FROM_CURRENT;
if (run_on_current_thread) {
load_task_ptr->thread_id = Thread::get_caller_id();
@@ -526,7 +531,7 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
if (run_on_current_thread) {
_thread_load_function(load_task_ptr);
- if (must_not_register) {
+ if (ignoring_cache) {
load_token->res_if_unregistered = load_task_ptr->resource;
}
}
@@ -656,39 +661,50 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
return Ref<Resource>();
}
- if (load_task.task_id != 0) {
+ bool loader_is_wtp = load_task.task_id != 0;
+ Error wtp_task_err = FAILED;
+ if (loader_is_wtp) {
// Loading thread is in the worker pool.
thread_load_mutex.unlock();
- Error err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
- if (err == ERR_BUSY) {
- // The WorkerThreadPool has reported that the current task wants to await on an older one.
- // That't not allowed for safety, to avoid deadlocks. Fortunately, though, in the context of
- // resource loading that means that the task to wait for can be restarted here to break the
- // cycle, with as much recursion into this process as needed.
- // When the stack is eventually unrolled, the original load will have been notified to go on.
- // CACHE_MODE_IGNORE is needed because, otherwise, the new request would just see there's
- // an ongoing load for that resource and wait for it again. This value forces a new load.
- Ref<ResourceLoader::LoadToken> token = _load_start(load_task.local_path, load_task.type_hint, LOAD_THREAD_DISTRIBUTE, ResourceFormatLoader::CACHE_MODE_IGNORE);
- Ref<Resource> resource = _load_complete(*token.ptr(), &err);
- if (r_error) {
- *r_error = err;
+ wtp_task_err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
+ }
+
+ if (load_task.status == THREAD_LOAD_IN_PROGRESS) { // If early errored, awaiting would deadlock.
+ if (loader_is_wtp) {
+ if (wtp_task_err == ERR_BUSY) {
+ // The WorkerThreadPool has reported that the current task wants to await on an older one.
+ // That't not allowed for safety, to avoid deadlocks. Fortunately, though, in the context of
+ // resource loading that means that the task to wait for can be restarted here to break the
+ // cycle, with as much recursion into this process as needed.
+ // When the stack is eventually unrolled, the original load will have been notified to go on.
+ // CACHE_MODE_IGNORE is needed because, otherwise, the new request would just see there's
+ // an ongoing load for that resource and wait for it again. This value forces a new load.
+ Ref<ResourceLoader::LoadToken> token = _load_start(load_task.local_path, load_task.type_hint, LOAD_THREAD_DISTRIBUTE, ResourceFormatLoader::CACHE_MODE_IGNORE);
+ Ref<Resource> resource = _load_complete(*token.ptr(), &wtp_task_err);
+ if (r_error) {
+ *r_error = wtp_task_err;
+ }
+ thread_load_mutex.lock();
+ return resource;
+ } else {
+ DEV_ASSERT(wtp_task_err == OK);
+ thread_load_mutex.lock();
+ load_task.awaited = true;
}
- thread_load_mutex.lock();
- return resource;
} else {
- DEV_ASSERT(err == OK);
- thread_load_mutex.lock();
- load_task.awaited = true;
+ // Loading thread is main or user thread.
+ if (!load_task.cond_var) {
+ load_task.cond_var = memnew(ConditionVariable);
+ }
+ do {
+ load_task.cond_var->wait(p_thread_load_lock);
+ DEV_ASSERT(thread_load_tasks.has(p_load_token.local_path) && p_load_token.get_reference_count());
+ } while (load_task.cond_var);
}
} else {
- // Loading thread is main or user thread.
- if (!load_task.cond_var) {
- load_task.cond_var = memnew(ConditionVariable);
+ if (loader_is_wtp) {
+ thread_load_mutex.lock();
}
- do {
- load_task.cond_var->wait(p_thread_load_lock);
- DEV_ASSERT(thread_load_tasks.has(p_load_token.local_path) && p_load_token.get_reference_count());
- } while (load_task.cond_var);
}
}
@@ -715,6 +731,40 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
}
}
+Ref<Resource> ResourceLoader::ensure_resource_ref_override_for_outer_load(const String &p_path, const String &p_res_type) {
+ ERR_FAIL_COND_V(load_nesting == 0, Ref<Resource>()); // It makes no sense to use this from nesting level 0.
+ const String &local_path = _validate_local_path(p_path);
+ HashMap<String, Ref<Resource>> &overrides = res_ref_overrides[load_nesting - 1];
+ HashMap<String, Ref<Resource>>::Iterator E = overrides.find(local_path);
+ if (E) {
+ return E->value;
+ } else {
+ Object *obj = ClassDB::instantiate(p_res_type);
+ ERR_FAIL_NULL_V(obj, Ref<Resource>());
+ Ref<Resource> res(obj);
+ if (!res.is_valid()) {
+ memdelete(obj);
+ ERR_FAIL_V(Ref<Resource>());
+ }
+ overrides[local_path] = res;
+ return res;
+ }
+}
+
+Ref<Resource> ResourceLoader::get_resource_ref_override(const String &p_path) {
+ DEV_ASSERT(p_path == _validate_local_path(p_path));
+ HashMap<int, HashMap<String, Ref<Resource>>>::Iterator E = res_ref_overrides.find(load_nesting);
+ if (!E) {
+ return nullptr;
+ }
+ HashMap<String, Ref<Resource>>::Iterator F = E->value.find(p_path);
+ if (!F) {
+ return nullptr;
+ }
+
+ return F->value;
+}
+
bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
String local_path = _validate_local_path(p_path);
@@ -1207,6 +1257,7 @@ bool ResourceLoader::timestamp_on_load = false;
thread_local int ResourceLoader::load_nesting = 0;
thread_local WorkerThreadPool::TaskID ResourceLoader::caller_task_id = 0;
thread_local Vector<String> *ResourceLoader::load_paths_stack;
+thread_local HashMap<int, HashMap<String, Ref<Resource>>> ResourceLoader::res_ref_overrides;
template <>
thread_local uint32_t SafeBinaryMutex<ResourceLoader::BINARY_MUTEX_TAG>::count = 0;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 5caf699d32..c48f39b5cc 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -187,6 +187,7 @@ private:
static thread_local int load_nesting;
static thread_local WorkerThreadPool::TaskID caller_task_id;
+ static thread_local HashMap<int, HashMap<String, Ref<Resource>>> res_ref_overrides; // Outermost key is nesting level.
static thread_local Vector<String> *load_paths_stack; // A pointer to avoid broken TLS implementations from double-running the destructor.
static SafeBinaryMutex<BINARY_MUTEX_TAG> thread_load_mutex;
static HashMap<String, ThreadLoadTask> thread_load_tasks;
@@ -226,7 +227,7 @@ public:
// Loaders can safely use this regardless which thread they are running on.
static void notify_load_error(const String &p_err) {
if (err_notify) {
- callable_mp_static(err_notify).bind(p_err).call_deferred();
+ MessageQueue::get_main_singleton()->push_callable(callable_mp_static(err_notify).bind(p_err));
}
}
static void set_error_notify_func(ResourceLoadErrorNotify p_err_notify) {
@@ -239,7 +240,7 @@ public:
if (Thread::get_caller_id() == Thread::get_main_id()) {
dep_err_notify(p_path, p_dependency, p_type);
} else {
- callable_mp_static(dep_err_notify).bind(p_path, p_dependency, p_type).call_deferred();
+ MessageQueue::get_main_singleton()->push_callable(callable_mp_static(dep_err_notify).bind(p_path, p_dependency, p_type));
}
}
}
@@ -272,6 +273,9 @@ public:
static void set_create_missing_resources_if_class_unavailable(bool p_enable);
_FORCE_INLINE_ static bool is_creating_missing_resources_if_class_unavailable_enabled() { return create_missing_resources_if_class_unavailable; }
+ static Ref<Resource> ensure_resource_ref_override_for_outer_load(const String &p_path, const String &p_res_type);
+ static Ref<Resource> get_resource_ref_override(const String &p_path);
+
static bool is_cleaning_tasks();
static void initialize();
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 9a74266ff7..cb358ca7ef 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -41,7 +41,7 @@
class Variant;
-struct _NO_DISCARD_ AABB {
+struct [[nodiscard]] AABB {
Vector3 position;
Vector3 size;
diff --git a/core/math/basis.h b/core/math/basis.h
index 918cbc18d4..5c1a5fbdda 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -34,7 +34,7 @@
#include "core/math/quaternion.h"
#include "core/math/vector3.h"
-struct _NO_DISCARD_ Basis {
+struct [[nodiscard]] Basis {
Vector3 rows[3] = {
Vector3(1, 0, 0),
Vector3(0, 1, 0),
diff --git a/core/math/color.cpp b/core/math/color.cpp
index d36306d968..1638acd74d 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -33,7 +33,7 @@
#include "color_names.inc"
#include "core/math/math_funcs.h"
#include "core/string/ustring.h"
-#include "core/templates/rb_map.h"
+#include "core/templates/hash_map.h"
#include "thirdparty/misc/ok_color.h"
@@ -414,7 +414,7 @@ Color Color::named(const String &p_name, const Color &p_default) {
int Color::find_named_color(const String &p_name) {
String name = p_name;
- // Normalize name
+ // Normalize name.
name = name.replace(" ", "");
name = name.replace("-", "");
name = name.replace("_", "");
@@ -422,23 +422,24 @@ int Color::find_named_color(const String &p_name) {
name = name.replace(".", "");
name = name.to_upper();
- int idx = 0;
- while (named_colors[idx].name != nullptr) {
- if (name == String(named_colors[idx].name).replace("_", "")) {
- return idx;
+ static HashMap<String, int> named_colors_hashmap;
+ if (unlikely(named_colors_hashmap.is_empty())) {
+ const int named_color_count = get_named_color_count();
+ for (int i = 0; i < named_color_count; i++) {
+ named_colors_hashmap[String(named_colors[i].name).replace("_", "")] = i;
}
- idx++;
+ }
+
+ const HashMap<String, int>::ConstIterator E = named_colors_hashmap.find(name);
+ if (E) {
+ return E->value;
}
return -1;
}
int Color::get_named_color_count() {
- int idx = 0;
- while (named_colors[idx].name != nullptr) {
- idx++;
- }
- return idx;
+ return sizeof(named_colors) / sizeof(NamedColor);
}
String Color::get_named_color_name(int p_idx) {
diff --git a/core/math/color.h b/core/math/color.h
index 65d7377c1c..e17b8c9fd7 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -35,7 +35,7 @@
class String;
-struct _NO_DISCARD_ Color {
+struct [[nodiscard]] Color {
union {
struct {
float r;
diff --git a/core/math/color_names.inc b/core/math/color_names.inc
index eaa1b1087f..6c0d2a4bfd 100644
--- a/core/math/color_names.inc
+++ b/core/math/color_names.inc
@@ -189,5 +189,4 @@ static NamedColor named_colors[] = {
{ "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
{ "YELLOW", Color::hex(0xFFFF00FF) },
{ "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
- { nullptr, Color() },
};
diff --git a/core/math/face3.h b/core/math/face3.h
index 3dd47d0226..519dcb6414 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -36,7 +36,7 @@
#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
-struct _NO_DISCARD_ Face3 {
+struct [[nodiscard]] Face3 {
enum Side {
SIDE_OVER,
SIDE_UNDER,
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 1502b2807c..83ebdc5a84 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -350,6 +350,8 @@ public:
return triangles;
}
+ // Assumes cartesian coordinate system with +x to the right, +y up.
+ // If using screen coordinates (+x to the right, +y down) the result will need to be flipped.
static bool is_polygon_clockwise(const Vector<Vector2> &p_polygon) {
int c = p_polygon.size();
if (c < 3) {
diff --git a/core/math/plane.h b/core/math/plane.h
index 8159f25342..6529fea60a 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -35,7 +35,7 @@
class Variant;
-struct _NO_DISCARD_ Plane {
+struct [[nodiscard]] Plane {
Vector3 normal;
real_t d = 0;
diff --git a/core/math/projection.h b/core/math/projection.h
index f3ed9d7b1c..5af43561c0 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -43,7 +43,7 @@ struct Rect2;
struct Transform3D;
struct Vector2;
-struct _NO_DISCARD_ Projection {
+struct [[nodiscard]] Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 868a2916f5..655e55e0a2 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -35,7 +35,7 @@
#include "core/math/vector3.h"
#include "core/string/ustring.h"
-struct _NO_DISCARD_ Quaternion {
+struct [[nodiscard]] Quaternion {
union {
struct {
real_t x;
diff --git a/core/math/rect2.h b/core/math/rect2.h
index b4069ae86a..9cb341b689 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -38,7 +38,7 @@ class String;
struct Rect2i;
struct Transform2D;
-struct _NO_DISCARD_ Rect2 {
+struct [[nodiscard]] Rect2 {
Point2 position;
Size2 size;
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index a1338da0bb..5f3a3d54f5 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -37,7 +37,7 @@
class String;
struct Rect2;
-struct _NO_DISCARD_ Rect2i {
+struct [[nodiscard]] Rect2i {
Point2i position;
Size2i size;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 4ec2dc119c..476577508f 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -38,7 +38,7 @@
class String;
-struct _NO_DISCARD_ Transform2D {
+struct [[nodiscard]] Transform2D {
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper":
// M = (columns[0][0] columns[1][0])
// (columns[0][1] columns[1][1])
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 7d89b86c75..b1de233445 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -36,7 +36,7 @@
#include "core/math/plane.h"
#include "core/templates/vector.h"
-struct _NO_DISCARD_ Transform3D {
+struct [[nodiscard]] Transform3D {
Basis basis;
Vector3 origin;
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 8851942cdd..edb47db6fd 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -37,7 +37,7 @@
class String;
struct Vector2i;
-struct _NO_DISCARD_ Vector2 {
+struct [[nodiscard]] Vector2 {
static const int AXIS_COUNT = 2;
enum Axis {
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index aca9ae8272..fff9b0a658 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -37,7 +37,7 @@
class String;
struct Vector2;
-struct _NO_DISCARD_ Vector2i {
+struct [[nodiscard]] Vector2i {
static const int AXIS_COUNT = 2;
enum Axis {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 2313eb557a..14bc44c4e7 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -39,7 +39,7 @@ struct Basis;
struct Vector2;
struct Vector3i;
-struct _NO_DISCARD_ Vector3 {
+struct [[nodiscard]] Vector3 {
static const int AXIS_COUNT = 3;
enum Axis {
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 035cfcf9e2..40d0700bf7 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -37,7 +37,7 @@
class String;
struct Vector3;
-struct _NO_DISCARD_ Vector3i {
+struct [[nodiscard]] Vector3i {
static const int AXIS_COUNT = 3;
enum Axis {
diff --git a/core/math/vector4.h b/core/math/vector4.h
index f69b4752bb..8632f69f57 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -38,7 +38,7 @@
class String;
struct Vector4i;
-struct _NO_DISCARD_ Vector4 {
+struct [[nodiscard]] Vector4 {
static const int AXIS_COUNT = 4;
enum Axis {
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index 8a9c580bc1..a9036d684a 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -37,7 +37,7 @@
class String;
struct Vector4;
-struct _NO_DISCARD_ Vector4i {
+struct [[nodiscard]] Vector4i {
static const int AXIS_COUNT = 4;
enum Axis {
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 7ea26c3fc5..fe4345aa0d 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -31,7 +31,6 @@
#include "class_db.h"
#include "core/config/engine.h"
-#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
#include "core/object/script_language.h"
#include "core/os/mutex.h"
@@ -506,7 +505,7 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require
ERR_FAIL_NULL_V_MSG(ti->creation_func, nullptr, "Class '" + String(p_class) + "' or its base class cannot be instantiated.");
}
#ifdef TOOLS_ENABLED
- if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
+ if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
ERR_PRINT("Class '" + String(p_class) + "' can only be instantiated by editor.");
return nullptr;
}
@@ -523,7 +522,7 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require
#ifdef TOOLS_ENABLED
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
if (!ti->inherits_ptr || !ti->inherits_ptr->creation_func) {
- ERR_PRINT_ONCE(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
+ ERR_PRINT(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
} else {
ObjectGDExtension *extension = get_placeholder_extension(ti->name);
return (Object *)extension->create_instance(extension->class_userdata);
@@ -665,7 +664,7 @@ bool ClassDB::can_instantiate(const StringName &p_class) {
return scr.is_valid() && scr->is_valid() && !scr->is_abstract();
}
#ifdef TOOLS_ENABLED
- if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
+ if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
return false;
}
#endif
@@ -685,7 +684,7 @@ bool ClassDB::is_virtual(const StringName &p_class) {
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
}
#ifdef TOOLS_ENABLED
- if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
+ if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
return false;
}
#endif
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index 9351253c6f..4b0b1ce63d 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -31,7 +31,6 @@
#include "message_queue.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
@@ -482,10 +481,7 @@ CallQueue::~CallQueue() {
if (!allocator_is_custom) {
memdelete(allocator);
}
- // This is done here to avoid a circular dependency between the safety checks and the thread singleton pointer.
- if (this == MessageQueue::thread_singleton) {
- MessageQueue::thread_singleton = nullptr;
- }
+ DEV_ASSERT(!is_current_thread_override);
}
//////////////////////
@@ -494,7 +490,6 @@ CallQueue *MessageQueue::main_singleton = nullptr;
thread_local CallQueue *MessageQueue::thread_singleton = nullptr;
void MessageQueue::set_thread_singleton_override(CallQueue *p_thread_singleton) {
- DEV_ASSERT(p_thread_singleton); // To unset the thread singleton, don't call this with nullptr, but just memfree() it.
#ifdef DEV_ENABLED
if (thread_singleton) {
thread_singleton->is_current_thread_override = false;
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index 9f567e4dd0..673eb3845b 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -164,6 +164,7 @@ class MessageQueue : public CallQueue {
public:
_FORCE_INLINE_ static CallQueue *get_singleton() { return thread_singleton ? thread_singleton : main_singleton; }
+ _FORCE_INLINE_ static CallQueue *get_main_singleton() { return main_singleton; }
static void set_thread_singleton_override(CallQueue *p_thread_singleton);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 57f8766509..97a3a405b9 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -31,7 +31,6 @@
#include "object.h"
#include "object.compat.inc"
-#include "core/core_string_names.h"
#include "core/extension/gdextension_manager.h"
#include "core/io/resource.h"
#include "core/object/class_db.h"
@@ -237,20 +236,12 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
if (_extension && _extension->set) {
-// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wignored-qualifiers"
-#endif
- if (_extension->set(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (const GDExtensionVariantPtr)&p_value)) {
+ if (_extension->set(_extension_instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionConstVariantPtr)&p_value)) {
if (r_valid) {
*r_valid = true;
}
return;
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
}
// Try built-in setter.
@@ -324,21 +315,12 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
}
}
if (_extension && _extension->get) {
-// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wignored-qualifiers"
-#endif
-
- if (_extension->get(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
+ if (_extension->get(_extension_instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
if (r_valid) {
*r_valid = true;
}
return ret;
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
}
// Try built-in getter.
@@ -576,19 +558,11 @@ bool Object::property_can_revert(const StringName &p_name) const {
}
}
-// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wignored-qualifiers"
-#endif
if (_extension && _extension->property_can_revert) {
- if (_extension->property_can_revert(_extension_instance, (const GDExtensionStringNamePtr)&p_name)) {
+ if (_extension->property_can_revert(_extension_instance, (GDExtensionConstStringNamePtr)&p_name)) {
return true;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
return _property_can_revertv(p_name);
}
@@ -602,19 +576,11 @@ Variant Object::property_get_revert(const StringName &p_name) const {
}
}
-// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wignored-qualifiers"
-#endif
if (_extension && _extension->property_get_revert) {
- if (_extension->property_get_revert(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
+ if (_extension->property_get_revert(_extension_instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
return ret;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
if (_property_get_revertv(p_name, ret)) {
return ret;
@@ -924,6 +890,7 @@ void Object::notification(int p_notification, bool p_reversed) {
}
String Object::to_string() {
+ // Keep this method in sync with `Node::to_string`.
if (script_instance) {
bool valid;
String ret = script_instance->to_string(&valid);
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 820296e66d..0b528e908a 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -31,7 +31,6 @@
#include "script_language.h"
#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/io/resource_loader.h"
@@ -698,7 +697,13 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
}
if (script.is_valid()) {
- return script->has_method(p_method);
+ Ref<Script> scr = script;
+ while (scr.is_valid()) {
+ if (scr->has_method(p_method)) {
+ return true;
+ }
+ scr = scr->get_base_script();
+ }
}
return false;
}
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index a18ef8d4d7..7b643e4637 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -132,6 +132,7 @@ void ScriptLanguageExtension::_bind_methods() {
GDVIRTUAL_BIND(_debug_get_stack_level_line, "level");
GDVIRTUAL_BIND(_debug_get_stack_level_function, "level");
+ GDVIRTUAL_BIND(_debug_get_stack_level_source, "level");
GDVIRTUAL_BIND(_debug_get_stack_level_locals, "level", "max_subitems", "max_depth");
GDVIRTUAL_BIND(_debug_get_stack_level_members, "level", "max_subitems", "max_depth");
GDVIRTUAL_BIND(_debug_get_stack_level_instance, "level");
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 8fd26c3d2c..c9344f5799 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -646,7 +646,7 @@ public:
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_profiling_get_accumulated_data, p_info_arr, p_info_max, ret);
+ GDVIRTUAL_REQUIRED_CALL(_profiling_get_frame_data, p_info_arr, p_info_max, ret);
return ret;
}
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index 9c9e0fa899..a7c0a0353e 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -53,7 +53,9 @@ void WorkerThreadPool::_process_task(Task *p_task) {
int pool_thread_index = thread_ids[Thread::get_caller_id()];
ThreadData &curr_thread = threads[pool_thread_index];
Task *prev_task = nullptr; // In case this is recursively called.
+
bool safe_for_nodes_backup = is_current_thread_safe_for_nodes();
+ CallQueue *call_queue_backup = MessageQueue::get_singleton() != MessageQueue::get_main_singleton() ? MessageQueue::get_singleton() : nullptr;
{
// Tasks must start with this unset. They are free to set-and-forget otherwise.
@@ -169,6 +171,7 @@ void WorkerThreadPool::_process_task(Task *p_task) {
}
set_current_thread_safe_for_nodes(safe_for_nodes_backup);
+ MessageQueue::set_thread_singleton_override(call_queue_backup);
#endif
}
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index 6870c84b49..6c748b1498 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -38,88 +38,167 @@ MIDIDriver *MIDIDriver::get_singleton() {
return singleton;
}
-void MIDIDriver::set_singleton() {
+MIDIDriver::MIDIDriver() {
singleton = this;
}
-void MIDIDriver::receive_input_packet(int device_index, uint64_t timestamp, uint8_t *data, uint32_t length) {
- Ref<InputEventMIDI> event;
- event.instantiate();
- event->set_device(device_index);
- uint32_t param_position = 1;
-
- if (length >= 1) {
- if (data[0] >= 0xF0) {
- // channel does not apply to system common messages
- event->set_channel(0);
- event->set_message(MIDIMessage(data[0]));
- last_received_message = data[0];
- } else if ((data[0] & 0x80) == 0x00) {
- // running status
- event->set_channel(last_received_message & 0xF);
- event->set_message(MIDIMessage(last_received_message >> 4));
- param_position = 0;
+MIDIDriver::MessageCategory MIDIDriver::Parser::category(uint8_t p_midi_fragment) {
+ if (p_midi_fragment >= 0xf8) {
+ return MessageCategory::RealTime;
+ } else if (p_midi_fragment >= 0xf0) {
+ // System Exclusive begin/end are specified as System Common Category
+ // messages, but we separate them here and give them their own categories
+ // as their behavior is significantly different.
+ if (p_midi_fragment == 0xf0) {
+ return MessageCategory::SysExBegin;
+ } else if (p_midi_fragment == 0xf7) {
+ return MessageCategory::SysExEnd;
+ }
+ return MessageCategory::SystemCommon;
+ } else if (p_midi_fragment >= 0x80) {
+ return MessageCategory::Voice;
+ }
+ return MessageCategory::Data;
+}
+
+MIDIMessage MIDIDriver::Parser::status_to_msg_enum(uint8_t p_status_byte) {
+ if (p_status_byte & 0x80) {
+ if (p_status_byte < 0xf0) {
+ return MIDIMessage(p_status_byte >> 4);
} else {
- event->set_channel(data[0] & 0xF);
- event->set_message(MIDIMessage(data[0] >> 4));
- param_position = 1;
- last_received_message = data[0];
+ return MIDIMessage(p_status_byte);
}
}
+ return MIDIMessage::NONE;
+}
- switch (event->get_message()) {
- case MIDIMessage::AFTERTOUCH:
- if (length >= 2 + param_position) {
- event->set_pitch(data[param_position]);
- event->set_pressure(data[param_position + 1]);
- }
- break;
+size_t MIDIDriver::Parser::expected_data(uint8_t p_status_byte) {
+ return expected_data(status_to_msg_enum(p_status_byte));
+}
+size_t MIDIDriver::Parser::expected_data(MIDIMessage p_msg_type) {
+ switch (p_msg_type) {
+ case MIDIMessage::NOTE_OFF:
+ case MIDIMessage::NOTE_ON:
+ case MIDIMessage::AFTERTOUCH:
case MIDIMessage::CONTROL_CHANGE:
- if (length >= 2 + param_position) {
- event->set_controller_number(data[param_position]);
- event->set_controller_value(data[param_position + 1]);
- }
- break;
+ case MIDIMessage::PITCH_BEND:
+ case MIDIMessage::SONG_POSITION_POINTER:
+ return 2;
+ case MIDIMessage::PROGRAM_CHANGE:
+ case MIDIMessage::CHANNEL_PRESSURE:
+ case MIDIMessage::QUARTER_FRAME:
+ case MIDIMessage::SONG_SELECT:
+ return 1;
+ default:
+ return 0;
+ }
+}
- case MIDIMessage::NOTE_ON:
+uint8_t MIDIDriver::Parser::channel(uint8_t p_status_byte) {
+ if (category(p_status_byte) == MessageCategory::Voice) {
+ return p_status_byte & 0x0f;
+ }
+ return 0;
+}
+
+void MIDIDriver::send_event(int p_device_index, uint8_t p_status,
+ const uint8_t *p_data, size_t p_data_len) {
+ const MIDIMessage msg = Parser::status_to_msg_enum(p_status);
+ ERR_FAIL_COND(p_data_len < Parser::expected_data(msg));
+
+ Ref<InputEventMIDI> event;
+ event.instantiate();
+ event->set_device(p_device_index);
+ event->set_channel(Parser::channel(p_status));
+ event->set_message(msg);
+ switch (msg) {
case MIDIMessage::NOTE_OFF:
- if (length >= 2 + param_position) {
- event->set_pitch(data[param_position]);
- event->set_velocity(data[param_position + 1]);
- }
+ case MIDIMessage::NOTE_ON:
+ event->set_pitch(p_data[0]);
+ event->set_velocity(p_data[1]);
break;
-
- case MIDIMessage::PITCH_BEND:
- if (length >= 2 + param_position) {
- event->set_pitch((data[param_position + 1] << 7) | data[param_position]);
- }
+ case MIDIMessage::AFTERTOUCH:
+ event->set_pitch(p_data[0]);
+ event->set_pressure(p_data[1]);
+ break;
+ case MIDIMessage::CONTROL_CHANGE:
+ event->set_controller_number(p_data[0]);
+ event->set_controller_value(p_data[1]);
break;
-
case MIDIMessage::PROGRAM_CHANGE:
- if (length >= 1 + param_position) {
- event->set_instrument(data[param_position]);
- }
+ event->set_instrument(p_data[0]);
break;
-
case MIDIMessage::CHANNEL_PRESSURE:
- if (length >= 1 + param_position) {
- event->set_pressure(data[param_position]);
- }
+ event->set_pressure(p_data[0]);
+ break;
+ case MIDIMessage::PITCH_BEND:
+ event->set_pitch((p_data[1] << 7) | p_data[0]);
break;
+ // QUARTER_FRAME, SONG_POSITION_POINTER, and SONG_SELECT not yet implemented.
default:
break;
}
-
- Input *id = Input::get_singleton();
- id->parse_input_event(event);
+ Input::get_singleton()->parse_input_event(event);
}
-PackedStringArray MIDIDriver::get_connected_inputs() {
- PackedStringArray list;
- return list;
+void MIDIDriver::Parser::parse_fragment(uint8_t p_fragment) {
+ switch (category(p_fragment)) {
+ case MessageCategory::RealTime:
+ // Real-Time messages are single byte messages that can
+ // occur at any point and do not interrupt other messages.
+ // We pass them straight through.
+ MIDIDriver::send_event(device_index, p_fragment);
+ break;
+
+ case MessageCategory::SysExBegin:
+ status_byte = p_fragment;
+ skipping_sys_ex = true;
+ break;
+
+ case MessageCategory::SysExEnd:
+ status_byte = 0;
+ skipping_sys_ex = false;
+ break;
+
+ case MessageCategory::Voice:
+ case MessageCategory::SystemCommon:
+ skipping_sys_ex = false; // If we were in SysEx, assume it was aborted.
+ received_data_len = 0;
+ status_byte = 0;
+ ERR_FAIL_COND(expected_data(p_fragment) > DATA_BUFFER_SIZE);
+ if (expected_data(p_fragment) == 0) {
+ // No data bytes needed, post it now.
+ MIDIDriver::send_event(device_index, p_fragment);
+ } else {
+ status_byte = p_fragment;
+ }
+ break;
+
+ case MessageCategory::Data:
+ // We don't currently process SysEx messages, so ignore their data.
+ if (!skipping_sys_ex) {
+ const size_t expected = expected_data(status_byte);
+ if (received_data_len < expected) {
+ data_buffer[received_data_len] = p_fragment;
+ received_data_len++;
+ if (received_data_len == expected) {
+ MIDIDriver::send_event(device_index, status_byte,
+ data_buffer, expected);
+ received_data_len = 0;
+ // Voice messages can use 'running status', sending further
+ // messages without resending their status byte.
+ // For other messages types we clear the cached status byte.
+ if (category(status_byte) != MessageCategory::Voice) {
+ status_byte = 0;
+ }
+ }
+ }
+ }
+ break;
+ }
}
-MIDIDriver::MIDIDriver() {
- set_singleton();
+PackedStringArray MIDIDriver::get_connected_inputs() const {
+ return connected_input_names;
}
diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h
index cad3d8189e..ddce63f9c8 100644
--- a/core/os/midi_driver.h
+++ b/core/os/midi_driver.h
@@ -42,19 +42,73 @@ class MIDIDriver {
static MIDIDriver *singleton;
static uint8_t last_received_message;
+protected:
+ // Categories of message for parser logic.
+ enum class MessageCategory {
+ Data,
+ Voice,
+ SysExBegin,
+ SystemCommon, // excluding System Exclusive Begin/End
+ SysExEnd,
+ RealTime,
+ };
+
+ // Convert midi data to InputEventMIDI and send it to Input.
+ // p_data_len is the length of the buffer passed at p_data, this must be
+ // at least equal to the data required by the passed message type, but
+ // may be larger. Only the required data will be read.
+ static void send_event(int p_device_index, uint8_t p_status,
+ const uint8_t *p_data = nullptr, size_t p_data_len = 0);
+
+ class Parser {
+ public:
+ Parser() = default;
+ Parser(int p_device_index) :
+ device_index{ p_device_index } {}
+ virtual ~Parser() = default;
+
+ // Push a byte of MIDI stream. Any completed messages will be
+ // forwarded to MIDIDriver::send_event.
+ void parse_fragment(uint8_t p_fragment);
+
+ static MessageCategory category(uint8_t p_midi_fragment);
+
+ // If the byte is a Voice Message status byte return the contained
+ // channel number, otherwise zero.
+ static uint8_t channel(uint8_t p_status_byte);
+
+ // If the byte is a status byte for a message with a fixed number of
+ // additional data bytes, return the number expected, otherwise zero.
+ static size_t expected_data(uint8_t p_status_byte);
+ static size_t expected_data(MIDIMessage p_msg_type);
+
+ // If the fragment is a status byte return the message type
+ // represented, otherwise MIDIMessage::NONE.
+ static MIDIMessage status_to_msg_enum(uint8_t p_status_byte);
+
+ private:
+ int device_index = 0;
+
+ static constexpr size_t DATA_BUFFER_SIZE = 2;
+
+ uint8_t status_byte = 0;
+ uint8_t data_buffer[DATA_BUFFER_SIZE] = { 0 };
+ size_t received_data_len = 0;
+ bool skipping_sys_ex = false;
+ };
+
+ PackedStringArray connected_input_names;
+
public:
static MIDIDriver *get_singleton();
- void set_singleton();
+
+ MIDIDriver();
+ virtual ~MIDIDriver() = default;
virtual Error open() = 0;
virtual void close() = 0;
- virtual PackedStringArray get_connected_inputs();
-
- static void receive_input_packet(int device_index, uint64_t timestamp, uint8_t *data, uint32_t length);
-
- MIDIDriver();
- virtual ~MIDIDriver() {}
+ PackedStringArray get_connected_inputs() const;
};
#endif // MIDI_DRIVER_H
diff --git a/core/os/os.cpp b/core/os/os.cpp
index fa7f23ded0..642de11a9f 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -247,7 +247,10 @@ String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_paths) const
for (int i = 0; i < invalid_chars.size(); i++) {
safe_dir_name = safe_dir_name.replace(invalid_chars[i], "-");
}
- return safe_dir_name;
+
+ // Trim trailing periods from the returned value as it's not valid for folder names on Windows.
+ // This check is still applied on non-Windows platforms so the returned value is consistent across platforms.
+ return safe_dir_name.rstrip(".");
}
// Path to data, config, cache, etc. OS-specific folders
@@ -513,6 +516,10 @@ bool OS::has_feature(const String &p_feature) {
if (p_feature == "threads") {
return true;
}
+#else
+ if (p_feature == "nothreads") {
+ return true;
+ }
#endif
if (_check_internal_feature_support(p_feature)) {
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 4c1ed8a69a..c0a86e9fb7 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -33,7 +33,6 @@
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/core_bind.h"
-#include "core/core_string_names.h"
#include "core/crypto/aes_context.h"
#include "core/crypto/crypto.h"
#include "core/crypto/hashing_context.h"
@@ -445,8 +444,8 @@ void unregister_core_types() {
unregister_global_constants();
- ClassDB::cleanup();
ResourceCache::clear();
+ ClassDB::cleanup();
CoreStringNames::free();
StringName::cleanup();
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 344fe42fa0..432016284a 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -752,10 +752,10 @@ StringName TranslationServer::tool_translate(const StringName &p_message, const
if (tool_translation.is_valid()) {
StringName r = tool_translation->get_message(p_message, p_context);
if (r) {
- return editor_pseudolocalization ? tool_pseudolocalize(r) : r;
+ return r;
}
}
- return editor_pseudolocalization ? tool_pseudolocalize(p_message) : p_message;
+ return p_message;
}
StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
@@ -856,10 +856,6 @@ void TranslationServer::set_pseudolocalization_enabled(bool p_enabled) {
}
}
-void TranslationServer::set_editor_pseudolocalization(bool p_enabled) {
- editor_pseudolocalization = p_enabled;
-}
-
void TranslationServer::reload_pseudolocalization() {
pseudolocalization_accents_enabled = GLOBAL_GET("internationalization/pseudolocalization/replace_with_accents");
pseudolocalization_double_vowels_enabled = GLOBAL_GET("internationalization/pseudolocalization/double_vowels");
diff --git a/core/string/translation.h b/core/string/translation.h
index 78d6721347..0a7eacc45f 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -94,7 +94,6 @@ class TranslationServer : public Object {
bool pseudolocalization_fake_bidi_enabled = false;
bool pseudolocalization_override_enabled = false;
bool pseudolocalization_skip_placeholders_enabled = false;
- bool editor_pseudolocalization = false;
float expansion_ratio = 0.0;
String pseudolocalization_prefix;
String pseudolocalization_suffix;
@@ -170,7 +169,6 @@ public:
bool is_pseudolocalization_enabled() const;
void set_pseudolocalization_enabled(bool p_enabled);
- void set_editor_pseudolocalization(bool p_enabled);
void reload_pseudolocalization();
String standardize_locale(const String &p_locale) const;
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index 06fd4717d7..8e275505b0 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -140,43 +140,87 @@ int TranslationPO::_get_plural_index(int p_n) const {
input_val.clear();
input_val.push_back(p_n);
- Variant result;
- for (int i = 0; i < equi_tests.size(); i++) {
- Error err = expr->parse(equi_tests[i], input_name);
- ERR_FAIL_COND_V_MSG(err != OK, 0, "Cannot parse expression. Error: " + expr->get_error_text());
+ return _eq_test(equi_tests, 0);
+}
- result = expr->execute(input_val);
- ERR_FAIL_COND_V_MSG(expr->has_execute_failed(), 0, "Cannot evaluate expression.");
+int TranslationPO::_eq_test(const Ref<EQNode> &p_node, const Variant &p_result) const {
+ if (p_node.is_valid()) {
+ Error err = expr->parse(p_node->regex, input_name);
+ ERR_FAIL_COND_V_MSG(err != OK, 0, vformat("Cannot parse expression \"%s\". Error: %s", p_node->regex, expr->get_error_text()));
- // Last expression. Variant result will either map to a bool or an integer, in both cases returning it will give the correct plural index.
- if (i + 1 == equi_tests.size()) {
- return result;
- }
+ Variant result = expr->execute(input_val);
+ ERR_FAIL_COND_V_MSG(expr->has_execute_failed(), 0, vformat("Cannot evaluate expression \"%s\".", p_node->regex));
if (bool(result)) {
- return i;
+ return _eq_test(p_node->left, result);
+ } else {
+ return _eq_test(p_node->right, result);
}
+ } else {
+ return p_result;
+ }
+}
+
+int TranslationPO::_find_unquoted(const String &p_src, char32_t p_chr) const {
+ const int len = p_src.length();
+ if (len == 0) {
+ return -1;
}
- ERR_FAIL_V_MSG(0, "Unexpected. Function should have returned. Please report this bug.");
+ const char32_t *src = p_src.get_data();
+ bool in_quote = false;
+ for (int i = 0; i < len; i++) {
+ if (in_quote) {
+ if (src[i] == ')') {
+ in_quote = false;
+ }
+ } else {
+ if (src[i] == '(') {
+ in_quote = true;
+ } else if (src[i] == p_chr) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
}
-void TranslationPO::_cache_plural_tests(const String &p_plural_rule) {
+void TranslationPO::_cache_plural_tests(const String &p_plural_rule, Ref<EQNode> &p_node) {
// Some examples of p_plural_rule passed in can have the form:
// "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5" (Arabic)
// "n >= 2" (French) // When evaluating the last, especially careful with this one.
// "n != 1" (English)
- int first_ques_mark = p_plural_rule.find("?");
+
+ String rule = p_plural_rule;
+ if (rule.begins_with("(") && rule.ends_with(")")) {
+ int bcount = 0;
+ for (int i = 1; i < rule.length() - 1 && bcount >= 0; i++) {
+ if (rule[i] == '(') {
+ bcount++;
+ } else if (rule[i] == ')') {
+ bcount--;
+ }
+ }
+ if (bcount == 0) {
+ rule = rule.substr(1, rule.length() - 2);
+ }
+ }
+
+ int first_ques_mark = _find_unquoted(rule, '?');
+ int first_colon = _find_unquoted(rule, ':');
+
if (first_ques_mark == -1) {
- equi_tests.push_back(p_plural_rule.strip_edges());
+ p_node->regex = rule.strip_edges();
return;
}
- String equi_test = p_plural_rule.substr(0, first_ques_mark).strip_edges();
- equi_tests.push_back(equi_test);
+ p_node->regex = rule.substr(0, first_ques_mark).strip_edges();
- String after_colon = p_plural_rule.substr(p_plural_rule.find(":") + 1, p_plural_rule.length());
- _cache_plural_tests(after_colon);
+ p_node->left.instantiate();
+ _cache_plural_tests(rule.substr(first_ques_mark + 1, first_colon - first_ques_mark - 1).strip_edges(), p_node->left);
+ p_node->right.instantiate();
+ _cache_plural_tests(rule.substr(first_colon + 1).strip_edges(), p_node->right);
}
void TranslationPO::set_plural_rule(const String &p_plural_rule) {
@@ -188,12 +232,12 @@ void TranslationPO::set_plural_rule(const String &p_plural_rule) {
int expression_start = p_plural_rule.find("=", first_semi_col) + 1;
int second_semi_col = p_plural_rule.rfind(";");
- plural_rule = p_plural_rule.substr(expression_start, second_semi_col - expression_start);
+ plural_rule = p_plural_rule.substr(expression_start, second_semi_col - expression_start).strip_edges();
// Setup the cache to make evaluating plural rule faster later on.
- plural_rule = plural_rule.replacen("(", "");
- plural_rule = plural_rule.replacen(")", "");
- _cache_plural_tests(plural_rule);
+ equi_tests.instantiate();
+ _cache_plural_tests(plural_rule, equi_tests);
+
expr.instantiate();
input_name.push_back("n");
}
diff --git a/core/string/translation_po.h b/core/string/translation_po.h
index 73f9b33a87..ba820c6ee4 100644
--- a/core/string/translation_po.h
+++ b/core/string/translation_po.h
@@ -50,7 +50,17 @@ class TranslationPO : public Translation {
String plural_rule;
// Cache temporary variables related to _get_plural_index() to make it faster
- Vector<String> equi_tests;
+ class EQNode : public RefCounted {
+ public:
+ String regex;
+ Ref<EQNode> left;
+ Ref<EQNode> right;
+ };
+ Ref<EQNode> equi_tests;
+
+ int _find_unquoted(const String &p_src, char32_t p_chr) const;
+ int _eq_test(const Ref<EQNode> &p_node, const Variant &p_result) const;
+
Vector<String> input_name;
mutable Ref<Expression> expr;
mutable Array input_val;
@@ -59,7 +69,7 @@ class TranslationPO : public Translation {
mutable int last_plural_n = -1; // Set it to an impossible value at the beginning.
mutable int last_plural_mapped_index = 0;
- void _cache_plural_tests(const String &p_plural_rule);
+ void _cache_plural_tests(const String &p_plural_rule, Ref<EQNode> &p_node);
int _get_plural_index(int p_n) const;
Vector<String> _get_message_list() const override;
diff --git a/core/typedefs.h b/core/typedefs.h
index 2b90a911cd..0de803293d 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -71,12 +71,7 @@
#endif
#endif
-// No discard allows the compiler to flag warnings if we don't use the return value of functions / classes
-#ifndef _NO_DISCARD_
-#define _NO_DISCARD_ [[nodiscard]]
-#endif
-
-// In some cases _NO_DISCARD_ will get false positives,
+// In some cases [[nodiscard]] will get false positives,
// we can prevent the warning in specific cases by preceding the call with a cast.
#ifndef _ALLOW_DISCARD_
#define _ALLOW_DISCARD_ (void)
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index c6fbfd93a1..667aae879c 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -324,6 +324,7 @@ void Callable::operator=(const Callable &p_callable) {
if (custom->ref_count.unref()) {
memdelete(custom);
+ custom = nullptr;
}
}
@@ -428,6 +429,7 @@ Callable::~Callable() {
if (is_custom()) {
if (custom->ref_count.unref()) {
memdelete(custom);
+ custom = nullptr;
}
}
}
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index e00947ed1e..07bf8afa7b 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -46,10 +46,15 @@ public:
_ref(p_array);
}
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
- Array(Array(p_variant), Variant::OBJECT, T::get_class_static(), Variant()) {
+ TypedArray(Array(p_variant)) {
}
- _FORCE_INLINE_ TypedArray(const Array &p_array) :
- Array(p_array, Variant::OBJECT, T::get_class_static(), Variant()) {
+ _FORCE_INLINE_ TypedArray(const Array &p_array) {
+ set_typed(Variant::OBJECT, T::get_class_static(), Variant());
+ if (is_same_typed(p_array)) {
+ _ref(p_array);
+ } else {
+ assign(p_array);
+ }
}
_FORCE_INLINE_ TypedArray() {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
@@ -78,10 +83,15 @@ struct VariantInternalAccessor<const TypedArray<T> &> {
_ref(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
- Array(Array(p_variant), m_variant_type, StringName(), Variant()) { \
+ TypedArray(Array(p_variant)) { \
} \
- _FORCE_INLINE_ TypedArray(const Array &p_array) : \
- Array(p_array, m_variant_type, StringName(), Variant()) { \
+ _FORCE_INLINE_ TypedArray(const Array &p_array) { \
+ set_typed(m_variant_type, StringName(), Variant()); \
+ if (is_same_typed(p_array)) { \
+ _ref(p_array); \
+ } else { \
+ assign(p_array); \
+ } \
} \
_FORCE_INLINE_ TypedArray() { \
set_typed(m_variant_type, StringName(), Variant()); \
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 8be00b1358..30a8facd67 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -30,7 +30,6 @@
#include "variant.h"
-#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/json.h"
#include "core/io/marshalls.h"
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 821edcfedf..f352af24da 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -31,6 +31,7 @@
#ifndef VARIANT_H
#define VARIANT_H
+#include "core/core_string_names.h"
#include "core/input/input_enums.h"
#include "core/io/ip_address.h"
#include "core/math/aabb.h"
@@ -164,10 +165,12 @@ private:
friend struct _VariantCall;
friend class VariantInternal;
- // Variant takes 20 bytes when real_t is float, and 36 if double
- // it only allocates extra memory for aabb/matrix.
+ // Variant takes 24 bytes when real_t is float, and 40 bytes if double.
+ // It only allocates extra memory for AABB/Transform2D (24, 48 if double),
+ // Basis/Transform3D (48, 96 if double), Projection (64, 128 if double),
+ // and PackedArray/Array/Dictionary (platform-dependent).
- Type type;
+ Type type = NIL;
struct ObjData {
ObjectID id;
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 9b7777f480..5e402937cf 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -30,7 +30,6 @@
#include "variant.h"
-#include "core/core_string_names.h"
#include "core/crypto/crypto_core.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/compression.h"
@@ -1632,7 +1631,7 @@ int Variant::get_enum_value(Variant::Type p_type, const StringName &p_enum_name,
VARARG_CLASS1(m_type, m_name, m_method, m_arg_type) \
register_builtin_method<Method_##m_type##_##m_name>(sarray(m_arg_name), Vector<Variant>());
-static void _register_variant_builtin_methods() {
+static void _register_variant_builtin_methods_string() {
_VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
_VariantCall::enum_data = memnew_arr(_VariantCall::EnumData, Variant::VARIANT_MAX);
builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX);
@@ -1762,7 +1761,9 @@ static void _register_variant_builtin_methods() {
/* StringName */
bind_method(StringName, hash, sarray(), varray());
+}
+static void _register_variant_builtin_methods_math() {
/* Vector2 */
bind_method(Vector2, angle, sarray(), varray());
@@ -2060,7 +2061,9 @@ static void _register_variant_builtin_methods() {
bind_static_method(Color, from_ok_hsl, sarray("h", "s", "l", "alpha"), varray(1.0));
bind_static_method(Color, from_rgbe9995, sarray("rgbe"), varray());
+}
+static void _register_variant_builtin_methods_misc() {
/* RID */
bind_method(RID, is_valid, sarray(), varray());
@@ -2262,7 +2265,10 @@ static void _register_variant_builtin_methods() {
bind_method(Dictionary, get_or_add, sarray("key", "default"), varray(Variant()));
bind_method(Dictionary, make_read_only, sarray(), varray());
bind_method(Dictionary, is_read_only, sarray(), varray());
+ bind_method(Dictionary, recursive_equal, sarray("dictionary", "recursion_count"), varray());
+}
+static void _register_variant_builtin_methods_array() {
/* Array */
bind_method(Array, size, sarray(), varray());
@@ -2592,7 +2598,9 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector4Array, find, sarray("value", "from"), varray(0));
bind_method(PackedVector4Array, rfind, sarray("value", "from"), varray(-1));
bind_method(PackedVector4Array, count, sarray("value"), varray());
+}
+static void _register_variant_builtin_constants() {
/* Register constants */
int ncc = Color::get_named_color_count();
@@ -2750,7 +2758,11 @@ static void _register_variant_builtin_methods() {
}
void Variant::_register_variant_methods() {
- _register_variant_builtin_methods(); //needs to be out due to namespace
+ _register_variant_builtin_methods_string();
+ _register_variant_builtin_methods_math();
+ _register_variant_builtin_methods_misc();
+ _register_variant_builtin_methods_array();
+ _register_variant_builtin_constants();
}
void Variant::_unregister_variant_methods() {
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 82995620aa..b824044b82 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -33,7 +33,6 @@
#include "variant.h"
-#include "core/core_string_names.h"
#include "core/crypto/crypto_core.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/compression.h"
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index 3142f49fc6..0b94d79a97 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -33,7 +33,6 @@
#include "variant.h"
-#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/object/class_db.h"
diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h
index 176967344f..cdacbad373 100644
--- a/core/variant/variant_setget.h
+++ b/core/variant/variant_setget.h
@@ -33,7 +33,6 @@
#include "variant.h"
-#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/object/class_db.h"
#include "core/templates/local_vector.h"
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 5522b5ba88..7534a154a1 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -30,7 +30,6 @@
#include "variant_utility.h"
-#include "core/core_string_names.h"
#include "core/io/marshalls.h"
#include "core/object/ref_counted.h"
#include "core/os/os.h"