summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub5
-rw-r--r--core/config/project_settings.cpp20
-rw-r--r--core/config/project_settings.h1
-rw-r--r--core/core_bind.cpp23
-rw-r--r--core/core_bind.h4
-rw-r--r--core/extension/gdextension.cpp78
-rw-r--r--core/extension/gdextension.h5
-rw-r--r--core/extension/gdextension_interface.h3
-rw-r--r--core/input/gamecontrollerdb.txt4
-rw-r--r--core/io/dir_access.cpp4
-rw-r--r--core/io/file_access.cpp1
-rw-r--r--core/io/file_access.h1
-rw-r--r--core/io/file_access_compressed.h1
-rw-r--r--core/io/file_access_encrypted.h1
-rw-r--r--core/io/file_access_memory.h1
-rw-r--r--core/io/file_access_pack.h1
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/file_access_zip.h1
-rw-r--r--core/io/json.cpp4
-rw-r--r--core/io/logger.cpp16
-rw-r--r--core/io/logger.h8
-rw-r--r--core/io/resource_loader.cpp12
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/math/basis.cpp2
-rw-r--r--core/math/basis.h2
-rw-r--r--core/math/delaunay_3d.h77
-rw-r--r--core/math/geometry_2d.cpp111
-rw-r--r--core/object/class_db.cpp32
-rw-r--r--core/object/class_db.h10
-rw-r--r--core/object/object.cpp11
-rw-r--r--core/object/object.h3
-rw-r--r--core/object/script_language.cpp8
-rw-r--r--core/object/script_language.h2
-rw-r--r--core/object/undo_redo.cpp4
-rw-r--r--core/os/os.cpp5
-rw-r--r--core/os/os.h10
-rw-r--r--core/os/shared_object.h51
-rw-r--r--core/string/char_utils.h2
-rw-r--r--core/string/translation.cpp2
-rw-r--r--core/templates/command_queue_mt.cpp29
-rw-r--r--core/templates/command_queue_mt.h73
-rw-r--r--core/templates/ring_buffer.h4
-rw-r--r--core/templates/safe_refcount.h2
-rw-r--r--core/variant/method_ptrcall.h10
-rw-r--r--core/variant/type_info.h37
-rw-r--r--core/variant/variant.cpp268
-rw-r--r--core/variant/variant.h32
-rw-r--r--core/variant/variant_parser.cpp29
-rw-r--r--core/variant/variant_parser.h4
-rw-r--r--core/variant/variant_setget.cpp14
50 files changed, 577 insertions, 455 deletions
diff --git a/core/SCsub b/core/SCsub
index f7b733a221..91620cb075 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -29,8 +29,8 @@ if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
ec_valid = False
txt += txts
if not ec_valid:
- print("Error: Invalid AES256 encryption key, not 64 hexadecimal characters: '" + key + "'.")
- print(
+ methods.print_error(
+ f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{key}".\n'
"Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment "
"or make sure that it contains exactly 64 hexadecimal characters."
)
@@ -61,7 +61,6 @@ thirdparty_misc_sources = [
# C++ sources
"pcg.cpp",
"polypartition.cpp",
- "clipper.cpp",
"smolv.cpp",
]
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 104b17961d..ee20aea35d 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1017,7 +1017,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
- if (_csproj_exists(get_resource_path())) {
+ if (_csproj_exists(p_path.get_base_dir())) {
// If there is a csproj file, add the C# feature if it doesn't already exist.
if (!project_features.has("C#")) {
project_features.append("C#");
@@ -1473,7 +1473,9 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
- GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false);
+#ifdef TOOLS_ENABLED
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor_hint", false);
+#endif
GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true);
GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
@@ -1531,6 +1533,10 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("internationalization/rendering/root_node_auto_translate", true);
GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"), 2000);
+ GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"), 0.5);
+#ifdef TOOLS_ENABLED
+ GLOBAL_DEF("gui/timers/tooltip_delay_sec.editor_hint", 0.5);
+#endif
GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
@@ -1568,6 +1574,14 @@ ProjectSettings::ProjectSettings() {
ProjectSettings::get_singleton()->add_hidden_prefix("input/");
}
+ProjectSettings::ProjectSettings(const String &p_path) {
+ if (load_custom(p_path) == OK) {
+ project_loaded = true;
+ }
+}
+
ProjectSettings::~ProjectSettings() {
- singleton = nullptr;
+ if (singleton == this) {
+ singleton = nullptr;
+ }
}
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 1bad76acb1..922c88c151 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -224,6 +224,7 @@ public:
#endif
ProjectSettings();
+ ProjectSettings(const String &p_path);
~ProjectSettings();
};
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 03c31bee28..0996db9d89 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -152,12 +152,10 @@ void ResourceLoader::_bind_methods() {
////// ResourceSaver //////
Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, BitField<SaverFlags> p_flags) {
- ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + p_path + "'.");
return ::ResourceSaver::save(p_resource, p_path, p_flags);
}
Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource) {
- ERR_FAIL_COND_V_MSG(p_resource.is_null(), Vector<String>(), "It's not a reference to a valid Resource object.");
List<String> exts;
::ResourceSaver::get_recognized_extensions(p_resource, &exts);
Vector<String> ret;
@@ -1444,6 +1442,15 @@ Error ClassDB::class_set_property(Object *p_object, const StringName &p_property
return OK;
}
+Variant ClassDB::class_get_property_default_value(const StringName &p_class, const StringName &p_property) const {
+ bool valid;
+ Variant ret = ::ClassDB::class_get_default_property_value(p_class, p_property, &valid);
+ if (valid) {
+ return ret;
+ }
+ return Variant();
+}
+
bool ClassDB::class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) const {
return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
}
@@ -1533,6 +1540,10 @@ StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, c
return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance);
}
+bool ClassDB::is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance) const {
+ return ::ClassDB::is_enum_bitfield(p_class, p_enum, p_no_inheritance);
+}
+
bool ClassDB::is_class_enabled(const StringName &p_class) const {
return ::ClassDB::is_class_enabled(p_class);
}
@@ -1549,7 +1560,7 @@ void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List
pf == "class_has_method" || pf == "class_get_method_list" ||
pf == "class_get_integer_constant_list" || pf == "class_has_integer_constant" || pf == "class_get_integer_constant" ||
pf == "class_has_enum" || pf == "class_get_enum_list" || pf == "class_get_enum_constants" || pf == "class_get_integer_constant_enum" ||
- pf == "is_class_enabled");
+ pf == "is_class_enabled" || pf == "is_class_enum_bitfield");
}
if (first_argument_is_class || pf == "is_parent_class") {
for (const String &E : get_class_list()) {
@@ -1578,6 +1589,8 @@ void ClassDB::_bind_methods() {
::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::class_get_property);
::ClassDB::bind_method(D_METHOD("class_set_property", "object", "property", "value"), &ClassDB::class_set_property);
+ ::ClassDB::bind_method(D_METHOD("class_get_property_default_value", "class", "property"), &ClassDB::class_get_property_default_value);
+
::ClassDB::bind_method(D_METHOD("class_has_method", "class", "method", "no_inheritance"), &ClassDB::class_has_method, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_method_argument_count", "class", "method", "no_inheritance"), &ClassDB::class_get_method_argument_count, DEFVAL(false));
@@ -1594,6 +1607,8 @@ void ClassDB::_bind_methods() {
::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::class_get_enum_constants, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::class_get_integer_constant_enum, DEFVAL(false));
+ ::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false));
+
::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
}
@@ -1906,7 +1921,7 @@ void EngineDebugger::send_message(const String &p_msg, const Array &p_data) {
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_null()) {
+ if (!capture.is_valid()) {
return FAILED;
}
Variant cmd = p_cmd, data = p_data;
diff --git a/core/core_bind.h b/core/core_bind.h
index 3c0cdc25ce..148e0ad83e 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -447,6 +447,8 @@ public:
Variant class_get_property(Object *p_object, const StringName &p_property) const;
Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
+ Variant class_get_property_default_value(const StringName &p_class, const StringName &p_property) const;
+
bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
@@ -462,6 +464,8 @@ public:
PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
+ bool is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
+
bool is_class_enabled(const StringName &p_class) const;
#ifdef TOOLS_ENABLED
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 546c40e9cb..b48ea97040 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -46,6 +46,41 @@ String GDExtension::get_extension_list_config_file() {
return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
}
+Vector<SharedObject> GDExtension::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) {
+ Vector<SharedObject> dependencies_shared_objects;
+ if (p_config->has_section("dependencies")) {
+ List<String> config_dependencies;
+ p_config->get_section_keys("dependencies", &config_dependencies);
+
+ for (const String &dependency : config_dependencies) {
+ Vector<String> dependency_tags = dependency.split(".");
+ bool all_tags_met = true;
+ for (int i = 0; i < dependency_tags.size(); i++) {
+ String tag = dependency_tags[i].strip_edges();
+ if (!p_has_feature(tag)) {
+ all_tags_met = false;
+ break;
+ }
+ }
+
+ if (all_tags_met) {
+ Dictionary dependency_value = p_config->get_value("dependencies", dependency);
+ for (const Variant *key = dependency_value.next(nullptr); key; key = dependency_value.next(key)) {
+ String dependency_path = *key;
+ String target_path = dependency_value[*key];
+ if (dependency_path.is_relative_path()) {
+ dependency_path = p_path.get_base_dir().path_join(dependency_path);
+ }
+ dependencies_shared_objects.push_back(SharedObject(dependency_path, dependency_tags, target_path));
+ }
+ break;
+ }
+ }
+ }
+
+ return dependencies_shared_objects;
+}
+
String GDExtension::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) {
// First, check the explicit libraries.
if (p_config->has_section("libraries")) {
@@ -240,7 +275,7 @@ public:
ret_opaque = r_ret->get_type() == Variant::NIL ? r_ret : VariantInternal::get_opaque_pointer(r_ret);
}
- ptrcall(p_object, argptrs, ret_opaque);
+ ptrcall_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstTypePtr *>(argptrs), (GDExtensionTypePtr)ret_opaque);
if (r_ret && r_ret->get_type() == Variant::OBJECT) {
VariantInternal::update_object_id(r_ret);
@@ -254,7 +289,7 @@ public:
ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call GDExtension method bind '%s' on placeholder instance.", name));
#endif
ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
- GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
+ GDExtensionClassInstancePtr extension_instance = is_static() ? nullptr : p_object->_get_extension_instance();
ptrcall_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstTypePtr *>(p_args), (GDExtensionTypePtr)r_ret);
}
@@ -352,7 +387,7 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
p_extension_funcs->set_func, // GDExtensionClassSet set_func;
p_extension_funcs->get_func, // GDExtensionClassGet get_func;
p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
- p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
+ nullptr, // GDExtensionClassFreePropertyList2 free_property_list_func;
p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
nullptr, // GDExtensionClassValidateProperty validate_property_func;
@@ -371,7 +406,8 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
};
const ClassCreationDeprecatedInfo legacy = {
- p_extension_funcs->notification_func,
+ p_extension_funcs->notification_func, // GDExtensionClassNotification notification_func;
+ p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
};
_register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3, &legacy);
}
@@ -385,7 +421,7 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
p_extension_funcs->set_func, // GDExtensionClassSet set_func;
p_extension_funcs->get_func, // GDExtensionClassGet get_func;
p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
- p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
+ nullptr, // GDExtensionClassFreePropertyList2 free_property_list_func;
p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
p_extension_funcs->validate_property_func, // GDExtensionClassValidateProperty validate_property_func;
@@ -403,7 +439,11 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar
p_extension_funcs->class_userdata, // void *class_userdata;
};
- _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3);
+ const ClassCreationDeprecatedInfo legacy = {
+ nullptr, // GDExtensionClassNotification notification_func;
+ p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
+ };
+ _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3, &legacy);
}
#endif // DISABLE_DEPRECATED
@@ -479,13 +519,14 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
extension->gdextension.set = p_extension_funcs->set_func;
extension->gdextension.get = p_extension_funcs->get_func;
extension->gdextension.get_property_list = p_extension_funcs->get_property_list_func;
- extension->gdextension.free_property_list = p_extension_funcs->free_property_list_func;
+ extension->gdextension.free_property_list2 = p_extension_funcs->free_property_list_func;
extension->gdextension.property_can_revert = p_extension_funcs->property_can_revert_func;
extension->gdextension.property_get_revert = p_extension_funcs->property_get_revert_func;
extension->gdextension.validate_property = p_extension_funcs->validate_property_func;
#ifndef DISABLE_DEPRECATED
if (p_deprecated_funcs) {
extension->gdextension.notification = p_deprecated_funcs->notification_func;
+ extension->gdextension.free_property_list = p_deprecated_funcs->free_property_list_func;
}
#endif // DISABLE_DEPRECATED
extension->gdextension.notification2 = p_extension_funcs->notification_func;
@@ -727,15 +768,31 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const String
return *function;
}
-Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) {
+Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies) {
String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path);
+
+ Vector<String> abs_dependencies_paths;
+ if (p_dependencies != nullptr && !p_dependencies->is_empty()) {
+ for (const SharedObject &dependency : *p_dependencies) {
+ abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path));
+ }
+ }
+
String actual_lib_path;
- Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &actual_lib_path, Engine::get_singleton()->is_editor_hint());
+ OS::GDExtensionData data = {
+ true, // also_set_library_path
+ &actual_lib_path, // r_resolved_path
+ Engine::get_singleton()->is_editor_hint(), // generate_temp_files
+ &abs_dependencies_paths, // library_dependencies
+ };
+ Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data);
if (actual_lib_path.get_file() != abs_path.get_file()) {
// If temporary files are generated, let's change the library path to point at the original,
// because that's what we want to check to see if it's changed.
library_path = actual_lib_path.get_base_dir().path_join(p_path.get_file());
+ } else {
+ library_path = p_path;
}
ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path);
@@ -970,7 +1027,8 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path,
FileAccess::get_modified_time(library_path));
#endif
- err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol);
+ Vector<SharedObject> library_dependencies = GDExtension::find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); });
+ err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol, &library_dependencies);
if (err != OK) {
// Unreference the extension so that this loading can be considered a failure.
p_extension.unref();
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index 1f48edecf7..3b15639890 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -37,6 +37,7 @@
#include "core/io/config_file.h"
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
+#include "core/os/shared_object.h"
class GDExtensionMethodBind;
@@ -70,6 +71,7 @@ class GDExtension : public Resource {
struct ClassCreationDeprecatedInfo {
#ifndef DISABLE_DEPRECATED
GDExtensionClassNotification notification_func = nullptr;
+ GDExtensionClassFreePropertyList free_property_list_func = nullptr;
#endif // DISABLE_DEPRECATED
};
@@ -123,8 +125,9 @@ public:
static String get_extension_list_config_file();
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
+ static Vector<SharedObject> find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature);
- Error open_library(const String &p_path, const String &p_entry_symbol);
+ Error open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies = nullptr);
void close_library();
enum InitializationLevel {
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index e9c570e994..00a98af4e2 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -256,6 +256,7 @@ typedef struct {
typedef const GDExtensionPropertyInfo *(*GDExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
typedef void (*GDExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list);
+typedef void (*GDExtensionClassFreePropertyList2)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count);
typedef GDExtensionBool (*GDExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name);
typedef GDExtensionBool (*GDExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret);
typedef GDExtensionBool (*GDExtensionClassValidateProperty)(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property);
@@ -333,7 +334,7 @@ typedef struct {
GDExtensionClassSet set_func;
GDExtensionClassGet get_func;
GDExtensionClassGetPropertyList get_property_list_func;
- GDExtensionClassFreePropertyList free_property_list_func;
+ GDExtensionClassFreePropertyList2 free_property_list_func;
GDExtensionClassPropertyCanRevert property_can_revert_func;
GDExtensionClassPropertyGetRevert property_get_revert_func;
GDExtensionClassValidateProperty validate_property_func;
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index a17e15a62c..7150911e75 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -917,6 +917,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -1282,6 +1283,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -1696,6 +1698,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index e99885befa..5df67b1103 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -582,6 +582,10 @@ void DirAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute);
+ ClassDB::bind_method(D_METHOD("is_link", "path"), &DirAccess::is_link);
+ ClassDB::bind_method(D_METHOD("read_link", "path"), &DirAccess::read_link);
+ ClassDB::bind_method(D_METHOD("create_link", "source", "target"), &DirAccess::create_link);
+
ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index d2a5103953..1cf388b33a 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -867,6 +867,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string);
+ ClassDB::bind_method(D_METHOD("resize", "length"), &FileAccess::resize);
ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush);
ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute);
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 0b631f68b1..2ab84db4b6 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -166,6 +166,7 @@ public:
virtual Error get_error() const = 0; ///< get last error
+ virtual Error resize(int64_t p_length) = 0;
virtual void flush() = 0;
virtual void store_8(uint8_t p_dest) = 0; ///< store a byte
virtual void store_16(uint16_t p_dest); ///< store 16 bits uint
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index bf57eaa07c..f706c82f8e 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -88,6 +88,7 @@ public:
virtual Error get_error() const override; ///< get last error
+ virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
virtual void flush() override;
virtual void store_8(uint8_t p_dest) override; ///< store a byte
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 489d213b8f..42afe49a5e 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -78,6 +78,7 @@ public:
virtual Error get_error() const override; ///< get last error
+ virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
virtual void flush() override;
virtual void store_8(uint8_t p_dest) override; ///< store a byte
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index d9efb354c3..e9fbc26d75 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -61,6 +61,7 @@ public:
virtual Error get_error() const override; ///< get last error
+ virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
virtual void flush() override;
virtual void store_8(uint8_t p_byte) override; ///< store a byte
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 0deacfebab..594ac8f089 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -177,6 +177,7 @@ public:
virtual Error get_error() const override;
+ virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
virtual void flush() override;
virtual void store_8(uint8_t p_dest) override;
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 3c7f67664d..c0d1afc8e1 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -277,7 +277,7 @@ void FileAccessZip::seek_end(int64_t p_position) {
uint64_t FileAccessZip::get_position() const {
ERR_FAIL_NULL_V(zfile, 0);
- return unztell(zfile);
+ return unztell64(zfile);
}
uint64_t FileAccessZip::get_length() const {
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index e9ea74e01d..88b63e93e2 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -100,6 +100,7 @@ public:
virtual Error get_error() const override; ///< get last error
+ virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
virtual void flush() override;
virtual void store_8(uint8_t p_dest) override; ///< store a byte
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 5a1fe45f70..61051727c1 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -344,10 +344,10 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
r_token.value = number;
return OK;
- } else if (is_ascii_char(p_str[index])) {
+ } else if (is_ascii_alphabet_char(p_str[index])) {
String id;
- while (is_ascii_char(p_str[index])) {
+ while (is_ascii_alphabet_char(p_str[index])) {
id += p_str[index];
index++;
}
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 441df7f5d1..1476b8ccac 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -37,6 +37,8 @@
#include "core/os/time.h"
#include "core/string/print_string.h"
+#include "modules/modules_enabled.gen.h" // For regex.
+
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
#define sprintf sprintf_s
#endif
@@ -180,6 +182,12 @@ RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files)
base_path(p_base_path.simplify_path()),
max_files(p_max_files > 0 ? p_max_files : 1) {
rotate_file();
+
+#ifdef MODULE_REGEX_ENABLED
+ strip_ansi_regex.instantiate();
+ strip_ansi_regex->detach_from_objectdb(); // Note: This RegEx instance will exist longer than ObjectDB, therefore can't be registered in ObjectDB.
+ strip_ansi_regex->compile("\u001b\\[((?:\\d|;)*)([a-zA-Z])");
+#endif // MODULE_REGEX_ENABLED
}
void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
@@ -199,7 +207,15 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
vsnprintf(buf, len + 1, p_format, list_copy);
}
va_end(list_copy);
+
+#ifdef MODULE_REGEX_ENABLED
+ // Strip ANSI escape codes (such as those inserted by `print_rich()`)
+ // before writing to file, as text editors cannot display those
+ // correctly.
+ file->store_string(strip_ansi_regex->sub(String(buf), "", true));
+#else
file->store_buffer((uint8_t *)buf, len);
+#endif // MODULE_REGEX_ENABLED
if (len >= static_buf_size) {
Memory::free_static(buf);
diff --git a/core/io/logger.h b/core/io/logger.h
index 3cd18965c5..85ef3031ec 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -34,6 +34,10 @@
#include "core/io/file_access.h"
#include "core/string/ustring.h"
#include "core/templates/vector.h"
+#include "modules/modules_enabled.gen.h" // For regex.
+#ifdef MODULE_REGEX_ENABLED
+#include "modules/regex/regex.h"
+#endif // MODULE_REGEX_ENABLED
#include <stdarg.h>
@@ -86,6 +90,10 @@ class RotatedFileLogger : public Logger {
void clear_old_backups();
void rotate_file();
+#ifdef MODULE_REGEX_ENABLED
+ Ref<RegEx> strip_ansi_regex;
+#endif // MODULE_REGEX_ENABLED
+
public:
explicit RotatedFileLogger(const String &p_base_path, int p_max_files = 10);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index eea6357084..c3c37aa89d 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -242,16 +242,20 @@ ResourceLoader::LoadToken::~LoadToken() {
}
Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
+ const String &original_path = p_original_path.is_empty() ? p_path : p_original_path;
load_nesting++;
if (load_paths_stack->size()) {
thread_load_mutex.lock();
- HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack->get(load_paths_stack->size() - 1));
- if (E) {
+ const String &parent_task_path = load_paths_stack->get(load_paths_stack->size() - 1);
+ HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(parent_task_path);
+ // Avoid double-tracking, for progress reporting, resources that boil down to a remapped path containing the real payload (e.g., imported resources).
+ bool is_remapped_load = original_path == parent_task_path;
+ if (E && !is_remapped_load) {
E->value.sub_tasks.insert(p_original_path);
}
thread_load_mutex.unlock();
}
- load_paths_stack->push_back(p_original_path);
+ load_paths_stack->push_back(original_path);
// Try all loaders and pick the first match for the type hint
bool found = false;
@@ -261,7 +265,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
continue;
}
found = true;
- res = loader[i]->load(p_path, !p_original_path.is_empty() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
+ res = loader[i]->load(p_path, original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (!res.is_null()) {
break;
}
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index e4022b2073..1dc1245355 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -98,6 +98,7 @@ void ResourceFormatSaver::_bind_methods() {
}
Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
+ ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + p_path + "'.");
String path = p_path;
if (path.is_empty()) {
path = p_resource->get_path();
@@ -174,6 +175,7 @@ void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) {
}
void ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) {
+ ERR_FAIL_COND_MSG(p_resource.is_null(), "It's not a reference to a valid Resource object.");
for (int i = 0; i < saver_count; i++) {
saver[i]->get_recognized_extensions(p_resource, p_extensions);
}
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 84ac878172..34ed1c2d85 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -293,7 +293,7 @@ Vector3 Basis::get_scale_abs() const {
Vector3(rows[0][2], rows[1][2], rows[2][2]).length());
}
-Vector3 Basis::get_scale_local() const {
+Vector3 Basis::get_scale_global() const {
real_t det_sign = SIGN(determinant());
return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length());
}
diff --git a/core/math/basis.h b/core/math/basis.h
index 79f3bda8f8..918cbc18d4 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -103,7 +103,7 @@ struct _NO_DISCARD_ Basis {
Vector3 get_scale() const;
Vector3 get_scale_abs() const;
- Vector3 get_scale_local() const;
+ Vector3 get_scale_global() const;
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ);
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 45571fb570..25bd4e8d89 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -46,7 +46,8 @@ class Delaunay3D {
struct Simplex;
enum {
- ACCEL_GRID_SIZE = 16
+ ACCEL_GRID_SIZE = 16,
+ QUANTIZATION_MAX = 1 << 16 // A power of two smaller than the 23 bit significand of a float.
};
struct GridPos {
Vector3i pos;
@@ -173,38 +174,25 @@ class Delaunay3D {
R128 radius2 = rel2_x * rel2_x + rel2_y * rel2_y + rel2_z * rel2_z;
- return radius2 < (p_simplex.circum_r2 - R128(0.00001));
+ return radius2 < (p_simplex.circum_r2 - R128(0.0000000001));
+ // When this tolerance is too big, it can result in overlapping simplices.
+ // When it's too small, large amounts of planar simplices are created.
}
static bool simplex_is_coplanar(const Vector3 *p_points, const Simplex &p_simplex) {
- Plane p(p_points[p_simplex.points[0]], p_points[p_simplex.points[1]], p_points[p_simplex.points[2]]);
- if (ABS(p.distance_to(p_points[p_simplex.points[3]])) < CMP_EPSILON) {
- return true;
+ // Checking every possible distance like this is overkill, but only checking
+ // one is not enough. If the simplex is almost planar then the vectors p1-p2
+ // and p1-p3 can be practically collinear, which makes Plane unreliable.
+ for (uint32_t i = 0; i < 4; i++) {
+ Plane p(p_points[p_simplex.points[i]], p_points[p_simplex.points[(i + 1) % 4]], p_points[p_simplex.points[(i + 2) % 4]]);
+ // This tolerance should not be smaller than the one used with
+ // Plane::has_point() when creating the LightmapGI probe BSP tree.
+ if (ABS(p.distance_to(p_points[p_simplex.points[(i + 3) % 4]])) < 0.001) {
+ return true;
+ }
}
- Projection cm;
-
- cm.columns[0][0] = p_points[p_simplex.points[0]].x;
- cm.columns[0][1] = p_points[p_simplex.points[1]].x;
- cm.columns[0][2] = p_points[p_simplex.points[2]].x;
- cm.columns[0][3] = p_points[p_simplex.points[3]].x;
-
- cm.columns[1][0] = p_points[p_simplex.points[0]].y;
- cm.columns[1][1] = p_points[p_simplex.points[1]].y;
- cm.columns[1][2] = p_points[p_simplex.points[2]].y;
- cm.columns[1][3] = p_points[p_simplex.points[3]].y;
-
- cm.columns[2][0] = p_points[p_simplex.points[0]].z;
- cm.columns[2][1] = p_points[p_simplex.points[1]].z;
- cm.columns[2][2] = p_points[p_simplex.points[2]].z;
- cm.columns[2][3] = p_points[p_simplex.points[3]].z;
-
- cm.columns[3][0] = 1.0;
- cm.columns[3][1] = 1.0;
- cm.columns[3][2] = 1.0;
- cm.columns[3][3] = 1.0;
-
- return ABS(cm.determinant()) <= CMP_EPSILON;
+ return false;
}
public:
@@ -215,9 +203,10 @@ public:
static Vector<OutputSimplex> tetrahedralize(const Vector<Vector3> &p_points) {
uint32_t point_count = p_points.size();
Vector3 *points = (Vector3 *)memalloc(sizeof(Vector3) * (point_count + 4));
+ const Vector3 *src_points = p_points.ptr();
+ Vector3 proportions;
{
- const Vector3 *src_points = p_points.ptr();
AABB rect;
for (uint32_t i = 0; i < point_count; i++) {
Vector3 point = src_points[i];
@@ -226,17 +215,25 @@ public:
} else {
rect.expand_to(point);
}
- points[i] = point;
}
+ real_t longest_axis = rect.size[rect.get_longest_axis_index()];
+ proportions = Vector3(longest_axis, longest_axis, longest_axis) / rect.size;
+
for (uint32_t i = 0; i < point_count; i++) {
- points[i] = (points[i] - rect.position) / rect.size;
+ // Scale points to the unit cube to better utilize R128 precision
+ // and quantize to stabilize triangulation over a wide range of
+ // distances.
+ points[i] = Vector3(Vector3i((src_points[i] - rect.position) / longest_axis * QUANTIZATION_MAX)) / QUANTIZATION_MAX;
}
- const real_t delta_max = Math::sqrt(2.0) * 20.0;
+ const real_t delta_max = Math::sqrt(2.0) * 100.0;
Vector3 center = Vector3(0.5, 0.5, 0.5);
- // any simplex that contains everything is good
+ // The larger the root simplex is, the more likely it is that the
+ // triangulation is convex. If it's not absolutely huge, there can
+ // be missing simplices that are not created for the outermost faces
+ // of the point cloud if the point density is very low there.
points[point_count + 0] = center + Vector3(0, 1, 0) * delta_max;
points[point_count + 1] = center + Vector3(0, -1, 1) * delta_max;
points[point_count + 2] = center + Vector3(1, -1, -1) * delta_max;
@@ -271,7 +268,7 @@ public:
for (uint32_t i = 0; i < point_count; i++) {
bool unique = true;
for (uint32_t j = i + 1; j < point_count; j++) {
- if (points[i].is_equal_approx(points[j])) {
+ if (points[i] == points[j]) {
unique = false;
break;
}
@@ -280,7 +277,7 @@ public:
continue;
}
- Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE);
+ Vector3i grid_pos = Vector3i(points[i] * proportions * ACCEL_GRID_SIZE);
grid_pos = grid_pos.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1));
for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) {
@@ -300,6 +297,9 @@ public:
Triangle t = Triangle(simplex->points[triangle_order[k][0]], simplex->points[triangle_order[k][1]], simplex->points[triangle_order[k][2]]);
uint32_t *p = triangles_inserted.lookup_ptr(t);
if (p) {
+ // This Delaunay implementation uses the Bowyer-Watson algorithm.
+ // The rule is that you don't reuse any triangles that were
+ // shared by any of the retriangulated simplices.
triangles[*p].bad = true;
} else {
triangles_inserted.insert(t, triangles.size());
@@ -307,7 +307,6 @@ public:
}
}
- //remove simplex and continue
simplex_list.erase(simplex->SE);
for (const GridPos &gp : simplex->grid_positions) {
@@ -334,8 +333,8 @@ public:
const real_t radius2 = Math::sqrt(double(new_simplex->circum_r2)) + 0.0001;
Vector3 extents = Vector3(radius2, radius2, radius2);
- Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE);
- Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE);
+ Vector3i from = Vector3i((center - extents) * proportions * ACCEL_GRID_SIZE);
+ Vector3i to = Vector3i((center + extents) * proportions * ACCEL_GRID_SIZE);
from = from.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1));
to = to.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1));
@@ -370,7 +369,7 @@ public:
break;
}
}
- if (invalid || simplex_is_coplanar(points, *simplex)) {
+ if (invalid || simplex_is_coplanar(src_points, *simplex)) {
memdelete(simplex);
continue;
}
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index 602e95bc13..d60619b27f 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -30,12 +30,12 @@
#include "geometry_2d.h"
-#include "thirdparty/misc/clipper.hpp"
+#include "thirdparty/clipper2/include/clipper2/clipper.h"
#include "thirdparty/misc/polypartition.h"
#define STB_RECT_PACK_IMPLEMENTATION
#include "thirdparty/misc/stb_rect_pack.h"
-#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON.
+#define PRECISION 5 // Based on CMP_EPSILON.
Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(const Vector<Point2> &polygon) {
Vector<Vector<Vector2>> decomp;
@@ -196,58 +196,59 @@ void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_re
}
Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) {
- using namespace ClipperLib;
+ using namespace Clipper2Lib;
- ClipType op = ctUnion;
+ ClipType op = ClipType::Union;
switch (p_op) {
case OPERATION_UNION:
- op = ctUnion;
+ op = ClipType::Union;
break;
case OPERATION_DIFFERENCE:
- op = ctDifference;
+ op = ClipType::Difference;
break;
case OPERATION_INTERSECTION:
- op = ctIntersection;
+ op = ClipType::Intersection;
break;
case OPERATION_XOR:
- op = ctXor;
+ op = ClipType::Xor;
break;
}
- Path path_a, path_b;
- // Need to scale points (Clipper's requirement for robust computation).
+ PathD path_a(p_polypath_a.size());
for (int i = 0; i != p_polypath_a.size(); ++i) {
- path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR);
+ path_a[i] = PointD(p_polypath_a[i].x, p_polypath_a[i].y);
}
+ PathD path_b(p_polypath_b.size());
for (int i = 0; i != p_polypath_b.size(); ++i) {
- path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR);
+ path_b[i] = PointD(p_polypath_b[i].x, p_polypath_b[i].y);
}
- Clipper clp;
- clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0.
- clp.AddPath(path_b, ptClip, true); // Polylines cannot be set as clip.
- Paths paths;
+ ClipperD clp(PRECISION); // Scale points up internally to attain the desired precision.
+ clp.PreserveCollinear(false); // Remove redundant vertices.
+ if (is_a_open) {
+ clp.AddOpenSubject({ path_a });
+ } else {
+ clp.AddSubject({ path_a });
+ }
+ clp.AddClip({ path_b });
+
+ PathsD paths;
if (is_a_open) {
- PolyTree tree; // Needed to populate polylines.
- clp.Execute(op, tree);
- OpenPathsFromPolyTree(tree, paths);
+ PolyTreeD tree; // Needed to populate polylines.
+ clp.Execute(op, FillRule::EvenOdd, tree, paths);
} else {
- clp.Execute(op, paths); // Works on closed polygons only.
+ clp.Execute(op, FillRule::EvenOdd, paths); // Works on closed polygons only.
}
- // Have to scale points down now.
+
Vector<Vector<Point2>> polypaths;
+ for (PathsD::size_type i = 0; i < paths.size(); ++i) {
+ const PathD &path = paths[i];
- for (Paths::size_type i = 0; i < paths.size(); ++i) {
Vector<Vector2> polypath;
-
- const Path &scaled_path = paths[i];
-
- for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
- polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
+ for (PathsD::size_type j = 0; j < path.size(); ++j) {
+ polypath.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y)));
}
polypaths.push_back(polypath);
}
@@ -255,67 +256,61 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
}
Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
- using namespace ClipperLib;
+ using namespace Clipper2Lib;
- JoinType jt = jtSquare;
+ JoinType jt = JoinType::Square;
switch (p_join_type) {
case JOIN_SQUARE:
- jt = jtSquare;
+ jt = JoinType::Square;
break;
case JOIN_ROUND:
- jt = jtRound;
+ jt = JoinType::Round;
break;
case JOIN_MITER:
- jt = jtMiter;
+ jt = JoinType::Miter;
break;
}
- EndType et = etClosedPolygon;
+ EndType et = EndType::Polygon;
switch (p_end_type) {
case END_POLYGON:
- et = etClosedPolygon;
+ et = EndType::Polygon;
break;
case END_JOINED:
- et = etClosedLine;
+ et = EndType::Joined;
break;
case END_BUTT:
- et = etOpenButt;
+ et = EndType::Butt;
break;
case END_SQUARE:
- et = etOpenSquare;
+ et = EndType::Square;
break;
case END_ROUND:
- et = etOpenRound;
+ et = EndType::Round;
break;
}
- ClipperOffset co(2.0, 0.25f * (real_t)SCALE_FACTOR); // Defaults from ClipperOffset.
- Path path;
- // Need to scale points (Clipper's requirement for robust computation).
+ PathD polypath(p_polypath.size());
for (int i = 0; i != p_polypath.size(); ++i) {
- path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR);
+ polypath[i] = PointD(p_polypath[i].x, p_polypath[i].y);
}
- co.AddPath(path, jt, et);
- Paths paths;
- co.Execute(paths, p_delta * (real_t)SCALE_FACTOR); // Inflate/deflate.
+ // Inflate/deflate.
+ PathsD paths = InflatePaths({ polypath }, p_delta, jt, et, 2.0, PRECISION, 0.0);
+ // Here the miter_limit = 2.0 and arc_tolerance = 0.0 are Clipper2 defaults,
+ // and the PRECISION is used to scale points up internally, to attain the desired precision.
- // Have to scale points down now.
Vector<Vector<Point2>> polypaths;
+ for (PathsD::size_type i = 0; i < paths.size(); ++i) {
+ const PathD &path = paths[i];
- for (Paths::size_type i = 0; i < paths.size(); ++i) {
- Vector<Vector2> polypath;
-
- const Path &scaled_path = paths[i];
-
- for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
- polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
+ Vector<Vector2> polypath2;
+ for (PathsD::size_type j = 0; j < path.size(); ++j) {
+ polypath2.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y)));
}
- polypaths.push_back(polypath);
+ polypaths.push_back(polypath2);
}
return polypaths;
}
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 80a2703c2f..876635529c 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -138,7 +138,7 @@ public:
return nullptr;
}
- static void placeholder_instance_free_property_list(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) {
+ static void placeholder_instance_free_property_list(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {
}
static GDExtensionBool placeholder_instance_property_can_revert(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) {
@@ -182,8 +182,20 @@ public:
// Construct a placeholder.
Object *obj = native_parent->creation_func();
+
+ // ClassDB::set_object_extension_instance() won't be called for placeholders.
+ // We need need to make sure that all the things it would have done (even if
+ // done in a different way to support placeholders) will also be done here.
+
obj->_extension = ClassDB::get_placeholder_extension(ti->name);
obj->_extension_instance = memnew(PlaceholderExtensionInstance(ti->name));
+
+#ifdef TOOLS_ENABLED
+ if (obj->_extension->track_instance) {
+ obj->_extension->track_instance(obj->_extension->tracking_userdata, obj);
+ }
+#endif
+
return obj;
}
@@ -506,14 +518,7 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require
extension = get_placeholder_extension(ti->name);
}
#endif
- Object *obj = (Object *)extension->create_instance(extension->class_userdata);
-
-#ifdef TOOLS_ENABLED
- if (extension->track_instance) {
- extension->track_instance(extension->tracking_userdata, obj);
- }
-#endif
- return obj;
+ return (Object *)extension->create_instance(extension->class_userdata);
} else {
#ifdef TOOLS_ENABLED
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
@@ -595,12 +600,13 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class)
placeholder_extension->set = &PlaceholderExtensionInstance::placeholder_instance_set;
placeholder_extension->get = &PlaceholderExtensionInstance::placeholder_instance_get;
placeholder_extension->get_property_list = &PlaceholderExtensionInstance::placeholder_instance_get_property_list;
- placeholder_extension->free_property_list = &PlaceholderExtensionInstance::placeholder_instance_free_property_list;
+ placeholder_extension->free_property_list2 = &PlaceholderExtensionInstance::placeholder_instance_free_property_list;
placeholder_extension->property_can_revert = &PlaceholderExtensionInstance::placeholder_instance_property_can_revert;
placeholder_extension->property_get_revert = &PlaceholderExtensionInstance::placeholder_instance_property_get_revert;
placeholder_extension->validate_property = &PlaceholderExtensionInstance::placeholder_instance_validate_property;
#ifndef DISABLE_DEPRECATED
placeholder_extension->notification = nullptr;
+ placeholder_extension->free_property_list = nullptr;
#endif // DISABLE_DEPRECATED
placeholder_extension->notification2 = &PlaceholderExtensionInstance::placeholder_instance_notification;
placeholder_extension->to_string = &PlaceholderExtensionInstance::placeholder_instance_to_string;
@@ -638,6 +644,12 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
p_object->_extension = ti->gdextension;
p_object->_extension_instance = p_instance;
+
+#ifdef TOOLS_ENABLED
+ if (p_object->_extension->track_instance) {
+ p_object->_extension->track_instance(p_object->_extension->tracking_userdata, p_object);
+ }
+#endif
}
bool ClassDB::can_instantiate(const StringName &p_class) {
diff --git a/core/object/class_db.h b/core/object/class_db.h
index adb525cbe8..37a864c109 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -195,7 +195,7 @@ public:
template <typename T>
static void register_class(bool p_virtual = false) {
GLOBAL_LOCK_FUNCTION;
- static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
+ static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_NULL(t);
@@ -210,7 +210,7 @@ public:
template <typename T>
static void register_abstract_class() {
GLOBAL_LOCK_FUNCTION;
- static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
+ static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_NULL(t);
@@ -223,7 +223,7 @@ public:
template <typename T>
static void register_internal_class() {
GLOBAL_LOCK_FUNCTION;
- static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
+ static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_NULL(t);
@@ -238,7 +238,7 @@ public:
template <typename T>
static void register_runtime_class() {
GLOBAL_LOCK_FUNCTION;
- static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
+ static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_NULL(t);
@@ -263,7 +263,7 @@ public:
template <typename T>
static void register_custom_instance_class() {
GLOBAL_LOCK_FUNCTION;
- static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
+ static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_NULL(t);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index f8d2feb5a8..b6c8a87a22 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -503,9 +503,14 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(pinfo[i]));
}
- if (current_extension->free_property_list) {
+ if (current_extension->free_property_list2) {
+ current_extension->free_property_list2(_extension_instance, pinfo, pcount);
+ }
+#ifndef DISABLE_DEPRECATED
+ else if (current_extension->free_property_list) {
current_extension->free_property_list(_extension_instance, pinfo);
}
+#endif // DISABLE_DEPRECATED
#ifdef TOOLS_ENABLED
}
#endif
@@ -1455,7 +1460,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
}
bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const {
- ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null.");
+ ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null."); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
const SignalData *s = signal_map.getptr(p_signal);
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
@@ -1478,7 +1483,7 @@ void Object::disconnect(const StringName &p_signal, const Callable &p_callable)
}
bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) {
- ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null.");
+ ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null."); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
SignalData *s = signal_map.getptr(p_signal);
if (!s) {
diff --git a/core/object/object.h b/core/object/object.h
index 915c3a8c25..adb50268d2 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -324,12 +324,13 @@ struct ObjectGDExtension {
GDExtensionClassSet set;
GDExtensionClassGet get;
GDExtensionClassGetPropertyList get_property_list;
- GDExtensionClassFreePropertyList free_property_list;
+ GDExtensionClassFreePropertyList2 free_property_list2;
GDExtensionClassPropertyCanRevert property_can_revert;
GDExtensionClassPropertyGetRevert property_get_revert;
GDExtensionClassValidateProperty validate_property;
#ifndef DISABLE_DEPRECATED
GDExtensionClassNotification notification;
+ GDExtensionClassFreePropertyList free_property_list;
#endif // DISABLE_DEPRECATED
GDExtensionClassNotification2 notification2;
GDExtensionClassToString to_string;
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 660e13e819..bd3199ca0a 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -51,7 +51,7 @@ void Script::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POSTINITIALIZE: {
if (EngineDebugger::is_active()) {
- EngineDebugger::get_script_debugger()->set_break_language(get_language());
+ callable_mp(this, &Script::_set_debugger_break_language).call_deferred();
}
} break;
}
@@ -103,6 +103,12 @@ Dictionary Script::_get_script_constant_map() {
return ret;
}
+void Script::_set_debugger_break_language() {
+ if (EngineDebugger::is_active()) {
+ EngineDebugger::get_script_debugger()->set_break_language(get_language());
+ }
+}
+
int Script::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
MethodInfo mi = get_method_info(p_method);
diff --git a/core/object/script_language.h b/core/object/script_language.h
index c6c6f3de9f..223f114150 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -124,6 +124,8 @@ protected:
TypedArray<Dictionary> _get_script_signal_list();
Dictionary _get_script_constant_map();
+ void _set_debugger_break_language();
+
public:
virtual void reload_from_file() override;
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 6a1385e268..4d67cd930e 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -144,7 +144,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode, bool p_back
}
void UndoRedo::add_do_method(const Callable &p_callable) {
- ERR_FAIL_COND(p_callable.is_null());
+ ERR_FAIL_COND(!p_callable.is_valid());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -169,7 +169,7 @@ void UndoRedo::add_do_method(const Callable &p_callable) {
}
void UndoRedo::add_undo_method(const Callable &p_callable) {
- ERR_FAIL_COND(p_callable.is_null());
+ ERR_FAIL_COND(!p_callable.is_valid());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 8582888740..fa7f23ded0 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -398,6 +398,11 @@ bool OS::has_feature(const String &p_feature) {
if (p_feature == "editor") {
return true;
}
+ if (p_feature == "editor_hint") {
+ return _in_editor;
+ } else if (p_feature == "editor_runtime") {
+ return !_in_editor;
+ }
#else
if (p_feature == "template") {
return true;
diff --git a/core/os/os.h b/core/os/os.h
index 06be0e2b41..d20f84b4ff 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -63,6 +63,7 @@ class OS {
bool _stdout_enabled = true;
bool _stderr_enabled = true;
bool _writing_movie = false;
+ bool _in_editor = false;
CompositeLogger *_logger = nullptr;
@@ -153,7 +154,14 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
- virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr, bool p_generate_temp_files = false) { return ERR_UNAVAILABLE; }
+ struct GDExtensionData {
+ bool also_set_library_path = false;
+ String *r_resolved_path = nullptr;
+ bool generate_temp_files = false;
+ PackedStringArray *library_dependencies = nullptr;
+ };
+
+ virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data = nullptr) { return ERR_UNAVAILABLE; }
virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; }
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; }
diff --git a/core/os/shared_object.h b/core/os/shared_object.h
new file mode 100644
index 0000000000..88423bed13
--- /dev/null
+++ b/core/os/shared_object.h
@@ -0,0 +1,51 @@
+/**************************************************************************/
+/* shared_object.h */
+/**************************************************************************/
+/* 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 SHARED_OBJECT_H
+#define SHARED_OBJECT_H
+
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
+
+struct SharedObject {
+ String path;
+ Vector<String> tags;
+ String target;
+
+ SharedObject(const String &p_path, const Vector<String> &p_tags, const String &p_target) :
+ path(p_path),
+ tags(p_tags),
+ target(p_target) {
+ }
+
+ SharedObject() {}
+};
+
+#endif // SHARED_OBJECT_H
diff --git a/core/string/char_utils.h b/core/string/char_utils.h
index aa9bc198ca..fc2fbb95a1 100644
--- a/core/string/char_utils.h
+++ b/core/string/char_utils.h
@@ -92,7 +92,7 @@ static _FORCE_INLINE_ bool is_binary_digit(char32_t c) {
return (c == '0' || c == '1');
}
-static _FORCE_INLINE_ bool is_ascii_char(char32_t c) {
+static _FORCE_INLINE_ bool is_ascii_alphabet_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 613edd11cd..344fe42fa0 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -993,7 +993,7 @@ String TranslationServer::add_padding(const String &p_message, int p_length) con
}
const char32_t *TranslationServer::get_accented_version(char32_t p_character) const {
- if (!is_ascii_char(p_character)) {
+ if (!is_ascii_alphabet_char(p_character)) {
return nullptr;
}
diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp
index 0c5c6394a1..d9e5e0b217 100644
--- a/core/templates/command_queue_mt.cpp
+++ b/core/templates/command_queue_mt.cpp
@@ -41,35 +41,6 @@ void CommandQueueMT::unlock() {
mutex.unlock();
}
-void CommandQueueMT::wait_for_flush() {
- // wait one millisecond for a flush to happen
- OS::get_singleton()->delay_usec(1000);
-}
-
-CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() {
- int idx = -1;
-
- while (true) {
- lock();
- for (int i = 0; i < SYNC_SEMAPHORES; i++) {
- if (!sync_sems[i].in_use) {
- sync_sems[i].in_use = true;
- idx = i;
- break;
- }
- }
- unlock();
-
- if (idx == -1) {
- wait_for_flush();
- } else {
- break;
- }
- }
-
- return &sync_sems[idx];
-}
-
CommandQueueMT::CommandQueueMT() {
}
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index a4ac338bed..c149861467 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -32,9 +32,9 @@
#define COMMAND_QUEUE_MT_H
#include "core/object/worker_thread_pool.h"
+#include "core/os/condition_variable.h"
#include "core/os/memory.h"
#include "core/os/mutex.h"
-#include "core/os/semaphore.h"
#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/simple_type.h"
@@ -251,14 +251,14 @@
#define DECL_PUSH(N) \
template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
void push(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \
- CMD_TYPE(N) *cmd = allocate_and_lock<CMD_TYPE(N)>(); \
+ MutexLock mlock(mutex); \
+ CMD_TYPE(N) *cmd = allocate<CMD_TYPE(N)>(); \
cmd->instance = p_instance; \
cmd->method = p_method; \
SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \
if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \
WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \
} \
- unlock(); \
}
#define CMD_RET_TYPE(N) CommandRet##N<T, M, COMMA_SEP_LIST(TYPE_ARG, N) COMMA(N) R>
@@ -266,19 +266,17 @@
#define DECL_PUSH_AND_RET(N) \
template <typename T, typename M, COMMA_SEP_LIST(TYPE_PARAM, N) COMMA(N) typename R> \
void push_and_ret(T *p_instance, M p_method, COMMA_SEP_LIST(PARAM, N) COMMA(N) R *r_ret) { \
- SyncSemaphore *ss = _alloc_sync_sem(); \
- CMD_RET_TYPE(N) *cmd = allocate_and_lock<CMD_RET_TYPE(N)>(); \
+ MutexLock mlock(mutex); \
+ CMD_RET_TYPE(N) *cmd = allocate<CMD_RET_TYPE(N)>(); \
cmd->instance = p_instance; \
cmd->method = p_method; \
SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \
cmd->ret = r_ret; \
- cmd->sync_sem = ss; \
if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \
WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \
} \
- unlock(); \
- ss->sem.wait(); \
- ss->in_use = false; \
+ sync_tail++; \
+ _wait_for_sync(mlock); \
}
#define CMD_SYNC_TYPE(N) CommandSync##N<T, M COMMA(N) COMMA_SEP_LIST(TYPE_ARG, N)>
@@ -286,39 +284,31 @@
#define DECL_PUSH_AND_SYNC(N) \
template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
void push_and_sync(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \
- SyncSemaphore *ss = _alloc_sync_sem(); \
- CMD_SYNC_TYPE(N) *cmd = allocate_and_lock<CMD_SYNC_TYPE(N)>(); \
+ MutexLock mlock(mutex); \
+ CMD_SYNC_TYPE(N) *cmd = allocate<CMD_SYNC_TYPE(N)>(); \
cmd->instance = p_instance; \
cmd->method = p_method; \
SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \
- cmd->sync_sem = ss; \
if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \
WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \
} \
- unlock(); \
- ss->sem.wait(); \
- ss->in_use = false; \
+ sync_tail++; \
+ _wait_for_sync(mlock); \
}
#define MAX_CMD_PARAMS 15
class CommandQueueMT {
- struct SyncSemaphore {
- Semaphore sem;
- bool in_use = false;
- };
-
struct CommandBase {
+ bool sync = false;
virtual void call() = 0;
- virtual SyncSemaphore *get_sync_semaphore() { return nullptr; }
virtual ~CommandBase() = default; // Won't be called.
};
struct SyncCommand : public CommandBase {
- SyncSemaphore *sync_sem = nullptr;
-
- virtual SyncSemaphore *get_sync_semaphore() override {
- return sync_sem;
+ virtual void call() override {}
+ SyncCommand() {
+ sync = true;
}
};
@@ -340,9 +330,11 @@ class CommandQueueMT {
SYNC_SEMAPHORES = 8
};
+ BinaryMutex mutex;
LocalVector<uint8_t> command_mem;
- SyncSemaphore sync_sems[SYNC_SEMAPHORES];
- Mutex mutex;
+ ConditionVariable sync_cond_var;
+ uint32_t sync_head = 0;
+ uint32_t sync_tail = 0;
WorkerThreadPool::TaskID pump_task_id = WorkerThreadPool::INVALID_TASK_ID;
uint64_t flush_read_ptr = 0;
@@ -357,32 +349,23 @@ class CommandQueueMT {
return cmd;
}
- template <typename T>
- T *allocate_and_lock() {
- lock();
- T *ret = allocate<T>();
- return ret;
- }
-
void _flush() {
- lock();
-
if (unlikely(flush_read_ptr)) {
// Re-entrant call.
- unlock();
return;
}
+ lock();
+
WorkerThreadPool::thread_enter_command_queue_mt_flush(this);
while (flush_read_ptr < command_mem.size()) {
uint64_t size = *(uint64_t *)&command_mem[flush_read_ptr];
flush_read_ptr += 8;
CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]);
-
- SyncSemaphore *sync_sem = cmd->get_sync_semaphore();
cmd->call();
- if (sync_sem) {
- sync_sem->sem.post(); // Release in case it needs sync/ret.
+ if (unlikely(cmd->sync)) {
+ sync_head++;
+ sync_cond_var.notify_all();
}
flush_read_ptr += size;
@@ -394,8 +377,12 @@ class CommandQueueMT {
unlock();
}
- void wait_for_flush();
- SyncSemaphore *_alloc_sync_sem();
+ _FORCE_INLINE_ void _wait_for_sync(MutexLock<BinaryMutex> &p_lock) {
+ uint32_t sync_head_goal = sync_tail;
+ do {
+ sync_cond_var.wait(p_lock);
+ } while (sync_head != sync_head_goal); // Can't use lower-than because of wraparound.
+ }
public:
void lock();
diff --git a/core/templates/ring_buffer.h b/core/templates/ring_buffer.h
index 54148a59bf..f5161cefa4 100644
--- a/core/templates/ring_buffer.h
+++ b/core/templates/ring_buffer.h
@@ -211,10 +211,10 @@ public:
size_mask = mask;
}
- RingBuffer<T>(int p_power = 0) {
+ RingBuffer(int p_power = 0) {
resize(p_power);
}
- ~RingBuffer<T>() {}
+ ~RingBuffer() {}
};
#endif // RING_BUFFER_H
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index 637b068da9..16b605eaff 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -146,7 +146,7 @@ public:
}
}
- _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
+ _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) {
set(p_value);
}
};
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index 123f2067e2..c8d1241d3d 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -159,10 +159,7 @@ MAKE_PTRARG_BY_REFERENCE(Variant);
template <typename T>
struct PtrToArg<T *> {
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
- if (p_ptr == nullptr) {
- return nullptr;
- }
- return const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr));
+ return likely(p_ptr) ? const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr)) : nullptr;
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
@@ -173,10 +170,7 @@ struct PtrToArg<T *> {
template <typename T>
struct PtrToArg<const T *> {
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
- if (p_ptr == nullptr) {
- return nullptr;
- }
- return *reinterpret_cast<T *const *>(p_ptr);
+ return likely(p_ptr) ? *reinterpret_cast<T *const *>(p_ptr) : nullptr;
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index 9c52db3345..15cb6c9c1a 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -33,31 +33,7 @@
#include "core/typedefs.h"
-template <bool C, typename T = void>
-struct EnableIf {
- typedef T type;
-};
-
-template <typename T>
-struct EnableIf<false, T> {
-};
-
-template <typename, typename>
-inline constexpr bool types_are_same_v = false;
-
-template <typename T>
-inline constexpr bool types_are_same_v<T, T> = true;
-
-template <typename B, typename D>
-struct TypeInherits {
- static D *get_d();
-
- static char (&test(B *))[1];
- static char (&test(...))[2];
-
- static bool const value = sizeof(test(get_d())) == sizeof(char) &&
- !types_are_same_v<B volatile const, void volatile const>;
-};
+#include <type_traits>
namespace GodotTypeInfo {
enum Metadata {
@@ -223,16 +199,7 @@ MAKE_TEMPLATE_TYPE_INFO(Vector, Face3, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::PACKED_STRING_ARRAY)
template <typename T>
-struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
- static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
- static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
- static inline PropertyInfo get_class_info() {
- return PropertyInfo(StringName(T::get_class_static()));
- }
-};
-
-template <typename T>
-struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
+struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 155a5b2781..fcbfdd4741 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -2373,184 +2373,183 @@ Variant::operator IPAddress() const {
return IPAddress(operator String());
}
-Variant::Variant(bool p_bool) {
- type = BOOL;
+Variant::Variant(bool p_bool) :
+ type(BOOL) {
_data._bool = p_bool;
}
-Variant::Variant(int64_t p_int64) {
- type = INT;
+Variant::Variant(int64_t p_int64) :
+ type(INT) {
_data._int = p_int64;
}
-Variant::Variant(int32_t p_int32) {
- type = INT;
+Variant::Variant(int32_t p_int32) :
+ type(INT) {
_data._int = p_int32;
}
-Variant::Variant(int16_t p_int16) {
- type = INT;
+Variant::Variant(int16_t p_int16) :
+ type(INT) {
_data._int = p_int16;
}
-Variant::Variant(int8_t p_int8) {
- type = INT;
+Variant::Variant(int8_t p_int8) :
+ type(INT) {
_data._int = p_int8;
}
-Variant::Variant(uint64_t p_uint64) {
- type = INT;
+Variant::Variant(uint64_t p_uint64) :
+ type(INT) {
_data._int = p_uint64;
}
-Variant::Variant(uint32_t p_uint32) {
- type = INT;
+Variant::Variant(uint32_t p_uint32) :
+ type(INT) {
_data._int = p_uint32;
}
-Variant::Variant(uint16_t p_uint16) {
- type = INT;
+Variant::Variant(uint16_t p_uint16) :
+ type(INT) {
_data._int = p_uint16;
}
-Variant::Variant(uint8_t p_uint8) {
- type = INT;
+Variant::Variant(uint8_t p_uint8) :
+ type(INT) {
_data._int = p_uint8;
}
-Variant::Variant(float p_float) {
- type = FLOAT;
+Variant::Variant(float p_float) :
+ type(FLOAT) {
_data._float = p_float;
}
-Variant::Variant(double p_double) {
- type = FLOAT;
+Variant::Variant(double p_double) :
+ type(FLOAT) {
_data._float = p_double;
}
-Variant::Variant(const ObjectID &p_id) {
- type = INT;
+Variant::Variant(const ObjectID &p_id) :
+ type(INT) {
_data._int = p_id;
}
-Variant::Variant(const StringName &p_string) {
- type = STRING_NAME;
+Variant::Variant(const StringName &p_string) :
+ type(STRING_NAME) {
memnew_placement(_data._mem, StringName(p_string));
}
-Variant::Variant(const String &p_string) {
- type = STRING;
+Variant::Variant(const String &p_string) :
+ type(STRING) {
memnew_placement(_data._mem, String(p_string));
}
-Variant::Variant(const char *const p_cstring) {
- type = STRING;
+Variant::Variant(const char *const p_cstring) :
+ type(STRING) {
memnew_placement(_data._mem, String((const char *)p_cstring));
}
-Variant::Variant(const char32_t *p_wstring) {
- type = STRING;
+Variant::Variant(const char32_t *p_wstring) :
+ type(STRING) {
memnew_placement(_data._mem, String(p_wstring));
}
-Variant::Variant(const Vector3 &p_vector3) {
- type = VECTOR3;
+Variant::Variant(const Vector3 &p_vector3) :
+ type(VECTOR3) {
memnew_placement(_data._mem, Vector3(p_vector3));
}
-Variant::Variant(const Vector3i &p_vector3i) {
- type = VECTOR3I;
+Variant::Variant(const Vector3i &p_vector3i) :
+ type(VECTOR3I) {
memnew_placement(_data._mem, Vector3i(p_vector3i));
}
-Variant::Variant(const Vector4 &p_vector4) {
- type = VECTOR4;
+Variant::Variant(const Vector4 &p_vector4) :
+ type(VECTOR4) {
memnew_placement(_data._mem, Vector4(p_vector4));
}
-Variant::Variant(const Vector4i &p_vector4i) {
- type = VECTOR4I;
+Variant::Variant(const Vector4i &p_vector4i) :
+ type(VECTOR4I) {
memnew_placement(_data._mem, Vector4i(p_vector4i));
}
-Variant::Variant(const Vector2 &p_vector2) {
- type = VECTOR2;
+Variant::Variant(const Vector2 &p_vector2) :
+ type(VECTOR2) {
memnew_placement(_data._mem, Vector2(p_vector2));
}
-Variant::Variant(const Vector2i &p_vector2i) {
- type = VECTOR2I;
+Variant::Variant(const Vector2i &p_vector2i) :
+ type(VECTOR2I) {
memnew_placement(_data._mem, Vector2i(p_vector2i));
}
-Variant::Variant(const Rect2 &p_rect2) {
- type = RECT2;
+Variant::Variant(const Rect2 &p_rect2) :
+ type(RECT2) {
memnew_placement(_data._mem, Rect2(p_rect2));
}
-Variant::Variant(const Rect2i &p_rect2i) {
- type = RECT2I;
+Variant::Variant(const Rect2i &p_rect2i) :
+ type(RECT2I) {
memnew_placement(_data._mem, Rect2i(p_rect2i));
}
-Variant::Variant(const Plane &p_plane) {
- type = PLANE;
+Variant::Variant(const Plane &p_plane) :
+ type(PLANE) {
memnew_placement(_data._mem, Plane(p_plane));
}
-Variant::Variant(const ::AABB &p_aabb) {
- type = AABB;
+Variant::Variant(const ::AABB &p_aabb) :
+ type(AABB) {
_data._aabb = (::AABB *)Pools::_bucket_small.alloc();
memnew_placement(_data._aabb, ::AABB(p_aabb));
}
-Variant::Variant(const Basis &p_matrix) {
- type = BASIS;
+Variant::Variant(const Basis &p_matrix) :
+ type(BASIS) {
_data._basis = (Basis *)Pools::_bucket_medium.alloc();
memnew_placement(_data._basis, Basis(p_matrix));
}
-Variant::Variant(const Quaternion &p_quaternion) {
- type = QUATERNION;
+Variant::Variant(const Quaternion &p_quaternion) :
+ type(QUATERNION) {
memnew_placement(_data._mem, Quaternion(p_quaternion));
}
-Variant::Variant(const Transform3D &p_transform) {
- type = TRANSFORM3D;
+Variant::Variant(const Transform3D &p_transform) :
+ type(TRANSFORM3D) {
_data._transform3d = (Transform3D *)Pools::_bucket_medium.alloc();
memnew_placement(_data._transform3d, Transform3D(p_transform));
}
-Variant::Variant(const Projection &pp_projection) {
- type = PROJECTION;
+Variant::Variant(const Projection &pp_projection) :
+ type(PROJECTION) {
_data._projection = (Projection *)Pools::_bucket_large.alloc();
memnew_placement(_data._projection, Projection(pp_projection));
}
-Variant::Variant(const Transform2D &p_transform) {
- type = TRANSFORM2D;
+Variant::Variant(const Transform2D &p_transform) :
+ type(TRANSFORM2D) {
_data._transform2d = (Transform2D *)Pools::_bucket_small.alloc();
memnew_placement(_data._transform2d, Transform2D(p_transform));
}
-Variant::Variant(const Color &p_color) {
- type = COLOR;
+Variant::Variant(const Color &p_color) :
+ type(COLOR) {
memnew_placement(_data._mem, Color(p_color));
}
-Variant::Variant(const NodePath &p_node_path) {
- type = NODE_PATH;
+Variant::Variant(const NodePath &p_node_path) :
+ type(NODE_PATH) {
memnew_placement(_data._mem, NodePath(p_node_path));
}
-Variant::Variant(const ::RID &p_rid) {
- type = RID;
+Variant::Variant(const ::RID &p_rid) :
+ type(RID) {
memnew_placement(_data._mem, ::RID(p_rid));
}
-Variant::Variant(const Object *p_object) {
- type = OBJECT;
-
+Variant::Variant(const Object *p_object) :
+ type(OBJECT) {
memnew_placement(_data._mem, ObjData);
if (p_object) {
@@ -2571,76 +2570,74 @@ Variant::Variant(const Object *p_object) {
}
}
-Variant::Variant(const Callable &p_callable) {
- type = CALLABLE;
+Variant::Variant(const Callable &p_callable) :
+ type(CALLABLE) {
memnew_placement(_data._mem, Callable(p_callable));
}
-Variant::Variant(const Signal &p_callable) {
- type = SIGNAL;
+Variant::Variant(const Signal &p_callable) :
+ type(SIGNAL) {
memnew_placement(_data._mem, Signal(p_callable));
}
-Variant::Variant(const Dictionary &p_dictionary) {
- type = DICTIONARY;
+Variant::Variant(const Dictionary &p_dictionary) :
+ type(DICTIONARY) {
memnew_placement(_data._mem, Dictionary(p_dictionary));
}
-Variant::Variant(const Array &p_array) {
- type = ARRAY;
+Variant::Variant(const Array &p_array) :
+ type(ARRAY) {
memnew_placement(_data._mem, Array(p_array));
}
-Variant::Variant(const PackedByteArray &p_byte_array) {
- type = PACKED_BYTE_ARRAY;
-
+Variant::Variant(const PackedByteArray &p_byte_array) :
+ type(PACKED_BYTE_ARRAY) {
_data.packed_array = PackedArrayRef<uint8_t>::create(p_byte_array);
}
-Variant::Variant(const PackedInt32Array &p_int32_array) {
- type = PACKED_INT32_ARRAY;
+Variant::Variant(const PackedInt32Array &p_int32_array) :
+ type(PACKED_INT32_ARRAY) {
_data.packed_array = PackedArrayRef<int32_t>::create(p_int32_array);
}
-Variant::Variant(const PackedInt64Array &p_int64_array) {
- type = PACKED_INT64_ARRAY;
+Variant::Variant(const PackedInt64Array &p_int64_array) :
+ type(PACKED_INT64_ARRAY) {
_data.packed_array = PackedArrayRef<int64_t>::create(p_int64_array);
}
-Variant::Variant(const PackedFloat32Array &p_float32_array) {
- type = PACKED_FLOAT32_ARRAY;
+Variant::Variant(const PackedFloat32Array &p_float32_array) :
+ type(PACKED_FLOAT32_ARRAY) {
_data.packed_array = PackedArrayRef<float>::create(p_float32_array);
}
-Variant::Variant(const PackedFloat64Array &p_float64_array) {
- type = PACKED_FLOAT64_ARRAY;
+Variant::Variant(const PackedFloat64Array &p_float64_array) :
+ type(PACKED_FLOAT64_ARRAY) {
_data.packed_array = PackedArrayRef<double>::create(p_float64_array);
}
-Variant::Variant(const PackedStringArray &p_string_array) {
- type = PACKED_STRING_ARRAY;
+Variant::Variant(const PackedStringArray &p_string_array) :
+ type(PACKED_STRING_ARRAY) {
_data.packed_array = PackedArrayRef<String>::create(p_string_array);
}
-Variant::Variant(const PackedVector2Array &p_vector2_array) {
- type = PACKED_VECTOR2_ARRAY;
+Variant::Variant(const PackedVector2Array &p_vector2_array) :
+ type(PACKED_VECTOR2_ARRAY) {
_data.packed_array = PackedArrayRef<Vector2>::create(p_vector2_array);
}
-Variant::Variant(const PackedVector3Array &p_vector3_array) {
- type = PACKED_VECTOR3_ARRAY;
+Variant::Variant(const PackedVector3Array &p_vector3_array) :
+ type(PACKED_VECTOR3_ARRAY) {
_data.packed_array = PackedArrayRef<Vector3>::create(p_vector3_array);
}
-Variant::Variant(const PackedColorArray &p_color_array) {
- type = PACKED_COLOR_ARRAY;
+Variant::Variant(const PackedColorArray &p_color_array) :
+ type(PACKED_COLOR_ARRAY) {
_data.packed_array = PackedArrayRef<Color>::create(p_color_array);
}
/* helpers */
-Variant::Variant(const Vector<::RID> &p_array) {
- type = ARRAY;
-
+Variant::Variant(const Vector<::RID> &p_array) :
+ type(ARRAY) {
Array *rid_array = memnew_placement(_data._mem, Array);
rid_array->resize(p_array.size());
@@ -2650,9 +2647,8 @@ Variant::Variant(const Vector<::RID> &p_array) {
}
}
-Variant::Variant(const Vector<Plane> &p_array) {
- type = ARRAY;
-
+Variant::Variant(const Vector<Plane> &p_array) :
+ type(ARRAY) {
Array *plane_array = memnew_placement(_data._mem, Array);
plane_array->resize(p_array.size());
@@ -2662,7 +2658,8 @@ Variant::Variant(const Vector<Plane> &p_array) {
}
}
-Variant::Variant(const Vector<Face3> &p_face_array) {
+Variant::Variant(const Vector<Face3> &p_face_array) :
+ type(NIL) {
PackedVector3Array vertices;
int face_count = p_face_array.size();
vertices.resize(face_count * 3);
@@ -2678,13 +2675,11 @@ Variant::Variant(const Vector<Face3> &p_face_array) {
}
}
- type = NIL;
-
*this = vertices;
}
-Variant::Variant(const Vector<Variant> &p_array) {
- type = NIL;
+Variant::Variant(const Vector<Variant> &p_array) :
+ type(NIL) {
Array arr;
arr.resize(p_array.size());
for (int i = 0; i < p_array.size(); i++) {
@@ -2693,8 +2688,8 @@ Variant::Variant(const Vector<Variant> &p_array) {
*this = arr;
}
-Variant::Variant(const Vector<StringName> &p_array) {
- type = NIL;
+Variant::Variant(const Vector<StringName> &p_array) :
+ type(NIL) {
PackedStringArray v;
int len = p_array.size();
v.resize(len);
@@ -2863,12 +2858,13 @@ void Variant::operator=(const Variant &p_variant) {
}
}
-Variant::Variant(const IPAddress &p_address) {
- type = STRING;
+Variant::Variant(const IPAddress &p_address) :
+ type(STRING) {
memnew_placement(_data._mem, String(p_address));
}
-Variant::Variant(const Variant &p_variant) {
+Variant::Variant(const Variant &p_variant) :
+ type(NIL) {
reference(p_variant);
}
@@ -3499,50 +3495,6 @@ bool Variant::is_ref_counted() const {
return type == OBJECT && _get_obj().id.is_ref_counted();
}
-Vector<Variant> varray() {
- return Vector<Variant>();
-}
-
-Vector<Variant> varray(const Variant &p_arg1) {
- Vector<Variant> v;
- v.push_back(p_arg1);
- return v;
-}
-
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2) {
- Vector<Variant> v;
- v.push_back(p_arg1);
- v.push_back(p_arg2);
- return v;
-}
-
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) {
- Vector<Variant> v;
- v.push_back(p_arg1);
- v.push_back(p_arg2);
- v.push_back(p_arg3);
- return v;
-}
-
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4) {
- Vector<Variant> v;
- v.push_back(p_arg1);
- v.push_back(p_arg2);
- v.push_back(p_arg3);
- v.push_back(p_arg4);
- return v;
-}
-
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5) {
- Vector<Variant> v;
- v.push_back(p_arg1);
- v.push_back(p_arg2);
- v.push_back(p_arg3);
- v.push_back(p_arg4);
- v.push_back(p_arg5);
- return v;
-}
-
void Variant::static_assign(const Variant &p_variant) {
}
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 10f8dc3c7f..ea6ae02c1e 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -165,7 +165,7 @@ private:
// Variant takes 20 bytes when real_t is float, and 36 if double
// it only allocates extra memory for aabb/matrix.
- Type type = NIL;
+ Type type;
struct ObjData {
ObjectID id;
@@ -483,8 +483,8 @@ public:
Variant(const IPAddress &p_address);
#define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \
- Variant(m_enum p_value) { \
- type = INT; \
+ Variant(m_enum p_value) : \
+ type(INT) { \
_data._int = (int64_t)p_value; \
}
@@ -788,7 +788,8 @@ public:
static void unregister_types();
Variant(const Variant &p_variant);
- _FORCE_INLINE_ Variant() {}
+ _FORCE_INLINE_ Variant() :
+ type(NIL) {}
_FORCE_INLINE_ ~Variant() {
clear();
}
@@ -797,12 +798,23 @@ public:
//typedef Dictionary Dictionary; no
//typedef Array Array;
-Vector<Variant> varray();
-Vector<Variant> varray(const Variant &p_arg1);
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2);
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3);
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4);
-Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5);
+template <typename... VarArgs>
+Vector<Variant> varray(VarArgs... p_args) {
+ Vector<Variant> v;
+
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ uint32_t argc = sizeof...(p_args);
+
+ if (argc > 0) {
+ v.resize(argc);
+ Variant *vw = v.ptrw();
+
+ for (uint32_t i = 0; i < argc; i++) {
+ vw[i] = args[i];
+ }
+ }
+ return v;
+}
struct VariantHasher {
static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); }
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index dcb94b16b1..50f8007efa 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -489,11 +489,11 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.value = num.as_int();
}
return OK;
- } else if (is_ascii_char(cchar) || is_underscore(cchar)) {
+ } else if (is_ascii_alphabet_char(cchar) || is_underscore(cchar)) {
StringBuffer<> id;
bool first = true;
- while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) {
+ while (is_ascii_alphabet_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) {
id += cchar;
cchar = p_stream->get_char();
first = false;
@@ -1789,7 +1789,7 @@ static String rtos_fix(double p_value) {
}
}
-Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count) {
+Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) {
switch (p_variant.get_type()) {
case Variant::NIL: {
p_store_string_func(p_store_string_ud, "null");
@@ -2009,7 +2009,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
}
p_store_string_func(p_store_string_ud, "\"" + E.name + "\":");
- write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
}
}
@@ -2035,9 +2035,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
p_store_string_func(p_store_string_ud, "{\n");
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
p_store_string_func(p_store_string_ud, ": ");
- write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
if (E->next()) {
p_store_string_func(p_store_string_ud, ",\n");
} else {
@@ -2096,7 +2096,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} else {
p_store_string_func(p_store_string_ud, ", ");
}
- write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
}
p_store_string_func(p_store_string_ud, "]");
@@ -2110,7 +2110,16 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
case Variant::PACKED_BYTE_ARRAY: {
p_store_string_func(p_store_string_ud, "PackedByteArray(");
Vector<uint8_t> data = p_variant;
- if (data.size() > 0) {
+ if (p_compat) {
+ int len = data.size();
+ const uint8_t *ptr = data.ptr();
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ p_store_string_func(p_store_string_ud, ", ");
+ }
+ p_store_string_func(p_store_string_ud, itos(ptr[i]));
+ }
+ } else if (data.size() > 0) {
p_store_string_func(p_store_string_ud, "\"");
p_store_string_func(p_store_string_ud, CryptoCore::b64_encode_str(data.ptr(), data.size()));
p_store_string_func(p_store_string_ud, "\"");
@@ -2255,8 +2264,8 @@ static Error _write_to_str(void *ud, const String &p_string) {
return OK;
}
-Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) {
+Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, bool p_compat) {
r_string = String();
- return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud);
+ return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud, 0, p_compat);
}
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index 2f8974849f..b0ac07170d 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -161,8 +161,8 @@ public:
typedef Error (*StoreStringFunc)(void *ud, const String &p_string);
typedef String (*EncodeResourceFunc)(void *ud, const Ref<Resource> &p_resource);
- static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0);
- static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr);
+ static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0, bool p_compat = true);
+ static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr, bool p_compat = true);
};
#endif // VARIANT_PARSER_H
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 9d5ed22b1a..f49e9e54b3 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -251,15 +251,21 @@ void Variant::set_named(const StringName &p_member, const Variant &p_value, bool
return;
}
} else if (type == Variant::DICTIONARY) {
- Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member);
+ Dictionary &dict = *VariantGetInternalPtr<Dictionary>::get_ptr(this);
+
+ if (dict.is_read_only()) {
+ r_valid = false;
+ return;
+ }
+
+ Variant *v = dict.getptr(p_member);
if (v) {
*v = p_value;
- r_valid = true;
} else {
- VariantGetInternalPtr<Dictionary>::get_ptr(this)->operator[](p_member) = p_value;
- r_valid = true;
+ dict[p_member] = p_value;
}
+ r_valid = true;
} else {
r_valid = false;
}