summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/engine.cpp12
-rw-r--r--core/config/engine.h6
-rw-r--r--core/config/project_settings.cpp38
-rw-r--r--core/config/project_settings.h6
-rw-r--r--core/core_bind.cpp19
-rw-r--r--core/core_bind.h2
-rw-r--r--core/doc_data.h44
-rw-r--r--core/error/error_macros.h15
-rw-r--r--core/extension/gdextension.cpp60
-rw-r--r--core/extension/gdextension.h8
-rw-r--r--core/extension/gdextension_interface.cpp20
-rw-r--r--core/extension/gdextension_interface.h13
-rw-r--r--core/input/input.cpp12
-rw-r--r--core/input/input.h4
-rw-r--r--core/io/file_access.cpp74
-rw-r--r--core/io/file_access.h34
-rw-r--r--core/io/file_access_compressed.cpp32
-rw-r--r--core/io/file_access_compressed.h9
-rw-r--r--core/io/file_access_encrypted.cpp41
-rw-r--r--core/io/file_access_encrypted.h9
-rw-r--r--core/io/file_access_memory.h9
-rw-r--r--core/io/file_access_pack.h9
-rw-r--r--core/io/file_access_zip.h9
-rw-r--r--core/io/image.cpp20
-rw-r--r--core/io/image.h4
-rw-r--r--core/io/remote_filesystem_client.cpp2
-rw-r--r--core/io/remote_filesystem_client.h4
-rw-r--r--core/io/resource.cpp5
-rw-r--r--core/io/resource.h2
-rw-r--r--core/io/resource_loader.cpp4
-rw-r--r--core/math/a_star_grid_2d.cpp34
-rw-r--r--core/math/a_star_grid_2d.h3
-rw-r--r--core/math/delaunay_3d.h13
-rw-r--r--core/object/class_db.cpp10
-rw-r--r--core/object/message_queue.cpp51
-rw-r--r--core/string/locales.h6
-rw-r--r--core/string/ustring.cpp27
-rw-r--r--core/string/ustring.h1
-rw-r--r--core/variant/typed_array.h3
-rw-r--r--core/variant/variant.cpp18
-rw-r--r--core/variant/variant_call.cpp1
-rw-r--r--core/variant/variant_op.h8
-rw-r--r--core/variant/variant_utility.cpp1571
-rw-r--r--core/variant/variant_utility.h153
44 files changed, 1525 insertions, 900 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 7fdea7d1aa..17d3bdb744 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -74,6 +74,14 @@ int Engine::get_max_fps() const {
return _max_fps;
}
+void Engine::set_audio_output_latency(int p_msec) {
+ _audio_output_latency = p_msec > 1 ? p_msec : 1;
+}
+
+int Engine::get_audio_output_latency() const {
+ return _audio_output_latency;
+}
+
uint64_t Engine::get_frames_drawn() {
return frames_drawn;
}
@@ -239,6 +247,10 @@ bool Engine::is_validation_layers_enabled() const {
return use_validation_layers;
}
+bool Engine::is_generate_spirv_debug_info_enabled() const {
+ return generate_spirv_debug_info;
+}
+
void Engine::set_print_error_messages(bool p_enabled) {
CoreGlobals::print_error_enabled = p_enabled;
}
diff --git a/core/config/engine.h b/core/config/engine.h
index 5ea653ba6c..ff88fbc787 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -61,12 +61,14 @@ private:
double physics_jitter_fix = 0.5;
double _fps = 1;
int _max_fps = 0;
+ int _audio_output_latency = 0;
double _time_scale = 1.0;
uint64_t _physics_frames = 0;
int max_physics_steps_per_frame = 8;
double _physics_interpolation_fraction = 0.0f;
bool abort_on_gpu_errors = false;
bool use_validation_layers = false;
+ bool generate_spirv_debug_info = false;
int32_t gpu_idx = -1;
uint64_t _process_frames = 0;
@@ -98,6 +100,9 @@ public:
virtual void set_max_fps(int p_fps);
virtual int get_max_fps() const;
+ virtual void set_audio_output_latency(int p_msec);
+ virtual int get_audio_output_latency() const;
+
virtual double get_frames_per_second() const { return _fps; }
uint64_t get_frames_drawn();
@@ -156,6 +161,7 @@ public:
bool is_abort_on_gpu_errors_enabled() const;
bool is_validation_layers_enabled() const;
+ bool is_generate_spirv_debug_info_enabled() const;
int32_t get_gpu_index() const;
Engine();
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 715ed61770..1bfb745662 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -146,30 +146,30 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
- if (resource_path.is_empty() || (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
- return p_path.simplify_path();
+ String path = p_path.simplify_path();
+
+ if (resource_path.is_empty() || (path.is_absolute_path() && !path.begins_with(resource_path))) {
+ return path;
}
// Check if we have a special path (like res://) or a protocol identifier.
- int p = p_path.find("://");
+ int p = path.find("://");
bool found = false;
if (p > 0) {
found = true;
for (int i = 0; i < p; i++) {
- if (!is_ascii_alphanumeric_char(p_path[i])) {
+ if (!is_ascii_alphanumeric_char(path[i])) {
found = false;
break;
}
}
}
if (found) {
- return p_path.simplify_path();
+ return path;
}
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- String path = p_path.replace("\\", "/").simplify_path();
-
if (dir->change_dir(path) == OK) {
String cwd = dir->get_current_dir();
cwd = cwd.replace("\\", "/");
@@ -187,7 +187,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
cwd = cwd.path_join("");
if (!cwd.begins_with(res_path)) {
- return p_path;
+ return path;
}
return cwd.replace_first(res_path, "res://");
@@ -283,6 +283,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < custom_feature_array.size(); i++) {
custom_features.insert(custom_feature_array[i]);
}
+ _queue_changed();
return true;
}
@@ -324,6 +325,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
}
}
+ _queue_changed();
return true;
}
@@ -424,6 +426,22 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void ProjectSettings::_queue_changed() {
+ if (is_changed || !MessageQueue::get_singleton() || MessageQueue::get_singleton()->get_max_buffer_usage() == 0) {
+ return;
+ }
+ is_changed = true;
+ callable_mp(this, &ProjectSettings::_emit_changed).call_deferred();
+}
+
+void ProjectSettings::_emit_changed() {
+ if (!is_changed) {
+ return;
+ }
+ is_changed = false;
+ emit_signal("settings_changed");
+}
+
bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
if (PackedData::get_singleton()->is_disabled()) {
return false;
@@ -1225,6 +1243,8 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
+
+ ADD_SIGNAL(MethodInfo("settings_changed"));
}
void ProjectSettings::_add_builtin_input_map() {
@@ -1260,6 +1280,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("application/config/name", "");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary());
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT), "");
+ GLOBAL_DEF_BASIC("application/config/version", "");
GLOBAL_DEF_INTERNAL(PropertyInfo(Variant::STRING, "application/config/tags"), PackedStringArray());
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"), "");
GLOBAL_DEF("application/run/disable_stdout", false);
@@ -1328,6 +1349,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,canvas_items,viewport"), "disabled");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"), "keep");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "display/window/stretch/scale", PROPERTY_HINT_RANGE, "0.5,8.0,0.01"), 1.0);
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/scale_mode", PROPERTY_HINT_ENUM, "fractional,integer"), "fractional");
GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"), 16384);
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index b89e6694b0..dba4aa6822 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -43,6 +43,9 @@ class TypedArray;
class ProjectSettings : public Object {
GDCLASS(ProjectSettings, Object);
_THREAD_SAFE_CLASS_
+ friend class TestProjectSettingsInternalsAccessor;
+
+ bool is_changed = false;
public:
typedef HashMap<String, Variant> CustomMap;
@@ -114,6 +117,9 @@ protected:
bool _property_can_revert(const StringName &p_name) const;
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
+ void _queue_changed();
+ void _emit_changed();
+
static ProjectSettings *singleton;
Error _load_settings_text(const String &p_path);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index a73b198be2..05fe393a2f 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -929,6 +929,17 @@ Geometry3D *Geometry3D::get_singleton() {
return singleton;
}
+Vector<Vector3> Geometry3D::compute_convex_mesh_points(const TypedArray<Plane> &p_planes) {
+ Vector<Plane> planes_vec;
+ int size = p_planes.size();
+ planes_vec.resize(size);
+ for (int i = 0; i < size; ++i) {
+ planes_vec.set(i, p_planes[i]);
+ }
+ Variant ret = ::Geometry3D::compute_convex_mesh_points(planes_vec.ptr(), size);
+ return ret;
+}
+
TypedArray<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
Variant ret = ::Geometry3D::build_box_planes(p_extents);
return ret;
@@ -961,6 +972,11 @@ Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point
return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, s);
}
+Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) {
+ Vector3 res = ::Geometry3D::triangle_get_barycentric_coords(p_v0, p_v1, p_v2, p_point);
+ return res;
+}
+
Variant Geometry3D::ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) {
Vector3 res;
if (::Geometry3D::ray_intersects_triangle(p_from, p_dir, p_v0, p_v1, p_v2, &res)) {
@@ -1024,6 +1040,7 @@ Vector<Vector3> Geometry3D::clip_polygon(const Vector<Vector3> &p_points, const
}
void Geometry3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("compute_convex_mesh_points", "planes"), &Geometry3D::compute_convex_mesh_points);
ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &Geometry3D::build_box_planes);
ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &Geometry3D::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z));
ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &Geometry3D::build_capsule_planes, DEFVAL(Vector3::AXIS_Z));
@@ -1034,6 +1051,8 @@ void Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped", "point", "s1", "s2"), &Geometry3D::get_closest_point_to_segment_uncapped);
+ ClassDB::bind_method(D_METHOD("get_triangle_barycentric_coords", "point", "a", "b", "c"), &Geometry3D::get_triangle_barycentric_coords);
+
ClassDB::bind_method(D_METHOD("ray_intersects_triangle", "from", "dir", "a", "b", "c"), &Geometry3D::ray_intersects_triangle);
ClassDB::bind_method(D_METHOD("segment_intersects_triangle", "from", "to", "a", "b", "c"), &Geometry3D::segment_intersects_triangle);
ClassDB::bind_method(D_METHOD("segment_intersects_sphere", "from", "to", "sphere_position", "sphere_radius"), &Geometry3D::segment_intersects_sphere);
diff --git a/core/core_bind.h b/core/core_bind.h
index dc0b2a1cf5..5f51b64eb7 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -320,12 +320,14 @@ protected:
public:
static Geometry3D *get_singleton();
+ Vector<Vector3> compute_convex_mesh_points(const TypedArray<Plane> &p_planes);
TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
+ Vector3 get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
diff --git a/core/doc_data.h b/core/doc_data.h
index 0fe7414b98..b8c92a4b67 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -532,6 +532,42 @@ public:
}
};
+ struct EnumDoc {
+ String description;
+ bool is_deprecated = false;
+ bool is_experimental = false;
+ static EnumDoc from_dict(const Dictionary &p_dict) {
+ EnumDoc doc;
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ return doc;
+ }
+ static Dictionary to_dict(const EnumDoc &p_doc) {
+ Dictionary dict;
+
+ if (!p_doc.description.is_empty()) {
+ dict["description"] = p_doc.description;
+ }
+
+ dict["is_deprecated"] = p_doc.is_deprecated;
+
+ dict["is_experimental"] = p_doc.is_experimental;
+
+ return dict;
+ }
+ };
+
struct ClassDoc {
String name;
String inherits;
@@ -543,7 +579,7 @@ public:
Vector<MethodDoc> operators;
Vector<MethodDoc> signals;
Vector<ConstantDoc> constants;
- HashMap<String, String> enums;
+ HashMap<String, EnumDoc> enums;
Vector<PropertyDoc> properties;
Vector<MethodDoc> annotations;
Vector<ThemeItemDoc> theme_properties;
@@ -626,7 +662,7 @@ public:
enums = p_dict["enums"];
}
for (int i = 0; i < enums.size(); i++) {
- doc.enums[enums.get_key_at_index(i)] = enums.get_value_at_index(i);
+ doc.enums[enums.get_key_at_index(i)] = EnumDoc::from_dict(enums.get_value_at_index(i));
}
Array properties;
@@ -740,8 +776,8 @@ public:
if (!p_doc.enums.is_empty()) {
Dictionary enums;
- for (const KeyValue<String, String> &E : p_doc.enums) {
- enums[E.key] = E.value;
+ for (const KeyValue<String, EnumDoc> &E : p_doc.enums) {
+ enums[E.key] = EnumDoc::to_dict(E.value);
}
dict["enums"] = enums;
}
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 65804b7796..c8182975d5 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -786,8 +786,19 @@ void _err_flush_stdout();
((void)0)
/**
- * This should be a 'free' assert for program flow and should not be needed in any releases,
- * only used in dev builds.
+ * Note: IN MOST CASES YOU SHOULD NOT USE THIS MACRO.
+ * Do not use unless you understand the trade-offs.
+ *
+ * DEV macros will be compiled out in releases, they are wrapped in DEV_ENABLED.
+ *
+ * Prefer WARNINGS / ERR_FAIL macros (which fail without crashing) - ERR_FAIL should be used in most cases.
+ * Then CRASH_NOW_MSG macros (on rare occasions where error cannot be recovered).
+ *
+ * DEV_ASSERT should generally only be used when both of the following conditions are met:
+ * 1) Bottleneck code where a check in release would be too expensive.
+ * 2) Situations where the check would fail obviously and straight away during the maintenance of the code
+ * (i.e. strict conditions that should be true no matter what)
+ * and that can't fail for other contributors once the code is finished and merged.
*/
#ifdef DEV_ENABLED
#define DEV_ASSERT(m_cond) \
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 67b55db3db..e39a531d0d 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -485,6 +485,13 @@ void GDExtension::close_library() {
ERR_FAIL_COND(library == nullptr);
OS::get_singleton()->close_dynamic_library(library);
+#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED)
+ // Delete temporary copy of library if it exists.
+ if (!temp_lib_path.is_empty() && Engine::get_singleton()->is_editor_hint()) {
+ DirAccess::remove_absolute(temp_lib_path);
+ }
+#endif
+
library = nullptr;
}
@@ -607,12 +614,13 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
}
bool compatible = true;
- if (VERSION_MAJOR < compatibility_minimum[0]) {
- compatible = false;
- } else if (VERSION_MINOR < compatibility_minimum[1]) {
- compatible = false;
- } else if (VERSION_PATCH < compatibility_minimum[2]) {
- compatible = false;
+ // Check version lexicographically.
+ if (VERSION_MAJOR != compatibility_minimum[0]) {
+ compatible = VERSION_MAJOR > compatibility_minimum[0];
+ } else if (VERSION_MINOR != compatibility_minimum[1]) {
+ compatible = VERSION_MINOR > compatibility_minimum[1];
+ } else {
+ compatible = VERSION_PATCH >= compatibility_minimum[2];
}
if (!compatible) {
if (r_error) {
@@ -640,6 +648,40 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
Ref<GDExtension> lib;
lib.instantiate();
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
+
+#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
+ // If running on the editor on Windows, we copy the library and open the copy.
+ // This is so the original file isn't locked and can be updated by a compiler.
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (!FileAccess::exists(abs_path)) {
+ if (r_error) {
+ *r_error = ERR_FILE_NOT_FOUND;
+ }
+ ERR_PRINT("GDExtension library not found: " + library_path);
+ return Ref<Resource>();
+ }
+
+ // Copy the file to the same directory as the original with a prefix in the name.
+ // This is so relative path to dependencies are satisfied.
+ String copy_path = abs_path.get_base_dir().path_join("~" + abs_path.get_file());
+
+ Error copy_err = DirAccess::copy_absolute(abs_path, copy_path);
+ if (copy_err) {
+ if (r_error) {
+ *r_error = ERR_CANT_CREATE;
+ }
+ ERR_PRINT("Error copying GDExtension library: " + library_path);
+ return Ref<Resource>();
+ }
+ FileAccess::set_hidden_attribute(copy_path, true);
+
+ // Save the copied path so it can be deleted later.
+ lib->set_temp_library_path(copy_path);
+
+ // Use the copy to open the library.
+ abs_path = copy_path;
+ }
+#endif
err = lib->open_library(abs_path, entry_symbol);
if (r_error) {
@@ -647,6 +689,12 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
}
if (err != OK) {
+#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
+ // If the DLL fails to load, make sure that temporary DLL copies are cleaned up.
+ if (Engine::get_singleton()->is_editor_hint()) {
+ DirAccess::remove_absolute(lib->get_temp_library_path());
+ }
+#endif
// Errors already logged in open_library()
return Ref<Resource>();
}
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index b935f8706f..5a0e39302b 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -43,6 +43,9 @@ class GDExtension : public Resource {
void *library = nullptr; // pointer if valid,
String library_path;
+#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
+ String temp_lib_path;
+#endif
struct Extension {
ObjectGDExtension gdextension;
@@ -76,6 +79,11 @@ public:
Error open_library(const String &p_path, const String &p_entry_symbol);
void close_library();
+#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
+ void set_temp_library_path(const String &p_path) { temp_lib_path = p_path; }
+ String get_temp_library_path() const { return temp_lib_path; }
+#endif
+
enum InitializationLevel {
INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 7ef956a470..b4541de8fe 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -1048,6 +1048,25 @@ static GDExtensionScriptInstancePtr gdextension_script_instance_create(const GDE
return reinterpret_cast<GDExtensionScriptInstancePtr>(script_instance_extension);
}
+static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExtensionConstObjectPtr p_object, GDExtensionConstObjectPtr p_language) {
+ if (!p_object || !p_language) {
+ return nullptr;
+ }
+
+ const Object *o = (const Object *)p_object;
+ ScriptInstanceExtension *script_instance_extension = reinterpret_cast<ScriptInstanceExtension *>(o->get_script_instance());
+ if (!script_instance_extension) {
+ return nullptr;
+ }
+
+ const ScriptLanguage *language = script_instance_extension->get_language();
+ if (language != p_language) {
+ return nullptr;
+ }
+
+ return script_instance_extension->instance;
+}
+
static GDExtensionMethodBindPtr gdextension_classdb_get_method_bind(GDExtensionConstStringNamePtr p_classname, GDExtensionConstStringNamePtr p_methodname, GDExtensionInt p_hash) {
const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
const StringName methodname = *reinterpret_cast<const StringName *>(p_methodname);
@@ -1216,6 +1235,7 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(ref_get_object);
REGISTER_INTERFACE_FUNC(ref_set_object);
REGISTER_INTERFACE_FUNC(script_instance_create);
+ REGISTER_INTERFACE_FUNC(object_get_script_instance);
REGISTER_INTERFACE_FUNC(classdb_construct_object);
REGISTER_INTERFACE_FUNC(classdb_get_method_bind);
REGISTER_INTERFACE_FUNC(classdb_get_class_tag);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 6c05f3988b..cfc21473d6 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -2126,6 +2126,19 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte
*/
typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data);
+/**
+ * @name object_get_script_instance
+ * @since 4.2
+ *
+ * Get the script instance data attached to this object.
+ *
+ * @param p_object A pointer to the Object.
+ * @param p_language A pointer to the language expected for this script instance.
+ *
+ * @return A GDExtensionScriptInstanceDataPtr that was attached to this object as part of script_instance_create.
+ */
+typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language);
+
/* INTERFACE: ClassDB */
/**
diff --git a/core/input/input.cpp b/core/input/input.cpp
index d481acf005..39f1acf623 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -113,6 +113,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
+ ClassDB::bind_method(D_METHOD("get_joy_info", "device"), &Input::get_joy_info);
ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device);
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
@@ -437,11 +438,12 @@ static String _hex_str(uint8_t p_byte) {
return ret;
}
-void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
+void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid, Dictionary p_joypad_info) {
_THREAD_SAFE_METHOD_
Joypad js;
js.name = p_connected ? p_name : "";
js.uid = p_connected ? p_guid : "";
+ js.info = p_connected ? p_joypad_info : Dictionary();
if (p_connected) {
String uidname = p_guid;
@@ -473,7 +475,8 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S
}
joy_names[p_idx] = js;
- emit_signal(SNAME("joy_connection_changed"), p_idx, p_connected);
+ // Ensure this signal is emitted on the main thread, as some platforms (e.g. Linux) call this from a different thread.
+ call_deferred("emit_signal", SNAME("joy_connection_changed"), p_idx, p_connected);
}
Vector3 Input::get_gravity() const {
@@ -1499,6 +1502,11 @@ String Input::get_joy_guid(int p_device) const {
return joy_names[p_device].uid;
}
+Dictionary Input::get_joy_info(int p_device) const {
+ ERR_FAIL_COND_V(!joy_names.has(p_device), Dictionary());
+ return joy_names[p_device].info;
+}
+
bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const {
uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id);
return ignored_device_ids.has(full_id);
diff --git a/core/input/input.h b/core/input/input.h
index ec16871b72..c63a4e52e3 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -149,6 +149,7 @@ private:
HatMask last_hat = HatMask::CENTER;
int mapping = -1;
int hat_current = 0;
+ Dictionary info;
};
VelocityTrack mouse_velocity_track;
@@ -276,7 +277,7 @@ public:
Vector2 get_joy_vibration_strength(int p_device);
float get_joy_vibration_duration(int p_device);
uint64_t get_joy_vibration_timestamp(int p_device);
- void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
+ void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "", Dictionary p_joypad_info = Dictionary());
Vector3 get_gravity() const;
Vector3 get_accelerometer() const;
@@ -332,6 +333,7 @@ public:
bool is_joy_known(int p_device);
String get_joy_guid(int p_device) const;
bool should_ignore_device(int p_vendor_id, int p_product_id) const;
+ Dictionary get_joy_info(int p_device) const;
void set_fallback_mapping(String p_guid);
void flush_buffered_events();
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index b669afdc99..6026dbf896 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -583,7 +583,7 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
return mt;
}
-uint32_t FileAccess::get_unix_permissions(const String &p_file) {
+BitField<FileAccess::UnixPermissionFlags> FileAccess::get_unix_permissions(const String &p_file) {
if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
return 0;
}
@@ -591,11 +591,10 @@ uint32_t FileAccess::get_unix_permissions(const String &p_file) {
Ref<FileAccess> fa = create_for_path(p_file);
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'.");
- uint32_t mt = fa->_get_unix_permissions(p_file);
- return mt;
+ return fa->_get_unix_permissions(p_file);
}
-Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+Error FileAccess::set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) {
if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
return ERR_UNAVAILABLE;
}
@@ -607,6 +606,52 @@ Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissi
return err;
}
+bool FileAccess::get_hidden_attribute(const String &p_file) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
+ return false;
+ }
+
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), false, "Cannot create FileAccess for path '" + p_file + "'.");
+
+ return fa->_get_hidden_attribute(p_file);
+}
+
+Error FileAccess::set_hidden_attribute(const String &p_file, bool p_hidden) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
+ return ERR_UNAVAILABLE;
+ }
+
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
+
+ Error err = fa->_set_hidden_attribute(p_file, p_hidden);
+ return err;
+}
+
+bool FileAccess::get_read_only_attribute(const String &p_file) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
+ return false;
+ }
+
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), false, "Cannot create FileAccess for path '" + p_file + "'.");
+
+ return fa->_get_read_only_attribute(p_file);
+}
+
+Error FileAccess::set_read_only_attribute(const String &p_file, bool p_ro) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
+ return ERR_UNAVAILABLE;
+ }
+
+ Ref<FileAccess> fa = create_for_path(p_file);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
+
+ Error err = fa->_set_read_only_attribute(p_file, p_ro);
+ return err;
+}
+
void FileAccess::store_string(const String &p_string) {
if (p_string.length() == 0) {
return;
@@ -865,6 +910,14 @@ void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_unix_permissions", "file"), &FileAccess::get_unix_permissions);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("set_unix_permissions", "file", "permissions"), &FileAccess::set_unix_permissions);
+
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_hidden_attribute", "file"), &FileAccess::get_hidden_attribute);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("set_hidden_attribute", "file", "hidden"), &FileAccess::set_hidden_attribute);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("set_read_only_attribute", "file", "ro"), &FileAccess::set_read_only_attribute);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_read_only_attribute", "file"), &FileAccess::get_read_only_attribute);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
BIND_ENUM_CONSTANT(READ);
@@ -877,4 +930,17 @@ void FileAccess::_bind_methods() {
BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
BIND_ENUM_CONSTANT(COMPRESSION_BROTLI);
+
+ BIND_BITFIELD_FLAG(UNIX_READ_OWNER);
+ BIND_BITFIELD_FLAG(UNIX_WRITE_OWNER);
+ BIND_BITFIELD_FLAG(UNIX_EXECUTE_OWNER);
+ BIND_BITFIELD_FLAG(UNIX_READ_GROUP);
+ BIND_BITFIELD_FLAG(UNIX_WRITE_GROUP);
+ BIND_BITFIELD_FLAG(UNIX_EXECUTE_GROUP);
+ BIND_BITFIELD_FLAG(UNIX_READ_OTHER);
+ BIND_BITFIELD_FLAG(UNIX_WRITE_OTHER);
+ BIND_BITFIELD_FLAG(UNIX_EXECUTE_OTHER);
+ BIND_BITFIELD_FLAG(UNIX_SET_USER_ID);
+ BIND_BITFIELD_FLAG(UNIX_SET_GROUP_ID);
+ BIND_BITFIELD_FLAG(UNIX_RESTRICTED_DELETE);
}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index ad1ac665f3..7b9e66bb83 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -60,6 +60,21 @@ public:
WRITE_READ = 7,
};
+ enum UnixPermissionFlags {
+ UNIX_EXECUTE_OTHER = 0x001,
+ UNIX_WRITE_OTHER = 0x002,
+ UNIX_READ_OTHER = 0x004,
+ UNIX_EXECUTE_GROUP = 0x008,
+ UNIX_WRITE_GROUP = 0x010,
+ UNIX_READ_GROUP = 0x020,
+ UNIX_EXECUTE_OWNER = 0x040,
+ UNIX_WRITE_OWNER = 0x080,
+ UNIX_READ_OWNER = 0x100,
+ UNIX_RESTRICTED_DELETE = 0x200,
+ UNIX_SET_GROUP_ID = 0x400,
+ UNIX_SET_USER_ID = 0x800,
+ };
+
enum CompressionMode {
COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
@@ -74,8 +89,13 @@ public:
bool big_endian = false;
bool real_is_double = false;
- virtual uint32_t _get_unix_permissions(const String &p_file) = 0;
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
+ virtual BitField<UnixPermissionFlags> _get_unix_permissions(const String &p_file) = 0;
+ virtual Error _set_unix_permissions(const String &p_file, BitField<UnixPermissionFlags> p_permissions) = 0;
+
+ virtual bool _get_hidden_attribute(const String &p_file) = 0;
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) = 0;
+ virtual bool _get_read_only_attribute(const String &p_file) = 0;
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) = 0;
protected:
static void _bind_methods();
@@ -185,8 +205,13 @@ public:
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
- static uint32_t get_unix_permissions(const String &p_file);
- static Error set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ static BitField<FileAccess::UnixPermissionFlags> get_unix_permissions(const String &p_file);
+ static Error set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions);
+
+ static bool get_hidden_attribute(const String &p_file);
+ static Error set_hidden_attribute(const String &p_file, bool p_hidden);
+ static bool get_read_only_attribute(const String &p_file);
+ static Error set_read_only_attribute(const String &p_file, bool p_ro);
static void set_backup_save(bool p_enable) { backup_save = p_enable; };
static bool is_backup_save_enabled() { return backup_save; };
@@ -212,5 +237,6 @@ public:
VARIANT_ENUM_CAST(FileAccess::CompressionMode);
VARIANT_ENUM_CAST(FileAccess::ModeFlags);
+VARIANT_BITFIELD_CAST(FileAccess::UnixPermissionFlags);
#endif // FILE_ACCESS_H
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 3e5a1217dd..0f00bd292c 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -365,20 +365,48 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) {
}
}
-uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) {
+BitField<FileAccess::UnixPermissionFlags> FileAccessCompressed::_get_unix_permissions(const String &p_file) {
if (f.is_valid()) {
return f->_get_unix_permissions(p_file);
}
return 0;
}
-Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+Error FileAccessCompressed::_set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) {
if (f.is_valid()) {
return f->_set_unix_permissions(p_file, p_permissions);
}
return FAILED;
}
+bool FileAccessCompressed::_get_hidden_attribute(const String &p_file) {
+ if (f.is_valid()) {
+ return f->_get_hidden_attribute(p_file);
+ }
+ return false;
+}
+
+Error FileAccessCompressed::_set_hidden_attribute(const String &p_file, bool p_hidden) {
+ if (f.is_valid()) {
+ return f->_set_hidden_attribute(p_file, p_hidden);
+ }
+ return FAILED;
+}
+
+bool FileAccessCompressed::_get_read_only_attribute(const String &p_file) {
+ if (f.is_valid()) {
+ return f->_get_read_only_attribute(p_file);
+ }
+ return false;
+}
+
+Error FileAccessCompressed::_set_read_only_attribute(const String &p_file, bool p_ro) {
+ if (f.is_valid()) {
+ return f->_set_read_only_attribute(p_file, p_ro);
+ }
+ return FAILED;
+}
+
void FileAccessCompressed::close() {
_close();
}
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 601b74a9c1..bf57eaa07c 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -94,8 +94,13 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override;
- virtual uint32_t _get_unix_permissions(const String &p_file) override;
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override;
+
+ virtual bool _get_hidden_attribute(const String &p_file) override;
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override;
+ virtual bool _get_read_only_attribute(const String &p_file) override;
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override;
virtual void close() override;
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index c39d19d52b..b689f5b628 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -285,13 +285,46 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) {
return 0;
}
-uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) {
+BitField<FileAccess::UnixPermissionFlags> FileAccessEncrypted::_get_unix_permissions(const String &p_file) {
+ if (file.is_valid()) {
+ return file->_get_unix_permissions(p_file);
+ }
return 0;
}
-Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
- ERR_PRINT("Setting UNIX permissions on encrypted files is not implemented yet.");
- return ERR_UNAVAILABLE;
+Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) {
+ if (file.is_valid()) {
+ return file->_set_unix_permissions(p_file, p_permissions);
+ }
+ return FAILED;
+}
+
+bool FileAccessEncrypted::_get_hidden_attribute(const String &p_file) {
+ if (file.is_valid()) {
+ return file->_get_hidden_attribute(p_file);
+ }
+ return false;
+}
+
+Error FileAccessEncrypted::_set_hidden_attribute(const String &p_file, bool p_hidden) {
+ if (file.is_valid()) {
+ return file->_set_hidden_attribute(p_file, p_hidden);
+ }
+ return FAILED;
+}
+
+bool FileAccessEncrypted::_get_read_only_attribute(const String &p_file) {
+ if (file.is_valid()) {
+ return file->_get_read_only_attribute(p_file);
+ }
+ return false;
+}
+
+Error FileAccessEncrypted::_set_read_only_attribute(const String &p_file, bool p_ro) {
+ if (file.is_valid()) {
+ return file->_set_read_only_attribute(p_file, p_ro);
+ }
+ return FAILED;
}
void FileAccessEncrypted::close() {
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 9702b5a517..489d213b8f 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -85,8 +85,13 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override;
- virtual uint32_t _get_unix_permissions(const String &p_file) override;
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override;
+
+ virtual bool _get_hidden_attribute(const String &p_file) override;
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override;
+ virtual bool _get_read_only_attribute(const String &p_file) override;
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override;
virtual void close() override;
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 43fe6ab658..ac08e5406f 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -68,8 +68,13 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
+
+ virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
+ virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
virtual void close() override {}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 1538b302c2..97391a5611 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -150,8 +150,13 @@ class FileAccessPack : public FileAccess {
Ref<FileAccess> f;
virtual Error open_internal(const String &p_path, int p_mode_flags) override;
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
+
+ virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
+ virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
public:
virtual bool is_open() const override;
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index f8b640946c..1062a06238 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -106,8 +106,13 @@ public:
virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } // todo
- virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
+
+ virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
+ virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
virtual void close() override;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 7326563f18..3ca39f98c0 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -3017,6 +3017,8 @@ ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_dds_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr;
void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
@@ -3488,6 +3490,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
+ ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer);
+ ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer);
ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
@@ -3863,6 +3867,22 @@ Error Image::load_svg_from_string(const String &p_svg_str, float scale) {
return load_svg_from_buffer(p_svg_str.to_utf8_buffer(), scale);
}
+Error Image::load_dds_from_buffer(const Vector<uint8_t> &p_array) {
+ ERR_FAIL_NULL_V_MSG(
+ _dds_mem_loader_func,
+ ERR_UNAVAILABLE,
+ "The DDS module isn't enabled. Recompile the Godot editor or export template binary with the `module_dds_enabled=yes` SCons option.");
+ return _load_from_buffer(p_array, _dds_mem_loader_func);
+}
+
+Error Image::load_ktx_from_buffer(const Vector<uint8_t> &p_array) {
+ ERR_FAIL_NULL_V_MSG(
+ _ktx_mem_loader_func,
+ ERR_UNAVAILABLE,
+ "The KTX module isn't enabled. Recompile the Godot editor or export template binary with the `module_ktx_enabled=yes` SCons option.");
+ return _load_from_buffer(p_array, _ktx_mem_loader_func);
+}
+
void Image::convert_rg_to_ra_rgba8() {
ERR_FAIL_COND(format != FORMAT_RGBA8);
ERR_FAIL_COND(!data.size());
diff --git a/core/io/image.h b/core/io/image.h
index f877b00ee6..cb7c6bff52 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -150,6 +150,8 @@ public:
static ImageMemLoadFunc _tga_mem_loader_func;
static ImageMemLoadFunc _bmp_mem_loader_func;
static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
+ static ImageMemLoadFunc _dds_mem_loader_func;
+ static ImageMemLoadFunc _ktx_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
@@ -402,6 +404,8 @@ public:
Error load_webp_from_buffer(const Vector<uint8_t> &p_array);
Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
+ Error load_dds_from_buffer(const Vector<uint8_t> &p_array);
+ Error load_ktx_from_buffer(const Vector<uint8_t> &p_array);
Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0);
Error load_svg_from_string(const String &p_svg_str, float scale = 1.0);
diff --git a/core/io/remote_filesystem_client.cpp b/core/io/remote_filesystem_client.cpp
index f22e442a34..1198810441 100644
--- a/core/io/remote_filesystem_client.cpp
+++ b/core/io/remote_filesystem_client.cpp
@@ -270,7 +270,7 @@ Error RemoteFilesystemClient::_synchronize_with_server(const String &p_host, int
String file = temp_file_cache[i].path;
if (temp_file_cache[i].server_modified_time == 0 || server_disconnected) {
- // File was removed, or server disconnected before tranferring it. Since it's no longer valid, remove anyway.
+ // File was removed, or server disconnected before transferring it. Since it's no longer valid, remove anyway.
_remove_file(file);
continue;
}
diff --git a/core/io/remote_filesystem_client.h b/core/io/remote_filesystem_client.h
index 42eba98eb1..fcb5c1cfc3 100644
--- a/core/io/remote_filesystem_client.h
+++ b/core/io/remote_filesystem_client.h
@@ -44,8 +44,8 @@ protected:
String _get_cache_path() { return cache_path; }
struct FileCache {
String path; // Local path (as in "folder/to/file.png")
- uint64_t server_modified_time; // MD5 checksum.
- uint64_t modified_time;
+ uint64_t server_modified_time = 0; // MD5 checksum.
+ uint64_t modified_time = 0;
};
virtual bool _is_configured() { return !cache_path.is_empty(); }
// Can be re-implemented per platform. If so, feel free to ignore get_cache_path()
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 07677337b4..68cdeabac7 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -239,6 +239,7 @@ void Resource::configure_for_local_scene(Node *p_for_scene, HashMap<Ref<Resource
List<PropertyInfo> plist;
get_property_list(&plist);
+ reset_local_to_scene();
local_scene = p_for_scene;
for (const PropertyInfo &E : plist) {
@@ -382,6 +383,10 @@ void Resource::setup_local_to_scene() {
emit_signal(SNAME("setup_local_to_scene_requested"));
}
+void Resource::reset_local_to_scene() {
+ // Restores the state as if setup_local_to_scene() hadn't been called.
+}
+
Node *(*Resource::_get_local_scene_func)() = nullptr;
void (*Resource::_update_configuration_warning)() = nullptr;
diff --git a/core/io/resource.h b/core/io/resource.h
index af8c275a1c..f848bdba99 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -80,6 +80,8 @@ protected:
void _set_path(const String &p_path);
void _take_over_path(const String &p_path);
+ virtual void reset_local_to_scene();
+
public:
static Node *(*_get_local_scene_func)(); //used by editor
static void (*_update_configuration_warning)(); //used by editor
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 1fe662b1fa..df0253349c 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -275,10 +275,10 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
#ifdef TOOLS_ENABLED
Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), Ref<Resource>(), "Resource file not found: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
#endif
- ERR_FAIL_V_MSG(Ref<Resource>(), "No loader found for resource: " + p_path + ".");
+ ERR_FAIL_V_MSG(Ref<Resource>(), vformat("No loader found for resource: %s (expected type: %s)", p_path, p_type_hint));
}
void ResourceLoader::_thread_load_function(void *p_userdata) {
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index 63f7c80bdd..9ba4c2ff9a 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -194,6 +194,38 @@ real_t AStarGrid2D::get_point_weight_scale(const Vector2i &p_id) const {
return GET_POINT_UNCHECKED(p_id).weight_scale;
}
+void AStarGrid2D::fill_solid_region(const Rect2i &p_region, bool p_solid) {
+ ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
+
+ Rect2i safe_region = p_region.intersection(region);
+ int from_x = safe_region.get_position().x;
+ int from_y = safe_region.get_position().y;
+ int end_x = safe_region.get_end().x;
+ int end_y = safe_region.get_end().y;
+
+ for (int x = from_x; x < end_x; x++) {
+ for (int y = from_y; y < end_y; y++) {
+ GET_POINT_UNCHECKED(Vector2i(x, y)).solid = p_solid;
+ }
+ }
+}
+
+void AStarGrid2D::fill_weight_scale_region(const Rect2i &p_region, real_t p_weight_scale) {
+ ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale));
+
+ Rect2i safe_region = p_region.intersection(region);
+ int from_x = safe_region.get_position().x;
+ int from_y = safe_region.get_position().y;
+ int end_x = safe_region.get_end().x;
+ int end_y = safe_region.get_end().y;
+ for (int x = from_x; x < end_x; x++) {
+ for (int y = from_y; y < end_y; y++) {
+ GET_POINT_UNCHECKED(Vector2i(x, y)).weight_scale = p_weight_scale;
+ }
+ }
+}
+
AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) {
if (!p_to || p_to->solid) {
return nullptr;
@@ -606,6 +638,8 @@ void AStarGrid2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_point_solid", "id"), &AStarGrid2D::is_point_solid);
ClassDB::bind_method(D_METHOD("set_point_weight_scale", "id", "weight_scale"), &AStarGrid2D::set_point_weight_scale);
ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStarGrid2D::get_point_weight_scale);
+ ClassDB::bind_method(D_METHOD("fill_solid_region", "region", "solid"), &AStarGrid2D::fill_solid_region, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("fill_weight_scale_region", "region", "weight_scale"), &AStarGrid2D::fill_weight_scale_region);
ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear);
ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStarGrid2D::get_point_position);
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index 50df58e0e9..dd5f9d0575 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -177,6 +177,9 @@ public:
void set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale);
real_t get_point_weight_scale(const Vector2i &p_id) const;
+ void fill_solid_region(const Rect2i &p_region, bool p_solid = true);
+ void fill_weight_scale_region(const Rect2i &p_region, real_t p_weight_scale);
+
void clear();
Vector2 get_point_position(const Vector2i &p_id) const;
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 55923e0133..7df8c37e3c 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -105,8 +105,8 @@ class Delaunay3D {
};
_FORCE_INLINE_ static void circum_sphere_compute(const Vector3 *p_points, Simplex *p_simplex) {
- // the only part in the algorithm where there may be precision errors is this one, so ensure that
- // we do it as maximum precision as possible
+ // The only part in the algorithm where there may be precision errors is this one,
+ // so ensure that we do it with the maximum precision possible.
R128 v0_x = p_points[p_simplex->points[0]].x;
R128 v0_y = p_points[p_simplex->points[0]].y;
@@ -121,7 +121,7 @@ class Delaunay3D {
R128 v3_y = p_points[p_simplex->points[3]].y;
R128 v3_z = p_points[p_simplex->points[3]].z;
- //Create the rows of our "unrolled" 3x3 matrix
+ // Create the rows of our "unrolled" 3x3 matrix.
R128 row1_x = v1_x - v0_x;
R128 row1_y = v1_y - v0_y;
R128 row1_z = v1_z - v0_z;
@@ -138,10 +138,10 @@ class Delaunay3D {
R128 sq_lenght2 = row2_x * row2_x + row2_y * row2_y + row2_z * row2_z;
R128 sq_lenght3 = row3_x * row3_x + row3_y * row3_y + row3_z * row3_z;
- //Compute the determinant of said matrix
+ // Compute the determinant of said matrix.
R128 determinant = row1_x * (row2_y * row3_z - row3_y * row2_z) - row2_x * (row1_y * row3_z - row3_y * row1_z) + row3_x * (row1_y * row2_z - row2_y * row1_z);
- // Compute the volume of the tetrahedron, and precompute a scalar quantity for re-use in the formula
+ // Compute the volume of the tetrahedron, and precompute a scalar quantity for reuse in the formula.
R128 volume = determinant / R128(6.f);
R128 i12volume = R128(1.f) / (volume * R128(12.f));
@@ -149,8 +149,7 @@ class Delaunay3D {
R128 center_y = v0_y + i12volume * (-(row2_x * row3_z - row3_x * row2_z) * sq_lenght1 + (row1_x * row3_z - row3_x * row1_z) * sq_lenght2 - (row1_x * row2_z - row2_x * row1_z) * sq_lenght3);
R128 center_z = v0_z + i12volume * ((row2_x * row3_y - row3_x * row2_y) * sq_lenght1 - (row1_x * row3_y - row3_x * row1_y) * sq_lenght2 + (row1_x * row2_y - row2_x * row1_y) * sq_lenght3);
- //Once we know the center, the radius is clearly the distance to any vertex
-
+ // Once we know the center, the radius is clearly the distance to any vertex.
R128 rel1_x = center_x - v0_x;
R128 rel1_y = center_y - v0_y;
R128 rel1_z = center_z - v0_z;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index c8c50fb957..e9fd8ad583 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -1661,7 +1661,15 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
c.name = p_extension->class_name;
c.is_virtual = p_extension->is_virtual;
if (!p_extension->is_abstract) {
- c.creation_func = parent->creation_func;
+ // Find the closest ancestor which is either non-abstract or native (or both).
+ ClassInfo *concrete_ancestor = parent;
+ while (concrete_ancestor->creation_func == nullptr &&
+ concrete_ancestor->inherits_ptr != nullptr &&
+ concrete_ancestor->gdextension != nullptr) {
+ concrete_ancestor = concrete_ancestor->inherits_ptr;
+ }
+ ERR_FAIL_NULL_MSG(concrete_ancestor->creation_func, "Extension class " + String(p_extension->class_name) + " cannot extend native abstract class " + String(concrete_ancestor->name));
+ c.creation_func = concrete_ancestor->creation_func;
}
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index dd7aba1384..506f8291eb 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -35,10 +35,6 @@
#include "core/object/class_db.h"
#include "core/object/script_language.h"
-#ifdef DEBUG_ENABLED
-#include "core/config/engine.h"
-#endif
-
#ifdef DEV_ENABLED
// Includes sanity checks to ensure that a queue set as a thread singleton override
// is only ever called from the thread it was set for.
@@ -320,34 +316,25 @@ Error CallQueue::flush() {
Object *target = message->callable.get_object();
UNLOCK_MUTEX;
-#ifdef DEBUG_ENABLED
- if (!message->callable.is_valid()) {
- // The editor would cause many of these.
- if (!Engine::get_singleton()->is_editor_hint()) {
- ERR_PRINT("Trying to execute a deferred call/notification/set on a previously freed instance. Consider using queue_free() instead of free().");
- }
- } else
-#endif
- {
- switch (message->type & FLAG_MASK) {
- case TYPE_CALL: {
- if (target || (message->type & FLAG_NULL_IS_OK)) {
- Variant *args = (Variant *)(message + 1);
- _call_function(message->callable, args, message->args, message->type & FLAG_SHOW_ERROR);
- }
- } break;
- case TYPE_NOTIFICATION: {
- if (target) {
- target->notification(message->notification);
- }
- } break;
- case TYPE_SET: {
- if (target) {
- Variant *arg = (Variant *)(message + 1);
- target->set(message->callable.get_method(), *arg);
- }
- } break;
- }
+
+ switch (message->type & FLAG_MASK) {
+ case TYPE_CALL: {
+ if (target || (message->type & FLAG_NULL_IS_OK)) {
+ Variant *args = (Variant *)(message + 1);
+ _call_function(message->callable, args, message->args, message->type & FLAG_SHOW_ERROR);
+ }
+ } break;
+ case TYPE_NOTIFICATION: {
+ if (target) {
+ target->notification(message->notification);
+ }
+ } break;
+ case TYPE_SET: {
+ if (target) {
+ Variant *arg = (Variant *)(message + 1);
+ target->set(message->callable.get_method(), *arg);
+ }
+ } break;
}
if ((message->type & FLAG_MASK) != TYPE_NOTIFICATION) {
diff --git a/core/string/locales.h b/core/string/locales.h
index 8a7efb4fd1..840fca65a7 100644
--- a/core/string/locales.h
+++ b/core/string/locales.h
@@ -1057,8 +1057,8 @@ static const char *script_list[][2] = {
{ "Hangul", "Hang" },
{ "Han", "Hani" },
{ "Hanunoo", "Hano" },
- { "Simplified", "Hans" },
- { "Traditional", "Hant" },
+ { "Simplified Han", "Hans" },
+ { "Traditional Han", "Hant" },
{ "Hatran", "Hatr" },
{ "Hebrew", "Hebr" },
{ "Hiragana", "Hira" },
@@ -1110,7 +1110,7 @@ static const char *script_list[][2] = {
{ "Mro", "Mroo" },
{ "Meitei Mayek", "Mtei" },
{ "Multani", "Mult" },
- { "Myanmar (Burmese)", "Mymr" },
+ { "Myanmar / Burmese", "Mymr" },
{ "​Nag Mundari", "Nagm" },
{ "Nandinagari", "Nand" },
{ "Old North Arabian", "Narb" },
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 12e6423724..3f11459a1e 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1750,7 +1750,7 @@ Vector<uint8_t> String::hex_decode() const {
void String::print_unicode_error(const String &p_message, bool p_critical) const {
if (p_critical) {
- print_error(vformat("Unicode parsing error, some characters were replaced with � (U+FFFD): %s", p_message));
+ print_error(vformat(U"Unicode parsing error, some characters were replaced with � (U+FFFD): %s", p_message));
} else {
print_error(vformat("Unicode parsing error: %s", p_message));
}
@@ -3635,6 +3635,23 @@ String String::repeat(int p_count) const {
return new_string;
}
+String String::reverse() const {
+ int len = length();
+ if (len <= 1) {
+ return *this;
+ }
+ String new_string;
+ new_string.resize(len + 1);
+
+ const char32_t *src = ptr();
+ char32_t *dst = new_string.ptrw();
+ for (int i = 0; i < len; i++) {
+ dst[i] = src[len - i - 1];
+ }
+ dst[len] = _null;
+ return new_string;
+}
+
String String::left(int p_len) const {
if (p_len < 0) {
p_len = length() + p_len;
@@ -3648,7 +3665,9 @@ String String::left(int p_len) const {
return *this;
}
- return substr(0, p_len);
+ String s;
+ s.copy_from_unchecked(&get_data()[0], p_len);
+ return s;
}
String String::right(int p_len) const {
@@ -3664,7 +3683,9 @@ String String::right(int p_len) const {
return *this;
}
- return substr(length() - p_len);
+ String s;
+ s.copy_from_unchecked(&get_data()[length() - p_len], p_len);
+ return s;
}
char32_t String::unicode_at(int p_idx) const {
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 295625395d..f45392eee1 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -305,6 +305,7 @@ public:
String replace(const char *p_key, const char *p_with) const;
String replacen(const String &p_key, const String &p_with) const;
String repeat(int p_count) const;
+ String reverse() const;
String insert(int p_at_pos, const String &p_string) const;
String erase(int p_pos, int p_chars = 1) const;
String pad_decimals(int p_digits) const;
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index 98afc7e717..055c52aa63 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -230,4 +230,7 @@ MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
+#undef MAKE_TYPED_ARRAY
+#undef MAKE_TYPED_ARRAY_INFO
+
#endif // TYPED_ARRAY_H
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 10a267e5a9..8a0289898d 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1754,11 +1754,10 @@ String Variant::stringify(int recursion_count) const {
case COLOR:
return operator Color();
case DICTIONARY: {
+ ERR_FAIL_COND_V_MSG(recursion_count > MAX_RECURSION, "{ ... }", "Maximum dictionary recursion reached!");
+ recursion_count++;
+
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
- if (recursion_count > MAX_RECURSION) {
- ERR_PRINT("Maximum dictionary recursion reached!");
- return "{ ... }";
- }
// Add leading and trailing space to Dictionary printing. This distinguishes it
// from array printing on fonts that have similar-looking {} and [] characters.
@@ -1768,7 +1767,6 @@ String Variant::stringify(int recursion_count) const {
Vector<_VariantStrPair> pairs;
- recursion_count++;
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
_VariantStrPair sp;
sp.key = stringify_variant_clean(E->get(), recursion_count);
@@ -1787,6 +1785,7 @@ String Variant::stringify(int recursion_count) const {
return str;
}
+ // Packed arrays cannot contain recursive structures, the recursion_count increment is not needed.
case PACKED_VECTOR2_ARRAY: {
return stringify_vector(operator Vector<Vector2>(), recursion_count);
}
@@ -1815,13 +1814,10 @@ String Variant::stringify(int recursion_count) const {
return stringify_vector(operator Vector<double>(), recursion_count);
}
case ARRAY: {
- Array arr = operator Array();
- if (recursion_count > MAX_RECURSION) {
- ERR_PRINT("Maximum array recursion reached!");
- return "[...]";
- }
+ ERR_FAIL_COND_V_MSG(recursion_count > MAX_RECURSION, "[...]", "Maximum array recursion reached!");
+ recursion_count++;
- return stringify_vector(arr, recursion_count);
+ return stringify_vector(operator Array(), recursion_count);
}
case OBJECT: {
if (_get_obj().obj) {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index dad9183216..ccf9b82022 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1659,6 +1659,7 @@ static void _register_variant_builtin_methods() {
bind_string_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
bind_string_method(replacen, sarray("what", "forwhat"), varray());
bind_string_method(repeat, sarray("count"), varray());
+ bind_string_method(reverse, sarray(), varray());
bind_string_method(insert, sarray("position", "what"), varray());
bind_string_method(erase, sarray("position", "chars"), varray(1));
bind_string_method(capitalize, sarray(), varray());
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index c11f726402..fc1f7828a2 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -284,7 +284,7 @@ public:
const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
if (b == 0) {
r_valid = false;
- *r_ret = "Module by zero error";
+ *r_ret = "Modulo by zero error";
return;
}
*r_ret = a % b;
@@ -307,7 +307,7 @@ public:
const Vector2i &b = *VariantGetInternalPtr<Vector2i>::get_ptr(&p_right);
if (unlikely(b.x == 0 || b.y == 0)) {
r_valid = false;
- *r_ret = "Module by zero error";
+ *r_ret = "Modulo by zero error";
return;
}
*r_ret = a % b;
@@ -331,7 +331,7 @@ public:
const Vector3i &b = *VariantGetInternalPtr<Vector3i>::get_ptr(&p_right);
if (unlikely(b.x == 0 || b.y == 0 || b.z == 0)) {
r_valid = false;
- *r_ret = "Module by zero error";
+ *r_ret = "Modulo by zero error";
return;
}
*r_ret = a % b;
@@ -355,7 +355,7 @@ public:
const Vector4i &b = *VariantGetInternalPtr<Vector4i>::get_ptr(&p_right);
if (unlikely(b.x == 0 || b.y == 0 || b.z == 0 || b.w == 0)) {
r_valid = false;
- *r_ret = "Module by zero error";
+ *r_ret = "Modulo by zero error";
return;
}
*r_ret = a % b;
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 545825011a..4f6bcb58b3 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "variant.h"
+#include "variant_utility.h"
#include "core/core_string_names.h"
#include "core/io/marshalls.h"
@@ -40,755 +40,772 @@
#include "core/variant/binder_common.h"
#include "core/variant/variant_parser.h"
-struct VariantUtilityFunctions {
- // Math
-
- static inline double sin(double arg) {
- return Math::sin(arg);
- }
+// Math
+double VariantUtilityFunctions::sin(double arg) {
+ return Math::sin(arg);
+}
- static inline double cos(double arg) {
- return Math::cos(arg);
- }
+double VariantUtilityFunctions::cos(double arg) {
+ return Math::cos(arg);
+}
- static inline double tan(double arg) {
- return Math::tan(arg);
- }
+double VariantUtilityFunctions::tan(double arg) {
+ return Math::tan(arg);
+}
- static inline double sinh(double arg) {
- return Math::sinh(arg);
- }
+double VariantUtilityFunctions::sinh(double arg) {
+ return Math::sinh(arg);
+}
- static inline double cosh(double arg) {
- return Math::cosh(arg);
- }
+double VariantUtilityFunctions::cosh(double arg) {
+ return Math::cosh(arg);
+}
- static inline double tanh(double arg) {
- return Math::tanh(arg);
- }
+double VariantUtilityFunctions::tanh(double arg) {
+ return Math::tanh(arg);
+}
- static inline double asin(double arg) {
- return Math::asin(arg);
- }
+double VariantUtilityFunctions::asin(double arg) {
+ return Math::asin(arg);
+}
- static inline double acos(double arg) {
- return Math::acos(arg);
- }
+double VariantUtilityFunctions::acos(double arg) {
+ return Math::acos(arg);
+}
- static inline double atan(double arg) {
- return Math::atan(arg);
- }
+double VariantUtilityFunctions::atan(double arg) {
+ return Math::atan(arg);
+}
- static inline double atan2(double y, double x) {
- return Math::atan2(y, x);
- }
+double VariantUtilityFunctions::atan2(double y, double x) {
+ return Math::atan2(y, x);
+}
- static inline double sqrt(double x) {
- return Math::sqrt(x);
- }
+double VariantUtilityFunctions::sqrt(double x) {
+ return Math::sqrt(x);
+}
- static inline double fmod(double b, double r) {
- return Math::fmod(b, r);
- }
+double VariantUtilityFunctions::fmod(double b, double r) {
+ return Math::fmod(b, r);
+}
- static inline double fposmod(double b, double r) {
- return Math::fposmod(b, r);
- }
+double VariantUtilityFunctions::fposmod(double b, double r) {
+ return Math::fposmod(b, r);
+}
- static inline int64_t posmod(int64_t b, int64_t r) {
- return Math::posmod(b, r);
- }
+int64_t VariantUtilityFunctions::posmod(int64_t b, int64_t r) {
+ return Math::posmod(b, r);
+}
- static inline Variant floor(Variant x, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- switch (x.get_type()) {
- case Variant::INT: {
- return VariantInternalAccessor<int64_t>::get(&x);
- } break;
- case Variant::FLOAT: {
- return Math::floor(VariantInternalAccessor<double>::get(&x));
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&x).floor();
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&x).floor();
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&x).floor();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+Variant VariantUtilityFunctions::floor(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::floor(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).floor();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).floor();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).floor();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
}
}
+}
- static inline double floorf(double x) {
- return Math::floor(x);
- }
+double VariantUtilityFunctions::floorf(double x) {
+ return Math::floor(x);
+}
- static inline int64_t floori(double x) {
- return int64_t(Math::floor(x));
- }
+int64_t VariantUtilityFunctions::floori(double x) {
+ return int64_t(Math::floor(x));
+}
- static inline Variant ceil(Variant x, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- switch (x.get_type()) {
- case Variant::INT: {
- return VariantInternalAccessor<int64_t>::get(&x);
- } break;
- case Variant::FLOAT: {
- return Math::ceil(VariantInternalAccessor<double>::get(&x));
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&x).ceil();
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&x).ceil();
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&x).ceil();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+Variant VariantUtilityFunctions::ceil(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::ceil(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).ceil();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).ceil();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).ceil();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
}
}
+}
- static inline double ceilf(double x) {
- return Math::ceil(x);
- }
+double VariantUtilityFunctions::ceilf(double x) {
+ return Math::ceil(x);
+}
- static inline int64_t ceili(double x) {
- return int64_t(Math::ceil(x));
- }
+int64_t VariantUtilityFunctions::ceili(double x) {
+ return int64_t(Math::ceil(x));
+}
- static inline Variant round(Variant x, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- switch (x.get_type()) {
- case Variant::INT: {
- return VariantInternalAccessor<int64_t>::get(&x);
- } break;
- case Variant::FLOAT: {
- return Math::round(VariantInternalAccessor<double>::get(&x));
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&x).round();
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&x).round();
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&x).round();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+Variant VariantUtilityFunctions::round(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::round(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).round();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).round();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).round();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
}
}
+}
- static inline double roundf(double x) {
- return Math::round(x);
- }
+double VariantUtilityFunctions::roundf(double x) {
+ return Math::round(x);
+}
- static inline int64_t roundi(double x) {
- return int64_t(Math::round(x));
- }
+int64_t VariantUtilityFunctions::roundi(double x) {
+ return int64_t(Math::round(x));
+}
- static inline Variant abs(const Variant &x, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- switch (x.get_type()) {
- case Variant::INT: {
- return ABS(VariantInternalAccessor<int64_t>::get(&x));
- } break;
- case Variant::FLOAT: {
- return Math::absd(VariantInternalAccessor<double>::get(&x));
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&x).abs();
- } break;
- case Variant::VECTOR2I: {
- return VariantInternalAccessor<Vector2i>::get(&x).abs();
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&x).abs();
- } break;
- case Variant::VECTOR3I: {
- return VariantInternalAccessor<Vector3i>::get(&x).abs();
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&x).abs();
- } break;
- case Variant::VECTOR4I: {
- return VariantInternalAccessor<Vector4i>::get(&x).abs();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+Variant VariantUtilityFunctions::abs(const Variant &x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return ABS(VariantInternalAccessor<int64_t>::get(&x));
+ } break;
+ case Variant::FLOAT: {
+ return Math::absd(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).abs();
+ } break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x).abs();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).abs();
+ } break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x).abs();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).abs();
+ } break;
+ case Variant::VECTOR4I: {
+ return VariantInternalAccessor<Vector4i>::get(&x).abs();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
}
}
+}
- static inline double absf(double x) {
- return Math::absd(x);
- }
+double VariantUtilityFunctions::absf(double x) {
+ return Math::absd(x);
+}
- static inline int64_t absi(int64_t x) {
- return ABS(x);
- }
+int64_t VariantUtilityFunctions::absi(int64_t x) {
+ return ABS(x);
+}
- static inline Variant sign(const Variant &x, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- switch (x.get_type()) {
- case Variant::INT: {
- return SIGN(VariantInternalAccessor<int64_t>::get(&x));
- } break;
- case Variant::FLOAT: {
- return SIGN(VariantInternalAccessor<double>::get(&x));
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&x).sign();
- } break;
- case Variant::VECTOR2I: {
- return VariantInternalAccessor<Vector2i>::get(&x).sign();
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&x).sign();
- } break;
- case Variant::VECTOR3I: {
- return VariantInternalAccessor<Vector3i>::get(&x).sign();
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&x).sign();
- } break;
- case Variant::VECTOR4I: {
- return VariantInternalAccessor<Vector4i>::get(&x).sign();
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
+Variant VariantUtilityFunctions::sign(const Variant &x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return SIGN(VariantInternalAccessor<int64_t>::get(&x));
+ } break;
+ case Variant::FLOAT: {
+ return SIGN(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).sign();
+ } break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x).sign();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).sign();
+ } break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x).sign();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).sign();
+ } break;
+ case Variant::VECTOR4I: {
+ return VariantInternalAccessor<Vector4i>::get(&x).sign();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
}
}
+}
- static inline double signf(double x) {
- return SIGN(x);
- }
+double VariantUtilityFunctions::signf(double x) {
+ return SIGN(x);
+}
- static inline int64_t signi(int64_t x) {
- return SIGN(x);
- }
+int64_t VariantUtilityFunctions::signi(int64_t x) {
+ return SIGN(x);
+}
- static inline double pow(double x, double y) {
- return Math::pow(x, y);
- }
+double VariantUtilityFunctions::pow(double x, double y) {
+ return Math::pow(x, y);
+}
- static inline double log(double x) {
- return Math::log(x);
- }
+double VariantUtilityFunctions::log(double x) {
+ return Math::log(x);
+}
- static inline double exp(double x) {
- return Math::exp(x);
- }
+double VariantUtilityFunctions::exp(double x) {
+ return Math::exp(x);
+}
- static inline bool is_nan(double x) {
- return Math::is_nan(x);
- }
+bool VariantUtilityFunctions::is_nan(double x) {
+ return Math::is_nan(x);
+}
- static inline bool is_inf(double x) {
- return Math::is_inf(x);
- }
+bool VariantUtilityFunctions::is_inf(double x) {
+ return Math::is_inf(x);
+}
- static inline bool is_equal_approx(double x, double y) {
- return Math::is_equal_approx(x, y);
- }
+bool VariantUtilityFunctions::is_equal_approx(double x, double y) {
+ return Math::is_equal_approx(x, y);
+}
- static inline bool is_zero_approx(double x) {
- return Math::is_zero_approx(x);
- }
+bool VariantUtilityFunctions::is_zero_approx(double x) {
+ return Math::is_zero_approx(x);
+}
- static inline bool is_finite(double x) {
- return Math::is_finite(x);
- }
+bool VariantUtilityFunctions::is_finite(double x) {
+ return Math::is_finite(x);
+}
- static inline double ease(float x, float curve) {
- return Math::ease(x, curve);
- }
+double VariantUtilityFunctions::ease(float x, float curve) {
+ return Math::ease(x, curve);
+}
- static inline int step_decimals(float step) {
- return Math::step_decimals(step);
- }
+int VariantUtilityFunctions::step_decimals(float step) {
+ return Math::step_decimals(step);
+}
- static inline Variant snapped(const Variant &x, const Variant &step, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- if (x.get_type() != step.get_type() && !((x.get_type() == Variant::INT && step.get_type() == Variant::FLOAT) || (x.get_type() == Variant::FLOAT && step.get_type() == Variant::INT))) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
+Variant VariantUtilityFunctions::snapped(const Variant &x, const Variant &step, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ if (x.get_type() != step.get_type() && !((x.get_type() == Variant::INT && step.get_type() == Variant::FLOAT) || (x.get_type() == Variant::FLOAT && step.get_type() == Variant::INT))) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ return Variant();
+ }
+
+ switch (step.get_type()) {
+ case Variant::INT: {
+ return snappedi(x, VariantInternalAccessor<int64_t>::get(&step));
+ } break;
+ case Variant::FLOAT: {
+ return snappedf(x, VariantInternalAccessor<double>::get(&step));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).snapped(VariantInternalAccessor<Vector2>::get(&step));
+ } break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x).snapped(VariantInternalAccessor<Vector2i>::get(&step));
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).snapped(VariantInternalAccessor<Vector3>::get(&step));
+ } break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x).snapped(VariantInternalAccessor<Vector3i>::get(&step));
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).snapped(VariantInternalAccessor<Vector4>::get(&step));
+ } break;
+ case Variant::VECTOR4I: {
+ return VariantInternalAccessor<Vector4i>::get(&x).snapped(VariantInternalAccessor<Vector4i>::get(&step));
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
-
- switch (step.get_type()) {
- case Variant::INT: {
- return snappedi(x, VariantInternalAccessor<int64_t>::get(&step));
- } break;
- case Variant::FLOAT: {
- return snappedf(x, VariantInternalAccessor<double>::get(&step));
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&x).snapped(VariantInternalAccessor<Vector2>::get(&step));
- } break;
- case Variant::VECTOR2I: {
- return VariantInternalAccessor<Vector2i>::get(&x).snapped(VariantInternalAccessor<Vector2i>::get(&step));
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&x).snapped(VariantInternalAccessor<Vector3>::get(&step));
- } break;
- case Variant::VECTOR3I: {
- return VariantInternalAccessor<Vector3i>::get(&x).snapped(VariantInternalAccessor<Vector3i>::get(&step));
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&x).snapped(VariantInternalAccessor<Vector4>::get(&step));
- } break;
- case Variant::VECTOR4I: {
- return VariantInternalAccessor<Vector4i>::get(&x).snapped(VariantInternalAccessor<Vector4i>::get(&step));
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
- }
}
+}
- static inline double snappedf(double x, double step) {
- return Math::snapped(x, step);
- }
+double VariantUtilityFunctions::snappedf(double x, double step) {
+ return Math::snapped(x, step);
+}
- static inline int64_t snappedi(double x, int64_t step) {
- return Math::snapped(x, step);
- }
+int64_t VariantUtilityFunctions::snappedi(double x, int64_t step) {
+ return Math::snapped(x, step);
+}
- static inline Variant lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK;
- if (from.get_type() != to.get_type()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = from.get_type();
- r_error.argument = 1;
+Variant VariantUtilityFunctions::lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ if (from.get_type() != to.get_type()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = from.get_type();
+ r_error.argument = 1;
+ return Variant();
+ }
+
+ switch (from.get_type()) {
+ case Variant::INT: {
+ return lerpf(VariantInternalAccessor<int64_t>::get(&from), to, weight);
+ } break;
+ case Variant::FLOAT: {
+ return lerpf(VariantInternalAccessor<double>::get(&from), to, weight);
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&from).lerp(VariantInternalAccessor<Vector2>::get(&to), weight);
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&from).lerp(VariantInternalAccessor<Vector3>::get(&to), weight);
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&from).lerp(VariantInternalAccessor<Vector4>::get(&to), weight);
+ } break;
+ case Variant::QUATERNION: {
+ return VariantInternalAccessor<Quaternion>::get(&from).slerp(VariantInternalAccessor<Quaternion>::get(&to), weight);
+ } break;
+ case Variant::BASIS: {
+ return VariantInternalAccessor<Basis>::get(&from).slerp(VariantInternalAccessor<Basis>::get(&to), weight);
+ } break;
+ case Variant::COLOR: {
+ return VariantInternalAccessor<Color>::get(&from).lerp(VariantInternalAccessor<Color>::get(&to), weight);
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
-
- switch (from.get_type()) {
- case Variant::INT: {
- return lerpf(VariantInternalAccessor<int64_t>::get(&from), to, weight);
- } break;
- case Variant::FLOAT: {
- return lerpf(VariantInternalAccessor<double>::get(&from), to, weight);
- } break;
- case Variant::VECTOR2: {
- return VariantInternalAccessor<Vector2>::get(&from).lerp(VariantInternalAccessor<Vector2>::get(&to), weight);
- } break;
- case Variant::VECTOR3: {
- return VariantInternalAccessor<Vector3>::get(&from).lerp(VariantInternalAccessor<Vector3>::get(&to), weight);
- } break;
- case Variant::VECTOR4: {
- return VariantInternalAccessor<Vector4>::get(&from).lerp(VariantInternalAccessor<Vector4>::get(&to), weight);
- } break;
- case Variant::QUATERNION: {
- return VariantInternalAccessor<Quaternion>::get(&from).slerp(VariantInternalAccessor<Quaternion>::get(&to), weight);
- } break;
- case Variant::BASIS: {
- return VariantInternalAccessor<Basis>::get(&from).slerp(VariantInternalAccessor<Basis>::get(&to), weight);
- } break;
- case Variant::COLOR: {
- return VariantInternalAccessor<Color>::get(&from).lerp(VariantInternalAccessor<Color>::get(&to), weight);
- } break;
- default: {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
- }
}
+}
- static inline double lerpf(double from, double to, double weight) {
- return Math::lerp(from, to, weight);
- }
+double VariantUtilityFunctions::lerpf(double from, double to, double weight) {
+ return Math::lerp(from, to, weight);
+}
- static inline double cubic_interpolate(double from, double to, double pre, double post, double weight) {
- return Math::cubic_interpolate(from, to, pre, post, weight);
- }
+double VariantUtilityFunctions::cubic_interpolate(double from, double to, double pre, double post, double weight) {
+ return Math::cubic_interpolate(from, to, pre, post, weight);
+}
- static inline double cubic_interpolate_angle(double from, double to, double pre, double post, double weight) {
- return Math::cubic_interpolate_angle(from, to, pre, post, weight);
- }
+double VariantUtilityFunctions::cubic_interpolate_angle(double from, double to, double pre, double post, double weight) {
+ return Math::cubic_interpolate_angle(from, to, pre, post, weight);
+}
- static inline double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
- double to_t, double pre_t, double post_t) {
- return Math::cubic_interpolate_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
- }
+double VariantUtilityFunctions::cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t) {
+ return Math::cubic_interpolate_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+}
- static inline double cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
- double to_t, double pre_t, double post_t) {
- return Math::cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
- }
+double VariantUtilityFunctions::cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t) {
+ return Math::cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+}
- static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
- return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t);
- }
+double VariantUtilityFunctions::bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
+ return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t);
+}
- static inline double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
- return Math::bezier_derivative(p_start, p_control_1, p_control_2, p_end, p_t);
- }
+double VariantUtilityFunctions::bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
+ return Math::bezier_derivative(p_start, p_control_1, p_control_2, p_end, p_t);
+}
- static inline double lerp_angle(double from, double to, double weight) {
- return Math::lerp_angle(from, to, weight);
- }
+double VariantUtilityFunctions::lerp_angle(double from, double to, double weight) {
+ return Math::lerp_angle(from, to, weight);
+}
- static inline double inverse_lerp(double from, double to, double weight) {
- return Math::inverse_lerp(from, to, weight);
- }
+double VariantUtilityFunctions::inverse_lerp(double from, double to, double weight) {
+ return Math::inverse_lerp(from, to, weight);
+}
- static inline double remap(double value, double istart, double istop, double ostart, double ostop) {
- return Math::remap(value, istart, istop, ostart, ostop);
- }
+double VariantUtilityFunctions::remap(double value, double istart, double istop, double ostart, double ostop) {
+ return Math::remap(value, istart, istop, ostart, ostop);
+}
- static inline double smoothstep(double from, double to, double val) {
- return Math::smoothstep(from, to, val);
- }
+double VariantUtilityFunctions::smoothstep(double from, double to, double val) {
+ return Math::smoothstep(from, to, val);
+}
- static inline double move_toward(double from, double to, double delta) {
- return Math::move_toward(from, to, delta);
- }
+double VariantUtilityFunctions::move_toward(double from, double to, double delta) {
+ return Math::move_toward(from, to, delta);
+}
- static inline double deg_to_rad(double angle_deg) {
- return Math::deg_to_rad(angle_deg);
- }
+double VariantUtilityFunctions::deg_to_rad(double angle_deg) {
+ return Math::deg_to_rad(angle_deg);
+}
- static inline double rad_to_deg(double angle_rad) {
- return Math::rad_to_deg(angle_rad);
- }
+double VariantUtilityFunctions::rad_to_deg(double angle_rad) {
+ return Math::rad_to_deg(angle_rad);
+}
- static inline double linear_to_db(double linear) {
- return Math::linear_to_db(linear);
- }
+double VariantUtilityFunctions::linear_to_db(double linear) {
+ return Math::linear_to_db(linear);
+}
+
+double VariantUtilityFunctions::db_to_linear(double db) {
+ return Math::db_to_linear(db);
+}
- static inline double db_to_linear(double db) {
- return Math::db_to_linear(db);
+Variant VariantUtilityFunctions::wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error) {
+ Variant::Type x_type = p_x.get_type();
+ if (x_type != Variant::INT && x_type != Variant::FLOAT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = x_type;
+ return Variant();
}
- static inline Variant wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error) {
- Variant::Type x_type = p_x.get_type();
- if (x_type != Variant::INT && x_type != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = x_type;
- return Variant();
- }
+ Variant::Type min_type = p_min.get_type();
+ if (min_type != Variant::INT && min_type != Variant::FLOAT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = x_type;
+ return Variant();
+ }
- Variant::Type min_type = p_min.get_type();
- if (min_type != Variant::INT && min_type != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = x_type;
- return Variant();
- }
+ Variant::Type max_type = p_max.get_type();
+ if (max_type != Variant::INT && max_type != Variant::FLOAT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 2;
+ r_error.expected = x_type;
+ return Variant();
+ }
- Variant::Type max_type = p_max.get_type();
- if (max_type != Variant::INT && max_type != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 2;
- r_error.expected = x_type;
- return Variant();
- }
+ Variant value;
- Variant value;
-
- switch (x_type) {
- case Variant::INT: {
- if (x_type != min_type || x_type != max_type) {
- value = wrapf((double)p_x, (double)p_min, (double)p_max);
- } else {
- value = wrapi((int)p_x, (int)p_min, (int)p_max);
- }
- } break;
- case Variant::FLOAT: {
+ switch (x_type) {
+ case Variant::INT: {
+ if (x_type != min_type || x_type != max_type) {
value = wrapf((double)p_x, (double)p_min, (double)p_max);
- } break;
- default:
- break;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
- return value;
+ } else {
+ value = wrapi((int)p_x, (int)p_min, (int)p_max);
+ }
+ } break;
+ case Variant::FLOAT: {
+ value = wrapf((double)p_x, (double)p_min, (double)p_max);
+ } break;
+ default:
+ break;
}
- static inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
- return Math::wrapi(value, min, max);
- }
+ r_error.error = Callable::CallError::CALL_OK;
+ return value;
+}
- static inline double wrapf(double value, double min, double max) {
- return Math::wrapf(value, min, max);
- }
+int64_t VariantUtilityFunctions::wrapi(int64_t value, int64_t min, int64_t max) {
+ return Math::wrapi(value, min, max);
+}
- static inline double pingpong(double value, double length) {
- return Math::pingpong(value, length);
+double VariantUtilityFunctions::wrapf(double value, double min, double max) {
+ return Math::wrapf(value, min, max);
+}
+
+double VariantUtilityFunctions::pingpong(double value, double length) {
+ return Math::pingpong(value, length);
+}
+
+Variant VariantUtilityFunctions::max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.expected = 2;
+ return Variant();
}
+ Variant base = *p_args[0];
+ Variant ret;
- static inline Variant max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.expected = 2;
+ for (int i = 0; i < p_argcount; i++) {
+ Variant::Type arg_type = p_args[i]->get_type();
+ if (arg_type != Variant::INT && arg_type != Variant::FLOAT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = Variant::FLOAT;
+ r_error.argument = i;
return Variant();
}
- Variant base = *p_args[0];
- Variant ret;
-
- for (int i = 0; i < p_argcount; i++) {
- Variant::Type arg_type = p_args[i]->get_type();
- if (arg_type != Variant::INT && arg_type != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = Variant::FLOAT;
- r_error.argument = i;
- return Variant();
- }
- if (i == 0) {
- continue;
- }
- bool valid;
- Variant::evaluate(Variant::OP_LESS, base, *p_args[i], ret, valid);
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = base.get_type();
- r_error.argument = i;
- return Variant();
- }
- if (ret.booleanize()) {
- base = *p_args[i];
- }
+ if (i == 0) {
+ continue;
}
- r_error.error = Callable::CallError::CALL_OK;
- return base;
- }
-
- static inline double maxf(double x, double y) {
- return MAX(x, y);
- }
-
- static inline int64_t maxi(int64_t x, int64_t y) {
- return MAX(x, y);
- }
-
- static inline Variant min(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.expected = 2;
+ bool valid;
+ Variant::evaluate(Variant::OP_LESS, base, *p_args[i], ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = base.get_type();
+ r_error.argument = i;
return Variant();
}
- Variant base = *p_args[0];
- Variant ret;
-
- for (int i = 0; i < p_argcount; i++) {
- Variant::Type arg_type = p_args[i]->get_type();
- if (arg_type != Variant::INT && arg_type != Variant::FLOAT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = Variant::FLOAT;
- r_error.argument = i;
- return Variant();
- }
- if (i == 0) {
- continue;
- }
- bool valid;
- Variant::evaluate(Variant::OP_GREATER, base, *p_args[i], ret, valid);
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = base.get_type();
- r_error.argument = i;
- return Variant();
- }
- if (ret.booleanize()) {
- base = *p_args[i];
- }
+ if (ret.booleanize()) {
+ base = *p_args[i];
}
- r_error.error = Callable::CallError::CALL_OK;
- return base;
- }
-
- static inline double minf(double x, double y) {
- return MIN(x, y);
}
+ r_error.error = Callable::CallError::CALL_OK;
+ return base;
+}
- static inline int64_t mini(int64_t x, int64_t y) {
- return MIN(x, y);
- }
+double VariantUtilityFunctions::maxf(double x, double y) {
+ return MAX(x, y);
+}
- static inline Variant clamp(const Variant &x, const Variant &min, const Variant &max, Callable::CallError &r_error) {
- Variant value = x;
+int64_t VariantUtilityFunctions::maxi(int64_t x, int64_t y) {
+ return MAX(x, y);
+}
- Variant ret;
+Variant VariantUtilityFunctions::min(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.expected = 2;
+ return Variant();
+ }
+ Variant base = *p_args[0];
+ Variant ret;
- bool valid;
- Variant::evaluate(Variant::OP_LESS, value, min, ret, valid);
- if (!valid) {
+ for (int i = 0; i < p_argcount; i++) {
+ Variant::Type arg_type = p_args[i]->get_type();
+ if (arg_type != Variant::INT && arg_type != Variant::FLOAT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = value.get_type();
- r_error.argument = 1;
+ r_error.expected = Variant::FLOAT;
+ r_error.argument = i;
return Variant();
}
- if (ret.booleanize()) {
- value = min;
+ if (i == 0) {
+ continue;
}
- Variant::evaluate(Variant::OP_GREATER, value, max, ret, valid);
+ bool valid;
+ Variant::evaluate(Variant::OP_GREATER, base, *p_args[i], ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = value.get_type();
- r_error.argument = 2;
+ r_error.expected = base.get_type();
+ r_error.argument = i;
return Variant();
}
if (ret.booleanize()) {
- value = max;
+ base = *p_args[i];
}
+ }
+ r_error.error = Callable::CallError::CALL_OK;
+ return base;
+}
- r_error.error = Callable::CallError::CALL_OK;
+double VariantUtilityFunctions::minf(double x, double y) {
+ return MIN(x, y);
+}
- return value;
- }
+int64_t VariantUtilityFunctions::mini(int64_t x, int64_t y) {
+ return MIN(x, y);
+}
- static inline double clampf(double x, double min, double max) {
- return CLAMP(x, min, max);
- }
+Variant VariantUtilityFunctions::clamp(const Variant &x, const Variant &min, const Variant &max, Callable::CallError &r_error) {
+ Variant value = x;
- static inline int64_t clampi(int64_t x, int64_t min, int64_t max) {
- return CLAMP(x, min, max);
- }
+ Variant ret;
- static inline int64_t nearest_po2(int64_t x) {
- return nearest_power_of_2_templated(uint64_t(x));
+ bool valid;
+ Variant::evaluate(Variant::OP_LESS, value, min, ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = value.get_type();
+ r_error.argument = 1;
+ return Variant();
+ }
+ if (ret.booleanize()) {
+ value = min;
+ }
+ Variant::evaluate(Variant::OP_GREATER, value, max, ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = value.get_type();
+ r_error.argument = 2;
+ return Variant();
+ }
+ if (ret.booleanize()) {
+ value = max;
}
- // Random
+ r_error.error = Callable::CallError::CALL_OK;
- static inline void randomize() {
- Math::randomize();
- }
+ return value;
+}
- static inline int64_t randi() {
- return Math::rand();
- }
+double VariantUtilityFunctions::clampf(double x, double min, double max) {
+ return CLAMP(x, min, max);
+}
- static inline double randf() {
- return Math::randf();
- }
+int64_t VariantUtilityFunctions::clampi(int64_t x, int64_t min, int64_t max) {
+ return CLAMP(x, min, max);
+}
- static inline double randfn(double mean, double deviation) {
- return Math::randfn(mean, deviation);
- }
+int64_t VariantUtilityFunctions::nearest_po2(int64_t x) {
+ return nearest_power_of_2_templated(uint64_t(x));
+}
- static inline int64_t randi_range(int64_t from, int64_t to) {
- return Math::random((int32_t)from, (int32_t)to);
- }
+// Random
- static inline double randf_range(double from, double to) {
- return Math::random(from, to);
- }
+void VariantUtilityFunctions::randomize() {
+ Math::randomize();
+}
- static inline void seed(int64_t s) {
- return Math::seed(s);
- }
+int64_t VariantUtilityFunctions::randi() {
+ return Math::rand();
+}
- static inline PackedInt64Array rand_from_seed(int64_t seed) {
- uint64_t s = seed;
- PackedInt64Array arr;
- arr.resize(2);
- arr.write[0] = Math::rand_from_seed(&s);
- arr.write[1] = s;
- return arr;
- }
+double VariantUtilityFunctions::randf() {
+ return Math::randf();
+}
- // Utility
+double VariantUtilityFunctions::randfn(double mean, double deviation) {
+ return Math::randfn(mean, deviation);
+}
- static inline Variant weakref(const Variant &obj, Callable::CallError &r_error) {
- if (obj.get_type() == Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_OK;
- if (obj.is_ref_counted()) {
- Ref<WeakRef> wref = memnew(WeakRef);
- Ref<RefCounted> r = obj;
- if (r.is_valid()) {
- wref->set_ref(r);
- }
- return wref;
- } else {
- Ref<WeakRef> wref = memnew(WeakRef);
- Object *o = obj.get_validated_object();
- if (o) {
- wref->set_obj(o);
- }
- return wref;
- }
- } else if (obj.get_type() == Variant::NIL) {
- r_error.error = Callable::CallError::CALL_OK;
+int64_t VariantUtilityFunctions::randi_range(int64_t from, int64_t to) {
+ return Math::random((int32_t)from, (int32_t)to);
+}
+
+double VariantUtilityFunctions::randf_range(double from, double to) {
+ return Math::random(from, to);
+}
+
+void VariantUtilityFunctions::seed(int64_t s) {
+ return Math::seed(s);
+}
+
+PackedInt64Array VariantUtilityFunctions::rand_from_seed(int64_t seed) {
+ uint64_t s = seed;
+ PackedInt64Array arr;
+ arr.resize(2);
+ arr.write[0] = Math::rand_from_seed(&s);
+ arr.write[1] = s;
+ return arr;
+}
+
+// Utility
+
+Variant VariantUtilityFunctions::weakref(const Variant &obj, Callable::CallError &r_error) {
+ if (obj.get_type() == Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_OK;
+ if (obj.is_ref_counted()) {
Ref<WeakRef> wref = memnew(WeakRef);
+ Ref<RefCounted> r = obj;
+ if (r.is_valid()) {
+ wref->set_ref(r);
+ }
return wref;
} else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return Variant();
+ Ref<WeakRef> wref = memnew(WeakRef);
+ Object *o = obj.get_validated_object();
+ if (o) {
+ wref->set_obj(o);
+ }
+ return wref;
}
+ } else if (obj.get_type() == Variant::NIL) {
+ r_error.error = Callable::CallError::CALL_OK;
+ Ref<WeakRef> wref = memnew(WeakRef);
+ return wref;
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return Variant();
}
+}
- static inline int64_t _typeof(const Variant &obj) {
- return obj.get_type();
+int64_t VariantUtilityFunctions::_typeof(const Variant &obj) {
+ return obj.get_type();
+}
+
+String VariantUtilityFunctions::str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ return String();
}
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
- static inline String str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- return String();
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
}
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
+ }
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
- }
+ r_error.error = Callable::CallError::CALL_OK;
- r_error.error = Callable::CallError::CALL_OK;
+ return s;
+}
- return s;
+String VariantUtilityFunctions::error_string(Error error) {
+ if (error < 0 || error >= ERR_MAX) {
+ return String("(invalid error code)");
}
- static inline String error_string(Error error) {
- if (error < 0 || error >= ERR_MAX) {
- return String("(invalid error code)");
- }
+ return String(error_names[error]);
+}
- return String(error_names[error]);
+void VariantUtilityFunctions::print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
+ }
}
- static inline void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
+ print_line(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
- }
+void VariantUtilityFunctions::print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
- print_line(s);
- r_error.error = Callable::CallError::CALL_OK;
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
+ }
}
- static inline void print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ print_line_rich(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
+
+#undef print_verbose
+
+void VariantUtilityFunctions::print_verbose(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
String s;
for (int i = 0; i < p_arg_count; i++) {
String os = p_args[i]->operator String();
@@ -800,247 +817,227 @@ struct VariantUtilityFunctions {
}
}
- print_line_rich(s);
- r_error.error = Callable::CallError::CALL_OK;
+ // No need to use `print_verbose()` as this call already only happens
+ // when verbose mode is enabled. This avoids performing string argument concatenation
+ // when not needed.
+ print_line(s);
}
-#undef print_verbose
+ r_error.error = Callable::CallError::CALL_OK;
+}
- static inline void print_verbose(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
-
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
- }
+void VariantUtilityFunctions::printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
- // No need to use `print_verbose()` as this call already only happens
- // when verbose mode is enabled. This avoids performing string argument concatenation
- // when not needed.
- print_line(s);
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
}
-
- r_error.error = Callable::CallError::CALL_OK;
}
- static inline void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
+ print_error(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
+void VariantUtilityFunctions::printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ if (i) {
+ s += "\t";
}
-
- print_error(s);
- r_error.error = Callable::CallError::CALL_OK;
+ s += p_args[i]->operator String();
}
- static inline void printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- s += "\t";
- }
- s += p_args[i]->operator String();
- }
-
- print_line(s);
- r_error.error = Callable::CallError::CALL_OK;
- }
+ print_line(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
- static inline void prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- if (i) {
- s += " ";
- }
- s += p_args[i]->operator String();
+void VariantUtilityFunctions::prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ if (i) {
+ s += " ";
}
-
- print_line(s);
- r_error.error = Callable::CallError::CALL_OK;
+ s += p_args[i]->operator String();
}
- static inline void printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
+ print_line(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
+void VariantUtilityFunctions::printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
}
+ }
- OS::get_singleton()->print("%s", s.utf8().get_data());
- r_error.error = Callable::CallError::CALL_OK;
+ OS::get_singleton()->print("%s", s.utf8().get_data());
+ r_error.error = Callable::CallError::CALL_OK;
+}
+
+void VariantUtilityFunctions::push_error(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
}
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
- static inline void push_error(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
}
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
+ }
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
- }
+ ERR_PRINT(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
- ERR_PRINT(s);
- r_error.error = Callable::CallError::CALL_OK;
+void VariantUtilityFunctions::push_warning(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
}
+ String s;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
- static inline void push_warning(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- if (p_arg_count < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
+ if (i == 0) {
+ s = os;
+ } else {
+ s += os;
}
- String s;
- for (int i = 0; i < p_arg_count; i++) {
- String os = p_args[i]->operator String();
+ }
- if (i == 0) {
- s = os;
- } else {
- s += os;
- }
- }
+ WARN_PRINT(s);
+ r_error.error = Callable::CallError::CALL_OK;
+}
- WARN_PRINT(s);
- r_error.error = Callable::CallError::CALL_OK;
- }
+String VariantUtilityFunctions::var_to_str(const Variant &p_var) {
+ String vars;
+ VariantWriter::write_to_string(p_var, vars);
+ return vars;
+}
- static inline String var_to_str(const Variant &p_var) {
- String vars;
- VariantWriter::write_to_string(p_var, vars);
- return vars;
- }
+Variant VariantUtilityFunctions::str_to_var(const String &p_var) {
+ VariantParser::StreamString ss;
+ ss.s = p_var;
- static inline Variant str_to_var(const String &p_var) {
- VariantParser::StreamString ss;
- ss.s = p_var;
+ String errs;
+ int line;
+ Variant ret;
+ (void)VariantParser::parse(&ss, ret, errs, line);
- String errs;
- int line;
- Variant ret;
- (void)VariantParser::parse(&ss, ret, errs, line);
+ return ret;
+}
- return ret;
+PackedByteArray VariantUtilityFunctions::var_to_bytes(const Variant &p_var) {
+ int len;
+ Error err = encode_variant(p_var, nullptr, len, false);
+ if (err != OK) {
+ return PackedByteArray();
}
- static inline PackedByteArray var_to_bytes(const Variant &p_var) {
- int len;
- Error err = encode_variant(p_var, nullptr, len, false);
+ PackedByteArray barr;
+ barr.resize(len);
+ {
+ uint8_t *w = barr.ptrw();
+ err = encode_variant(p_var, w, len, false);
if (err != OK) {
return PackedByteArray();
}
+ }
- PackedByteArray barr;
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- err = encode_variant(p_var, w, len, false);
- if (err != OK) {
- return PackedByteArray();
- }
- }
+ return barr;
+}
- return barr;
+PackedByteArray VariantUtilityFunctions::var_to_bytes_with_objects(const Variant &p_var) {
+ int len;
+ Error err = encode_variant(p_var, nullptr, len, true);
+ if (err != OK) {
+ return PackedByteArray();
}
- static inline PackedByteArray var_to_bytes_with_objects(const Variant &p_var) {
- int len;
- Error err = encode_variant(p_var, nullptr, len, true);
+ PackedByteArray barr;
+ barr.resize(len);
+ {
+ uint8_t *w = barr.ptrw();
+ err = encode_variant(p_var, w, len, true);
if (err != OK) {
return PackedByteArray();
}
-
- PackedByteArray barr;
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- err = encode_variant(p_var, w, len, true);
- if (err != OK) {
- return PackedByteArray();
- }
- }
-
- return barr;
}
- static inline Variant bytes_to_var(const PackedByteArray &p_arr) {
- Variant ret;
- {
- const uint8_t *r = p_arr.ptr();
- Error err = decode_variant(ret, r, p_arr.size(), nullptr, false);
- if (err != OK) {
- return Variant();
- }
+ return barr;
+}
+
+Variant VariantUtilityFunctions::bytes_to_var(const PackedByteArray &p_arr) {
+ Variant ret;
+ {
+ const uint8_t *r = p_arr.ptr();
+ Error err = decode_variant(ret, r, p_arr.size(), nullptr, false);
+ if (err != OK) {
+ return Variant();
}
- return ret;
}
+ return ret;
+}
- static inline Variant bytes_to_var_with_objects(const PackedByteArray &p_arr) {
- Variant ret;
- {
- const uint8_t *r = p_arr.ptr();
- Error err = decode_variant(ret, r, p_arr.size(), nullptr, true);
- if (err != OK) {
- return Variant();
- }
+Variant VariantUtilityFunctions::bytes_to_var_with_objects(const PackedByteArray &p_arr) {
+ Variant ret;
+ {
+ const uint8_t *r = p_arr.ptr();
+ Error err = decode_variant(ret, r, p_arr.size(), nullptr, true);
+ if (err != OK) {
+ return Variant();
}
- return ret;
}
+ return ret;
+}
- static inline int64_t hash(const Variant &p_arr) {
- return p_arr.hash();
- }
+int64_t VariantUtilityFunctions::hash(const Variant &p_arr) {
+ return p_arr.hash();
+}
- static inline Object *instance_from_id(int64_t p_id) {
- ObjectID id = ObjectID((uint64_t)p_id);
- Object *ret = ObjectDB::get_instance(id);
- return ret;
- }
+Object *VariantUtilityFunctions::instance_from_id(int64_t p_id) {
+ ObjectID id = ObjectID((uint64_t)p_id);
+ Object *ret = ObjectDB::get_instance(id);
+ return ret;
+}
- static inline bool is_instance_id_valid(int64_t p_id) {
- return ObjectDB::get_instance(ObjectID((uint64_t)p_id)) != nullptr;
- }
+bool VariantUtilityFunctions::is_instance_id_valid(int64_t p_id) {
+ return ObjectDB::get_instance(ObjectID((uint64_t)p_id)) != nullptr;
+}
- static inline bool is_instance_valid(const Variant &p_instance) {
- if (p_instance.get_type() != Variant::OBJECT) {
- return false;
- }
- return p_instance.get_validated_object() != nullptr;
+bool VariantUtilityFunctions::is_instance_valid(const Variant &p_instance) {
+ if (p_instance.get_type() != Variant::OBJECT) {
+ return false;
}
+ return p_instance.get_validated_object() != nullptr;
+}
- static inline uint64_t rid_allocate_id() {
- return RID_AllocBase::_gen_id();
- }
+uint64_t VariantUtilityFunctions::rid_allocate_id() {
+ return RID_AllocBase::_gen_id();
+}
- static inline RID rid_from_int64(uint64_t p_base) {
- return RID::from_uint64(p_base);
- }
+RID VariantUtilityFunctions::rid_from_int64(uint64_t p_base) {
+ return RID::from_uint64(p_base);
+}
- static inline bool is_same(const Variant &p_a, const Variant &p_b) {
- return p_a.identity_compare(p_b);
- }
-};
+bool VariantUtilityFunctions::is_same(const Variant &p_a, const Variant &p_b) {
+ return p_a.identity_compare(p_b);
+}
#ifdef DEBUG_METHODS_ENABLED
#define VCALLR *ret = p_func(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...)
diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h
new file mode 100644
index 0000000000..78f66987cb
--- /dev/null
+++ b/core/variant/variant_utility.h
@@ -0,0 +1,153 @@
+/**************************************************************************/
+/* variant_utility.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 VARIANT_UTILITY_H
+#define VARIANT_UTILITY_H
+
+#include "variant.h"
+
+struct VariantUtilityFunctions {
+ // Math
+ static double sin(double arg);
+ static double cos(double arg);
+ static double tan(double arg);
+ static double sinh(double arg);
+ static double cosh(double arg);
+ static double tanh(double arg);
+ static double asin(double arg);
+ static double acos(double arg);
+ static double atan(double arg);
+ static double atan2(double y, double x);
+ static double sqrt(double x);
+ static double fmod(double b, double r);
+ static double fposmod(double b, double r);
+ static int64_t posmod(int64_t b, int64_t r);
+ static Variant floor(Variant x, Callable::CallError &r_error);
+ static double floorf(double x);
+ static int64_t floori(double x);
+ static Variant ceil(Variant x, Callable::CallError &r_error);
+ static double ceilf(double x);
+ static int64_t ceili(double x);
+ static Variant round(Variant x, Callable::CallError &r_error);
+ static double roundf(double x);
+ static int64_t roundi(double x);
+ static Variant abs(const Variant &x, Callable::CallError &r_error);
+ static double absf(double x);
+ static int64_t absi(int64_t x);
+ static Variant sign(const Variant &x, Callable::CallError &r_error);
+ static double signf(double x);
+ static int64_t signi(int64_t x);
+ static double pow(double x, double y);
+ static double log(double x);
+ static double exp(double x);
+ static bool is_nan(double x);
+ static bool is_inf(double x);
+ static bool is_equal_approx(double x, double y);
+ static bool is_zero_approx(double x);
+ static bool is_finite(double x);
+ static double ease(float x, float curve);
+ static int step_decimals(float step);
+ static Variant snapped(const Variant &x, const Variant &step, Callable::CallError &r_error);
+ static double snappedf(double x, double step);
+ static int64_t snappedi(double x, int64_t step);
+ static Variant lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error);
+ static double lerpf(double from, double to, double weight);
+ static double cubic_interpolate(double from, double to, double pre, double post, double weight);
+ static double cubic_interpolate_angle(double from, double to, double pre, double post, double weight);
+ static double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t);
+ static double cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t);
+ static double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t);
+ static double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t);
+ static double lerp_angle(double from, double to, double weight);
+ static double inverse_lerp(double from, double to, double weight);
+ static double remap(double value, double istart, double istop, double ostart, double ostop);
+ static double smoothstep(double from, double to, double val);
+ static double move_toward(double from, double to, double delta);
+ static double deg_to_rad(double angle_deg);
+ static double rad_to_deg(double angle_rad);
+ static double linear_to_db(double linear);
+ static double db_to_linear(double db);
+ static Variant wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error);
+ static int64_t wrapi(int64_t value, int64_t min, int64_t max);
+ static double wrapf(double value, double min, double max);
+ static double pingpong(double value, double length);
+ static Variant max(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ static double maxf(double x, double y);
+ static int64_t maxi(int64_t x, int64_t y);
+ static Variant min(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ static double minf(double x, double y);
+ static int64_t mini(int64_t x, int64_t y);
+ static Variant clamp(const Variant &x, const Variant &min, const Variant &max, Callable::CallError &r_error);
+ static double clampf(double x, double min, double max);
+ static int64_t clampi(int64_t x, int64_t min, int64_t max);
+ static int64_t nearest_po2(int64_t x);
+ // Random
+ static void randomize();
+ static int64_t randi();
+ static double randf();
+ static double randfn(double mean, double deviation);
+ static int64_t randi_range(int64_t from, int64_t to);
+ static double randf_range(double from, double to);
+ static void seed(int64_t s);
+ static PackedInt64Array rand_from_seed(int64_t seed);
+ // Utility
+ static Variant weakref(const Variant &obj, Callable::CallError &r_error);
+ static int64_t _typeof(const Variant &obj);
+ static Variant type_convert(const Variant &p_variant, const Variant::Type p_type);
+ static String str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static String error_string(Error error);
+ static void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void print_rich(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+#undef print_verbose
+ static void print_verbose(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void push_error(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static void push_warning(const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
+ static String var_to_str(const Variant &p_var);
+ static Variant str_to_var(const String &p_var);
+ static PackedByteArray var_to_bytes(const Variant &p_var);
+ static PackedByteArray var_to_bytes_with_objects(const Variant &p_var);
+ static Variant bytes_to_var(const PackedByteArray &p_arr);
+ static Variant bytes_to_var_with_objects(const PackedByteArray &p_arr);
+ static int64_t hash(const Variant &p_arr);
+ static Object *instance_from_id(int64_t p_id);
+ static bool is_instance_id_valid(int64_t p_id);
+ static bool is_instance_valid(const Variant &p_instance);
+ static uint64_t rid_allocate_id();
+ static RID rid_from_int64(uint64_t p_base);
+ static bool is_same(const Variant &p_a, const Variant &p_b);
+};
+
+#endif // VARIANT_UTILITY_H