summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/engine.cpp9
-rw-r--r--core/config/engine.h4
-rw-r--r--core/config/project_settings.cpp54
-rw-r--r--core/core_bind.cpp32
-rw-r--r--core/core_bind.h16
-rw-r--r--core/core_constants.cpp11
-rw-r--r--core/debugger/remote_debugger.cpp87
-rw-r--r--core/debugger/remote_debugger.h2
-rw-r--r--core/doc_data.h340
-rw-r--r--core/extension/SCsub7
-rw-r--r--core/extension/extension_api_dump.cpp281
-rw-r--r--core/extension/extension_api_dump.h4
-rw-r--r--core/extension/gdextension.cpp569
-rw-r--r--core/extension/gdextension.h (renamed from core/extension/native_extension.h)60
-rw-r--r--core/extension/gdextension_interface.cpp1105
-rw-r--r--core/extension/gdextension_interface.h619
-rw-r--r--core/extension/gdextension_manager.cpp (renamed from core/extension/native_extension_manager.cpp)76
-rw-r--r--core/extension/gdextension_manager.h (renamed from core/extension/native_extension_manager.h)30
-rw-r--r--core/extension/gdnative_interface.cpp1074
-rw-r--r--core/extension/gdnative_interface.h592
-rw-r--r--core/extension/make_interface_dumper.py47
-rw-r--r--core/extension/native_extension.cpp458
-rw-r--r--core/input/gamecontrollerdb.txt120
-rw-r--r--core/input/input.cpp4
-rw-r--r--core/input/input_event.cpp17
-rw-r--r--core/input/input_event.h4
-rw-r--r--core/input/input_map.cpp36
-rw-r--r--core/input/shortcut.cpp2
-rw-r--r--core/io/dir_access.cpp2
-rw-r--r--core/io/file_access.cpp7
-rw-r--r--core/io/file_access.h5
-rw-r--r--core/io/image.cpp235
-rw-r--r--core/io/image.h21
-rw-r--r--core/io/image_loader.cpp6
-rw-r--r--core/io/packet_peer.h4
-rw-r--r--core/io/pck_packer.cpp4
-rw-r--r--core/io/resource.cpp2
-rw-r--r--core/io/resource_format_binary.cpp7
-rw-r--r--core/io/resource_loader.cpp70
-rw-r--r--core/io/resource_loader.h3
-rw-r--r--core/io/resource_saver.cpp47
-rw-r--r--core/io/resource_saver.h2
-rw-r--r--core/io/stream_peer.h8
-rw-r--r--core/io/xml_parser.cpp69
-rw-r--r--core/io/xml_parser.h8
-rw-r--r--core/io/zip_io.cpp12
-rw-r--r--core/math/aabb.cpp6
-rw-r--r--core/math/aabb.h2
-rw-r--r--core/math/audio_frame.h8
-rw-r--r--core/math/basis.cpp40
-rw-r--r--core/math/basis.h24
-rw-r--r--core/math/bvh_tree.h1
-rw-r--r--core/math/color.cpp80
-rw-r--r--core/math/color.h26
-rw-r--r--core/math/convex_hull.cpp54
-rw-r--r--core/math/convex_hull.h6
-rw-r--r--core/math/delaunay_3d.h1
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/geometry_3d.cpp52
-rw-r--r--core/math/geometry_3d.h12
-rw-r--r--core/math/math_defs.h10
-rw-r--r--core/math/math_funcs.h23
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h1
-rw-r--r--core/math/projection.cpp21
-rw-r--r--core/math/quaternion.cpp35
-rw-r--r--core/math/quaternion.h11
-rw-r--r--core/math/quick_hull.cpp19
-rw-r--r--core/math/random_number_generator.h2
-rw-r--r--core/math/rect2.cpp4
-rw-r--r--core/math/rect2.h11
-rw-r--r--core/math/rect2i.h2
-rw-r--r--core/math/transform_2d.cpp6
-rw-r--r--core/math/transform_2d.h1
-rw-r--r--core/math/transform_3d.cpp6
-rw-r--r--core/math/transform_3d.h1
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h25
-rw-r--r--core/math/vector2i.cpp6
-rw-r--r--core/math/vector2i.h1
-rw-r--r--core/math/vector3.cpp4
-rw-r--r--core/math/vector3.h30
-rw-r--r--core/math/vector3i.cpp7
-rw-r--r--core/math/vector3i.h1
-rw-r--r--core/math/vector4.cpp18
-rw-r--r--core/math/vector4.h1
-rw-r--r--core/math/vector4i.cpp8
-rw-r--r--core/math/vector4i.h1
-rw-r--r--core/object/class_db.cpp35
-rw-r--r--core/object/class_db.h4
-rw-r--r--core/object/make_virtuals.py12
-rw-r--r--core/object/method_bind.cpp4
-rw-r--r--core/object/method_bind.h82
-rw-r--r--core/object/object.cpp65
-rw-r--r--core/object/object.h120
-rw-r--r--core/object/ref_counted.h3
-rw-r--r--core/object/script_language.cpp13
-rw-r--r--core/object/script_language_extension.h87
-rw-r--r--core/object/undo_redo.cpp4
-rw-r--r--core/object/undo_redo.h1
-rw-r--r--core/object/worker_thread_pool.cpp4
-rw-r--r--core/os/main_loop.cpp18
-rw-r--r--core/os/midi_driver.cpp5
-rw-r--r--core/os/os.cpp32
-rw-r--r--core/os/os.h7
-rw-r--r--core/register_core_types.cpp34
-rw-r--r--core/string/optimized_translation.cpp33
-rw-r--r--core/string/optimized_translation.h1
-rw-r--r--core/string/translation.cpp55
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/translation_po.cpp17
-rw-r--r--core/string/translation_po.h1
-rw-r--r--core/string/ustring.cpp167
-rw-r--r--core/string/ustring.h8
-rw-r--r--core/templates/hashfuncs.h1
-rw-r--r--core/variant/array.cpp109
-rw-r--r--core/variant/array.h2
-rw-r--r--core/variant/binder_common.h2
-rw-r--r--core/variant/callable.h10
-rw-r--r--core/variant/container_type_validate.h34
-rw-r--r--core/variant/dictionary.cpp56
-rw-r--r--core/variant/native_ptr.h92
-rw-r--r--core/variant/type_info.h1
-rw-r--r--core/variant/variant.cpp375
-rw-r--r--core/variant/variant.h5
-rw-r--r--core/variant/variant_call.cpp387
-rw-r--r--core/variant/variant_construct.cpp3
-rw-r--r--core/variant/variant_construct.h58
-rw-r--r--core/variant/variant_destruct.cpp5
-rw-r--r--core/variant/variant_destruct.h5
-rw-r--r--core/variant/variant_internal.h33
-rw-r--r--core/variant/variant_op.cpp129
-rw-r--r--core/variant/variant_op.h89
-rw-r--r--core/variant/variant_parser.cpp84
-rw-r--r--core/variant/variant_parser.h42
-rw-r--r--core/variant/variant_utility.cpp100
136 files changed, 5357 insertions, 3828 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 21e910be5b..7aa5f4d06d 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -48,6 +48,15 @@ int Engine::get_physics_ticks_per_second() const {
return ips;
}
+void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
+ ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0.");
+ max_physics_steps_per_frame = p_max_physics_steps;
+}
+
+int Engine::get_max_physics_steps_per_frame() const {
+ return max_physics_steps_per_frame;
+}
+
void Engine::set_physics_jitter_fix(double p_threshold) {
if (p_threshold < 0) {
p_threshold = 0;
diff --git a/core/config/engine.h b/core/config/engine.h
index 21517e46b7..1b179c5727 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -63,6 +63,7 @@ private:
int _max_fps = 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;
@@ -93,6 +94,9 @@ public:
virtual void set_physics_ticks_per_second(int p_ips);
virtual int get_physics_ticks_per_second() const;
+ virtual void set_max_physics_steps_per_frame(int p_max_physics_steps);
+ virtual int get_max_physics_steps_per_frame() const;
+
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 001a351e0b..310df46085 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -82,7 +82,7 @@ String ProjectSettings::get_imported_files_path() const {
// Returns the features that a project must have when opened with this build of Godot.
// This is used by the project manager to provide the initial_settings for config/features.
const PackedStringArray ProjectSettings::get_required_features() {
- PackedStringArray features = PackedStringArray();
+ PackedStringArray features;
features.append(VERSION_BRANCH);
#ifdef REAL_T_IS_DOUBLE
features.append("Double Precision");
@@ -115,7 +115,7 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
// Returns the features that this project needs but this build of Godot lacks.
const PackedStringArray ProjectSettings::get_unsupported_features(const PackedStringArray &p_project_features) {
- PackedStringArray unsupported_features = PackedStringArray();
+ PackedStringArray unsupported_features;
PackedStringArray supported_features = singleton->_get_supported_features();
for (int i = 0; i < p_project_features.size(); i++) {
if (!supported_features.has(p_project_features[i])) {
@@ -153,8 +153,23 @@ 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.begins_with("res://") || p_path.begins_with("user://") ||
- (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ if (resource_path.is_empty() || (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ return p_path.simplify_path();
+ }
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = 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])) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found) {
return p_path.simplify_path();
}
@@ -604,7 +619,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
Error err = _setup(p_path, p_main_pack, p_upwards, p_ignore_override);
if (err == OK) {
- String custom_settings = GLOBAL_DEF("application/config/project_settings_override", "");
+ String custom_settings = GLOBAL_GET("application/config/project_settings_override");
if (!custom_settings.is_empty()) {
_load_settings_text(custom_settings);
}
@@ -1022,7 +1037,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
}
- ret = ProjectSettings::get_singleton()->get(p_var);
+ ret = GLOBAL_GET(p_var);
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
@@ -1185,6 +1200,7 @@ ProjectSettings::ProjectSettings() {
// Initialization of engine variables should be done in the setup() method,
// so that the values can be overridden from project.godot or project.binary.
+ CRASH_COND_MSG(singleton != nullptr, "Instantiating a new ProjectSettings singleton is not supported.");
singleton = this;
GLOBAL_DEF_BASIC("application/config/name", "");
@@ -1231,12 +1247,12 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
- GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f);
- custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01");
- GLOBAL_DEF_RST("audio/general/3d_panning_strength", 1.0f);
- custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01");
+ GLOBAL_DEF_RST("audio/general/2d_panning_strength", 0.5f);
+ custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01");
+ GLOBAL_DEF_RST("audio/general/3d_panning_strength", 0.5f);
+ custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01");
- PackedStringArray extensions = PackedStringArray();
+ PackedStringArray extensions;
extensions.push_back("gd");
if (Engine::get_singleton()->has_singleton("GodotSharp")) {
extensions.push_back("cs");
@@ -1277,6 +1293,22 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level);
custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
+ GLOBAL_DEF("debug/settings/crash_handler/message",
+ String("Please include this when reporting the bug to the project developer."));
+ GLOBAL_DEF("debug/settings/crash_handler/message.editor",
+ String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues"));
+ GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
+ GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
+ GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
+
+ GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers.
+
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
+ GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
+
// These properties will not show up in the dialog nor in the documentation. If you want to exclude whole groups, see _get_property_list() method.
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 7496ba1979..9503bd2575 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -236,8 +236,12 @@ Vector<String> OS::get_system_fonts() const {
return ::OS::get_singleton()->get_system_fonts();
}
-String OS::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const {
- return ::OS::get_singleton()->get_system_font_path(p_font_name, p_bold, p_italic);
+String OS::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const {
+ return ::OS::get_singleton()->get_system_font_path(p_font_name, p_weight, p_stretch, p_italic);
+}
+
+Vector<String> OS::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const {
+ return ::OS::get_singleton()->get_system_font_path_for_text(p_font_name, p_text, p_locale, p_script, p_weight, p_stretch, p_italic);
}
String OS::get_executable_path() const {
@@ -334,6 +338,10 @@ String OS::get_version() const {
return ::OS::get_singleton()->get_version();
}
+Vector<String> OS::get_video_adapter_driver_info() const {
+ return ::OS::get_singleton()->get_video_adapter_driver_info();
+}
+
Vector<String> OS::get_cmdline_args() {
List<String> cmdline = ::OS::get_singleton()->get_cmdline_args();
Vector<String> cmdlinev;
@@ -528,7 +536,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_processor_name"), &OS::get_processor_name);
ClassDB::bind_method(D_METHOD("get_system_fonts"), &OS::get_system_fonts);
- ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "bold", "italic"), &OS::get_system_font_path, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
ClassDB::bind_method(D_METHOD("read_string_from_stdin", "block"), &OS::read_string_from_stdin, DEFVAL(true));
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
@@ -549,6 +558,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
+ ClassDB::bind_method(D_METHOD("get_video_adapter_driver_info"), &OS::get_video_adapter_driver_info);
+
ClassDB::bind_method(D_METHOD("set_restart_on_exit", "restart", "arguments"), &OS::set_restart_on_exit, DEFVAL(Vector<String>()));
ClassDB::bind_method(D_METHOD("is_restart_on_exit_set"), &OS::is_restart_on_exit_set);
ClassDB::bind_method(D_METHOD("get_restart_on_exit_arguments"), &OS::get_restart_on_exit_arguments);
@@ -599,8 +610,8 @@ void OS::_bind_methods() {
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
- BIND_ENUM_CONSTANT(VIDEO_DRIVER_VULKAN);
- BIND_ENUM_CONSTANT(VIDEO_DRIVER_OPENGL_3);
+ BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
+ BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
BIND_ENUM_CONSTANT(DAY_SUNDAY);
BIND_ENUM_CONSTANT(DAY_MONDAY);
@@ -1471,6 +1482,14 @@ int Engine::get_physics_ticks_per_second() const {
return ::Engine::get_singleton()->get_physics_ticks_per_second();
}
+void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
+ ::Engine::get_singleton()->set_max_physics_steps_per_frame(p_max_physics_steps);
+}
+
+int Engine::get_max_physics_steps_per_frame() const {
+ return ::Engine::get_singleton()->get_max_physics_steps_per_frame();
+}
+
void Engine::set_physics_jitter_fix(double p_threshold) {
::Engine::get_singleton()->set_physics_jitter_fix(p_threshold);
}
@@ -1622,6 +1641,8 @@ bool Engine::is_printing_error_messages() const {
void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physics_ticks_per_second", "physics_ticks_per_second"), &Engine::set_physics_ticks_per_second);
ClassDB::bind_method(D_METHOD("get_physics_ticks_per_second"), &Engine::get_physics_ticks_per_second);
+ ClassDB::bind_method(D_METHOD("set_max_physics_steps_per_frame", "max_physics_steps"), &Engine::set_max_physics_steps_per_frame);
+ ClassDB::bind_method(D_METHOD("get_max_physics_steps_per_frame"), &Engine::get_max_physics_steps_per_frame);
ClassDB::bind_method(D_METHOD("set_physics_jitter_fix", "physics_jitter_fix"), &Engine::set_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_jitter_fix"), &Engine::get_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_interpolation_fraction"), &Engine::get_physics_interpolation_fraction);
@@ -1669,6 +1690,7 @@ void Engine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages");
ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_physics_steps_per_frame"), "set_max_physics_steps_per_frame", "get_max_physics_steps_per_frame");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix");
diff --git a/core/core_bind.h b/core/core_bind.h
index 9261698076..c863a8094c 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -124,9 +124,9 @@ protected:
static OS *singleton;
public:
- enum VideoDriver {
- VIDEO_DRIVER_VULKAN,
- VIDEO_DRIVER_OPENGL_3,
+ enum RenderingDriver {
+ RENDERING_DRIVER_VULKAN,
+ RENDERING_DRIVER_OPENGL3,
};
enum Weekday {
@@ -170,7 +170,8 @@ public:
void crash(const String &p_message);
Vector<String> get_system_fonts() const;
- String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const;
+ String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
+ Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
String get_executable_path() const;
String read_string_from_stdin(bool p_block = true);
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
@@ -196,6 +197,8 @@ public:
Vector<String> get_cmdline_args();
Vector<String> get_cmdline_user_args();
+ Vector<String> get_video_adapter_driver_info() const;
+
String get_locale() const;
String get_locale_language() const;
@@ -484,6 +487,9 @@ public:
void set_physics_ticks_per_second(int p_ips);
int get_physics_ticks_per_second() const;
+ void set_max_physics_steps_per_frame(int p_max_physics_steps);
+ int get_max_physics_steps_per_frame() const;
+
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
double get_physics_interpolation_fraction() const;
@@ -576,7 +582,7 @@ VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
-VARIANT_ENUM_CAST(core_bind::OS::VideoDriver);
+VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::Weekday);
VARIANT_ENUM_CAST(core_bind::OS::Month);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index c784d87c87..c72b6212d7 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -153,6 +153,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TOP_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_CENTER_TO);
+ BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BASELINE_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_BOTTOM_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TO_TOP);
@@ -167,6 +168,13 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XYZ);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XZY);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YXZ);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YZX);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZXY);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZYX);
+
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
@@ -588,8 +596,6 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
- BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
- BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
@@ -632,7 +638,6 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NULL);
- BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_ANIMATE_AS_TRIGGER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CLASS_IS_ENUM);
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 23ee977df4..a2e3fab82c 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -39,89 +39,6 @@
#include "core/object/script_language.h"
#include "core/os/os.h"
-class RemoteDebugger::MultiplayerProfiler : public EngineProfiler {
- struct BandwidthFrame {
- uint32_t timestamp;
- int packet_size;
- };
-
- int bandwidth_in_ptr = 0;
- Vector<BandwidthFrame> bandwidth_in;
- int bandwidth_out_ptr = 0;
- Vector<BandwidthFrame> bandwidth_out;
- uint64_t last_bandwidth_time = 0;
-
- int bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) {
- ERR_FAIL_COND_V(p_buffer.size() == 0, 0);
- int total_bandwidth = 0;
-
- uint64_t timestamp = OS::get_singleton()->get_ticks_msec();
- uint64_t final_timestamp = timestamp - 1000;
-
- int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size();
-
- while (i != p_pointer && p_buffer[i].packet_size > 0) {
- if (p_buffer[i].timestamp < final_timestamp) {
- return total_bandwidth;
- }
- total_bandwidth += p_buffer[i].packet_size;
- i = (i + p_buffer.size() - 1) % p_buffer.size();
- }
-
- ERR_FAIL_COND_V_MSG(i == p_pointer, total_bandwidth, "Reached the end of the bandwidth profiler buffer, values might be inaccurate.");
- return total_bandwidth;
- }
-
-public:
- void toggle(bool p_enable, const Array &p_opts) {
- if (!p_enable) {
- bandwidth_in.clear();
- bandwidth_out.clear();
- } else {
- bandwidth_in_ptr = 0;
- bandwidth_in.resize(16384); // ~128kB
- for (int i = 0; i < bandwidth_in.size(); ++i) {
- bandwidth_in.write[i].packet_size = -1;
- }
- bandwidth_out_ptr = 0;
- bandwidth_out.resize(16384); // ~128kB
- for (int i = 0; i < bandwidth_out.size(); ++i) {
- bandwidth_out.write[i].packet_size = -1;
- }
- }
- }
-
- void add(const Array &p_data) {
- ERR_FAIL_COND(p_data.size() < 3);
- const String inout = p_data[0];
- int time = p_data[1];
- int size = p_data[2];
- if (inout == "in") {
- bandwidth_in.write[bandwidth_in_ptr].timestamp = time;
- bandwidth_in.write[bandwidth_in_ptr].packet_size = size;
- bandwidth_in_ptr = (bandwidth_in_ptr + 1) % bandwidth_in.size();
- } else if (inout == "out") {
- bandwidth_out.write[bandwidth_out_ptr].timestamp = time;
- bandwidth_out.write[bandwidth_out_ptr].packet_size = size;
- bandwidth_out_ptr = (bandwidth_out_ptr + 1) % bandwidth_out.size();
- }
- }
-
- void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
- uint64_t pt = OS::get_singleton()->get_ticks_msec();
- if (pt - last_bandwidth_time > 200) {
- last_bandwidth_time = pt;
- int incoming_bandwidth = bandwidth_usage(bandwidth_in, bandwidth_in_ptr);
- int outgoing_bandwidth = bandwidth_usage(bandwidth_out, bandwidth_out_ptr);
-
- Array arr;
- arr.push_back(incoming_bandwidth);
- arr.push_back(outgoing_bandwidth);
- EngineDebugger::get_singleton()->send_message("multiplayer:bandwidth", arr);
- }
- }
-};
-
class RemoteDebugger::PerformanceProfiler : public EngineProfiler {
Object *performance = nullptr;
int last_perf_time = 0;
@@ -659,10 +576,6 @@ RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
max_errors_per_second = GLOBAL_GET("network/limits/debugger/max_errors_per_second");
max_warnings_per_second = GLOBAL_GET("network/limits/debugger/max_warnings_per_second");
- // Multiplayer Profiler
- multiplayer_profiler.instantiate();
- multiplayer_profiler->bind("multiplayer");
-
// Performance Profiler
Object *perf = Engine::get_singleton()->get_singleton_object("Performance");
if (perf) {
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index fe4bbe86ea..944229d361 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -50,10 +50,8 @@ public:
private:
typedef DebuggerMarshalls::OutputError ErrorMessage;
- class MultiplayerProfiler;
class PerformanceProfiler;
- Ref<MultiplayerProfiler> multiplayer_profiler;
Ref<PerformanceProfiler> performance_profiler;
Ref<RemoteDebuggerPeer> peer;
diff --git a/core/doc_data.h b/core/doc_data.h
index bb356f027e..d5fbe37c96 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -57,6 +57,27 @@ public:
}
return name < p_arg.name;
}
+ static ArgumentDoc from_dict(const Dictionary &p_dict) {
+ ArgumentDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ return doc;
+ }
};
struct MethodDoc {
@@ -97,6 +118,55 @@ public:
}
return name < p_method.name;
}
+ static MethodDoc from_dict(const Dictionary &p_dict) {
+ MethodDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("return_type")) {
+ doc.return_type = p_dict["return_type"];
+ }
+
+ if (p_dict.has("return_enum")) {
+ doc.return_enum = p_dict["return_enum"];
+ }
+
+ if (p_dict.has("qualifiers")) {
+ doc.qualifiers = p_dict["qualifiers"];
+ }
+
+ 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"];
+ }
+
+ Array arguments;
+ if (p_dict.has("arguments")) {
+ arguments = p_dict["arguments"];
+ }
+ for (int i = 0; i < arguments.size(); i++) {
+ doc.arguments.push_back(ArgumentDoc::from_dict(arguments[i]));
+ }
+
+ Array errors_returned;
+ if (p_dict.has("errors_returned")) {
+ errors_returned = p_dict["errors_returned"];
+ }
+ for (int i = 0; i < errors_returned.size(); i++) {
+ doc.errors_returned.push_back(errors_returned[i]);
+ }
+
+ return doc;
+ }
};
struct ConstantDoc {
@@ -111,6 +181,43 @@ public:
bool operator<(const ConstantDoc &p_const) const {
return name < p_const.name;
}
+ static ConstantDoc from_dict(const Dictionary &p_dict) {
+ ConstantDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("value")) {
+ doc.value = p_dict["value"];
+ }
+
+ if (p_dict.has("is_value_valid")) {
+ doc.is_value_valid = p_dict["is_value_valid"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
+
+ 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;
+ }
};
struct EnumDoc {
@@ -118,6 +225,31 @@ public:
bool is_bitfield = false;
String description;
Vector<DocData::ConstantDoc> values;
+ static EnumDoc from_dict(const Dictionary &p_dict) {
+ EnumDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ Array values;
+ if (p_dict.has("values")) {
+ values = p_dict["values"];
+ }
+ for (int i = 0; i < values.size(); i++) {
+ doc.values.push_back(ConstantDoc::from_dict(values[i]));
+ }
+
+ return doc;
+ }
};
struct PropertyDoc {
@@ -134,6 +266,55 @@ public:
bool operator<(const PropertyDoc &p_prop) const {
return name < p_prop.name;
}
+ static PropertyDoc from_dict(const Dictionary &p_dict) {
+ PropertyDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("setter")) {
+ doc.setter = p_dict["setter"];
+ }
+
+ if (p_dict.has("getter")) {
+ doc.getter = p_dict["getter"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ if (p_dict.has("overridden")) {
+ doc.overridden = p_dict["overridden"];
+ }
+
+ if (p_dict.has("overrides")) {
+ doc.overrides = p_dict["overrides"];
+ }
+
+ 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;
+ }
};
struct ThemeItemDoc {
@@ -149,11 +330,49 @@ public:
}
return data_type < p_theme_item.data_type;
}
+ static ThemeItemDoc from_dict(const Dictionary &p_dict) {
+ ThemeItemDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("data_type")) {
+ doc.data_type = p_dict["data_type"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ return doc;
+ }
};
struct TutorialDoc {
String link;
String title;
+ static TutorialDoc from_dict(const Dictionary &p_dict) {
+ TutorialDoc doc;
+
+ if (p_dict.has("link")) {
+ doc.link = p_dict["link"];
+ }
+
+ if (p_dict.has("title")) {
+ doc.title = p_dict["title"];
+ }
+
+ return doc;
+ }
};
struct ClassDoc {
@@ -179,6 +398,127 @@ public:
bool operator<(const ClassDoc &p_class) const {
return name < p_class.name;
}
+ static ClassDoc from_dict(const Dictionary &p_dict) {
+ ClassDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("inherits")) {
+ doc.inherits = p_dict["inherits"];
+ }
+
+ if (p_dict.has("category")) {
+ doc.category = p_dict["category"];
+ }
+
+ if (p_dict.has("brief_description")) {
+ doc.brief_description = p_dict["brief_description"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ Array tutorials;
+ if (p_dict.has("tutorials")) {
+ tutorials = p_dict["tutorials"];
+ }
+ for (int i = 0; i < tutorials.size(); i++) {
+ doc.tutorials.push_back(TutorialDoc::from_dict(tutorials[i]));
+ }
+
+ Array constructors;
+ if (p_dict.has("constructors")) {
+ constructors = p_dict["constructors"];
+ }
+ for (int i = 0; i < constructors.size(); i++) {
+ doc.constructors.push_back(MethodDoc::from_dict(constructors[i]));
+ }
+
+ Array methods;
+ if (p_dict.has("methods")) {
+ methods = p_dict["methods"];
+ }
+ for (int i = 0; i < methods.size(); i++) {
+ doc.methods.push_back(MethodDoc::from_dict(methods[i]));
+ }
+
+ Array operators;
+ if (p_dict.has("operators")) {
+ operators = p_dict["operators"];
+ }
+ for (int i = 0; i < operators.size(); i++) {
+ doc.operators.push_back(MethodDoc::from_dict(operators[i]));
+ }
+
+ Array signals;
+ if (p_dict.has("signals")) {
+ signals = p_dict["signals"];
+ }
+ for (int i = 0; i < signals.size(); i++) {
+ doc.signals.push_back(MethodDoc::from_dict(signals[i]));
+ }
+
+ Array constants;
+ if (p_dict.has("constants")) {
+ constants = p_dict["constants"];
+ }
+ for (int i = 0; i < constants.size(); i++) {
+ doc.constants.push_back(ConstantDoc::from_dict(constants[i]));
+ }
+
+ Dictionary enums;
+ if (p_dict.has("enums")) {
+ 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);
+ }
+
+ Array properties;
+ if (p_dict.has("properties")) {
+ properties = p_dict["properties"];
+ }
+ for (int i = 0; i < properties.size(); i++) {
+ doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
+ }
+
+ Array annotations;
+ if (p_dict.has("annotations")) {
+ annotations = p_dict["annotations"];
+ }
+ for (int i = 0; i < annotations.size(); i++) {
+ doc.annotations.push_back(MethodDoc::from_dict(annotations[i]));
+ }
+
+ Array theme_properties;
+ if (p_dict.has("theme_properties")) {
+ theme_properties = p_dict["theme_properties"];
+ }
+ for (int i = 0; i < theme_properties.size(); i++) {
+ doc.theme_properties.push_back(ThemeItemDoc::from_dict(theme_properties[i]));
+ }
+
+ 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"];
+ }
+
+ if (p_dict.has("is_script_doc")) {
+ doc.is_script_doc = p_dict["is_script_doc"];
+ }
+
+ if (p_dict.has("script_path")) {
+ doc.script_path = p_dict["script_path"];
+ }
+
+ return doc;
+ }
};
static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
diff --git a/core/extension/SCsub b/core/extension/SCsub
index 23727c1b76..361ce43a2c 100644
--- a/core/extension/SCsub
+++ b/core/extension/SCsub
@@ -3,10 +3,15 @@
Import("env")
import make_wrappers
+import make_interface_dumper
from platform_methods import run_in_subprocess
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", run_in_subprocess(make_wrappers.run))
-
+env.CommandNoCache(
+ "gdextension_interface_dump.gen.h",
+ ["gdextension_interface.h", "make_interface_dumper.py"],
+ run_in_subprocess(make_interface_dumper.run),
+)
env_extension = env.Clone()
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index e6e0fff266..a0e3778dcc 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "extension_api_dump.h"
+
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
@@ -38,7 +39,15 @@
#ifdef TOOLS_ENABLED
-static String get_type_name(const PropertyInfo &p_info) {
+static String get_builtin_or_variant_type_name(const Variant::Type p_type) {
+ if (p_type == Variant::NIL) {
+ return "Variant";
+ } else {
+ return Variant::get_type_name(p_type);
+ }
+}
+
+static String get_property_info_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::INT && (p_info.hint == PROPERTY_HINT_INT_IS_POINTER)) {
if (p_info.hint_string.is_empty()) {
return "void*";
@@ -70,10 +79,10 @@ static String get_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::NIL) {
return "void";
}
- return Variant::get_type_name(p_info.type);
+ return get_builtin_or_variant_type_name(p_info.type);
}
-Dictionary NativeExtensionAPIDump::generate_extension_api() {
+Dictionary GDExtensionAPIDump::generate_extension_api() {
Dictionary api_dump;
{
@@ -168,8 +177,8 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
};
// Validate sizes at compile time for the current build configuration.
- static_assert(type_size_array[Variant::BOOL][sizeof(void *)] == sizeof(GDNativeBool), "Size of bool mismatch");
- static_assert(type_size_array[Variant::INT][sizeof(void *)] == sizeof(GDNativeInt), "Size of int mismatch");
+ static_assert(type_size_array[Variant::BOOL][sizeof(void *)] == sizeof(GDExtensionBool), "Size of bool mismatch");
+ static_assert(type_size_array[Variant::INT][sizeof(void *)] == sizeof(GDExtensionInt), "Size of int mismatch");
static_assert(type_size_array[Variant::FLOAT][sizeof(void *)] == sizeof(double), "Size of float mismatch");
static_assert(type_size_array[Variant::STRING][sizeof(void *)] == sizeof(String), "Size of String mismatch");
static_assert(type_size_array[Variant::VECTOR2][sizeof(void *)] == sizeof(Vector2), "Size of Vector2 mismatch");
@@ -243,63 +252,140 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
{
- // Member offsets sizes.
+ // Member offsets, meta types and sizes.
+
+#define REAL_MEMBER_OFFSET(type, member) \
+ { \
+ type, \
+ member, \
+ "float", \
+ sizeof(float), \
+ "float", \
+ sizeof(float), \
+ "double", \
+ sizeof(double), \
+ "double", \
+ sizeof(double), \
+ }
+
+#define INT32_MEMBER_OFFSET(type, member) \
+ { \
+ type, \
+ member, \
+ "int32", \
+ sizeof(int32_t), \
+ "int32", \
+ sizeof(int32_t), \
+ "int32", \
+ sizeof(int32_t), \
+ "int32", \
+ sizeof(int32_t), \
+ }
+
+#define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
+ { \
+ type, \
+ member, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ member_type, \
+ sizeof(int32_t) * member_elems, \
+ }
+
+#define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \
+ { \
+ type, \
+ member, \
+ member_type, \
+ sizeof(float) * member_elems, \
+ member_type, \
+ sizeof(float) * member_elems, \
+ member_type, \
+ sizeof(double) * member_elems, \
+ member_type, \
+ sizeof(double) * member_elems, \
+ }
+
struct {
Variant::Type type;
const char *member;
- uint32_t offset_32_bits_real_float;
- uint32_t offset_64_bits_real_float;
- uint32_t offset_32_bits_real_double;
- uint32_t offset_64_bits_real_double;
+ const char *member_meta_32_bits_real_float;
+ const uint32_t member_size_32_bits_real_float;
+ const char *member_meta_64_bits_real_float;
+ const uint32_t member_size_64_bits_real_float;
+ const char *member_meta_32_bits_real_double;
+ const uint32_t member_size_32_bits_real_double;
+ const char *member_meta_64_bits_real_double;
+ const uint32_t member_size_64_bits_real_double;
} member_offset_array[] = {
- { Variant::VECTOR2, "x", 0, 0, 0, 0 },
- { Variant::VECTOR2, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::VECTOR2I, "x", 0, 0, 0, 0 },
- { Variant::VECTOR2I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
- { Variant::RECT2, "position", 0, 0, 0, 0 },
- { Variant::RECT2, "size", 2 * sizeof(Vector2), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::RECT2I, "position", 0, 0, 0, 0 },
- { Variant::RECT2I, "size", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
- { Variant::VECTOR3, "x", 0, 0, 0, 0 },
- { Variant::VECTOR3, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::VECTOR3, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::VECTOR3I, "x", 0, 0, 0, 0 },
- { Variant::VECTOR3I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
- { Variant::VECTOR3I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
- { Variant::TRANSFORM2D, "x", 0, 0, 0, 0 },
- { Variant::TRANSFORM2D, "y", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::TRANSFORM2D, "origin", 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) },
- { Variant::VECTOR4, "x", 0, 0, 0, 0 },
- { Variant::VECTOR4, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::VECTOR4, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::VECTOR4, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) },
- { Variant::VECTOR4I, "x", 0, 0, 0, 0 },
- { Variant::VECTOR4I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
- { Variant::VECTOR4I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
- { Variant::VECTOR4I, "w", 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t) },
- { Variant::PLANE, "normal", 0, 0, 0, 0 },
- { Variant::PLANE, "d", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
- { Variant::QUATERNION, "x", 0, 0, 0, 0 },
- { Variant::QUATERNION, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
- { Variant::QUATERNION, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
- { Variant::QUATERNION, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) },
- { Variant::AABB, "position", 0, 0, 0, 0 },
- { Variant::AABB, "size", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
- // Remember that basis vectors are flipped!
- { Variant::BASIS, "x", 0, 0, 0, 0 },
- { Variant::BASIS, "y", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
- { Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) },
- { Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 },
- { Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
- { Variant::PROJECTION, "x", 0, 0, 0, 0 },
- { Variant::PROJECTION, "y", vec4_elems * sizeof(float), vec4_elems * sizeof(float), vec4_elems * sizeof(double), vec4_elems * sizeof(double) },
- { Variant::PROJECTION, "z", vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(double), vec4_elems * 2 * sizeof(double) },
- { Variant::PROJECTION, "w", vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(double), vec4_elems * 3 * sizeof(double) },
- { Variant::COLOR, "r", 0, 0, 0, 0 },
- { Variant::COLOR, "g", sizeof(float), sizeof(float), sizeof(float), sizeof(float) },
- { Variant::COLOR, "b", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) },
- { Variant::COLOR, "a", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float) },
- { Variant::NIL, nullptr, 0, 0, 0, 0 },
+ // Vector2
+ REAL_MEMBER_OFFSET(Variant::VECTOR2, "x"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR2, "y"),
+ // Vector2i
+ INT32_MEMBER_OFFSET(Variant::VECTOR2I, "x"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR2I, "y"),
+ // Rect2
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2, "position", "Vector2", 2),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2, "size", "Vector2", 2),
+ // Rect2i
+ INT32_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2I, "position", "Vector2i", 2),
+ INT32_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2I, "size", "Vector2i", 2),
+ // Vector3
+ REAL_MEMBER_OFFSET(Variant::VECTOR3, "x"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR3, "y"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR3, "z"),
+ // Vector3i
+ INT32_MEMBER_OFFSET(Variant::VECTOR3I, "x"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR3I, "y"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR3I, "z"),
+ // Transform2D
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "x", "Vector2", 2),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "y", "Vector2", 2),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "origin", "Vector2", 2),
+ // Vector4
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "x"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "y"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "z"),
+ REAL_MEMBER_OFFSET(Variant::VECTOR4, "w"),
+ // Vector4i
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "x"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "y"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "z"),
+ INT32_MEMBER_OFFSET(Variant::VECTOR4I, "w"),
+ // Plane
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PLANE, "normal", "Vector3", vec3_elems),
+ REAL_MEMBER_OFFSET(Variant::PLANE, "d"),
+ // Quaternion
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "x"),
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "y"),
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "z"),
+ REAL_MEMBER_OFFSET(Variant::QUATERNION, "w"),
+ // AABB
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::AABB, "position", "Vector3", vec3_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::AABB, "size", "Vector3", vec3_elems),
+ // Basis (remember that basis vectors are flipped!)
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "x", "Vector3", vec3_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "y", "Vector3", vec3_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "z", "Vector3", vec3_elems),
+ // Transform3D
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM3D, "basis", "Basis", vec3_elems * 3),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM3D, "origin", "Vector3", vec3_elems),
+ // Projection
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "x", "Vector4", vec4_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "y", "Vector4", vec4_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "z", "Vector4", vec4_elems),
+ REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "w", "Vector4", vec4_elems),
+ // Color (always composed of 4bytes floats)
+ { Variant::COLOR, "r", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ { Variant::COLOR, "g", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ { Variant::COLOR, "b", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ { Variant::COLOR, "a", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) },
+ // End marker, must stay last
+ { Variant::NIL, nullptr, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0 },
};
Array core_type_member_offsets;
@@ -310,15 +396,16 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Array type_offsets;
uint32_t idx = 0;
- Variant::Type last_type = Variant::NIL;
+ Variant::Type previous_type = Variant::NIL;
Dictionary d2;
Array members;
+ uint32_t offset = 0;
while (true) {
Variant::Type t = member_offset_array[idx].type;
- if (t != last_type) {
- if (last_type != Variant::NIL) {
+ if (t != previous_type) {
+ if (previous_type != Variant::NIL) {
d2["members"] = members;
type_offsets.push_back(d2);
}
@@ -329,27 +416,35 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
d2 = Dictionary();
members = Array();
+ offset = 0;
d2["name"] = name;
- last_type = t;
+ previous_type = t;
}
Dictionary d3;
- uint32_t offset = 0;
+ const char *member_meta = nullptr;
+ uint32_t member_size = 0;
switch (i) {
case 0:
- offset = member_offset_array[idx].offset_32_bits_real_float;
+ member_meta = member_offset_array[idx].member_meta_32_bits_real_float;
+ member_size = member_offset_array[idx].member_size_32_bits_real_float;
break;
case 1:
- offset = member_offset_array[idx].offset_64_bits_real_float;
+ member_meta = member_offset_array[idx].member_meta_64_bits_real_float;
+ member_size = member_offset_array[idx].member_size_64_bits_real_float;
break;
case 2:
- offset = member_offset_array[idx].offset_32_bits_real_double;
+ member_meta = member_offset_array[idx].member_meta_32_bits_real_double;
+ member_size = member_offset_array[idx].member_size_32_bits_real_double;
break;
case 3:
- offset = member_offset_array[idx].offset_64_bits_real_double;
+ member_meta = member_offset_array[idx].member_meta_64_bits_real_double;
+ member_size = member_offset_array[idx].member_size_64_bits_real_double;
break;
}
d3["member"] = member_offset_array[idx].member;
d3["offset"] = offset;
+ d3["meta"] = member_meta;
+ offset += member_size;
members.push_back(d3);
idx++;
}
@@ -430,8 +525,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary arg;
String argname = vararg ? "arg" + itos(i + 1) : Variant::get_utility_function_argument_name(name, i);
arg["name"] = argname;
- Variant::Type argtype = Variant::get_utility_function_argument_type(name, i);
- arg["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
+ arg["type"] = get_builtin_or_variant_type_name(Variant::get_utility_function_argument_type(name, i));
//no default value support in utility functions
arguments.push_back(arg);
}
@@ -461,8 +555,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d;
d["name"] = Variant::get_type_name(type);
if (Variant::has_indexing(type)) {
- Variant::Type index_type = Variant::get_indexed_element_type(type);
- d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
+ d["indexing_return_type"] = get_builtin_or_variant_type_name(Variant::get_indexed_element_type(type));
}
d["is_keyed"] = Variant::is_keyed(type);
@@ -476,7 +569,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (const StringName &member_name : member_names) {
Dictionary d2;
d2["name"] = String(member_name);
- d2["type"] = Variant::get_type_name(Variant::get_member_type(type, member_name));
+ d2["type"] = get_builtin_or_variant_type_name(Variant::get_member_type(type, member_name));
members.push_back(d2);
}
if (members.size()) {
@@ -493,7 +586,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = String(constant_name);
Variant constant = Variant::get_constant_value(type, constant_name);
- d2["type"] = Variant::get_type_name(constant.get_type());
+ d2["type"] = get_builtin_or_variant_type_name(constant.get_type());
d2["value"] = constant.get_construct_string();
constants.push_back(d2);
}
@@ -544,9 +637,9 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = Variant::get_operator_name(Variant::Operator(k));
if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) {
- d2["right_type"] = Variant::get_type_name(Variant::Type(j));
+ d2["right_type"] = get_builtin_or_variant_type_name(Variant::Type(j));
}
- d2["return_type"] = Variant::get_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
+ d2["return_type"] = get_builtin_or_variant_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
operators.push_back(d2);
}
}
@@ -580,8 +673,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int j = 0; j < argcount; j++) {
Dictionary d3;
d3["name"] = Variant::get_builtin_method_argument_name(type, method_name, j);
- Variant::Type argtype = Variant::get_builtin_method_argument_type(type, method_name, j);
- d3["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
+ d3["type"] = get_builtin_or_variant_type_name(Variant::get_builtin_method_argument_type(type, method_name, j));
if (j >= (argcount - default_args.size())) {
int dargidx = j - (argcount - default_args.size());
@@ -613,7 +705,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int k = 0; k < argcount; k++) {
Dictionary d3;
d3["name"] = Variant::get_constructor_argument_name(type, j, k);
- d3["type"] = Variant::get_type_name(Variant::get_constructor_argument_type(type, j, k));
+ d3["type"] = get_builtin_or_variant_type_name(Variant::get_constructor_argument_type(type, j, k));
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -741,7 +833,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d3["name"] = pinfo.name;
}
- d3["type"] = get_type_name(pinfo);
+ d3["type"] = get_property_info_type_name(pinfo);
if (i == -1) {
d2["return_value"] = d3;
@@ -784,7 +876,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
if (i >= 0) {
d3["name"] = pinfo.name;
}
- d3["type"] = get_type_name(pinfo);
+ d3["type"] = get_property_info_type_name(pinfo);
if (method->get_argument_meta(i) > 0) {
static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" };
@@ -831,7 +923,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int i = 0; i < F.arguments.size(); i++) {
Dictionary d3;
d3["name"] = F.arguments[i].name;
- d3["type"] = get_type_name(F.arguments[i]);
+ d3["type"] = get_property_info_type_name(F.arguments[i]);
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -863,11 +955,20 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
StringName property_name = F.name;
Dictionary d2;
- d2["type"] = get_type_name(F);
+ d2["type"] = get_property_info_type_name(F);
d2["name"] = String(property_name);
- d2["setter"] = ClassDB::get_property_setter(class_name, F.name);
- d2["getter"] = ClassDB::get_property_getter(class_name, F.name);
- d2["index"] = ClassDB::get_property_index(class_name, F.name);
+ StringName setter = ClassDB::get_property_setter(class_name, F.name);
+ if (!(setter == "")) {
+ d2["setter"] = setter;
+ }
+ StringName getter = ClassDB::get_property_getter(class_name, F.name);
+ if (!(getter == "")) {
+ d2["getter"] = getter;
+ }
+ int index = ClassDB::get_property_index(class_name, F.name);
+ if (index != -1) {
+ d2["index"] = index;
+ }
properties.push_back(d2);
}
@@ -928,14 +1029,14 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
return api_dump;
}
-void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path) {
+void GDExtensionAPIDump::generate_extension_json_file(const String &p_path) {
Dictionary api = generate_extension_api();
Ref<JSON> json;
json.instantiate();
- String text = json->stringify(api, "\t", false);
+ String text = json->stringify(api, "\t", false) + "\n";
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
- CharString cs = text.ascii();
- fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
+ fa->store_string(text);
}
-#endif
+
+#endif // TOOLS_ENABLED
diff --git a/core/extension/extension_api_dump.h b/core/extension/extension_api_dump.h
index 1bc455ea67..e488d8a086 100644
--- a/core/extension/extension_api_dump.h
+++ b/core/extension/extension_api_dump.h
@@ -31,11 +31,11 @@
#ifndef EXTENSION_API_DUMP_H
#define EXTENSION_API_DUMP_H
-#include "core/extension/native_extension.h"
+#include "core/extension/gdextension.h"
#ifdef TOOLS_ENABLED
-class NativeExtensionAPIDump {
+class GDExtensionAPIDump {
public:
static Dictionary generate_extension_api();
static void generate_extension_json_file(const String &p_path);
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
new file mode 100644
index 0000000000..0c5c736efe
--- /dev/null
+++ b/core/extension/gdextension.cpp
@@ -0,0 +1,569 @@
+/*************************************************************************/
+/* gdextension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "gdextension.h"
+#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/os/os.h"
+
+String GDExtension::get_extension_list_config_file() {
+ return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
+}
+
+String GDExtension::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) {
+ // First, check the explicit libraries.
+ if (p_config->has_section("libraries")) {
+ List<String> libraries;
+ p_config->get_section_keys("libraries", &libraries);
+
+ // Iterate the libraries, finding the best matching tags.
+ String best_library_path;
+ Vector<String> best_library_tags;
+ for (const String &E : libraries) {
+ Vector<String> tags = E.split(".");
+ bool all_tags_met = true;
+ for (int i = 0; i < tags.size(); i++) {
+ String tag = tags[i].strip_edges();
+ if (!p_has_feature(tag)) {
+ all_tags_met = false;
+ break;
+ }
+ }
+
+ if (all_tags_met && tags.size() > best_library_tags.size()) {
+ best_library_path = p_config->get_value("libraries", E);
+ best_library_tags = tags;
+ }
+ }
+
+ if (!best_library_path.is_empty()) {
+ if (best_library_path.is_relative_path()) {
+ best_library_path = p_path.get_base_dir().path_join(best_library_path);
+ }
+ if (r_tags != nullptr) {
+ r_tags->append_array(best_library_tags);
+ }
+ return best_library_path;
+ }
+ }
+
+ // Second, try to autodetect
+ String autodetect_library_prefix;
+ if (p_config->has_section_key("configuration", "autodetect_library_prefix")) {
+ autodetect_library_prefix = p_config->get_value("configuration", "autodetect_library_prefix");
+ }
+ if (!autodetect_library_prefix.is_empty()) {
+ String autodetect_path = autodetect_library_prefix;
+ if (autodetect_path.is_relative_path()) {
+ autodetect_path = p_path.get_base_dir().path_join(autodetect_path);
+ }
+
+ // Find the folder and file parts of the prefix.
+ String folder;
+ String file_prefix;
+ if (DirAccess::dir_exists_absolute(autodetect_path)) {
+ folder = autodetect_path;
+ } else if (DirAccess::dir_exists_absolute(autodetect_path.get_base_dir())) {
+ folder = autodetect_path.get_base_dir();
+ file_prefix = autodetect_path.get_file();
+ } else {
+ ERR_FAIL_V_MSG(String(), vformat("Error in extension: %s. Could not find folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
+ }
+
+ // Open the folder.
+ Ref<DirAccess> dir = DirAccess::open(folder);
+ ERR_FAIL_COND_V_MSG(!dir.is_valid(), String(), vformat("Error in extension: %s. Could not open folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix));
+
+ // Iterate the files and check the prefixes, finding the best matching file.
+ String best_file;
+ Vector<String> best_file_tags;
+ dir->list_dir_begin();
+ String file_name = dir->_get_next();
+ while (file_name != "") {
+ if (!dir->current_is_dir() && file_name.begins_with(file_prefix)) {
+ // Check if the files matches all requested feature tags.
+ String tags_str = file_name.trim_prefix(file_prefix);
+ tags_str = tags_str.trim_suffix(tags_str.get_extension());
+
+ Vector<String> tags = tags_str.split(".", false);
+ bool all_tags_met = true;
+ for (int i = 0; i < tags.size(); i++) {
+ String tag = tags[i].strip_edges();
+ if (!p_has_feature(tag)) {
+ all_tags_met = false;
+ break;
+ }
+ }
+
+ // If all tags are found in the feature list, and we found more tags than before, use this file.
+ if (all_tags_met && tags.size() > best_file_tags.size()) {
+ best_file_tags = tags;
+ best_file = file_name;
+ }
+ }
+ file_name = dir->_get_next();
+ }
+
+ if (!best_file.is_empty()) {
+ String library_path = folder.path_join(best_file);
+ if (r_tags != nullptr) {
+ r_tags->append_array(best_file_tags);
+ }
+ return library_path;
+ }
+ }
+ return String();
+}
+
+class GDExtensionMethodBind : public MethodBind {
+ GDExtensionClassMethodCall call_func;
+ GDExtensionClassMethodPtrCall ptrcall_func;
+ void *method_userdata;
+ bool vararg;
+ PropertyInfo return_value_info;
+ GodotTypeInfo::Metadata return_value_metadata;
+ List<PropertyInfo> arguments_info;
+ List<GodotTypeInfo::Metadata> arguments_metadata;
+
+protected:
+ virtual Variant::Type _gen_argument_type(int p_arg) const override {
+ if (p_arg < 0) {
+ return return_value_info.type;
+ } else {
+ return arguments_info[p_arg].type;
+ }
+ }
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
+ if (p_arg < 0) {
+ return return_value_info;
+ } else {
+ return arguments_info[p_arg];
+ }
+ }
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
+ if (p_arg < 0) {
+ return return_value_metadata;
+ } else {
+ return arguments_metadata[p_arg];
+ }
+ }
+#endif
+
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
+ Variant ret;
+ GDExtensionClassInstancePtr extension_instance = is_static() ? nullptr : p_object->_get_extension_instance();
+ GDExtensionCallError ce{ GDEXTENSION_CALL_OK, 0, 0 };
+ call_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstVariantPtr *>(p_args), p_arg_count, (GDExtensionVariantPtr)&ret, &ce);
+ r_error.error = Callable::CallError::Error(ce.error);
+ r_error.argument = ce.argument;
+ r_error.expected = ce.expected;
+ return ret;
+ }
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
+ ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
+ GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
+ ptrcall_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstTypePtr *>(p_args), (GDExtensionTypePtr)r_ret);
+ }
+
+ virtual bool is_vararg() const override {
+ return false;
+ }
+
+ explicit GDExtensionMethodBind(const GDExtensionClassMethodInfo *p_method_info) {
+ method_userdata = p_method_info->method_userdata;
+ call_func = p_method_info->call_func;
+ ptrcall_func = p_method_info->ptrcall_func;
+ set_name(*reinterpret_cast<StringName *>(p_method_info->name));
+
+ if (p_method_info->has_return_value) {
+ return_value_info = PropertyInfo(*p_method_info->return_value_info);
+ return_value_metadata = GodotTypeInfo::Metadata(p_method_info->return_value_metadata);
+ }
+
+ for (uint32_t i = 0; i < p_method_info->argument_count; i++) {
+ arguments_info.push_back(PropertyInfo(p_method_info->arguments_info[i]));
+ arguments_metadata.push_back(GodotTypeInfo::Metadata(p_method_info->arguments_metadata[i]));
+ }
+
+ set_hint_flags(p_method_info->method_flags);
+
+ vararg = p_method_info->method_flags & GDEXTENSION_METHOD_FLAG_VARARG;
+ _set_returns(p_method_info->has_return_value);
+ _set_const(p_method_info->method_flags & GDEXTENSION_METHOD_FLAG_CONST);
+ _set_static(p_method_info->method_flags & GDEXTENSION_METHOD_FLAG_STATIC);
+#ifdef DEBUG_METHODS_ENABLED
+ _generate_argument_types(p_method_info->argument_count);
+#endif
+ set_argument_count(p_method_info->argument_count);
+
+ Vector<Variant> defargs;
+ defargs.resize(p_method_info->default_argument_count);
+ for (uint32_t i = 0; i < p_method_info->default_argument_count; i++) {
+ defargs.write[i] = *static_cast<Variant *>(p_method_info->default_arguments[i]);
+ }
+
+ set_default_arguments(defargs);
+ }
+};
+
+static GDExtensionInterface gdextension_interface;
+
+void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName parent_class_name = *reinterpret_cast<const StringName *>(p_parent_class_name);
+ ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
+ ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
+
+ Extension *parent_extension = nullptr;
+
+ if (self->extension_classes.has(parent_class_name)) {
+ parent_extension = &self->extension_classes[parent_class_name];
+ } else if (ClassDB::class_exists(parent_class_name)) {
+ if (ClassDB::get_api_type(parent_class_name) == ClassDB::API_EXTENSION || ClassDB::get_api_type(parent_class_name) == ClassDB::API_EDITOR_EXTENSION) {
+ ERR_PRINT("Unimplemented yet");
+ //inheriting from another extension
+ } else {
+ //inheriting from engine class
+ }
+ } else {
+ ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'");
+ }
+
+ self->extension_classes[class_name] = Extension();
+
+ Extension *extension = &self->extension_classes[class_name];
+
+ if (parent_extension) {
+ extension->gdextension.parent = &parent_extension->gdextension;
+ parent_extension->gdextension.children.push_back(&extension->gdextension);
+ }
+
+ extension->gdextension.parent_class_name = parent_class_name;
+ extension->gdextension.class_name = class_name;
+ extension->gdextension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
+ extension->gdextension.is_virtual = p_extension_funcs->is_virtual;
+ extension->gdextension.is_abstract = p_extension_funcs->is_abstract;
+ extension->gdextension.set = p_extension_funcs->set_func;
+ extension->gdextension.get = p_extension_funcs->get_func;
+ extension->gdextension.get_property_list = p_extension_funcs->get_property_list_func;
+ extension->gdextension.free_property_list = p_extension_funcs->free_property_list_func;
+ extension->gdextension.property_can_revert = p_extension_funcs->property_can_revert_func;
+ extension->gdextension.property_get_revert = p_extension_funcs->property_get_revert_func;
+ extension->gdextension.notification = p_extension_funcs->notification_func;
+ extension->gdextension.to_string = p_extension_funcs->to_string_func;
+ extension->gdextension.reference = p_extension_funcs->reference_func;
+ extension->gdextension.unreference = p_extension_funcs->unreference_func;
+ extension->gdextension.class_userdata = p_extension_funcs->class_userdata;
+ extension->gdextension.create_instance = p_extension_funcs->create_instance_func;
+ extension->gdextension.free_instance = p_extension_funcs->free_instance_func;
+ extension->gdextension.get_virtual = p_extension_funcs->get_virtual_func;
+ extension->gdextension.get_rid = p_extension_funcs->get_rid_func;
+
+ ClassDB::register_extension_class(&extension->gdextension);
+}
+void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName method_name = *reinterpret_cast<const StringName *>(p_method_info->name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
+
+ //Extension *extension = &self->extension_classes[class_name];
+
+ GDExtensionMethodBind *method = memnew(GDExtensionMethodBind(p_method_info));
+ method->set_instance_class(class_name);
+
+ ClassDB::bind_method_custom(class_name, method);
+}
+void GDExtension::_register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName enum_name = *reinterpret_cast<const StringName *>(p_enum_name);
+ StringName constant_name = *reinterpret_cast<const StringName *>(p_constant_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + constant_name + "' for unexisting class '" + class_name + "'.");
+
+ ClassDB::bind_integer_constant(class_name, enum_name, constant_name, p_constant_value, p_is_bitfield);
+}
+
+void GDExtension::_register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName setter = *reinterpret_cast<const StringName *>(p_setter);
+ StringName getter = *reinterpret_cast<const StringName *>(p_getter);
+ String property_name = *reinterpret_cast<const StringName *>(p_info->name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'.");
+
+ //Extension *extension = &self->extension_classes[class_name];
+ PropertyInfo pinfo(*p_info);
+
+ ClassDB::add_property(class_name, pinfo, setter, getter);
+}
+
+void GDExtension::_register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_group_name, GDExtensionConstStringPtr p_prefix) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ String group_name = *reinterpret_cast<const String *>(p_group_name);
+ String prefix = *reinterpret_cast<const String *>(p_prefix);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + group_name + "' for unexisting class '" + class_name + "'.");
+
+ ClassDB::add_property_group(class_name, group_name, prefix);
+}
+
+void GDExtension::_register_extension_class_property_subgroup(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_subgroup_name, GDExtensionConstStringPtr p_prefix) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ String subgroup_name = *reinterpret_cast<const String *>(p_subgroup_name);
+ String prefix = *reinterpret_cast<const String *>(p_prefix);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + subgroup_name + "' for unexisting class '" + class_name + "'.");
+
+ ClassDB::add_property_subgroup(class_name, subgroup_name, prefix);
+}
+
+void GDExtension::_register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName signal_name = *reinterpret_cast<const StringName *>(p_signal_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + signal_name + "' for unexisting class '" + class_name + "'.");
+
+ MethodInfo s;
+ s.name = signal_name;
+ for (int i = 0; i < p_argument_count; i++) {
+ PropertyInfo arg(p_argument_info[i]);
+ s.arguments.push_back(arg);
+ }
+ ClassDB::add_signal(class_name, s);
+}
+
+void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
+ Extension *ext = &self->extension_classes[class_name];
+ ERR_FAIL_COND_MSG(ext->gdextension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
+
+ ClassDB::unregister_extension_class(class_name);
+ if (ext->gdextension.parent != nullptr) {
+ ext->gdextension.parent->children.erase(&ext->gdextension);
+ }
+ self->extension_classes.erase(class_name);
+}
+
+void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path) {
+ GDExtension *self = reinterpret_cast<GDExtension *>(p_library);
+
+ *(String *)r_path = self->library_path;
+}
+
+Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) {
+ Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path);
+ if (err != OK) {
+ ERR_PRINT("GDExtension dynamic library not found: " + p_path);
+ return err;
+ }
+
+ void *entry_funcptr = nullptr;
+
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false);
+
+ if (err != OK) {
+ ERR_PRINT("GDExtension entry point '" + p_entry_symbol + "' not found in library " + p_path);
+ OS::get_singleton()->close_dynamic_library(library);
+ return err;
+ }
+
+ GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
+
+ if (initialization_function(&gdextension_interface, this, &initialization)) {
+ level_initialized = -1;
+ return OK;
+ } else {
+ ERR_PRINT("GDExtension initialization function '" + p_entry_symbol + "' returned an error.");
+ return FAILED;
+ }
+}
+
+void GDExtension::close_library() {
+ ERR_FAIL_COND(library == nullptr);
+ OS::get_singleton()->close_dynamic_library(library);
+
+ library = nullptr;
+}
+
+bool GDExtension::is_library_open() const {
+ return library != nullptr;
+}
+
+GDExtension::InitializationLevel GDExtension::get_minimum_library_initialization_level() const {
+ ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE);
+ return InitializationLevel(initialization.minimum_initialization_level);
+}
+
+void GDExtension::initialize_library(InitializationLevel p_level) {
+ ERR_FAIL_COND(library == nullptr);
+ ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
+
+ level_initialized = int32_t(p_level);
+
+ ERR_FAIL_COND(initialization.initialize == nullptr);
+
+ initialization.initialize(initialization.userdata, GDExtensionInitializationLevel(p_level));
+}
+void GDExtension::deinitialize_library(InitializationLevel p_level) {
+ ERR_FAIL_COND(library == nullptr);
+ ERR_FAIL_COND(p_level > int32_t(level_initialized));
+
+ level_initialized = int32_t(p_level) - 1;
+ initialization.deinitialize(initialization.userdata, GDExtensionInitializationLevel(p_level));
+}
+
+void GDExtension::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library);
+ ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library);
+ ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open);
+
+ ClassDB::bind_method(D_METHOD("get_minimum_library_initialization_level"), &GDExtension::get_minimum_library_initialization_level);
+ ClassDB::bind_method(D_METHOD("initialize_library", "level"), &GDExtension::initialize_library);
+
+ BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_CORE);
+ BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SERVERS);
+ BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SCENE);
+ BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_EDITOR);
+}
+
+GDExtension::GDExtension() {
+}
+
+GDExtension::~GDExtension() {
+ if (library != nullptr) {
+ close_library();
+ }
+}
+
+extern void gdextension_setup_interface(GDExtensionInterface *p_interface);
+
+void GDExtension::initialize_gdextensions() {
+ gdextension_setup_interface(&gdextension_interface);
+
+ gdextension_interface.classdb_register_extension_class = _register_extension_class;
+ gdextension_interface.classdb_register_extension_class_method = _register_extension_class_method;
+ gdextension_interface.classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant;
+ gdextension_interface.classdb_register_extension_class_property = _register_extension_class_property;
+ gdextension_interface.classdb_register_extension_class_property_group = _register_extension_class_property_group;
+ gdextension_interface.classdb_register_extension_class_property_subgroup = _register_extension_class_property_subgroup;
+ gdextension_interface.classdb_register_extension_class_signal = _register_extension_class_signal;
+ gdextension_interface.classdb_unregister_extension_class = _unregister_extension_class;
+ gdextension_interface.get_library_path = _get_library_path;
+}
+
+Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ Error err = config->load(p_path);
+
+ if (r_error) {
+ *r_error = err;
+ }
+
+ if (err != OK) {
+ ERR_PRINT("Error loading GDExtension configuration file: " + p_path);
+ return Ref<Resource>();
+ }
+
+ if (!config->has_section_key("configuration", "entry_symbol")) {
+ if (r_error) {
+ *r_error = ERR_INVALID_DATA;
+ }
+ ERR_PRINT("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: " + p_path);
+ return Ref<Resource>();
+ }
+
+ String entry_symbol = config->get_value("configuration", "entry_symbol");
+
+ String library_path = GDExtension::find_extension_library(p_path, config, [](String p_feature) { return OS::get_singleton()->has_feature(p_feature); });
+
+ if (library_path.is_empty()) {
+ if (r_error) {
+ *r_error = ERR_FILE_NOT_FOUND;
+ }
+ const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
+ ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
+ return Ref<Resource>();
+ }
+
+ if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
+ library_path = p_path.get_base_dir().path_join(library_path);
+ }
+
+ Ref<GDExtension> lib;
+ lib.instantiate();
+ String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
+ err = lib->open_library(abs_path, entry_symbol);
+
+ if (r_error) {
+ *r_error = err;
+ }
+
+ if (err != OK) {
+ // Errors already logged in open_library()
+ return Ref<Resource>();
+ }
+
+ return lib;
+}
+
+void GDExtensionResourceLoader::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("gdextension");
+}
+
+bool GDExtensionResourceLoader::handles_type(const String &p_type) const {
+ return p_type == "GDExtension";
+}
+
+String GDExtensionResourceLoader::get_resource_type(const String &p_path) const {
+ String el = p_path.get_extension().to_lower();
+ if (el == "gdextension") {
+ return "GDExtension";
+ }
+ return "";
+}
diff --git a/core/extension/native_extension.h b/core/extension/gdextension.h
index b7238d2899..26ebdc9a08 100644
--- a/core/extension/native_extension.h
+++ b/core/extension/gdextension.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* native_extension.h */
+/* gdextension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,36 +28,39 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NATIVE_EXTENSION_H
-#define NATIVE_EXTENSION_H
+#ifndef GDEXTENSION_H
+#define GDEXTENSION_H
-#include "core/extension/gdnative_interface.h"
+#include <functional>
+
+#include "core/extension/gdextension_interface.h"
+#include "core/io/config_file.h"
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
-class NativeExtension : public Resource {
- GDCLASS(NativeExtension, Resource)
+class GDExtension : public Resource {
+ GDCLASS(GDExtension, Resource)
void *library = nullptr; // pointer if valid,
String library_path;
struct Extension {
- ObjectNativeExtension native_extension;
+ ObjectGDExtension gdextension;
};
HashMap<StringName, Extension> extension_classes;
- static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
- static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
- static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
- static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
- static void _register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
- static void _register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
- static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
- static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name);
- static void _get_library_path(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
-
- GDNativeInitialization initialization;
+ static void _register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs);
+ static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
+ static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
+ static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
+ static void _register_extension_class_property_group(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_group_name, GDExtensionConstStringNamePtr p_prefix);
+ static void _register_extension_class_property_subgroup(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_subgroup_name, GDExtensionConstStringNamePtr p_prefix);
+ static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
+ static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name);
+ static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
+
+ GDExtensionInitialization initialization;
int32_t level_initialized = -1;
protected:
@@ -65,15 +68,16 @@ protected:
public:
static String get_extension_list_config_file();
+ static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
Error open_library(const String &p_path, const String &p_entry_symbol);
void close_library();
enum InitializationLevel {
- INITIALIZATION_LEVEL_CORE = GDNATIVE_INITIALIZATION_CORE,
- INITIALIZATION_LEVEL_SERVERS = GDNATIVE_INITIALIZATION_SERVERS,
- INITIALIZATION_LEVEL_SCENE = GDNATIVE_INITIALIZATION_SCENE,
- INITIALIZATION_LEVEL_EDITOR = GDNATIVE_INITIALIZATION_EDITOR
+ INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
+ INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
+ INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
+ INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
};
bool is_library_open() const;
@@ -82,14 +86,14 @@ public:
void initialize_library(InitializationLevel p_level);
void deinitialize_library(InitializationLevel p_level);
- static void initialize_native_extensions();
- NativeExtension();
- ~NativeExtension();
+ static void initialize_gdextensions();
+ GDExtension();
+ ~GDExtension();
};
-VARIANT_ENUM_CAST(NativeExtension::InitializationLevel)
+VARIANT_ENUM_CAST(GDExtension::InitializationLevel)
-class NativeExtensionResourceLoader : public ResourceFormatLoader {
+class GDExtensionResourceLoader : public ResourceFormatLoader {
public:
virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
@@ -97,4 +101,4 @@ public:
virtual String get_resource_type(const String &p_path) const;
};
-#endif // NATIVE_EXTENSION_H
+#endif // GDEXTENSION_H
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
new file mode 100644
index 0000000000..2074495aa9
--- /dev/null
+++ b/core/extension/gdextension_interface.cpp
@@ -0,0 +1,1105 @@
+/*************************************************************************/
+/* gdextension_interface.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "gdextension_interface.h"
+
+#include "core/config/engine.h"
+#include "core/object/class_db.h"
+#include "core/object/script_language_extension.h"
+#include "core/os/memory.h"
+#include "core/variant/variant.h"
+#include "core/version.h"
+
+// Memory Functions
+static void *gdextension_alloc(size_t p_size) {
+ return memalloc(p_size);
+}
+
+static void *gdextension_realloc(void *p_mem, size_t p_size) {
+ return memrealloc(p_mem, p_size);
+}
+
+static void gdextension_free(void *p_mem) {
+ memfree(p_mem);
+}
+
+// Helper print functions.
+static void gdextension_print_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
+ _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_ERROR);
+}
+static void gdextension_print_warning(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
+ _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_WARNING);
+}
+static void gdextension_print_script_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
+ _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
+}
+
+uint64_t gdextension_get_native_struct_size(GDExtensionConstStringNamePtr p_name) {
+ const StringName name = *reinterpret_cast<const StringName *>(p_name);
+ return ClassDB::get_native_struct_size(name);
+}
+
+// Variant functions
+
+static void gdextension_variant_new_copy(GDExtensionVariantPtr r_dest, GDExtensionConstVariantPtr p_src) {
+ memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant(*reinterpret_cast<const Variant *>(p_src)));
+}
+static void gdextension_variant_new_nil(GDExtensionVariantPtr r_dest) {
+ memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant);
+}
+static void gdextension_variant_destroy(GDExtensionVariantPtr p_self) {
+ reinterpret_cast<Variant *>(p_self)->~Variant();
+}
+
+// variant type
+
+static void gdextension_variant_call(GDExtensionVariantPtr p_self, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argcount, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
+ Variant *self = (Variant *)p_self;
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ self->callp(method, args, p_argcount, ret, error);
+ memnew_placement(r_return, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (GDExtensionCallErrorType)(error.error);
+ r_error->argument = error.argument;
+ r_error->expected = error.expected;
+ }
+}
+
+static void gdextension_variant_call_static(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argcount, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
+ Variant::Type type = (Variant::Type)p_type;
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ Variant::call_static(type, method, args, p_argcount, ret, error);
+ memnew_placement(r_return, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (GDExtensionCallErrorType)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = error.expected;
+ }
+}
+
+static void gdextension_variant_evaluate(GDExtensionVariantOperator p_op, GDExtensionConstVariantPtr p_a, GDExtensionConstVariantPtr p_b, GDExtensionVariantPtr r_return, GDExtensionBool *r_valid) {
+ Variant::Operator op = (Variant::Operator)p_op;
+ const Variant *a = (const Variant *)p_a;
+ const Variant *b = (const Variant *)p_b;
+ Variant *ret = (Variant *)r_return;
+ bool valid;
+ Variant::evaluate(op, *a, *b, *ret, valid);
+ *r_valid = valid;
+}
+
+static void gdextension_variant_set(GDExtensionVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ const Variant *value = (const Variant *)p_value;
+
+ bool valid;
+ self->set(*key, *value, &valid);
+ *r_valid = valid;
+}
+
+static void gdextension_variant_set_named(GDExtensionVariantPtr p_self, GDExtensionConstStringNamePtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const StringName *key = (const StringName *)p_key;
+ const Variant *value = (const Variant *)p_value;
+
+ bool valid;
+ self->set_named(*key, *value, valid);
+ *r_valid = valid;
+}
+
+static void gdextension_variant_set_keyed(GDExtensionVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ const Variant *value = (const Variant *)p_value;
+
+ bool valid;
+ self->set_keyed(*key, *value, valid);
+ *r_valid = valid;
+}
+
+static void gdextension_variant_set_indexed(GDExtensionVariantPtr p_self, GDExtensionInt p_index, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid, GDExtensionBool *r_oob) {
+ Variant *self = (Variant *)p_self;
+ const Variant *value = (const Variant *)p_value;
+
+ bool valid;
+ bool oob;
+ self->set_indexed(p_index, *value, valid, oob);
+ *r_valid = valid;
+ *r_oob = oob;
+}
+
+static void gdextension_variant_get(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+
+ bool valid;
+ memnew_placement(r_ret, Variant(self->get(*key, &valid)));
+ *r_valid = valid;
+}
+
+static void gdextension_variant_get_named(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_key, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const StringName *key = (const StringName *)p_key;
+
+ bool valid;
+ memnew_placement(r_ret, Variant(self->get_named(*key, valid)));
+ *r_valid = valid;
+}
+
+static void gdextension_variant_get_keyed(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+
+ bool valid;
+ memnew_placement(r_ret, Variant(self->get_keyed(*key, valid)));
+ *r_valid = valid;
+}
+
+static void gdextension_variant_get_indexed(GDExtensionConstVariantPtr p_self, GDExtensionInt p_index, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid, GDExtensionBool *r_oob) {
+ const Variant *self = (const Variant *)p_self;
+
+ bool valid;
+ bool oob;
+ memnew_placement(r_ret, Variant(self->get_indexed(p_index, valid, oob)));
+ *r_valid = valid;
+ *r_oob = oob;
+}
+
+/// Iteration.
+static GDExtensionBool gdextension_variant_iter_init(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ Variant *iter = (Variant *)r_iter;
+
+ bool valid;
+ bool ret = self->iter_init(*iter, valid);
+ *r_valid = valid;
+ return ret;
+}
+
+static GDExtensionBool gdextension_variant_iter_next(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ Variant *iter = (Variant *)r_iter;
+
+ bool valid;
+ bool ret = self->iter_next(*iter, valid);
+ *r_valid = valid;
+ return ret;
+}
+
+static void gdextension_variant_iter_get(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ Variant *iter = (Variant *)r_iter;
+
+ bool valid;
+ memnew_placement(r_ret, Variant(self->iter_next(*iter, valid)));
+ *r_valid = valid;
+}
+
+/// Variant functions.
+static GDExtensionInt gdextension_variant_hash(GDExtensionConstVariantPtr p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return self->hash();
+}
+
+static GDExtensionInt gdextension_variant_recursive_hash(GDExtensionConstVariantPtr p_self, GDExtensionInt p_recursion_count) {
+ const Variant *self = (const Variant *)p_self;
+ return self->recursive_hash(p_recursion_count);
+}
+
+static GDExtensionBool gdextension_variant_hash_compare(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_other) {
+ const Variant *self = (const Variant *)p_self;
+ const Variant *other = (const Variant *)p_other;
+ return self->hash_compare(*other);
+}
+
+static GDExtensionBool gdextension_variant_booleanize(GDExtensionConstVariantPtr p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return self->booleanize();
+}
+
+static void gdextension_variant_duplicate(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_ret, GDExtensionBool p_deep) {
+ const Variant *self = (const Variant *)p_self;
+ memnew_placement(r_ret, Variant(self->duplicate(p_deep)));
+}
+
+static void gdextension_variant_stringify(GDExtensionConstVariantPtr p_self, GDExtensionStringPtr r_ret) {
+ const Variant *self = (const Variant *)p_self;
+ memnew_placement(r_ret, String(*self));
+}
+
+static GDExtensionVariantType gdextension_variant_get_type(GDExtensionConstVariantPtr p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return (GDExtensionVariantType)self->get_type();
+}
+
+static GDExtensionBool gdextension_variant_has_method(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_method) {
+ const Variant *self = (const Variant *)p_self;
+ const StringName *method = (const StringName *)p_method;
+ return self->has_method(*method);
+}
+
+static GDExtensionBool gdextension_variant_has_member(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member) {
+ return Variant::has_member((Variant::Type)p_type, *((const StringName *)p_member));
+}
+
+static GDExtensionBool gdextension_variant_has_key(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ bool valid;
+ bool ret = self->has_key(*key, valid);
+ *r_valid = valid;
+ return ret;
+}
+
+static void gdextension_variant_get_type_name(GDExtensionVariantType p_type, GDExtensionStringPtr r_ret) {
+ String name = Variant::get_type_name((Variant::Type)p_type);
+ memnew_placement(r_ret, String(name));
+}
+
+static GDExtensionBool gdextension_variant_can_convert(GDExtensionVariantType p_from, GDExtensionVariantType p_to) {
+ return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to);
+}
+
+static GDExtensionBool gdextension_variant_can_convert_strict(GDExtensionVariantType p_from, GDExtensionVariantType p_to) {
+ return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to);
+}
+
+// Variant interaction.
+static GDExtensionVariantFromTypeConstructorFunc gdextension_get_variant_from_type_constructor(GDExtensionVariantType p_type) {
+ switch (p_type) {
+ case GDEXTENSION_VARIANT_TYPE_BOOL:
+ return VariantTypeConstructor<bool>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_INT:
+ return VariantTypeConstructor<int64_t>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_FLOAT:
+ return VariantTypeConstructor<double>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_STRING:
+ return VariantTypeConstructor<String>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR2:
+ return VariantTypeConstructor<Vector2>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR2I:
+ return VariantTypeConstructor<Vector2i>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_RECT2:
+ return VariantTypeConstructor<Rect2>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_RECT2I:
+ return VariantTypeConstructor<Rect2i>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR3:
+ return VariantTypeConstructor<Vector3>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR3I:
+ return VariantTypeConstructor<Vector3i>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_TRANSFORM2D:
+ return VariantTypeConstructor<Transform2D>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR4:
+ return VariantTypeConstructor<Vector4>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR4I:
+ return VariantTypeConstructor<Vector4i>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PLANE:
+ return VariantTypeConstructor<Plane>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_QUATERNION:
+ return VariantTypeConstructor<Quaternion>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_AABB:
+ return VariantTypeConstructor<AABB>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_BASIS:
+ return VariantTypeConstructor<Basis>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_TRANSFORM3D:
+ return VariantTypeConstructor<Transform3D>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PROJECTION:
+ return VariantTypeConstructor<Projection>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_COLOR:
+ return VariantTypeConstructor<Color>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_STRING_NAME:
+ return VariantTypeConstructor<StringName>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_NODE_PATH:
+ return VariantTypeConstructor<NodePath>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_RID:
+ return VariantTypeConstructor<RID>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_OBJECT:
+ return VariantTypeConstructor<Object *>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_CALLABLE:
+ return VariantTypeConstructor<Callable>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_SIGNAL:
+ return VariantTypeConstructor<Signal>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_DICTIONARY:
+ return VariantTypeConstructor<Dictionary>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_ARRAY:
+ return VariantTypeConstructor<Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY:
+ return VariantTypeConstructor<PackedByteArray>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY:
+ return VariantTypeConstructor<PackedInt32Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY:
+ return VariantTypeConstructor<PackedInt64Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
+ return VariantTypeConstructor<PackedFloat32Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
+ return VariantTypeConstructor<PackedFloat64Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY:
+ return VariantTypeConstructor<PackedStringArray>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
+ return VariantTypeConstructor<PackedVector2Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
+ return VariantTypeConstructor<PackedVector3Array>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY:
+ return VariantTypeConstructor<PackedColorArray>::variant_from_type;
+ case GDEXTENSION_VARIANT_TYPE_NIL:
+ case GDEXTENSION_VARIANT_TYPE_VARIANT_MAX:
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+ }
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+}
+
+static GDExtensionTypeFromVariantConstructorFunc gdextension_get_type_from_variant_constructor(GDExtensionVariantType p_type) {
+ switch (p_type) {
+ case GDEXTENSION_VARIANT_TYPE_BOOL:
+ return VariantTypeConstructor<bool>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_INT:
+ return VariantTypeConstructor<int64_t>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_FLOAT:
+ return VariantTypeConstructor<double>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_STRING:
+ return VariantTypeConstructor<String>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR2:
+ return VariantTypeConstructor<Vector2>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR2I:
+ return VariantTypeConstructor<Vector2i>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_RECT2:
+ return VariantTypeConstructor<Rect2>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_RECT2I:
+ return VariantTypeConstructor<Rect2i>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR3:
+ return VariantTypeConstructor<Vector3>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR3I:
+ return VariantTypeConstructor<Vector3i>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_TRANSFORM2D:
+ return VariantTypeConstructor<Transform2D>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR4:
+ return VariantTypeConstructor<Vector4>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_VECTOR4I:
+ return VariantTypeConstructor<Vector4i>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PLANE:
+ return VariantTypeConstructor<Plane>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_QUATERNION:
+ return VariantTypeConstructor<Quaternion>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_AABB:
+ return VariantTypeConstructor<AABB>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_BASIS:
+ return VariantTypeConstructor<Basis>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_TRANSFORM3D:
+ return VariantTypeConstructor<Transform3D>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PROJECTION:
+ return VariantTypeConstructor<Projection>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_COLOR:
+ return VariantTypeConstructor<Color>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_STRING_NAME:
+ return VariantTypeConstructor<StringName>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_NODE_PATH:
+ return VariantTypeConstructor<NodePath>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_RID:
+ return VariantTypeConstructor<RID>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_OBJECT:
+ return VariantTypeConstructor<Object *>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_CALLABLE:
+ return VariantTypeConstructor<Callable>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_SIGNAL:
+ return VariantTypeConstructor<Signal>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_DICTIONARY:
+ return VariantTypeConstructor<Dictionary>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_ARRAY:
+ return VariantTypeConstructor<Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY:
+ return VariantTypeConstructor<PackedByteArray>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY:
+ return VariantTypeConstructor<PackedInt32Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY:
+ return VariantTypeConstructor<PackedInt64Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
+ return VariantTypeConstructor<PackedFloat32Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
+ return VariantTypeConstructor<PackedFloat64Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY:
+ return VariantTypeConstructor<PackedStringArray>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
+ return VariantTypeConstructor<PackedVector2Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
+ return VariantTypeConstructor<PackedVector3Array>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY:
+ return VariantTypeConstructor<PackedColorArray>::type_from_variant;
+ case GDEXTENSION_VARIANT_TYPE_NIL:
+ case GDEXTENSION_VARIANT_TYPE_VARIANT_MAX:
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+ }
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
+}
+
+// ptrcalls
+static GDExtensionPtrOperatorEvaluator gdextension_variant_get_ptr_operator_evaluator(GDExtensionVariantOperator p_operator, GDExtensionVariantType p_type_a, GDExtensionVariantType p_type_b) {
+ return (GDExtensionPtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
+}
+static GDExtensionPtrBuiltInMethod gdextension_variant_get_ptr_builtin_method(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_method, GDExtensionInt p_hash) {
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
+ uint32_t hash = Variant::get_builtin_method_hash(Variant::Type(p_type), method);
+ if (hash != p_hash) {
+ ERR_PRINT_ONCE("Error getting method " + method + ", hash mismatch.");
+ return nullptr;
+ }
+
+ return (GDExtensionPtrBuiltInMethod)Variant::get_ptr_builtin_method(Variant::Type(p_type), method);
+}
+static GDExtensionPtrConstructor gdextension_variant_get_ptr_constructor(GDExtensionVariantType p_type, int32_t p_constructor) {
+ return (GDExtensionPtrConstructor)Variant::get_ptr_constructor(Variant::Type(p_type), p_constructor);
+}
+static GDExtensionPtrDestructor gdextension_variant_get_ptr_destructor(GDExtensionVariantType p_type) {
+ return (GDExtensionPtrDestructor)Variant::get_ptr_destructor(Variant::Type(p_type));
+}
+static void gdextension_variant_construct(GDExtensionVariantType p_type, GDExtensionVariantPtr p_base, const GDExtensionConstVariantPtr *p_args, int32_t p_argument_count, GDExtensionCallError *r_error) {
+ memnew_placement(p_base, Variant);
+
+ Callable::CallError error;
+ Variant::construct(Variant::Type(p_type), *(Variant *)p_base, (const Variant **)p_args, p_argument_count, error);
+
+ if (r_error) {
+ r_error->error = (GDExtensionCallErrorType)(error.error);
+ r_error->argument = error.argument;
+ r_error->expected = error.expected;
+ }
+}
+static GDExtensionPtrSetter gdextension_variant_get_ptr_setter(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member) {
+ const StringName member = *reinterpret_cast<const StringName *>(p_member);
+ return (GDExtensionPtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), member);
+}
+static GDExtensionPtrGetter gdextension_variant_get_ptr_getter(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member) {
+ const StringName member = *reinterpret_cast<const StringName *>(p_member);
+ return (GDExtensionPtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), member);
+}
+static GDExtensionPtrIndexedSetter gdextension_variant_get_ptr_indexed_setter(GDExtensionVariantType p_type) {
+ return (GDExtensionPtrIndexedSetter)Variant::get_member_ptr_indexed_setter(Variant::Type(p_type));
+}
+static GDExtensionPtrIndexedGetter gdextension_variant_get_ptr_indexed_getter(GDExtensionVariantType p_type) {
+ return (GDExtensionPtrIndexedGetter)Variant::get_member_ptr_indexed_getter(Variant::Type(p_type));
+}
+static GDExtensionPtrKeyedSetter gdextension_variant_get_ptr_keyed_setter(GDExtensionVariantType p_type) {
+ return (GDExtensionPtrKeyedSetter)Variant::get_member_ptr_keyed_setter(Variant::Type(p_type));
+}
+static GDExtensionPtrKeyedGetter gdextension_variant_get_ptr_keyed_getter(GDExtensionVariantType p_type) {
+ return (GDExtensionPtrKeyedGetter)Variant::get_member_ptr_keyed_getter(Variant::Type(p_type));
+}
+static GDExtensionPtrKeyedChecker gdextension_variant_get_ptr_keyed_checker(GDExtensionVariantType p_type) {
+ return (GDExtensionPtrKeyedChecker)Variant::get_member_ptr_keyed_checker(Variant::Type(p_type));
+}
+static void gdextension_variant_get_constant_value(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_constant, GDExtensionVariantPtr r_ret) {
+ StringName constant = *reinterpret_cast<const StringName *>(p_constant);
+ memnew_placement(r_ret, Variant(Variant::get_constant_value(Variant::Type(p_type), constant)));
+}
+static GDExtensionPtrUtilityFunction gdextension_variant_get_ptr_utility_function(GDExtensionConstStringNamePtr p_function, GDExtensionInt p_hash) {
+ StringName function = *reinterpret_cast<const StringName *>(p_function);
+ uint32_t hash = Variant::get_utility_function_hash(function);
+ if (hash != p_hash) {
+ ERR_PRINT_ONCE("Error getting utility function " + function + ", hash mismatch.");
+ return nullptr;
+ }
+ return (GDExtensionPtrUtilityFunction)Variant::get_ptr_utility_function(function);
+}
+
+//string helpers
+
+static void gdextension_string_new_with_latin1_chars(GDExtensionStringPtr r_dest, const char *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String(p_contents);
+}
+
+static void gdextension_string_new_with_utf8_chars(GDExtensionStringPtr r_dest, const char *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf8(p_contents);
+}
+
+static void gdextension_string_new_with_utf16_chars(GDExtensionStringPtr r_dest, const char16_t *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf16(p_contents);
+}
+
+static void gdextension_string_new_with_utf32_chars(GDExtensionStringPtr r_dest, const char32_t *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents);
+}
+
+static void gdextension_string_new_with_wide_chars(GDExtensionStringPtr r_dest, const wchar_t *p_contents) {
+ String *dest = (String *)r_dest;
+ if constexpr (sizeof(wchar_t) == 2) {
+ // wchar_t is 16 bit, parse.
+ memnew_placement(dest, String);
+ dest->parse_utf16((const char16_t *)p_contents);
+ } else {
+ // wchar_t is 32 bit, copy.
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents);
+ }
+}
+
+static void gdextension_string_new_with_latin1_chars_and_len(GDExtensionStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String(p_contents, p_size);
+}
+
+static void gdextension_string_new_with_utf8_chars_and_len(GDExtensionStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf8(p_contents, p_size);
+}
+
+static void gdextension_string_new_with_utf16_chars_and_len(GDExtensionStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf16(p_contents, p_size);
+}
+
+static void gdextension_string_new_with_utf32_chars_and_len(GDExtensionStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents, p_size);
+}
+
+static void gdextension_string_new_with_wide_chars_and_len(GDExtensionStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_size) {
+ String *dest = (String *)r_dest;
+ if constexpr (sizeof(wchar_t) == 2) {
+ // wchar_t is 16 bit, parse.
+ memnew_placement(dest, String);
+ dest->parse_utf16((const char16_t *)p_contents, p_size);
+ } else {
+ // wchar_t is 32 bit, copy.
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents, p_size);
+ }
+}
+
+static GDExtensionInt gdextension_string_to_latin1_chars(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) {
+ String *self = (String *)p_self;
+ CharString cs = self->ascii(true);
+ GDExtensionInt len = cs.length();
+ if (r_text) {
+ const char *s_text = cs.ptr();
+ for (GDExtensionInt i = 0; i < MIN(len, p_max_write_length); i++) {
+ r_text[i] = s_text[i];
+ }
+ }
+ return len;
+}
+static GDExtensionInt gdextension_string_to_utf8_chars(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) {
+ String *self = (String *)p_self;
+ CharString cs = self->utf8();
+ GDExtensionInt len = cs.length();
+ if (r_text) {
+ const char *s_text = cs.ptr();
+ for (GDExtensionInt i = 0; i < MIN(len, p_max_write_length); i++) {
+ r_text[i] = s_text[i];
+ }
+ }
+ return len;
+}
+static GDExtensionInt gdextension_string_to_utf16_chars(GDExtensionConstStringPtr p_self, char16_t *r_text, GDExtensionInt p_max_write_length) {
+ String *self = (String *)p_self;
+ Char16String cs = self->utf16();
+ GDExtensionInt len = cs.length();
+ if (r_text) {
+ const char16_t *s_text = cs.ptr();
+ for (GDExtensionInt i = 0; i < MIN(len, p_max_write_length); i++) {
+ r_text[i] = s_text[i];
+ }
+ }
+ return len;
+}
+static GDExtensionInt gdextension_string_to_utf32_chars(GDExtensionConstStringPtr p_self, char32_t *r_text, GDExtensionInt p_max_write_length) {
+ String *self = (String *)p_self;
+ GDExtensionInt len = self->length();
+ if (r_text) {
+ const char32_t *s_text = self->ptr();
+ for (GDExtensionInt i = 0; i < MIN(len, p_max_write_length); i++) {
+ r_text[i] = s_text[i];
+ }
+ }
+ return len;
+}
+static GDExtensionInt gdextension_string_to_wide_chars(GDExtensionConstStringPtr p_self, wchar_t *r_text, GDExtensionInt p_max_write_length) {
+ if constexpr (sizeof(wchar_t) == 4) {
+ return gdextension_string_to_utf32_chars(p_self, (char32_t *)r_text, p_max_write_length);
+ } else {
+ return gdextension_string_to_utf16_chars(p_self, (char16_t *)r_text, p_max_write_length);
+ }
+}
+
+static char32_t *gdextension_string_operator_index(GDExtensionStringPtr p_self, GDExtensionInt p_index) {
+ String *self = (String *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr);
+ return &self->ptrw()[p_index];
+}
+
+static const char32_t *gdextension_string_operator_index_const(GDExtensionConstStringPtr p_self, GDExtensionInt p_index) {
+ const String *self = (const String *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr);
+ return &self->ptr()[p_index];
+}
+
+/* Packed array functions */
+
+static uint8_t *gdextension_packed_byte_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedByteArray *self = (PackedByteArray *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptrw()[p_index];
+}
+
+static const uint8_t *gdextension_packed_byte_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedByteArray *self = (const PackedByteArray *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptr()[p_index];
+}
+
+static GDExtensionTypePtr gdextension_packed_color_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedColorArray *self = (PackedColorArray *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionTypePtr)&self->ptrw()[p_index];
+}
+
+static GDExtensionTypePtr gdextension_packed_color_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedColorArray *self = (const PackedColorArray *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionTypePtr)&self->ptr()[p_index];
+}
+
+static float *gdextension_packed_float32_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedFloat32Array *self = (PackedFloat32Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptrw()[p_index];
+}
+
+static const float *gdextension_packed_float32_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedFloat32Array *self = (const PackedFloat32Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptr()[p_index];
+}
+
+static double *gdextension_packed_float64_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedFloat64Array *self = (PackedFloat64Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptrw()[p_index];
+}
+
+static const double *gdextension_packed_float64_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedFloat64Array *self = (const PackedFloat64Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptr()[p_index];
+}
+
+static int32_t *gdextension_packed_int32_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedInt32Array *self = (PackedInt32Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptrw()[p_index];
+}
+
+static const int32_t *gdextension_packed_int32_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedInt32Array *self = (const PackedInt32Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptr()[p_index];
+}
+
+static int64_t *gdextension_packed_int64_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedInt64Array *self = (PackedInt64Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptrw()[p_index];
+}
+
+static const int64_t *gdextension_packed_int64_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedInt64Array *self = (const PackedInt64Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return &self->ptr()[p_index];
+}
+
+static GDExtensionStringPtr gdextension_packed_string_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedStringArray *self = (PackedStringArray *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionStringPtr)&self->ptrw()[p_index];
+}
+
+static GDExtensionStringPtr gdextension_packed_string_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedStringArray *self = (const PackedStringArray *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionStringPtr)&self->ptr()[p_index];
+}
+
+static GDExtensionTypePtr gdextension_packed_vector2_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedVector2Array *self = (PackedVector2Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionTypePtr)&self->ptrw()[p_index];
+}
+
+static GDExtensionTypePtr gdextension_packed_vector2_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedVector2Array *self = (const PackedVector2Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionTypePtr)&self->ptr()[p_index];
+}
+
+static GDExtensionTypePtr gdextension_packed_vector3_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ PackedVector3Array *self = (PackedVector3Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionTypePtr)&self->ptrw()[p_index];
+}
+
+static GDExtensionTypePtr gdextension_packed_vector3_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const PackedVector3Array *self = (const PackedVector3Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionTypePtr)&self->ptr()[p_index];
+}
+
+static GDExtensionVariantPtr gdextension_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
+ Array *self = (Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionVariantPtr)&self->operator[](p_index);
+}
+
+static GDExtensionVariantPtr gdextension_array_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionInt p_index) {
+ const Array *self = (const Array *)p_self;
+ ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
+ return (GDExtensionVariantPtr)&self->operator[](p_index);
+}
+
+/* Dictionary functions */
+
+static GDExtensionVariantPtr gdextension_dictionary_operator_index(GDExtensionTypePtr p_self, GDExtensionConstVariantPtr p_key) {
+ Dictionary *self = (Dictionary *)p_self;
+ return (GDExtensionVariantPtr)&self->operator[](*(const Variant *)p_key);
+}
+
+static GDExtensionVariantPtr gdextension_dictionary_operator_index_const(GDExtensionConstTypePtr p_self, GDExtensionConstVariantPtr p_key) {
+ const Dictionary *self = (const Dictionary *)p_self;
+ return (GDExtensionVariantPtr)&self->operator[](*(const Variant *)p_key);
+}
+
+/* OBJECT API */
+
+static void gdextension_object_method_bind_call(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
+ const MethodBind *mb = reinterpret_cast<const MethodBind *>(p_method_bind);
+ Object *o = (Object *)p_instance;
+ const Variant **args = (const Variant **)p_args;
+ Callable::CallError error;
+
+ Variant ret = mb->call(o, args, p_arg_count, error);
+ memnew_placement(r_return, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (GDExtensionCallErrorType)(error.error);
+ r_error->argument = error.argument;
+ r_error->expected = error.expected;
+ }
+}
+
+static void gdextension_object_method_bind_ptrcall(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) {
+ const MethodBind *mb = reinterpret_cast<const MethodBind *>(p_method_bind);
+ Object *o = (Object *)p_instance;
+ mb->ptrcall(o, (const void **)p_args, p_ret);
+}
+
+static void gdextension_object_destroy(GDExtensionObjectPtr p_o) {
+ memdelete((Object *)p_o);
+}
+
+static GDExtensionObjectPtr gdextension_global_get_singleton(GDExtensionConstStringNamePtr p_name) {
+ const StringName name = *reinterpret_cast<const StringName *>(p_name);
+ return (GDExtensionObjectPtr)Engine::get_singleton()->get_singleton_object(name);
+}
+
+static void *gdextension_object_get_instance_binding(GDExtensionObjectPtr p_object, void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
+ Object *o = (Object *)p_object;
+ return o->get_instance_binding(p_token, p_callbacks);
+}
+
+static void gdextension_object_set_instance_binding(GDExtensionObjectPtr p_object, void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
+ Object *o = (Object *)p_object;
+ o->set_instance_binding(p_token, p_binding, p_callbacks);
+}
+
+static void gdextension_object_set_instance(GDExtensionObjectPtr p_object, GDExtensionConstStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ Object *o = (Object *)p_object;
+ ClassDB::set_object_extension_instance(o, classname, p_instance);
+}
+
+static GDExtensionObjectPtr gdextension_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
+ return (GDExtensionObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
+}
+
+static GDExtensionObjectPtr gdextension_object_cast_to(GDExtensionConstObjectPtr p_object, void *p_class_tag) {
+ if (!p_object) {
+ return nullptr;
+ }
+ Object *o = (Object *)p_object;
+
+ return o->is_class_ptr(p_class_tag) ? (GDExtensionObjectPtr)o : (GDExtensionObjectPtr) nullptr;
+}
+
+static GDObjectInstanceID gdextension_object_get_instance_id(GDExtensionConstObjectPtr p_object) {
+ const Object *o = (const Object *)p_object;
+ return (GDObjectInstanceID)o->get_instance_id();
+}
+
+static GDExtensionObjectPtr gdextension_ref_get_object(GDExtensionConstRefPtr p_ref) {
+ const Ref<RefCounted> *ref = (const Ref<RefCounted> *)p_ref;
+ if (ref == nullptr || ref->is_null()) {
+ return (GDExtensionObjectPtr) nullptr;
+ } else {
+ return (GDExtensionObjectPtr)ref->ptr();
+ }
+}
+
+static void gdextension_ref_set_object(GDExtensionRefPtr p_ref, GDExtensionObjectPtr p_object) {
+ Ref<RefCounted> *ref = (Ref<RefCounted> *)p_ref;
+ ERR_FAIL_NULL(ref);
+
+ Object *o = (RefCounted *)p_object;
+ ref->reference_ptr(o);
+}
+
+static GDExtensionScriptInstancePtr gdextension_script_instance_create(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data) {
+ ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension);
+ script_instance_extension->instance = p_instance_data;
+ script_instance_extension->native_info = p_info;
+ return reinterpret_cast<GDExtensionScriptInstancePtr>(script_instance_extension);
+}
+
+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);
+ MethodBind *mb = ClassDB::get_method(classname, methodname);
+ ERR_FAIL_COND_V(!mb, nullptr);
+ if (mb->get_hash() != p_hash) {
+ ERR_PRINT("Hash mismatch for method '" + classname + "." + methodname + "'.");
+ return nullptr;
+ }
+ return (GDExtensionMethodBindPtr)mb;
+}
+
+static GDExtensionObjectPtr gdextension_classdb_construct_object(GDExtensionConstStringNamePtr p_classname) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ return (GDExtensionObjectPtr)ClassDB::instantiate(classname);
+}
+
+static void *gdextension_classdb_get_class_tag(GDExtensionConstStringNamePtr p_classname) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(classname);
+ return class_info ? class_info->class_ptr : nullptr;
+}
+
+void gdextension_setup_interface(GDExtensionInterface *p_interface) {
+ GDExtensionInterface &gde_interface = *p_interface;
+
+ gde_interface.version_major = VERSION_MAJOR;
+ gde_interface.version_minor = VERSION_MINOR;
+#if VERSION_PATCH
+ gde_interface.version_patch = VERSION_PATCH;
+#else
+ gde_interface.version_patch = 0;
+#endif
+ gde_interface.version_string = VERSION_FULL_NAME;
+
+ /* GODOT CORE */
+
+ gde_interface.mem_alloc = gdextension_alloc;
+ gde_interface.mem_realloc = gdextension_realloc;
+ gde_interface.mem_free = gdextension_free;
+
+ gde_interface.print_error = gdextension_print_error;
+ gde_interface.print_warning = gdextension_print_warning;
+ gde_interface.print_script_error = gdextension_print_script_error;
+
+ gde_interface.get_native_struct_size = gdextension_get_native_struct_size;
+
+ /* GODOT VARIANT */
+
+ // variant general
+ gde_interface.variant_new_copy = gdextension_variant_new_copy;
+ gde_interface.variant_new_nil = gdextension_variant_new_nil;
+ gde_interface.variant_destroy = gdextension_variant_destroy;
+
+ gde_interface.variant_call = gdextension_variant_call;
+ gde_interface.variant_call_static = gdextension_variant_call_static;
+ gde_interface.variant_evaluate = gdextension_variant_evaluate;
+ gde_interface.variant_set = gdextension_variant_set;
+ gde_interface.variant_set_named = gdextension_variant_set_named;
+ gde_interface.variant_set_keyed = gdextension_variant_set_keyed;
+ gde_interface.variant_set_indexed = gdextension_variant_set_indexed;
+ gde_interface.variant_get = gdextension_variant_get;
+ gde_interface.variant_get_named = gdextension_variant_get_named;
+ gde_interface.variant_get_keyed = gdextension_variant_get_keyed;
+ gde_interface.variant_get_indexed = gdextension_variant_get_indexed;
+ gde_interface.variant_iter_init = gdextension_variant_iter_init;
+ gde_interface.variant_iter_next = gdextension_variant_iter_next;
+ gde_interface.variant_iter_get = gdextension_variant_iter_get;
+ gde_interface.variant_hash = gdextension_variant_hash;
+ gde_interface.variant_recursive_hash = gdextension_variant_recursive_hash;
+ gde_interface.variant_hash_compare = gdextension_variant_hash_compare;
+ gde_interface.variant_booleanize = gdextension_variant_booleanize;
+ gde_interface.variant_duplicate = gdextension_variant_duplicate;
+ gde_interface.variant_stringify = gdextension_variant_stringify;
+
+ gde_interface.variant_get_type = gdextension_variant_get_type;
+ gde_interface.variant_has_method = gdextension_variant_has_method;
+ gde_interface.variant_has_member = gdextension_variant_has_member;
+ gde_interface.variant_has_key = gdextension_variant_has_key;
+ gde_interface.variant_get_type_name = gdextension_variant_get_type_name;
+ gde_interface.variant_can_convert = gdextension_variant_can_convert;
+ gde_interface.variant_can_convert_strict = gdextension_variant_can_convert_strict;
+
+ gde_interface.get_variant_from_type_constructor = gdextension_get_variant_from_type_constructor;
+ gde_interface.get_variant_to_type_constructor = gdextension_get_type_from_variant_constructor;
+
+ // ptrcalls.
+
+ gde_interface.variant_get_ptr_operator_evaluator = gdextension_variant_get_ptr_operator_evaluator;
+ gde_interface.variant_get_ptr_builtin_method = gdextension_variant_get_ptr_builtin_method;
+ gde_interface.variant_get_ptr_constructor = gdextension_variant_get_ptr_constructor;
+ gde_interface.variant_get_ptr_destructor = gdextension_variant_get_ptr_destructor;
+ gde_interface.variant_construct = gdextension_variant_construct;
+ gde_interface.variant_get_ptr_setter = gdextension_variant_get_ptr_setter;
+ gde_interface.variant_get_ptr_getter = gdextension_variant_get_ptr_getter;
+ gde_interface.variant_get_ptr_indexed_setter = gdextension_variant_get_ptr_indexed_setter;
+ gde_interface.variant_get_ptr_indexed_getter = gdextension_variant_get_ptr_indexed_getter;
+ gde_interface.variant_get_ptr_keyed_setter = gdextension_variant_get_ptr_keyed_setter;
+ gde_interface.variant_get_ptr_keyed_getter = gdextension_variant_get_ptr_keyed_getter;
+ gde_interface.variant_get_ptr_keyed_checker = gdextension_variant_get_ptr_keyed_checker;
+ gde_interface.variant_get_constant_value = gdextension_variant_get_constant_value;
+ gde_interface.variant_get_ptr_utility_function = gdextension_variant_get_ptr_utility_function;
+
+ // extra utilities
+
+ gde_interface.string_new_with_latin1_chars = gdextension_string_new_with_latin1_chars;
+ gde_interface.string_new_with_utf8_chars = gdextension_string_new_with_utf8_chars;
+ gde_interface.string_new_with_utf16_chars = gdextension_string_new_with_utf16_chars;
+ gde_interface.string_new_with_utf32_chars = gdextension_string_new_with_utf32_chars;
+ gde_interface.string_new_with_wide_chars = gdextension_string_new_with_wide_chars;
+ gde_interface.string_new_with_latin1_chars_and_len = gdextension_string_new_with_latin1_chars_and_len;
+ gde_interface.string_new_with_utf8_chars_and_len = gdextension_string_new_with_utf8_chars_and_len;
+ gde_interface.string_new_with_utf16_chars_and_len = gdextension_string_new_with_utf16_chars_and_len;
+ gde_interface.string_new_with_utf32_chars_and_len = gdextension_string_new_with_utf32_chars_and_len;
+ gde_interface.string_new_with_wide_chars_and_len = gdextension_string_new_with_wide_chars_and_len;
+ gde_interface.string_to_latin1_chars = gdextension_string_to_latin1_chars;
+ gde_interface.string_to_utf8_chars = gdextension_string_to_utf8_chars;
+ gde_interface.string_to_utf16_chars = gdextension_string_to_utf16_chars;
+ gde_interface.string_to_utf32_chars = gdextension_string_to_utf32_chars;
+ gde_interface.string_to_wide_chars = gdextension_string_to_wide_chars;
+ gde_interface.string_operator_index = gdextension_string_operator_index;
+ gde_interface.string_operator_index_const = gdextension_string_operator_index_const;
+
+ /* Packed array functions */
+
+ gde_interface.packed_byte_array_operator_index = gdextension_packed_byte_array_operator_index;
+ gde_interface.packed_byte_array_operator_index_const = gdextension_packed_byte_array_operator_index_const;
+
+ gde_interface.packed_color_array_operator_index = gdextension_packed_color_array_operator_index;
+ gde_interface.packed_color_array_operator_index_const = gdextension_packed_color_array_operator_index_const;
+
+ gde_interface.packed_float32_array_operator_index = gdextension_packed_float32_array_operator_index;
+ gde_interface.packed_float32_array_operator_index_const = gdextension_packed_float32_array_operator_index_const;
+ gde_interface.packed_float64_array_operator_index = gdextension_packed_float64_array_operator_index;
+ gde_interface.packed_float64_array_operator_index_const = gdextension_packed_float64_array_operator_index_const;
+
+ gde_interface.packed_int32_array_operator_index = gdextension_packed_int32_array_operator_index;
+ gde_interface.packed_int32_array_operator_index_const = gdextension_packed_int32_array_operator_index_const;
+ gde_interface.packed_int64_array_operator_index = gdextension_packed_int64_array_operator_index;
+ gde_interface.packed_int64_array_operator_index_const = gdextension_packed_int64_array_operator_index_const;
+
+ gde_interface.packed_string_array_operator_index = gdextension_packed_string_array_operator_index;
+ gde_interface.packed_string_array_operator_index_const = gdextension_packed_string_array_operator_index_const;
+
+ gde_interface.packed_vector2_array_operator_index = gdextension_packed_vector2_array_operator_index;
+ gde_interface.packed_vector2_array_operator_index_const = gdextension_packed_vector2_array_operator_index_const;
+ gde_interface.packed_vector3_array_operator_index = gdextension_packed_vector3_array_operator_index;
+ gde_interface.packed_vector3_array_operator_index_const = gdextension_packed_vector3_array_operator_index_const;
+
+ gde_interface.array_operator_index = gdextension_array_operator_index;
+ gde_interface.array_operator_index_const = gdextension_array_operator_index_const;
+
+ /* Dictionary functions */
+
+ gde_interface.dictionary_operator_index = gdextension_dictionary_operator_index;
+ gde_interface.dictionary_operator_index_const = gdextension_dictionary_operator_index_const;
+
+ /* OBJECT */
+
+ gde_interface.object_method_bind_call = gdextension_object_method_bind_call;
+ gde_interface.object_method_bind_ptrcall = gdextension_object_method_bind_ptrcall;
+ gde_interface.object_destroy = gdextension_object_destroy;
+ gde_interface.global_get_singleton = gdextension_global_get_singleton;
+ gde_interface.object_get_instance_binding = gdextension_object_get_instance_binding;
+ gde_interface.object_set_instance_binding = gdextension_object_set_instance_binding;
+ gde_interface.object_set_instance = gdextension_object_set_instance;
+
+ gde_interface.object_cast_to = gdextension_object_cast_to;
+ gde_interface.object_get_instance_from_id = gdextension_object_get_instance_from_id;
+ gde_interface.object_get_instance_id = gdextension_object_get_instance_id;
+
+ /* REFERENCE */
+
+ gde_interface.ref_get_object = gdextension_ref_get_object;
+ gde_interface.ref_set_object = gdextension_ref_set_object;
+
+ /* SCRIPT INSTANCE */
+
+ gde_interface.script_instance_create = gdextension_script_instance_create;
+
+ /* CLASSDB */
+
+ gde_interface.classdb_construct_object = gdextension_classdb_construct_object;
+ gde_interface.classdb_get_method_bind = gdextension_classdb_get_method_bind;
+ gde_interface.classdb_get_class_tag = gdextension_classdb_get_class_tag;
+
+ /* CLASSDB EXTENSION */
+
+ //these are filled by implementation, since it will want to keep track of registered classes
+ gde_interface.classdb_register_extension_class = nullptr;
+ gde_interface.classdb_register_extension_class_method = nullptr;
+ gde_interface.classdb_register_extension_class_integer_constant = nullptr;
+ gde_interface.classdb_register_extension_class_property = nullptr;
+ gde_interface.classdb_register_extension_class_property_group = nullptr;
+ gde_interface.classdb_register_extension_class_property_subgroup = nullptr;
+ gde_interface.classdb_register_extension_class_signal = nullptr;
+ gde_interface.classdb_unregister_extension_class = nullptr;
+
+ gde_interface.get_library_path = nullptr;
+}
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
new file mode 100644
index 0000000000..0b7615ffdd
--- /dev/null
+++ b/core/extension/gdextension_interface.h
@@ -0,0 +1,619 @@
+/*************************************************************************/
+/* gdextension_interface.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 GDEXTENSION_INTERFACE_H
+#define GDEXTENSION_INTERFACE_H
+
+/* This is a C class header, you can copy it and use it directly in your own binders.
+ * Together with the JSON file, you should be able to generate any binder.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#ifndef __cplusplus
+typedef uint32_t char32_t;
+typedef uint16_t char16_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* VARIANT TYPES */
+
+typedef enum {
+ GDEXTENSION_VARIANT_TYPE_NIL,
+
+ /* atomic types */
+ GDEXTENSION_VARIANT_TYPE_BOOL,
+ GDEXTENSION_VARIANT_TYPE_INT,
+ GDEXTENSION_VARIANT_TYPE_FLOAT,
+ GDEXTENSION_VARIANT_TYPE_STRING,
+
+ /* math types */
+ GDEXTENSION_VARIANT_TYPE_VECTOR2,
+ GDEXTENSION_VARIANT_TYPE_VECTOR2I,
+ GDEXTENSION_VARIANT_TYPE_RECT2,
+ GDEXTENSION_VARIANT_TYPE_RECT2I,
+ GDEXTENSION_VARIANT_TYPE_VECTOR3,
+ GDEXTENSION_VARIANT_TYPE_VECTOR3I,
+ GDEXTENSION_VARIANT_TYPE_TRANSFORM2D,
+ GDEXTENSION_VARIANT_TYPE_VECTOR4,
+ GDEXTENSION_VARIANT_TYPE_VECTOR4I,
+ GDEXTENSION_VARIANT_TYPE_PLANE,
+ GDEXTENSION_VARIANT_TYPE_QUATERNION,
+ GDEXTENSION_VARIANT_TYPE_AABB,
+ GDEXTENSION_VARIANT_TYPE_BASIS,
+ GDEXTENSION_VARIANT_TYPE_TRANSFORM3D,
+ GDEXTENSION_VARIANT_TYPE_PROJECTION,
+
+ /* misc types */
+ GDEXTENSION_VARIANT_TYPE_COLOR,
+ GDEXTENSION_VARIANT_TYPE_STRING_NAME,
+ GDEXTENSION_VARIANT_TYPE_NODE_PATH,
+ GDEXTENSION_VARIANT_TYPE_RID,
+ GDEXTENSION_VARIANT_TYPE_OBJECT,
+ GDEXTENSION_VARIANT_TYPE_CALLABLE,
+ GDEXTENSION_VARIANT_TYPE_SIGNAL,
+ GDEXTENSION_VARIANT_TYPE_DICTIONARY,
+ GDEXTENSION_VARIANT_TYPE_ARRAY,
+
+ /* typed arrays */
+ GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY,
+ GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY,
+
+ GDEXTENSION_VARIANT_TYPE_VARIANT_MAX
+} GDExtensionVariantType;
+
+typedef enum {
+ /* comparison */
+ GDEXTENSION_VARIANT_OP_EQUAL,
+ GDEXTENSION_VARIANT_OP_NOT_EQUAL,
+ GDEXTENSION_VARIANT_OP_LESS,
+ GDEXTENSION_VARIANT_OP_LESS_EQUAL,
+ GDEXTENSION_VARIANT_OP_GREATER,
+ GDEXTENSION_VARIANT_OP_GREATER_EQUAL,
+
+ /* mathematic */
+ GDEXTENSION_VARIANT_OP_ADD,
+ GDEXTENSION_VARIANT_OP_SUBTRACT,
+ GDEXTENSION_VARIANT_OP_MULTIPLY,
+ GDEXTENSION_VARIANT_OP_DIVIDE,
+ GDEXTENSION_VARIANT_OP_NEGATE,
+ GDEXTENSION_VARIANT_OP_POSITIVE,
+ GDEXTENSION_VARIANT_OP_MODULE,
+ GDEXTENSION_VARIANT_OP_POWER,
+
+ /* bitwise */
+ GDEXTENSION_VARIANT_OP_SHIFT_LEFT,
+ GDEXTENSION_VARIANT_OP_SHIFT_RIGHT,
+ GDEXTENSION_VARIANT_OP_BIT_AND,
+ GDEXTENSION_VARIANT_OP_BIT_OR,
+ GDEXTENSION_VARIANT_OP_BIT_XOR,
+ GDEXTENSION_VARIANT_OP_BIT_NEGATE,
+
+ /* logic */
+ GDEXTENSION_VARIANT_OP_AND,
+ GDEXTENSION_VARIANT_OP_OR,
+ GDEXTENSION_VARIANT_OP_XOR,
+ GDEXTENSION_VARIANT_OP_NOT,
+
+ /* containment */
+ GDEXTENSION_VARIANT_OP_IN,
+ GDEXTENSION_VARIANT_OP_MAX
+
+} GDExtensionVariantOperator;
+
+typedef void *GDExtensionVariantPtr;
+typedef const void *GDExtensionConstVariantPtr;
+typedef void *GDExtensionStringNamePtr;
+typedef const void *GDExtensionConstStringNamePtr;
+typedef void *GDExtensionStringPtr;
+typedef const void *GDExtensionConstStringPtr;
+typedef void *GDExtensionObjectPtr;
+typedef const void *GDExtensionConstObjectPtr;
+typedef void *GDExtensionTypePtr;
+typedef const void *GDExtensionConstTypePtr;
+typedef const void *GDExtensionMethodBindPtr;
+typedef int64_t GDExtensionInt;
+typedef uint8_t GDExtensionBool;
+typedef uint64_t GDObjectInstanceID;
+typedef void *GDExtensionRefPtr;
+typedef const void *GDExtensionConstRefPtr;
+
+/* VARIANT DATA I/O */
+
+typedef enum {
+ GDEXTENSION_CALL_OK,
+ GDEXTENSION_CALL_ERROR_INVALID_METHOD,
+ GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT, // Expected a different variant type.
+ GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS, // Expected lower number of arguments.
+ GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS, // Expected higher number of arguments.
+ GDEXTENSION_CALL_ERROR_INSTANCE_IS_NULL,
+ GDEXTENSION_CALL_ERROR_METHOD_NOT_CONST, // Used for const call.
+} GDExtensionCallErrorType;
+
+typedef struct {
+ GDExtensionCallErrorType error;
+ int32_t argument;
+ int32_t expected;
+} GDExtensionCallError;
+
+typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionVariantPtr, GDExtensionTypePtr);
+typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionTypePtr, GDExtensionVariantPtr);
+typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
+typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
+typedef void (*GDExtensionPtrConstructor)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args);
+typedef void (*GDExtensionPtrDestructor)(GDExtensionTypePtr p_base);
+typedef void (*GDExtensionPtrSetter)(GDExtensionTypePtr p_base, GDExtensionConstTypePtr p_value);
+typedef void (*GDExtensionPtrGetter)(GDExtensionConstTypePtr p_base, GDExtensionTypePtr r_value);
+typedef void (*GDExtensionPtrIndexedSetter)(GDExtensionTypePtr p_base, GDExtensionInt p_index, GDExtensionConstTypePtr p_value);
+typedef void (*GDExtensionPtrIndexedGetter)(GDExtensionConstTypePtr p_base, GDExtensionInt p_index, GDExtensionTypePtr r_value);
+typedef void (*GDExtensionPtrKeyedSetter)(GDExtensionTypePtr p_base, GDExtensionConstTypePtr p_key, GDExtensionConstTypePtr p_value);
+typedef void (*GDExtensionPtrKeyedGetter)(GDExtensionConstTypePtr p_base, GDExtensionConstTypePtr p_key, GDExtensionTypePtr r_value);
+typedef uint32_t (*GDExtensionPtrKeyedChecker)(GDExtensionConstVariantPtr p_base, GDExtensionConstVariantPtr p_key);
+typedef void (*GDExtensionPtrUtilityFunction)(GDExtensionTypePtr r_return, const GDExtensionConstTypePtr *p_args, int p_argument_count);
+
+typedef GDExtensionObjectPtr (*GDExtensionClassConstructor)();
+
+typedef void *(*GDExtensionInstanceBindingCreateCallback)(void *p_token, void *p_instance);
+typedef void (*GDExtensionInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding);
+typedef GDExtensionBool (*GDExtensionInstanceBindingReferenceCallback)(void *p_token, void *p_binding, GDExtensionBool p_reference);
+
+typedef struct {
+ GDExtensionInstanceBindingCreateCallback create_callback;
+ GDExtensionInstanceBindingFreeCallback free_callback;
+ GDExtensionInstanceBindingReferenceCallback reference_callback;
+} GDExtensionInstanceBindingCallbacks;
+
+/* EXTENSION CLASSES */
+
+typedef void *GDExtensionClassInstancePtr;
+
+typedef GDExtensionBool (*GDExtensionClassSet)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value);
+typedef GDExtensionBool (*GDExtensionClassGet)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret);
+typedef uint64_t (*GDExtensionClassGetRID)(GDExtensionClassInstancePtr p_instance);
+
+typedef struct {
+ GDExtensionVariantType type;
+ GDExtensionStringNamePtr name;
+ GDExtensionStringNamePtr class_name;
+ uint32_t hint; // Bitfield of `PropertyHint` (defined in `extension_api.json`).
+ GDExtensionStringPtr hint_string;
+ uint32_t usage; // Bitfield of `PropertyUsageFlags` (defined in `extension_api.json`).
+} GDExtensionPropertyInfo;
+
+typedef struct {
+ GDExtensionStringNamePtr name;
+ GDExtensionPropertyInfo return_value;
+ uint32_t flags; // Bitfield of `GDExtensionClassMethodFlags`.
+ int32_t id;
+
+ /* Arguments: `default_arguments` is an array of size `argument_count`. */
+ uint32_t argument_count;
+ GDExtensionPropertyInfo *arguments;
+
+ /* Default arguments: `default_arguments` is an array of size `default_argument_count`. */
+ uint32_t default_argument_count;
+ GDExtensionVariantPtr *default_arguments;
+} GDExtensionMethodInfo;
+
+typedef const GDExtensionPropertyInfo *(*GDExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
+typedef void (*GDExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list);
+typedef GDExtensionBool (*GDExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name);
+typedef GDExtensionBool (*GDExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret);
+typedef void (*GDExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
+typedef void (*GDExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr p_out);
+typedef void (*GDExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
+typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
+typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
+typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_userdata);
+typedef void (*GDExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
+typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_userdata, GDExtensionConstStringNamePtr p_name);
+
+typedef struct {
+ GDExtensionBool is_virtual;
+ GDExtensionBool is_abstract;
+ GDExtensionClassSet set_func;
+ GDExtensionClassGet get_func;
+ GDExtensionClassGetPropertyList get_property_list_func;
+ GDExtensionClassFreePropertyList free_property_list_func;
+ GDExtensionClassPropertyCanRevert property_can_revert_func;
+ GDExtensionClassPropertyGetRevert property_get_revert_func;
+ GDExtensionClassNotification notification_func;
+ GDExtensionClassToString to_string_func;
+ GDExtensionClassReference reference_func;
+ GDExtensionClassUnreference unreference_func;
+ GDExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
+ GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
+ GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
+ GDExtensionClassGetRID get_rid_func;
+ void *class_userdata; // Per-class user data, later accessible in instance bindings.
+} GDExtensionClassCreationInfo;
+
+typedef void *GDExtensionClassLibraryPtr;
+
+/* Method */
+
+typedef enum {
+ GDEXTENSION_METHOD_FLAG_NORMAL = 1,
+ GDEXTENSION_METHOD_FLAG_EDITOR = 2,
+ GDEXTENSION_METHOD_FLAG_CONST = 4,
+ GDEXTENSION_METHOD_FLAG_VIRTUAL = 8,
+ GDEXTENSION_METHOD_FLAG_VARARG = 16,
+ GDEXTENSION_METHOD_FLAG_STATIC = 32,
+ GDEXTENSION_METHOD_FLAGS_DEFAULT = GDEXTENSION_METHOD_FLAG_NORMAL,
+} GDExtensionClassMethodFlags;
+
+typedef enum {
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT,
+ GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE
+} GDExtensionClassMethodArgumentMetadata;
+
+typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
+typedef void (*GDExtensionClassMethodPtrCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
+
+typedef struct {
+ GDExtensionStringNamePtr name;
+ void *method_userdata;
+ GDExtensionClassMethodCall call_func;
+ GDExtensionClassMethodPtrCall ptrcall_func;
+ uint32_t method_flags; // Bitfield of `GDExtensionClassMethodFlags`.
+
+ /* If `has_return_value` is false, `return_value_info` and `return_value_metadata` are ignored. */
+ GDExtensionBool has_return_value;
+ GDExtensionPropertyInfo *return_value_info;
+ GDExtensionClassMethodArgumentMetadata return_value_metadata;
+
+ /* Arguments: `arguments_info` and `arguments_metadata` are array of size `argument_count`.
+ * Name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies.
+ */
+ uint32_t argument_count;
+ GDExtensionPropertyInfo *arguments_info;
+ GDExtensionClassMethodArgumentMetadata *arguments_metadata;
+
+ /* Default arguments: `default_arguments` is an array of size `default_argument_count`. */
+ uint32_t default_argument_count;
+ GDExtensionVariantPtr *default_arguments;
+} GDExtensionClassMethodInfo;
+
+/* SCRIPT INSTANCE EXTENSION */
+
+typedef void *GDExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation.
+
+typedef GDExtensionBool (*GDExtensionScriptInstanceSet)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value);
+typedef GDExtensionBool (*GDExtensionScriptInstanceGet)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret);
+typedef const GDExtensionPropertyInfo *(*GDExtensionScriptInstanceGetPropertyList)(GDExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
+typedef void (*GDExtensionScriptInstanceFreePropertyList)(GDExtensionScriptInstanceDataPtr p_instance, const GDExtensionPropertyInfo *p_list);
+typedef GDExtensionVariantType (*GDExtensionScriptInstanceGetPropertyType)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionBool *r_is_valid);
+
+typedef GDExtensionBool (*GDExtensionScriptInstancePropertyCanRevert)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name);
+typedef GDExtensionBool (*GDExtensionScriptInstancePropertyGetRevert)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret);
+
+typedef GDExtensionObjectPtr (*GDExtensionScriptInstanceGetOwner)(GDExtensionScriptInstanceDataPtr p_instance);
+typedef void (*GDExtensionScriptInstancePropertyStateAdd)(GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value, void *p_userdata);
+typedef void (*GDExtensionScriptInstanceGetPropertyState)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionScriptInstancePropertyStateAdd p_add_func, void *p_userdata);
+
+typedef const GDExtensionMethodInfo *(*GDExtensionScriptInstanceGetMethodList)(GDExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
+typedef void (*GDExtensionScriptInstanceFreeMethodList)(GDExtensionScriptInstanceDataPtr p_instance, const GDExtensionMethodInfo *p_list);
+
+typedef GDExtensionBool (*GDExtensionScriptInstanceHasMethod)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name);
+
+typedef void (*GDExtensionScriptInstanceCall)(GDExtensionScriptInstanceDataPtr p_self, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
+typedef void (*GDExtensionScriptInstanceNotification)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what);
+typedef void (*GDExtensionScriptInstanceToString)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
+
+typedef void (*GDExtensionScriptInstanceRefCountIncremented)(GDExtensionScriptInstanceDataPtr p_instance);
+typedef GDExtensionBool (*GDExtensionScriptInstanceRefCountDecremented)(GDExtensionScriptInstanceDataPtr p_instance);
+
+typedef GDExtensionObjectPtr (*GDExtensionScriptInstanceGetScript)(GDExtensionScriptInstanceDataPtr p_instance);
+typedef GDExtensionBool (*GDExtensionScriptInstanceIsPlaceholder)(GDExtensionScriptInstanceDataPtr p_instance);
+
+typedef void *GDExtensionScriptLanguagePtr;
+
+typedef GDExtensionScriptLanguagePtr (*GDExtensionScriptInstanceGetLanguage)(GDExtensionScriptInstanceDataPtr p_instance);
+
+typedef void (*GDExtensionScriptInstanceFree)(GDExtensionScriptInstanceDataPtr p_instance);
+
+typedef void *GDExtensionScriptInstancePtr; // Pointer to ScriptInstance.
+
+typedef struct {
+ GDExtensionScriptInstanceSet set_func;
+ GDExtensionScriptInstanceGet get_func;
+ GDExtensionScriptInstanceGetPropertyList get_property_list_func;
+ GDExtensionScriptInstanceFreePropertyList free_property_list_func;
+
+ GDExtensionScriptInstancePropertyCanRevert property_can_revert_func;
+ GDExtensionScriptInstancePropertyGetRevert property_get_revert_func;
+
+ GDExtensionScriptInstanceGetOwner get_owner_func;
+ GDExtensionScriptInstanceGetPropertyState get_property_state_func;
+
+ GDExtensionScriptInstanceGetMethodList get_method_list_func;
+ GDExtensionScriptInstanceFreeMethodList free_method_list_func;
+ GDExtensionScriptInstanceGetPropertyType get_property_type_func;
+
+ GDExtensionScriptInstanceHasMethod has_method_func;
+
+ GDExtensionScriptInstanceCall call_func;
+ GDExtensionScriptInstanceNotification notification_func;
+
+ GDExtensionScriptInstanceToString to_string_func;
+
+ GDExtensionScriptInstanceRefCountIncremented refcount_incremented_func;
+ GDExtensionScriptInstanceRefCountDecremented refcount_decremented_func;
+
+ GDExtensionScriptInstanceGetScript get_script_func;
+
+ GDExtensionScriptInstanceIsPlaceholder is_placeholder_func;
+
+ GDExtensionScriptInstanceSet set_fallback_func;
+ GDExtensionScriptInstanceGet get_fallback_func;
+
+ GDExtensionScriptInstanceGetLanguage get_language_func;
+
+ GDExtensionScriptInstanceFree free_func;
+
+} GDExtensionScriptInstanceInfo;
+
+/* INTERFACE */
+
+typedef struct {
+ uint32_t version_major;
+ uint32_t version_minor;
+ uint32_t version_patch;
+ const char *version_string;
+
+ /* GODOT CORE */
+
+ void *(*mem_alloc)(size_t p_bytes);
+ void *(*mem_realloc)(void *p_ptr, size_t p_bytes);
+ void (*mem_free)(void *p_ptr);
+
+ void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
+ void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
+ void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
+
+ uint64_t (*get_native_struct_size)(GDExtensionConstStringNamePtr p_name);
+
+ /* GODOT VARIANT */
+
+ /* variant general */
+ void (*variant_new_copy)(GDExtensionVariantPtr r_dest, GDExtensionConstVariantPtr p_src);
+ void (*variant_new_nil)(GDExtensionVariantPtr r_dest);
+ void (*variant_destroy)(GDExtensionVariantPtr p_self);
+
+ /* variant type */
+ void (*variant_call)(GDExtensionVariantPtr p_self, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
+ void (*variant_call_static)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
+ void (*variant_evaluate)(GDExtensionVariantOperator p_op, GDExtensionConstVariantPtr p_a, GDExtensionConstVariantPtr p_b, GDExtensionVariantPtr r_return, GDExtensionBool *r_valid);
+ void (*variant_set)(GDExtensionVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid);
+ void (*variant_set_named)(GDExtensionVariantPtr p_self, GDExtensionConstStringNamePtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid);
+ void (*variant_set_keyed)(GDExtensionVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid);
+ void (*variant_set_indexed)(GDExtensionVariantPtr p_self, GDExtensionInt p_index, GDExtensionConstVariantPtr p_value, GDExtensionBool *r_valid, GDExtensionBool *r_oob);
+ void (*variant_get)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid);
+ void (*variant_get_named)(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_key, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid);
+ void (*variant_get_keyed)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid);
+ void (*variant_get_indexed)(GDExtensionConstVariantPtr p_self, GDExtensionInt p_index, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid, GDExtensionBool *r_oob);
+ GDExtensionBool (*variant_iter_init)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionBool *r_valid);
+ GDExtensionBool (*variant_iter_next)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionBool *r_valid);
+ void (*variant_iter_get)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_iter, GDExtensionVariantPtr r_ret, GDExtensionBool *r_valid);
+ GDExtensionInt (*variant_hash)(GDExtensionConstVariantPtr p_self);
+ GDExtensionInt (*variant_recursive_hash)(GDExtensionConstVariantPtr p_self, GDExtensionInt p_recursion_count);
+ GDExtensionBool (*variant_hash_compare)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_other);
+ GDExtensionBool (*variant_booleanize)(GDExtensionConstVariantPtr p_self);
+ void (*variant_duplicate)(GDExtensionConstVariantPtr p_self, GDExtensionVariantPtr r_ret, GDExtensionBool p_deep);
+ void (*variant_stringify)(GDExtensionConstVariantPtr p_self, GDExtensionStringPtr r_ret);
+
+ GDExtensionVariantType (*variant_get_type)(GDExtensionConstVariantPtr p_self);
+ GDExtensionBool (*variant_has_method)(GDExtensionConstVariantPtr p_self, GDExtensionConstStringNamePtr p_method);
+ GDExtensionBool (*variant_has_member)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member);
+ GDExtensionBool (*variant_has_key)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid);
+ void (*variant_get_type_name)(GDExtensionVariantType p_type, GDExtensionStringPtr r_name);
+ GDExtensionBool (*variant_can_convert)(GDExtensionVariantType p_from, GDExtensionVariantType p_to);
+ GDExtensionBool (*variant_can_convert_strict)(GDExtensionVariantType p_from, GDExtensionVariantType p_to);
+
+ /* ptrcalls */
+ GDExtensionVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDExtensionVariantType p_type);
+ GDExtensionTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDExtensionVariantType p_type);
+ GDExtensionPtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDExtensionVariantOperator p_operator, GDExtensionVariantType p_type_a, GDExtensionVariantType p_type_b);
+ GDExtensionPtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_method, GDExtensionInt p_hash);
+ GDExtensionPtrConstructor (*variant_get_ptr_constructor)(GDExtensionVariantType p_type, int32_t p_constructor);
+ GDExtensionPtrDestructor (*variant_get_ptr_destructor)(GDExtensionVariantType p_type);
+ void (*variant_construct)(GDExtensionVariantType p_type, GDExtensionVariantPtr p_base, const GDExtensionConstVariantPtr *p_args, int32_t p_argument_count, GDExtensionCallError *r_error);
+ GDExtensionPtrSetter (*variant_get_ptr_setter)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member);
+ GDExtensionPtrGetter (*variant_get_ptr_getter)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_member);
+ GDExtensionPtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDExtensionVariantType p_type);
+ GDExtensionPtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDExtensionVariantType p_type);
+ GDExtensionPtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDExtensionVariantType p_type);
+ GDExtensionPtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDExtensionVariantType p_type);
+ GDExtensionPtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDExtensionVariantType p_type);
+ void (*variant_get_constant_value)(GDExtensionVariantType p_type, GDExtensionConstStringNamePtr p_constant, GDExtensionVariantPtr r_ret);
+ GDExtensionPtrUtilityFunction (*variant_get_ptr_utility_function)(GDExtensionConstStringNamePtr p_function, GDExtensionInt p_hash);
+
+ /* extra utilities */
+ void (*string_new_with_latin1_chars)(GDExtensionStringPtr r_dest, const char *p_contents);
+ void (*string_new_with_utf8_chars)(GDExtensionStringPtr r_dest, const char *p_contents);
+ void (*string_new_with_utf16_chars)(GDExtensionStringPtr r_dest, const char16_t *p_contents);
+ void (*string_new_with_utf32_chars)(GDExtensionStringPtr r_dest, const char32_t *p_contents);
+ void (*string_new_with_wide_chars)(GDExtensionStringPtr r_dest, const wchar_t *p_contents);
+ void (*string_new_with_latin1_chars_and_len)(GDExtensionStringPtr r_dest, const char *p_contents, GDExtensionInt p_size);
+ void (*string_new_with_utf8_chars_and_len)(GDExtensionStringPtr r_dest, const char *p_contents, GDExtensionInt p_size);
+ void (*string_new_with_utf16_chars_and_len)(GDExtensionStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_size);
+ void (*string_new_with_utf32_chars_and_len)(GDExtensionStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_size);
+ void (*string_new_with_wide_chars_and_len)(GDExtensionStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_size);
+ /* Information about the following functions:
+ * - The return value is the resulting encoded string length.
+ * - The length returned is in characters, not in bytes. It also does not include a trailing zero.
+ * - These functions also do not write trailing zero, If you need it, write it yourself at the position indicated by the length (and make sure to allocate it).
+ * - Passing NULL in r_text means only the length is computed (again, without including trailing zero).
+ * - p_max_write_length argument is in characters, not bytes. It will be ignored if r_text is NULL.
+ * - p_max_write_length argument does not affect the return value, it's only to cap write length.
+ */
+ GDExtensionInt (*string_to_latin1_chars)(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length);
+ GDExtensionInt (*string_to_utf8_chars)(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length);
+ GDExtensionInt (*string_to_utf16_chars)(GDExtensionConstStringPtr p_self, char16_t *r_text, GDExtensionInt p_max_write_length);
+ GDExtensionInt (*string_to_utf32_chars)(GDExtensionConstStringPtr p_self, char32_t *r_text, GDExtensionInt p_max_write_length);
+ GDExtensionInt (*string_to_wide_chars)(GDExtensionConstStringPtr p_self, wchar_t *r_text, GDExtensionInt p_max_write_length);
+ char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index);
+ const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index);
+
+ /* Packed array functions */
+
+ uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray
+ const uint8_t *(*packed_byte_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray
+
+ GDExtensionTypePtr (*packed_color_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedColorArray, returns Color ptr
+ GDExtensionTypePtr (*packed_color_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedColorArray, returns Color ptr
+
+ float *(*packed_float32_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedFloat32Array
+ const float *(*packed_float32_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedFloat32Array
+ double *(*packed_float64_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedFloat64Array
+ const double *(*packed_float64_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedFloat64Array
+
+ int32_t *(*packed_int32_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedInt32Array
+ const int32_t *(*packed_int32_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedInt32Array
+ int64_t *(*packed_int64_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedInt32Array
+ const int64_t *(*packed_int64_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedInt32Array
+
+ GDExtensionStringPtr (*packed_string_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedStringArray
+ GDExtensionStringPtr (*packed_string_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedStringArray
+
+ GDExtensionTypePtr (*packed_vector2_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedVector2Array, returns Vector2 ptr
+ GDExtensionTypePtr (*packed_vector2_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedVector2Array, returns Vector2 ptr
+ GDExtensionTypePtr (*packed_vector3_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedVector3Array, returns Vector3 ptr
+ GDExtensionTypePtr (*packed_vector3_array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedVector3Array, returns Vector3 ptr
+
+ GDExtensionVariantPtr (*array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be an Array ptr
+ GDExtensionVariantPtr (*array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be an Array ptr
+
+ /* Dictionary functions */
+
+ GDExtensionVariantPtr (*dictionary_operator_index)(GDExtensionTypePtr p_self, GDExtensionConstVariantPtr p_key); // p_self should be an Dictionary ptr
+ GDExtensionVariantPtr (*dictionary_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionConstVariantPtr p_key); // p_self should be an Dictionary ptr
+
+ /* OBJECT */
+
+ void (*object_method_bind_call)(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionVariantPtr r_ret, GDExtensionCallError *r_error);
+ void (*object_method_bind_ptrcall)(GDExtensionMethodBindPtr p_method_bind, GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
+ void (*object_destroy)(GDExtensionObjectPtr p_o);
+ GDExtensionObjectPtr (*global_get_singleton)(GDExtensionConstStringNamePtr p_name);
+
+ void *(*object_get_instance_binding)(GDExtensionObjectPtr p_o, void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks);
+ void (*object_set_instance_binding)(GDExtensionObjectPtr p_o, void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks);
+
+ void (*object_set_instance)(GDExtensionObjectPtr p_o, GDExtensionConstStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
+
+ GDExtensionObjectPtr (*object_cast_to)(GDExtensionConstObjectPtr p_object, void *p_class_tag);
+ GDExtensionObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
+ GDObjectInstanceID (*object_get_instance_id)(GDExtensionConstObjectPtr p_object);
+
+ /* REFERENCE */
+
+ GDExtensionObjectPtr (*ref_get_object)(GDExtensionConstRefPtr p_ref);
+ void (*ref_set_object)(GDExtensionRefPtr p_ref, GDExtensionObjectPtr p_object);
+
+ /* SCRIPT INSTANCE */
+
+ GDExtensionScriptInstancePtr (*script_instance_create)(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data);
+
+ /* CLASSDB */
+
+ GDExtensionObjectPtr (*classdb_construct_object)(GDExtensionConstStringNamePtr p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
+ GDExtensionMethodBindPtr (*classdb_get_method_bind)(GDExtensionConstStringNamePtr p_classname, GDExtensionConstStringNamePtr p_methodname, GDExtensionInt p_hash);
+ void *(*classdb_get_class_tag)(GDExtensionConstStringNamePtr p_classname);
+
+ /* CLASSDB EXTENSION */
+
+ /* Provided parameters for `classdb_register_extension_*` can be safely freed once the function returns. */
+ void (*classdb_register_extension_class)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs);
+ void (*classdb_register_extension_class_method)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info);
+ void (*classdb_register_extension_class_integer_constant)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
+ void (*classdb_register_extension_class_property)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);
+ void (*classdb_register_extension_class_property_group)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_group_name, GDExtensionConstStringPtr p_prefix);
+ void (*classdb_register_extension_class_property_subgroup)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringPtr p_subgroup_name, GDExtensionConstStringPtr p_prefix);
+ void (*classdb_register_extension_class_signal)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count);
+ void (*classdb_unregister_extension_class)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
+
+ void (*get_library_path)(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path);
+
+} GDExtensionInterface;
+
+/* INITIALIZATION */
+
+typedef enum {
+ GDEXTENSION_INITIALIZATION_CORE,
+ GDEXTENSION_INITIALIZATION_SERVERS,
+ GDEXTENSION_INITIALIZATION_SCENE,
+ GDEXTENSION_INITIALIZATION_EDITOR,
+ GDEXTENSION_MAX_INITIALIZATION_LEVEL,
+} GDExtensionInitializationLevel;
+
+typedef struct {
+ /* Minimum initialization level required.
+ * If Core or Servers, the extension needs editor or game restart to take effect */
+ GDExtensionInitializationLevel minimum_initialization_level;
+ /* Up to the user to supply when initializing */
+ void *userdata;
+ /* This function will be called multiple times for each initialization level. */
+ void (*initialize)(void *userdata, GDExtensionInitializationLevel p_level);
+ void (*deinitialize)(void *userdata, GDExtensionInitializationLevel p_level);
+} GDExtensionInitialization;
+
+/* Define a C function prototype that implements the function below and expose it to dlopen() (or similar).
+ * This is the entry point of the GDExtension library and will be called on initialization.
+ * It can be used to set up different init levels, which are called during various stages of initialization/shutdown.
+ * The function name must be a unique one specified in the .gdextension config file.
+ */
+typedef GDExtensionBool (*GDExtensionInitializationFunction)(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GDEXTENSION_INTERFACE_H
diff --git a/core/extension/native_extension_manager.cpp b/core/extension/gdextension_manager.cpp
index 186fcc44f6..5bdde78793 100644
--- a/core/extension/native_extension_manager.cpp
+++ b/core/extension/gdextension_manager.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* native_extension_manager.cpp */
+/* gdextension_manager.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,91 +28,91 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "native_extension_manager.h"
+#include "gdextension_manager.h"
#include "core/io/file_access.h"
-NativeExtensionManager::LoadStatus NativeExtensionManager::load_extension(const String &p_path) {
- if (native_extension_map.has(p_path)) {
+GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
+ if (gdextension_map.has(p_path)) {
return LOAD_STATUS_ALREADY_LOADED;
}
- Ref<NativeExtension> extension = ResourceLoader::load(p_path);
+ Ref<GDExtension> extension = ResourceLoader::load(p_path);
if (extension.is_null()) {
return LOAD_STATUS_FAILED;
}
if (level >= 0) { // Already initialized up to some level.
int32_t minimum_level = extension->get_minimum_library_initialization_level();
- if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) {
+ if (minimum_level < MIN(level, GDExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
// Initialize up to current level.
for (int32_t i = minimum_level; i <= level; i++) {
- extension->initialize_library(NativeExtension::InitializationLevel(i));
+ extension->initialize_library(GDExtension::InitializationLevel(i));
}
}
- native_extension_map[p_path] = extension;
+ gdextension_map[p_path] = extension;
return LOAD_STATUS_OK;
}
-NativeExtensionManager::LoadStatus NativeExtensionManager::reload_extension(const String &p_path) {
+GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String &p_path) {
return LOAD_STATUS_OK; //TODO
}
-NativeExtensionManager::LoadStatus NativeExtensionManager::unload_extension(const String &p_path) {
- if (!native_extension_map.has(p_path)) {
+GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) {
+ if (!gdextension_map.has(p_path)) {
return LOAD_STATUS_NOT_LOADED;
}
- Ref<NativeExtension> extension = native_extension_map[p_path];
+ Ref<GDExtension> extension = gdextension_map[p_path];
if (level >= 0) { // Already initialized up to some level.
int32_t minimum_level = extension->get_minimum_library_initialization_level();
- if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) {
+ if (minimum_level < MIN(level, GDExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
// Deinitialize down to current level.
for (int32_t i = level; i >= minimum_level; i--) {
- extension->deinitialize_library(NativeExtension::InitializationLevel(i));
+ extension->deinitialize_library(GDExtension::InitializationLevel(i));
}
}
- native_extension_map.erase(p_path);
+ gdextension_map.erase(p_path);
return LOAD_STATUS_OK;
}
-bool NativeExtensionManager::is_extension_loaded(const String &p_path) const {
- return native_extension_map.has(p_path);
+bool GDExtensionManager::is_extension_loaded(const String &p_path) const {
+ return gdextension_map.has(p_path);
}
-Vector<String> NativeExtensionManager::get_loaded_extensions() const {
+Vector<String> GDExtensionManager::get_loaded_extensions() const {
Vector<String> ret;
- for (const KeyValue<String, Ref<NativeExtension>> &E : native_extension_map) {
+ for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
ret.push_back(E.key);
}
return ret;
}
-Ref<NativeExtension> NativeExtensionManager::get_extension(const String &p_path) {
- HashMap<String, Ref<NativeExtension>>::Iterator E = native_extension_map.find(p_path);
- ERR_FAIL_COND_V(!E, Ref<NativeExtension>());
+Ref<GDExtension> GDExtensionManager::get_extension(const String &p_path) {
+ HashMap<String, Ref<GDExtension>>::Iterator E = gdextension_map.find(p_path);
+ ERR_FAIL_COND_V(!E, Ref<GDExtension>());
return E->value;
}
-void NativeExtensionManager::initialize_extensions(NativeExtension::InitializationLevel p_level) {
+void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
ERR_FAIL_COND(int32_t(p_level) - 1 != level);
- for (KeyValue<String, Ref<NativeExtension>> &E : native_extension_map) {
+ for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
E.value->initialize_library(p_level);
}
level = p_level;
}
-void NativeExtensionManager::deinitialize_extensions(NativeExtension::InitializationLevel p_level) {
+void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel p_level) {
ERR_FAIL_COND(int32_t(p_level) != level);
- for (KeyValue<String, Ref<NativeExtension>> &E : native_extension_map) {
+ for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
E.value->deinitialize_library(p_level);
}
level = int32_t(p_level) - 1;
}
-void NativeExtensionManager::load_extensions() {
- Ref<FileAccess> f = FileAccess::open(NativeExtension::get_extension_list_config_file(), FileAccess::READ);
+void GDExtensionManager::load_extensions() {
+ Ref<FileAccess> f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ);
while (f.is_valid() && !f->eof_reached()) {
String s = f->get_line().strip_edges();
if (!s.is_empty()) {
@@ -122,17 +122,17 @@ void NativeExtensionManager::load_extensions() {
}
}
-NativeExtensionManager *NativeExtensionManager::get_singleton() {
+GDExtensionManager *GDExtensionManager::get_singleton() {
return singleton;
}
-void NativeExtensionManager::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load_extension", "path"), &NativeExtensionManager::load_extension);
- ClassDB::bind_method(D_METHOD("reload_extension", "path"), &NativeExtensionManager::reload_extension);
- ClassDB::bind_method(D_METHOD("unload_extension", "path"), &NativeExtensionManager::unload_extension);
- ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &NativeExtensionManager::is_extension_loaded);
+void GDExtensionManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load_extension", "path"), &GDExtensionManager::load_extension);
+ ClassDB::bind_method(D_METHOD("reload_extension", "path"), &GDExtensionManager::reload_extension);
+ ClassDB::bind_method(D_METHOD("unload_extension", "path"), &GDExtensionManager::unload_extension);
+ ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &GDExtensionManager::is_extension_loaded);
- ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &NativeExtensionManager::get_loaded_extensions);
- ClassDB::bind_method(D_METHOD("get_extension", "path"), &NativeExtensionManager::get_extension);
+ ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &GDExtensionManager::get_loaded_extensions);
+ ClassDB::bind_method(D_METHOD("get_extension", "path"), &GDExtensionManager::get_extension);
BIND_ENUM_CONSTANT(LOAD_STATUS_OK);
BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED);
@@ -141,9 +141,9 @@ void NativeExtensionManager::_bind_methods() {
BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
}
-NativeExtensionManager *NativeExtensionManager::singleton = nullptr;
+GDExtensionManager *GDExtensionManager::singleton = nullptr;
-NativeExtensionManager::NativeExtensionManager() {
+GDExtensionManager::GDExtensionManager() {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
}
diff --git a/core/extension/native_extension_manager.h b/core/extension/gdextension_manager.h
index ed80cd6b7a..2f2aa0e0d4 100644
--- a/core/extension/native_extension_manager.h
+++ b/core/extension/gdextension_manager.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* native_extension_manager.h */
+/* gdextension_manager.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,20 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NATIVE_EXTENSION_MANAGER_H
-#define NATIVE_EXTENSION_MANAGER_H
+#ifndef GDEXTENSION_MANAGER_H
+#define GDEXTENSION_MANAGER_H
-#include "core/extension/native_extension.h"
+#include "core/extension/gdextension.h"
-class NativeExtensionManager : public Object {
- GDCLASS(NativeExtensionManager, Object);
+class GDExtensionManager : public Object {
+ GDCLASS(GDExtensionManager, Object);
int32_t level = -1;
- HashMap<String, Ref<NativeExtension>> native_extension_map;
+ HashMap<String, Ref<GDExtension>> gdextension_map;
static void _bind_methods();
- static NativeExtensionManager *singleton;
+ static GDExtensionManager *singleton;
public:
enum LoadStatus {
@@ -57,18 +57,18 @@ public:
LoadStatus unload_extension(const String &p_path);
bool is_extension_loaded(const String &p_path) const;
Vector<String> get_loaded_extensions() const;
- Ref<NativeExtension> get_extension(const String &p_path);
+ Ref<GDExtension> get_extension(const String &p_path);
- void initialize_extensions(NativeExtension::InitializationLevel p_level);
- void deinitialize_extensions(NativeExtension::InitializationLevel p_level);
+ void initialize_extensions(GDExtension::InitializationLevel p_level);
+ void deinitialize_extensions(GDExtension::InitializationLevel p_level);
- static NativeExtensionManager *get_singleton();
+ static GDExtensionManager *get_singleton();
void load_extensions();
- NativeExtensionManager();
+ GDExtensionManager();
};
-VARIANT_ENUM_CAST(NativeExtensionManager::LoadStatus)
+VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus)
-#endif // NATIVE_EXTENSION_MANAGER_H
+#endif // GDEXTENSION_MANAGER_H
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
deleted file mode 100644
index 193fcb8916..0000000000
--- a/core/extension/gdnative_interface.cpp
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*************************************************************************/
-/* gdnative_interface.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#include "gdnative_interface.h"
-
-#include "core/config/engine.h"
-#include "core/object/class_db.h"
-#include "core/object/script_language_extension.h"
-#include "core/os/memory.h"
-#include "core/variant/variant.h"
-#include "core/version.h"
-
-// Memory Functions
-static void *gdnative_alloc(size_t p_size) {
- return memalloc(p_size);
-}
-
-static void *gdnative_realloc(void *p_mem, size_t p_size) {
- return memrealloc(p_mem, p_size);
-}
-
-static void gdnative_free(void *p_mem) {
- memfree(p_mem);
-}
-
-// Helper print functions.
-static void gdnative_print_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_ERROR);
-}
-static void gdnative_print_warning(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_WARNING);
-}
-static void gdnative_print_script_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
-}
-
-uint64_t gdnative_get_native_struct_size(const char *p_name) {
- return ClassDB::get_native_struct_size(p_name);
-}
-
-// Variant functions
-
-static void gdnative_variant_new_copy(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src) {
- memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant(*reinterpret_cast<Variant *>(p_src)));
-}
-static void gdnative_variant_new_nil(GDNativeVariantPtr r_dest) {
- memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant);
-}
-static void gdnative_variant_destroy(GDNativeVariantPtr p_self) {
- reinterpret_cast<Variant *>(p_self)->~Variant();
-}
-
-// variant type
-
-static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
- Variant *self = (Variant *)p_self;
- const StringName *method = (const StringName *)p_method;
- const Variant **args = (const Variant **)p_args;
- Variant ret;
- Callable::CallError error;
- self->callp(*method, args, p_argcount, ret, error);
- memnew_placement(r_return, Variant(ret));
-
- if (r_error) {
- r_error->error = (GDNativeCallErrorType)(error.error);
- r_error->argument = error.argument;
- r_error->expected = error.expected;
- }
-}
-
-static void gdnative_variant_call_static(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
- Variant::Type type = (Variant::Type)p_type;
- const StringName *method = (const StringName *)p_method;
- const Variant **args = (const Variant **)p_args;
- Variant ret;
- Callable::CallError error;
- Variant::call_static(type, *method, args, p_argcount, ret, error);
- memnew_placement(r_return, Variant(ret));
-
- if (r_error) {
- r_error->error = (GDNativeCallErrorType)error.error;
- r_error->argument = error.argument;
- r_error->expected = error.expected;
- }
-}
-
-static void gdnative_variant_evaluate(GDNativeVariantOperator p_op, const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_return, GDNativeBool *r_valid) {
- Variant::Operator op = (Variant::Operator)p_op;
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- Variant *ret = (Variant *)r_return;
- bool valid;
- Variant::evaluate(op, *a, *b, *ret, valid);
- *r_valid = valid;
-}
-
-static void gdnative_variant_set(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) {
- Variant *self = (Variant *)p_self;
- const Variant *key = (const Variant *)p_key;
- const Variant *value = (const Variant *)p_value;
-
- bool valid;
- self->set(*key, *value, &valid);
- *r_valid = valid;
-}
-
-static void gdnative_variant_set_named(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) {
- Variant *self = (Variant *)p_self;
- const StringName *key = (const StringName *)p_key;
- const Variant *value = (const Variant *)p_value;
-
- bool valid;
- self->set_named(*key, *value, valid);
- *r_valid = valid;
-}
-
-static void gdnative_variant_set_keyed(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) {
- Variant *self = (Variant *)p_self;
- const Variant *key = (const Variant *)p_key;
- const Variant *value = (const Variant *)p_value;
-
- bool valid;
- self->set_keyed(*key, *value, valid);
- *r_valid = valid;
-}
-
-static void gdnative_variant_set_indexed(GDNativeVariantPtr p_self, GDNativeInt p_index, const GDNativeVariantPtr p_value, GDNativeBool *r_valid, GDNativeBool *r_oob) {
- Variant *self = (Variant *)p_self;
- const Variant *value = (const Variant *)p_value;
-
- bool valid;
- bool oob;
- self->set_indexed(p_index, *value, valid, oob);
- *r_valid = valid;
- *r_oob = oob;
-}
-
-static void gdnative_variant_get(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- const Variant *key = (const Variant *)p_key;
-
- bool valid;
- memnew_placement(r_ret, Variant(self->get(*key, &valid)));
- *r_valid = valid;
-}
-
-static void gdnative_variant_get_named(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- const StringName *key = (const StringName *)p_key;
-
- bool valid;
- memnew_placement(r_ret, Variant(self->get_named(*key, valid)));
- *r_valid = valid;
-}
-
-static void gdnative_variant_get_keyed(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- const Variant *key = (const Variant *)p_key;
-
- bool valid;
- memnew_placement(r_ret, Variant(self->get_keyed(*key, valid)));
- *r_valid = valid;
-}
-
-static void gdnative_variant_get_indexed(const GDNativeVariantPtr p_self, GDNativeInt p_index, GDNativeVariantPtr r_ret, GDNativeBool *r_valid, GDNativeBool *r_oob) {
- const Variant *self = (const Variant *)p_self;
-
- bool valid;
- bool oob;
- memnew_placement(r_ret, Variant(self->get_indexed(p_index, valid, oob)));
- *r_valid = valid;
- *r_oob = oob;
-}
-
-/// Iteration.
-static GDNativeBool gdnative_variant_iter_init(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- Variant *iter = (Variant *)r_iter;
-
- bool valid;
- bool ret = self->iter_init(*iter, valid);
- *r_valid = valid;
- return ret;
-}
-
-static GDNativeBool gdnative_variant_iter_next(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- Variant *iter = (Variant *)r_iter;
-
- bool valid;
- bool ret = self->iter_next(*iter, valid);
- *r_valid = valid;
- return ret;
-}
-
-static void gdnative_variant_iter_get(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- Variant *iter = (Variant *)r_iter;
-
- bool valid;
- memnew_placement(r_ret, Variant(self->iter_next(*iter, valid)));
- *r_valid = valid;
-}
-
-/// Variant functions.
-static GDNativeInt gdnative_variant_hash(const GDNativeVariantPtr p_self) {
- const Variant *self = (const Variant *)p_self;
- return self->hash();
-}
-
-static GDNativeInt gdnative_variant_recursive_hash(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count) {
- const Variant *self = (const Variant *)p_self;
- return self->recursive_hash(p_recursion_count);
-}
-
-static GDNativeBool gdnative_variant_hash_compare(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other) {
- const Variant *self = (const Variant *)p_self;
- const Variant *other = (const Variant *)p_other;
- return self->hash_compare(*other);
-}
-
-static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self) {
- const Variant *self = (const Variant *)p_self;
- return self->booleanize();
-}
-
-static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) {
- const Variant *self = (const Variant *)p_self;
- memnew_placement(r_ret, Variant(self->duplicate(p_deep)));
-}
-
-static void gdnative_variant_stringify(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret) {
- const Variant *self = (const Variant *)p_self;
- memnew_placement(r_ret, String(*self));
-}
-
-static GDNativeVariantType gdnative_variant_get_type(const GDNativeVariantPtr p_self) {
- const Variant *self = (const Variant *)p_self;
- return (GDNativeVariantType)self->get_type();
-}
-
-static GDNativeBool gdnative_variant_has_method(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method) {
- const Variant *self = (const Variant *)p_self;
- const StringName *method = (const StringName *)p_method;
- return self->has_method(*method);
-}
-
-static GDNativeBool gdnative_variant_has_member(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) {
- return Variant::has_member((Variant::Type)p_type, *((const StringName *)p_member));
-}
-
-static GDNativeBool gdnative_variant_has_key(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeBool *r_valid) {
- const Variant *self = (const Variant *)p_self;
- const Variant *key = (const Variant *)p_key;
- bool valid;
- bool ret = self->has_key(*key, valid);
- *r_valid = valid;
- return ret;
-}
-
-static void gdnative_variant_get_type_name(GDNativeVariantType p_type, GDNativeStringPtr r_ret) {
- String name = Variant::get_type_name((Variant::Type)p_type);
- memnew_placement(r_ret, String(name));
-}
-
-static GDNativeBool gdnative_variant_can_convert(GDNativeVariantType p_from, GDNativeVariantType p_to) {
- return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to);
-}
-
-static GDNativeBool gdnative_variant_can_convert_strict(GDNativeVariantType p_from, GDNativeVariantType p_to) {
- return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to);
-}
-
-// Variant interaction.
-static GDNativeVariantFromTypeConstructorFunc gdnative_get_variant_from_type_constructor(GDNativeVariantType p_type) {
- switch (p_type) {
- case GDNATIVE_VARIANT_TYPE_BOOL:
- return VariantTypeConstructor<bool>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_INT:
- return VariantTypeConstructor<int64_t>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_FLOAT:
- return VariantTypeConstructor<double>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_STRING:
- return VariantTypeConstructor<String>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_VECTOR2:
- return VariantTypeConstructor<Vector2>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_VECTOR2I:
- return VariantTypeConstructor<Vector2i>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_RECT2:
- return VariantTypeConstructor<Rect2>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_RECT2I:
- return VariantTypeConstructor<Rect2i>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_VECTOR3:
- return VariantTypeConstructor<Vector3>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_VECTOR3I:
- return VariantTypeConstructor<Vector3i>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_TRANSFORM2D:
- return VariantTypeConstructor<Transform2D>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_VECTOR4:
- return VariantTypeConstructor<Vector4>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_VECTOR4I:
- return VariantTypeConstructor<Vector4i>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PLANE:
- return VariantTypeConstructor<Plane>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_QUATERNION:
- return VariantTypeConstructor<Quaternion>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_AABB:
- return VariantTypeConstructor<AABB>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_BASIS:
- return VariantTypeConstructor<Basis>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_TRANSFORM3D:
- return VariantTypeConstructor<Transform3D>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PROJECTION:
- return VariantTypeConstructor<Projection>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_COLOR:
- return VariantTypeConstructor<Color>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_STRING_NAME:
- return VariantTypeConstructor<StringName>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_NODE_PATH:
- return VariantTypeConstructor<NodePath>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_RID:
- return VariantTypeConstructor<RID>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_OBJECT:
- return VariantTypeConstructor<Object *>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_CALLABLE:
- return VariantTypeConstructor<Callable>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_SIGNAL:
- return VariantTypeConstructor<Signal>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_DICTIONARY:
- return VariantTypeConstructor<Dictionary>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_ARRAY:
- return VariantTypeConstructor<Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY:
- return VariantTypeConstructor<PackedByteArray>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY:
- return VariantTypeConstructor<PackedInt32Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY:
- return VariantTypeConstructor<PackedInt64Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
- return VariantTypeConstructor<PackedFloat32Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
- return VariantTypeConstructor<PackedFloat64Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY:
- return VariantTypeConstructor<PackedStringArray>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
- return VariantTypeConstructor<PackedVector2Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
- return VariantTypeConstructor<PackedVector3Array>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY:
- return VariantTypeConstructor<PackedColorArray>::variant_from_type;
- case GDNATIVE_VARIANT_TYPE_NIL:
- case GDNATIVE_VARIANT_TYPE_VARIANT_MAX:
- ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
- }
- ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
-}
-
-static GDNativeTypeFromVariantConstructorFunc gdnative_get_type_from_variant_constructor(GDNativeVariantType p_type) {
- switch (p_type) {
- case GDNATIVE_VARIANT_TYPE_BOOL:
- return VariantTypeConstructor<bool>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_INT:
- return VariantTypeConstructor<int64_t>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_FLOAT:
- return VariantTypeConstructor<double>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_STRING:
- return VariantTypeConstructor<String>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_VECTOR2:
- return VariantTypeConstructor<Vector2>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_VECTOR2I:
- return VariantTypeConstructor<Vector2i>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_RECT2:
- return VariantTypeConstructor<Rect2>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_RECT2I:
- return VariantTypeConstructor<Rect2i>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_VECTOR3:
- return VariantTypeConstructor<Vector3>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_VECTOR3I:
- return VariantTypeConstructor<Vector3i>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_TRANSFORM2D:
- return VariantTypeConstructor<Transform2D>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_VECTOR4:
- return VariantTypeConstructor<Vector4>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_VECTOR4I:
- return VariantTypeConstructor<Vector4i>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PLANE:
- return VariantTypeConstructor<Plane>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_QUATERNION:
- return VariantTypeConstructor<Quaternion>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_AABB:
- return VariantTypeConstructor<AABB>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_BASIS:
- return VariantTypeConstructor<Basis>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_TRANSFORM3D:
- return VariantTypeConstructor<Transform3D>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PROJECTION:
- return VariantTypeConstructor<Projection>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_COLOR:
- return VariantTypeConstructor<Color>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_STRING_NAME:
- return VariantTypeConstructor<StringName>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_NODE_PATH:
- return VariantTypeConstructor<NodePath>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_RID:
- return VariantTypeConstructor<RID>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_OBJECT:
- return VariantTypeConstructor<Object *>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_CALLABLE:
- return VariantTypeConstructor<Callable>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_SIGNAL:
- return VariantTypeConstructor<Signal>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_DICTIONARY:
- return VariantTypeConstructor<Dictionary>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_ARRAY:
- return VariantTypeConstructor<Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY:
- return VariantTypeConstructor<PackedByteArray>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY:
- return VariantTypeConstructor<PackedInt32Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY:
- return VariantTypeConstructor<PackedInt64Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
- return VariantTypeConstructor<PackedFloat32Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
- return VariantTypeConstructor<PackedFloat64Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY:
- return VariantTypeConstructor<PackedStringArray>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
- return VariantTypeConstructor<PackedVector2Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
- return VariantTypeConstructor<PackedVector3Array>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY:
- return VariantTypeConstructor<PackedColorArray>::type_from_variant;
- case GDNATIVE_VARIANT_TYPE_NIL:
- case GDNATIVE_VARIANT_TYPE_VARIANT_MAX:
- ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
- }
- ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
-}
-
-// ptrcalls
-static GDNativePtrOperatorEvaluator gdnative_variant_get_ptr_operator_evaluator(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b) {
- return (GDNativePtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
-}
-static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash) {
- StringName method = p_method;
- uint32_t hash = Variant::get_builtin_method_hash(Variant::Type(p_type), method);
- if (hash != p_hash) {
- ERR_PRINT_ONCE("Error getting method " + String(method) + ", hash mismatch.");
- return nullptr;
- }
-
- return (GDNativePtrBuiltInMethod)Variant::get_ptr_builtin_method(Variant::Type(p_type), method);
-}
-static GDNativePtrConstructor gdnative_variant_get_ptr_constructor(GDNativeVariantType p_type, int32_t p_constructor) {
- return (GDNativePtrConstructor)Variant::get_ptr_constructor(Variant::Type(p_type), p_constructor);
-}
-static GDNativePtrDestructor gdnative_variant_get_ptr_destructor(GDNativeVariantType p_type) {
- return (GDNativePtrDestructor)Variant::get_ptr_destructor(Variant::Type(p_type));
-}
-static void gdnative_variant_construct(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error) {
- memnew_placement(p_base, Variant);
-
- Callable::CallError error;
- Variant::construct(Variant::Type(p_type), *(Variant *)p_base, (const Variant **)p_args, p_argument_count, error);
-
- if (r_error) {
- r_error->error = (GDNativeCallErrorType)(error.error);
- r_error->argument = error.argument;
- r_error->expected = error.expected;
- }
-}
-static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const char *p_member) {
- return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), p_member);
-}
-static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const char *p_member) {
- return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), p_member);
-}
-static GDNativePtrIndexedSetter gdnative_variant_get_ptr_indexed_setter(GDNativeVariantType p_type) {
- return (GDNativePtrIndexedSetter)Variant::get_member_ptr_indexed_setter(Variant::Type(p_type));
-}
-static GDNativePtrIndexedGetter gdnative_variant_get_ptr_indexed_getter(GDNativeVariantType p_type) {
- return (GDNativePtrIndexedGetter)Variant::get_member_ptr_indexed_getter(Variant::Type(p_type));
-}
-static GDNativePtrKeyedSetter gdnative_variant_get_ptr_keyed_setter(GDNativeVariantType p_type) {
- return (GDNativePtrKeyedSetter)Variant::get_member_ptr_keyed_setter(Variant::Type(p_type));
-}
-static GDNativePtrKeyedGetter gdnative_variant_get_ptr_keyed_getter(GDNativeVariantType p_type) {
- return (GDNativePtrKeyedGetter)Variant::get_member_ptr_keyed_getter(Variant::Type(p_type));
-}
-static GDNativePtrKeyedChecker gdnative_variant_get_ptr_keyed_checker(GDNativeVariantType p_type) {
- return (GDNativePtrKeyedChecker)Variant::get_member_ptr_keyed_checker(Variant::Type(p_type));
-}
-static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret) {
- memnew_placement(r_ret, Variant(Variant::get_constant_value(Variant::Type(p_type), p_constant)));
-}
-static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const char *p_function, GDNativeInt p_hash) {
- StringName function = p_function;
- uint32_t hash = Variant::get_utility_function_hash(function);
- if (hash != p_hash) {
- ERR_PRINT_ONCE("Error getting utility function " + String(function) + ", hash mismatch.");
- return nullptr;
- }
- return (GDNativePtrUtilityFunction)Variant::get_ptr_utility_function(function);
-}
-
-//string helpers
-
-static void gdnative_string_new_with_latin1_chars(GDNativeStringPtr r_dest, const char *p_contents) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- *dest = String(p_contents);
-}
-
-static void gdnative_string_new_with_utf8_chars(GDNativeStringPtr r_dest, const char *p_contents) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- dest->parse_utf8(p_contents);
-}
-
-static void gdnative_string_new_with_utf16_chars(GDNativeStringPtr r_dest, const char16_t *p_contents) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- dest->parse_utf16(p_contents);
-}
-
-static void gdnative_string_new_with_utf32_chars(GDNativeStringPtr r_dest, const char32_t *p_contents) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- *dest = String((const char32_t *)p_contents);
-}
-
-static void gdnative_string_new_with_wide_chars(GDNativeStringPtr r_dest, const wchar_t *p_contents) {
- String *dest = (String *)r_dest;
- if constexpr (sizeof(wchar_t) == 2) {
- // wchar_t is 16 bit, parse.
- memnew_placement(dest, String);
- dest->parse_utf16((const char16_t *)p_contents);
- } else {
- // wchar_t is 32 bit, copy.
- memnew_placement(dest, String);
- *dest = String((const char32_t *)p_contents);
- }
-}
-
-static void gdnative_string_new_with_latin1_chars_and_len(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- *dest = String(p_contents, p_size);
-}
-
-static void gdnative_string_new_with_utf8_chars_and_len(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- dest->parse_utf8(p_contents, p_size);
-}
-
-static void gdnative_string_new_with_utf16_chars_and_len(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- dest->parse_utf16(p_contents, p_size);
-}
-
-static void gdnative_string_new_with_utf32_chars_and_len(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size) {
- String *dest = (String *)r_dest;
- memnew_placement(dest, String);
- *dest = String((const char32_t *)p_contents, p_size);
-}
-
-static void gdnative_string_new_with_wide_chars_and_len(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size) {
- String *dest = (String *)r_dest;
- if constexpr (sizeof(wchar_t) == 2) {
- // wchar_t is 16 bit, parse.
- memnew_placement(dest, String);
- dest->parse_utf16((const char16_t *)p_contents, p_size);
- } else {
- // wchar_t is 32 bit, copy.
- memnew_placement(dest, String);
- *dest = String((const char32_t *)p_contents, p_size);
- }
-}
-
-static GDNativeInt gdnative_string_to_latin1_chars(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length) {
- String *self = (String *)p_self;
- CharString cs = self->ascii(true);
- GDNativeInt len = cs.length();
- if (r_text) {
- const char *s_text = cs.ptr();
- for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
- r_text[i] = s_text[i];
- }
- }
- return len;
-}
-static GDNativeInt gdnative_string_to_utf8_chars(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length) {
- String *self = (String *)p_self;
- CharString cs = self->utf8();
- GDNativeInt len = cs.length();
- if (r_text) {
- const char *s_text = cs.ptr();
- for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
- r_text[i] = s_text[i];
- }
- }
- return len;
-}
-static GDNativeInt gdnative_string_to_utf16_chars(const GDNativeStringPtr p_self, char16_t *r_text, GDNativeInt p_max_write_length) {
- String *self = (String *)p_self;
- Char16String cs = self->utf16();
- GDNativeInt len = cs.length();
- if (r_text) {
- const char16_t *s_text = cs.ptr();
- for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
- r_text[i] = s_text[i];
- }
- }
- return len;
-}
-static GDNativeInt gdnative_string_to_utf32_chars(const GDNativeStringPtr p_self, char32_t *r_text, GDNativeInt p_max_write_length) {
- String *self = (String *)p_self;
- GDNativeInt len = self->length();
- if (r_text) {
- const char32_t *s_text = self->ptr();
- for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
- r_text[i] = s_text[i];
- }
- }
- return len;
-}
-static GDNativeInt gdnative_string_to_wide_chars(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length) {
- if constexpr (sizeof(wchar_t) == 4) {
- return gdnative_string_to_utf32_chars(p_self, (char32_t *)r_text, p_max_write_length);
- } else {
- return gdnative_string_to_utf16_chars(p_self, (char16_t *)r_text, p_max_write_length);
- }
-}
-
-static char32_t *gdnative_string_operator_index(GDNativeStringPtr p_self, GDNativeInt p_index) {
- String *self = (String *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr);
- return &self->ptrw()[p_index];
-}
-
-static const char32_t *gdnative_string_operator_index_const(const GDNativeStringPtr p_self, GDNativeInt p_index) {
- const String *self = (const String *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr);
- return &self->ptr()[p_index];
-}
-
-/* Packed array functions */
-
-static uint8_t *gdnative_packed_byte_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedByteArray *self = (PackedByteArray *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptrw()[p_index];
-}
-
-static const uint8_t *gdnative_packed_byte_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedByteArray *self = (const PackedByteArray *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptr()[p_index];
-}
-
-static GDNativeTypePtr gdnative_packed_color_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedColorArray *self = (PackedColorArray *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeTypePtr)&self->ptrw()[p_index];
-}
-
-static GDNativeTypePtr gdnative_packed_color_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedColorArray *self = (const PackedColorArray *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeTypePtr)&self->ptr()[p_index];
-}
-
-static float *gdnative_packed_float32_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedFloat32Array *self = (PackedFloat32Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptrw()[p_index];
-}
-
-static const float *gdnative_packed_float32_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedFloat32Array *self = (const PackedFloat32Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptr()[p_index];
-}
-
-static double *gdnative_packed_float64_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedFloat64Array *self = (PackedFloat64Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptrw()[p_index];
-}
-
-static const double *gdnative_packed_float64_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedFloat64Array *self = (const PackedFloat64Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptr()[p_index];
-}
-
-static int32_t *gdnative_packed_int32_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedInt32Array *self = (PackedInt32Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptrw()[p_index];
-}
-
-static const int32_t *gdnative_packed_int32_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedInt32Array *self = (const PackedInt32Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptr()[p_index];
-}
-
-static int64_t *gdnative_packed_int64_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedInt64Array *self = (PackedInt64Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptrw()[p_index];
-}
-
-static const int64_t *gdnative_packed_int64_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedInt64Array *self = (const PackedInt64Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return &self->ptr()[p_index];
-}
-
-static GDNativeStringPtr gdnative_packed_string_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedStringArray *self = (PackedStringArray *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeStringPtr)&self->ptrw()[p_index];
-}
-
-static GDNativeStringPtr gdnative_packed_string_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedStringArray *self = (const PackedStringArray *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeStringPtr)&self->ptr()[p_index];
-}
-
-static GDNativeTypePtr gdnative_packed_vector2_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedVector2Array *self = (PackedVector2Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeTypePtr)&self->ptrw()[p_index];
-}
-
-static GDNativeTypePtr gdnative_packed_vector2_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedVector2Array *self = (const PackedVector2Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeTypePtr)&self->ptr()[p_index];
-}
-
-static GDNativeTypePtr gdnative_packed_vector3_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- PackedVector3Array *self = (PackedVector3Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeTypePtr)&self->ptrw()[p_index];
-}
-
-static GDNativeTypePtr gdnative_packed_vector3_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const PackedVector3Array *self = (const PackedVector3Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeTypePtr)&self->ptr()[p_index];
-}
-
-static GDNativeVariantPtr gdnative_array_operator_index(GDNativeTypePtr p_self, GDNativeInt p_index) {
- Array *self = (Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeVariantPtr)&self->operator[](p_index);
-}
-
-static GDNativeVariantPtr gdnative_array_operator_index_const(const GDNativeTypePtr p_self, GDNativeInt p_index) {
- const Array *self = (const Array *)p_self;
- ERR_FAIL_INDEX_V(p_index, self->size(), nullptr);
- return (GDNativeVariantPtr)&self->operator[](p_index);
-}
-
-/* Dictionary functions */
-
-static GDNativeVariantPtr gdnative_dictionary_operator_index(GDNativeTypePtr p_self, const GDNativeVariantPtr p_key) {
- Dictionary *self = (Dictionary *)p_self;
- return (GDNativeVariantPtr)&self->operator[](*(const Variant *)p_key);
-}
-
-static GDNativeVariantPtr gdnative_dictionary_operator_index_const(const GDNativeTypePtr p_self, const GDNativeVariantPtr p_key) {
- const Dictionary *self = (const Dictionary *)p_self;
- return (GDNativeVariantPtr)&self->operator[](*(const Variant *)p_key);
-}
-
-/* OBJECT API */
-
-static void gdnative_object_method_bind_call(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeVariantPtr *p_args, GDNativeInt p_arg_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
- MethodBind *mb = (MethodBind *)p_method_bind;
- Object *o = (Object *)p_instance;
- const Variant **args = (const Variant **)p_args;
- Callable::CallError error;
-
- Variant ret = mb->call(o, args, p_arg_count, error);
- memnew_placement(r_return, Variant(ret));
-
- if (r_error) {
- r_error->error = (GDNativeCallErrorType)(error.error);
- r_error->argument = error.argument;
- r_error->expected = error.expected;
- }
-}
-
-static void gdnative_object_method_bind_ptrcall(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr p_ret) {
- MethodBind *mb = (MethodBind *)p_method_bind;
- Object *o = (Object *)p_instance;
- mb->ptrcall(o, (const void **)p_args, p_ret);
-}
-
-static void gdnative_object_destroy(GDNativeObjectPtr p_o) {
- memdelete((Object *)p_o);
-}
-
-static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
- return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
-}
-
-static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_object, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
- Object *o = (Object *)p_object;
- return o->get_instance_binding(p_token, p_callbacks);
-}
-
-static void gdnative_object_set_instance_binding(GDNativeObjectPtr p_object, void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks) {
- Object *o = (Object *)p_object;
- o->set_instance_binding(p_token, p_binding, p_callbacks);
-}
-
-static void gdnative_object_set_instance(GDNativeObjectPtr p_object, const char *p_classname, GDExtensionClassInstancePtr p_instance) {
- Object *o = (Object *)p_object;
- ClassDB::set_object_extension_instance(o, p_classname, p_instance);
-}
-
-static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
- return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
-}
-
-static GDNativeObjectPtr gdnative_object_cast_to(const GDNativeObjectPtr p_object, void *p_class_tag) {
- if (!p_object) {
- return nullptr;
- }
- Object *o = (Object *)p_object;
-
- return o->is_class_ptr(p_class_tag) ? (GDNativeObjectPtr)o : (GDNativeObjectPtr) nullptr;
-}
-
-static GDObjectInstanceID gdnative_object_get_instance_id(const GDNativeObjectPtr p_object) {
- const Object *o = (const Object *)p_object;
- return (GDObjectInstanceID)o->get_instance_id();
-}
-
-static GDNativeScriptInstancePtr gdnative_script_instance_create(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data) {
- ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension);
- script_instance_extension->instance = p_instance_data;
- script_instance_extension->native_info = p_info;
- return reinterpret_cast<GDNativeScriptInstancePtr>(script_instance_extension);
-}
-
-static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_classname, const char *p_methodname, GDNativeInt p_hash) {
- MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
- ERR_FAIL_COND_V(!mb, nullptr);
- if (mb->get_hash() != p_hash) {
- ERR_PRINT("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
- return nullptr;
- }
- // MethodBind *mb = ClassDB::get_method("Node", "get_name");
- return (GDNativeMethodBindPtr)mb;
-}
-
-static GDNativeObjectPtr gdnative_classdb_construct_object(const char *p_classname) {
- return (GDNativeObjectPtr)ClassDB::instantiate(p_classname);
-}
-
-static void *gdnative_classdb_get_class_tag(const char *p_classname) {
- ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(p_classname);
- return class_info ? class_info->class_ptr : nullptr;
-}
-
-void gdnative_setup_interface(GDNativeInterface *p_interface) {
- GDNativeInterface &gdni = *p_interface;
-
- gdni.version_major = VERSION_MAJOR;
- gdni.version_minor = VERSION_MINOR;
-#if VERSION_PATCH
- gdni.version_patch = VERSION_PATCH;
-#else
- gdni.version_patch = 0;
-#endif
- gdni.version_string = VERSION_FULL_NAME;
-
- /* GODOT CORE */
-
- gdni.mem_alloc = gdnative_alloc;
- gdni.mem_realloc = gdnative_realloc;
- gdni.mem_free = gdnative_free;
-
- gdni.print_error = gdnative_print_error;
- gdni.print_warning = gdnative_print_warning;
- gdni.print_script_error = gdnative_print_script_error;
-
- gdni.get_native_struct_size = gdnative_get_native_struct_size;
-
- /* GODOT VARIANT */
-
- // variant general
- gdni.variant_new_copy = gdnative_variant_new_copy;
- gdni.variant_new_nil = gdnative_variant_new_nil;
- gdni.variant_destroy = gdnative_variant_destroy;
-
- gdni.variant_call = gdnative_variant_call;
- gdni.variant_call_static = gdnative_variant_call_static;
- gdni.variant_evaluate = gdnative_variant_evaluate;
- gdni.variant_set = gdnative_variant_set;
- gdni.variant_set_named = gdnative_variant_set_named;
- gdni.variant_set_keyed = gdnative_variant_set_keyed;
- gdni.variant_set_indexed = gdnative_variant_set_indexed;
- gdni.variant_get = gdnative_variant_get;
- gdni.variant_get_named = gdnative_variant_get_named;
- gdni.variant_get_keyed = gdnative_variant_get_keyed;
- gdni.variant_get_indexed = gdnative_variant_get_indexed;
- gdni.variant_iter_init = gdnative_variant_iter_init;
- gdni.variant_iter_next = gdnative_variant_iter_next;
- gdni.variant_iter_get = gdnative_variant_iter_get;
- gdni.variant_hash = gdnative_variant_hash;
- gdni.variant_recursive_hash = gdnative_variant_recursive_hash;
- gdni.variant_hash_compare = gdnative_variant_hash_compare;
- gdni.variant_booleanize = gdnative_variant_booleanize;
- gdni.variant_duplicate = gdnative_variant_duplicate;
- gdni.variant_stringify = gdnative_variant_stringify;
-
- gdni.variant_get_type = gdnative_variant_get_type;
- gdni.variant_has_method = gdnative_variant_has_method;
- gdni.variant_has_member = gdnative_variant_has_member;
- gdni.variant_has_key = gdnative_variant_has_key;
- gdni.variant_get_type_name = gdnative_variant_get_type_name;
- gdni.variant_can_convert = gdnative_variant_can_convert;
- gdni.variant_can_convert_strict = gdnative_variant_can_convert_strict;
-
- gdni.get_variant_from_type_constructor = gdnative_get_variant_from_type_constructor;
- gdni.get_variant_to_type_constructor = gdnative_get_type_from_variant_constructor;
-
- // ptrcalls.
-
- gdni.variant_get_ptr_operator_evaluator = gdnative_variant_get_ptr_operator_evaluator;
- gdni.variant_get_ptr_builtin_method = gdnative_variant_get_ptr_builtin_method;
- gdni.variant_get_ptr_constructor = gdnative_variant_get_ptr_constructor;
- gdni.variant_get_ptr_destructor = gdnative_variant_get_ptr_destructor;
- gdni.variant_construct = gdnative_variant_construct;
- gdni.variant_get_ptr_setter = gdnative_variant_get_ptr_setter;
- gdni.variant_get_ptr_getter = gdnative_variant_get_ptr_getter;
- gdni.variant_get_ptr_indexed_setter = gdnative_variant_get_ptr_indexed_setter;
- gdni.variant_get_ptr_indexed_getter = gdnative_variant_get_ptr_indexed_getter;
- gdni.variant_get_ptr_keyed_setter = gdnative_variant_get_ptr_keyed_setter;
- gdni.variant_get_ptr_keyed_getter = gdnative_variant_get_ptr_keyed_getter;
- gdni.variant_get_ptr_keyed_checker = gdnative_variant_get_ptr_keyed_checker;
- gdni.variant_get_constant_value = gdnative_variant_get_constant_value;
- gdni.variant_get_ptr_utility_function = gdnative_variant_get_ptr_utility_function;
-
- // extra utilities
-
- gdni.string_new_with_latin1_chars = gdnative_string_new_with_latin1_chars;
- gdni.string_new_with_utf8_chars = gdnative_string_new_with_utf8_chars;
- gdni.string_new_with_utf16_chars = gdnative_string_new_with_utf16_chars;
- gdni.string_new_with_utf32_chars = gdnative_string_new_with_utf32_chars;
- gdni.string_new_with_wide_chars = gdnative_string_new_with_wide_chars;
- gdni.string_new_with_latin1_chars_and_len = gdnative_string_new_with_latin1_chars_and_len;
- gdni.string_new_with_utf8_chars_and_len = gdnative_string_new_with_utf8_chars_and_len;
- gdni.string_new_with_utf16_chars_and_len = gdnative_string_new_with_utf16_chars_and_len;
- gdni.string_new_with_utf32_chars_and_len = gdnative_string_new_with_utf32_chars_and_len;
- gdni.string_new_with_wide_chars_and_len = gdnative_string_new_with_wide_chars_and_len;
- gdni.string_to_latin1_chars = gdnative_string_to_latin1_chars;
- gdni.string_to_utf8_chars = gdnative_string_to_utf8_chars;
- gdni.string_to_utf16_chars = gdnative_string_to_utf16_chars;
- gdni.string_to_utf32_chars = gdnative_string_to_utf32_chars;
- gdni.string_to_wide_chars = gdnative_string_to_wide_chars;
- gdni.string_operator_index = gdnative_string_operator_index;
- gdni.string_operator_index_const = gdnative_string_operator_index_const;
-
- /* Packed array functions */
-
- gdni.packed_byte_array_operator_index = gdnative_packed_byte_array_operator_index;
- gdni.packed_byte_array_operator_index_const = gdnative_packed_byte_array_operator_index_const;
-
- gdni.packed_color_array_operator_index = gdnative_packed_color_array_operator_index;
- gdni.packed_color_array_operator_index_const = gdnative_packed_color_array_operator_index_const;
-
- gdni.packed_float32_array_operator_index = gdnative_packed_float32_array_operator_index;
- gdni.packed_float32_array_operator_index_const = gdnative_packed_float32_array_operator_index_const;
- gdni.packed_float64_array_operator_index = gdnative_packed_float64_array_operator_index;
- gdni.packed_float64_array_operator_index_const = gdnative_packed_float64_array_operator_index_const;
-
- gdni.packed_int32_array_operator_index = gdnative_packed_int32_array_operator_index;
- gdni.packed_int32_array_operator_index_const = gdnative_packed_int32_array_operator_index_const;
- gdni.packed_int64_array_operator_index = gdnative_packed_int64_array_operator_index;
- gdni.packed_int64_array_operator_index_const = gdnative_packed_int64_array_operator_index_const;
-
- gdni.packed_string_array_operator_index = gdnative_packed_string_array_operator_index;
- gdni.packed_string_array_operator_index_const = gdnative_packed_string_array_operator_index_const;
-
- gdni.packed_vector2_array_operator_index = gdnative_packed_vector2_array_operator_index;
- gdni.packed_vector2_array_operator_index_const = gdnative_packed_vector2_array_operator_index_const;
- gdni.packed_vector3_array_operator_index = gdnative_packed_vector3_array_operator_index;
- gdni.packed_vector3_array_operator_index_const = gdnative_packed_vector3_array_operator_index_const;
-
- gdni.array_operator_index = gdnative_array_operator_index;
- gdni.array_operator_index_const = gdnative_array_operator_index_const;
-
- /* Dictionary functions */
-
- gdni.dictionary_operator_index = gdnative_dictionary_operator_index;
- gdni.dictionary_operator_index_const = gdnative_dictionary_operator_index_const;
-
- /* OBJECT */
-
- gdni.object_method_bind_call = gdnative_object_method_bind_call;
- gdni.object_method_bind_ptrcall = gdnative_object_method_bind_ptrcall;
- gdni.object_destroy = gdnative_object_destroy;
- gdni.global_get_singleton = gdnative_global_get_singleton;
- gdni.object_get_instance_binding = gdnative_object_get_instance_binding;
- gdni.object_set_instance_binding = gdnative_object_set_instance_binding;
- gdni.object_set_instance = gdnative_object_set_instance;
-
- gdni.object_cast_to = gdnative_object_cast_to;
- gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
- gdni.object_get_instance_id = gdnative_object_get_instance_id;
-
- /* SCRIPT INSTANCE */
-
- gdni.script_instance_create = gdnative_script_instance_create;
-
- /* CLASSDB */
-
- gdni.classdb_construct_object = gdnative_classdb_construct_object;
- gdni.classdb_get_method_bind = gdnative_classdb_get_method_bind;
- gdni.classdb_get_class_tag = gdnative_classdb_get_class_tag;
-
- /* CLASSDB EXTENSION */
-
- //these are filled by implementation, since it will want to keep track of registered classes
- gdni.classdb_register_extension_class = nullptr;
- gdni.classdb_register_extension_class_method = nullptr;
- gdni.classdb_register_extension_class_integer_constant = nullptr;
- gdni.classdb_register_extension_class_property = nullptr;
- gdni.classdb_register_extension_class_property_group = nullptr;
- gdni.classdb_register_extension_class_property_subgroup = nullptr;
- gdni.classdb_register_extension_class_signal = nullptr;
- gdni.classdb_unregister_extension_class = nullptr;
-
- gdni.get_library_path = nullptr;
-}
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
deleted file mode 100644
index 39378d8261..0000000000
--- a/core/extension/gdnative_interface.h
+++ /dev/null
@@ -1,592 +0,0 @@
-/*************************************************************************/
-/* gdnative_interface.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 GDNATIVE_INTERFACE_H
-#define GDNATIVE_INTERFACE_H
-
-/* This is a C class header, you can copy it and use it directly in your own binders.
- * Together with the JSON file, you should be able to generate any binder.
- */
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#ifndef __cplusplus
-typedef uint32_t char32_t;
-typedef uint16_t char16_t;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* VARIANT TYPES */
-
-typedef enum {
- GDNATIVE_VARIANT_TYPE_NIL,
-
- /* atomic types */
- GDNATIVE_VARIANT_TYPE_BOOL,
- GDNATIVE_VARIANT_TYPE_INT,
- GDNATIVE_VARIANT_TYPE_FLOAT,
- GDNATIVE_VARIANT_TYPE_STRING,
-
- /* math types */
- GDNATIVE_VARIANT_TYPE_VECTOR2,
- GDNATIVE_VARIANT_TYPE_VECTOR2I,
- GDNATIVE_VARIANT_TYPE_RECT2,
- GDNATIVE_VARIANT_TYPE_RECT2I,
- GDNATIVE_VARIANT_TYPE_VECTOR3,
- GDNATIVE_VARIANT_TYPE_VECTOR3I,
- GDNATIVE_VARIANT_TYPE_TRANSFORM2D,
- GDNATIVE_VARIANT_TYPE_VECTOR4,
- GDNATIVE_VARIANT_TYPE_VECTOR4I,
- GDNATIVE_VARIANT_TYPE_PLANE,
- GDNATIVE_VARIANT_TYPE_QUATERNION,
- GDNATIVE_VARIANT_TYPE_AABB,
- GDNATIVE_VARIANT_TYPE_BASIS,
- GDNATIVE_VARIANT_TYPE_TRANSFORM3D,
- GDNATIVE_VARIANT_TYPE_PROJECTION,
-
- /* misc types */
- GDNATIVE_VARIANT_TYPE_COLOR,
- GDNATIVE_VARIANT_TYPE_STRING_NAME,
- GDNATIVE_VARIANT_TYPE_NODE_PATH,
- GDNATIVE_VARIANT_TYPE_RID,
- GDNATIVE_VARIANT_TYPE_OBJECT,
- GDNATIVE_VARIANT_TYPE_CALLABLE,
- GDNATIVE_VARIANT_TYPE_SIGNAL,
- GDNATIVE_VARIANT_TYPE_DICTIONARY,
- GDNATIVE_VARIANT_TYPE_ARRAY,
-
- /* typed arrays */
- GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY,
- GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY,
-
- GDNATIVE_VARIANT_TYPE_VARIANT_MAX
-} GDNativeVariantType;
-
-typedef enum {
- /* comparison */
- GDNATIVE_VARIANT_OP_EQUAL,
- GDNATIVE_VARIANT_OP_NOT_EQUAL,
- GDNATIVE_VARIANT_OP_LESS,
- GDNATIVE_VARIANT_OP_LESS_EQUAL,
- GDNATIVE_VARIANT_OP_GREATER,
- GDNATIVE_VARIANT_OP_GREATER_EQUAL,
- /* mathematic */
- GDNATIVE_VARIANT_OP_ADD,
- GDNATIVE_VARIANT_OP_SUBTRACT,
- GDNATIVE_VARIANT_OP_MULTIPLY,
- GDNATIVE_VARIANT_OP_DIVIDE,
- GDNATIVE_VARIANT_OP_NEGATE,
- GDNATIVE_VARIANT_OP_POSITIVE,
- GDNATIVE_VARIANT_OP_MODULE,
- GDNATIVE_VARIANT_OP_POWER,
- /* bitwise */
- GDNATIVE_VARIANT_OP_SHIFT_LEFT,
- GDNATIVE_VARIANT_OP_SHIFT_RIGHT,
- GDNATIVE_VARIANT_OP_BIT_AND,
- GDNATIVE_VARIANT_OP_BIT_OR,
- GDNATIVE_VARIANT_OP_BIT_XOR,
- GDNATIVE_VARIANT_OP_BIT_NEGATE,
- /* logic */
- GDNATIVE_VARIANT_OP_AND,
- GDNATIVE_VARIANT_OP_OR,
- GDNATIVE_VARIANT_OP_XOR,
- GDNATIVE_VARIANT_OP_NOT,
- /* containment */
- GDNATIVE_VARIANT_OP_IN,
- GDNATIVE_VARIANT_OP_MAX
-
-} GDNativeVariantOperator;
-
-typedef void *GDNativeVariantPtr;
-typedef void *GDNativeStringNamePtr;
-typedef void *GDNativeStringPtr;
-typedef void *GDNativeObjectPtr;
-typedef void *GDNativeTypePtr;
-typedef void *GDNativeExtensionPtr;
-typedef void *GDNativeMethodBindPtr;
-typedef int64_t GDNativeInt;
-typedef uint8_t GDNativeBool;
-typedef uint64_t GDObjectInstanceID;
-
-/* VARIANT DATA I/O */
-
-typedef enum {
- GDNATIVE_CALL_OK,
- GDNATIVE_CALL_ERROR_INVALID_METHOD,
- GDNATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */
- GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
- GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
- GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL,
- GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, /* used for const call */
-} GDNativeCallErrorType;
-
-typedef struct {
- GDNativeCallErrorType error;
- int32_t argument;
- int32_t expected;
-} GDNativeCallError;
-
-typedef void (*GDNativeVariantFromTypeConstructorFunc)(GDNativeVariantPtr, GDNativeTypePtr);
-typedef void (*GDNativeTypeFromVariantConstructorFunc)(GDNativeTypePtr, GDNativeVariantPtr);
-typedef void (*GDNativePtrOperatorEvaluator)(const GDNativeTypePtr p_left, const GDNativeTypePtr p_right, GDNativeTypePtr r_result);
-typedef void (*GDNativePtrBuiltInMethod)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args, GDNativeTypePtr r_return, int p_argument_count);
-typedef void (*GDNativePtrConstructor)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args);
-typedef void (*GDNativePtrDestructor)(GDNativeTypePtr p_base);
-typedef void (*GDNativePtrSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_value);
-typedef void (*GDNativePtrGetter)(const GDNativeTypePtr p_base, GDNativeTypePtr r_value);
-typedef void (*GDNativePtrIndexedSetter)(GDNativeTypePtr p_base, GDNativeInt p_index, const GDNativeTypePtr p_value);
-typedef void (*GDNativePtrIndexedGetter)(const GDNativeTypePtr p_base, GDNativeInt p_index, GDNativeTypePtr r_value);
-typedef void (*GDNativePtrKeyedSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_key, const GDNativeTypePtr p_value);
-typedef void (*GDNativePtrKeyedGetter)(const GDNativeTypePtr p_base, const GDNativeTypePtr p_key, GDNativeTypePtr r_value);
-typedef uint32_t (*GDNativePtrKeyedChecker)(const GDNativeVariantPtr p_base, const GDNativeVariantPtr p_key);
-typedef void (*GDNativePtrUtilityFunction)(GDNativeTypePtr r_return, const GDNativeTypePtr *p_arguments, int p_argument_count);
-
-typedef GDNativeObjectPtr (*GDNativeClassConstructor)();
-
-typedef void *(*GDNativeInstanceBindingCreateCallback)(void *p_token, void *p_instance);
-typedef void (*GDNativeInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding);
-typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_binding, GDNativeBool p_reference);
-
-typedef struct {
- GDNativeInstanceBindingCreateCallback create_callback;
- GDNativeInstanceBindingFreeCallback free_callback;
- GDNativeInstanceBindingReferenceCallback reference_callback;
-} GDNativeInstanceBindingCallbacks;
-
-/* EXTENSION CLASSES */
-
-typedef void *GDExtensionClassInstancePtr;
-
-typedef GDNativeBool (*GDNativeExtensionClassSet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
-typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
-typedef uint64_t (*GDNativeExtensionClassGetRID)(GDExtensionClassInstancePtr p_instance);
-
-typedef struct {
- uint32_t type;
- const char *name;
- const char *class_name;
- uint32_t hint;
- const char *hint_string;
- uint32_t usage;
-} GDNativePropertyInfo;
-
-typedef struct {
- const char *name;
- GDNativePropertyInfo return_value;
- uint32_t flags; // From GDNativeExtensionClassMethodFlags
- int32_t id;
- GDNativePropertyInfo *arguments;
- uint32_t argument_count;
- GDNativeVariantPtr default_arguments;
- uint32_t default_argument_count;
-} GDNativeMethodInfo;
-
-typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
-typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list);
-typedef GDNativeBool (*GDNativeExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name);
-typedef GDNativeBool (*GDNativeExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
-typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
-typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr p_out);
-typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
-typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
-typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
-typedef GDNativeObjectPtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata);
-typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
-typedef void (*GDNativeExtensionClassObjectInstance)(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance);
-typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name);
-
-typedef struct {
- GDNativeExtensionClassSet set_func;
- GDNativeExtensionClassGet get_func;
- GDNativeExtensionClassGetPropertyList get_property_list_func;
- GDNativeExtensionClassFreePropertyList free_property_list_func;
- GDNativeExtensionClassPropertyCanRevert property_can_revert_func;
- GDNativeExtensionClassPropertyGetRevert property_get_revert_func;
- GDNativeExtensionClassNotification notification_func;
- GDNativeExtensionClassToString to_string_func;
- GDNativeExtensionClassReference reference_func;
- GDNativeExtensionClassUnreference unreference_func;
- GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
- GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
- GDNativeExtensionClassGetVirtual get_virtual_func;
- GDNativeExtensionClassGetRID get_rid_func;
- void *class_userdata;
-} GDNativeExtensionClassCreationInfo;
-
-typedef void *GDNativeExtensionClassLibraryPtr;
-
-/* Method */
-
-typedef enum {
- GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL = 1,
- GDNATIVE_EXTENSION_METHOD_FLAG_EDITOR = 2,
- GDNATIVE_EXTENSION_METHOD_FLAG_CONST = 4,
- GDNATIVE_EXTENSION_METHOD_FLAG_VIRTUAL = 8,
- GDNATIVE_EXTENSION_METHOD_FLAG_VARARG = 16,
- GDNATIVE_EXTENSION_METHOD_FLAG_STATIC = 32,
- GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT = GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL,
-} GDNativeExtensionClassMethodFlags;
-
-typedef enum {
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_NONE,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT,
- GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE
-} GDNativeExtensionClassMethodArgumentMetadata;
-
-typedef void (*GDNativeExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
-typedef void (*GDNativeExtensionClassMethodPtrCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
-
-/* passing -1 as argument in the following functions refers to the return type */
-typedef GDNativeVariantType (*GDNativeExtensionClassMethodGetArgumentType)(void *p_method_userdata, int32_t p_argument);
-typedef void (*GDNativeExtensionClassMethodGetArgumentInfo)(void *p_method_userdata, int32_t p_argument, GDNativePropertyInfo *r_info);
-typedef GDNativeExtensionClassMethodArgumentMetadata (*GDNativeExtensionClassMethodGetArgumentMetadata)(void *p_method_userdata, int32_t p_argument);
-
-typedef struct {
- const char *name;
- void *method_userdata;
- GDNativeExtensionClassMethodCall call_func;
- GDNativeExtensionClassMethodPtrCall ptrcall_func;
- uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */
- uint32_t argument_count;
- GDNativeBool has_return_value;
- GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
- GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
- GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
- uint32_t default_argument_count;
- GDNativeVariantPtr *default_arguments;
-} GDNativeExtensionClassMethodInfo;
-
-/* SCRIPT INSTANCE EXTENSION */
-
-typedef void *GDNativeExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation
-
-typedef GDNativeBool (*GDNativeExtensionScriptInstanceSet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
-typedef GDNativeBool (*GDNativeExtensionScriptInstanceGet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
-typedef const GDNativePropertyInfo *(*GDNativeExtensionScriptInstanceGetPropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
-typedef void (*GDNativeExtensionScriptInstanceFreePropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativePropertyInfo *p_list);
-typedef GDNativeVariantType (*GDNativeExtensionScriptInstanceGetPropertyType)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeBool *r_is_valid);
-
-typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyCanRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name);
-typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyGetRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
-
-typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetOwner)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-typedef void (*GDNativeExtensionScriptInstancePropertyStateAdd)(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata);
-typedef void (*GDNativeExtensionScriptInstanceGetPropertyState)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeExtensionScriptInstancePropertyStateAdd p_add_func, void *p_userdata);
-
-typedef const GDNativeMethodInfo *(*GDNativeExtensionScriptInstanceGetMethodList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
-typedef void (*GDNativeExtensionScriptInstanceFreeMethodList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeMethodInfo *p_list);
-
-typedef GDNativeBool (*GDNativeExtensionScriptInstanceHasMethod)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name);
-
-typedef void (*GDNativeExtensionScriptInstanceCall)(GDNativeExtensionScriptInstanceDataPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
-typedef void (*GDNativeExtensionScriptInstanceNotification)(GDNativeExtensionScriptInstanceDataPtr p_instance, int32_t p_what);
-typedef const char *(*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid);
-
-typedef void (*GDNativeExtensionScriptInstanceRefCountIncremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-typedef GDNativeBool (*GDNativeExtensionScriptInstanceRefCountDecremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-
-typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetScript)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-typedef GDNativeBool (*GDNativeExtensionScriptInstanceIsPlaceholder)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-
-typedef void *GDNativeExtensionScriptLanguagePtr;
-
-typedef GDNativeExtensionScriptLanguagePtr (*GDNativeExtensionScriptInstanceGetLanguage)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-
-typedef void (*GDNativeExtensionScriptInstanceFree)(GDNativeExtensionScriptInstanceDataPtr p_instance);
-
-typedef void *GDNativeScriptInstancePtr; // Pointer to ScriptInstance.
-
-typedef struct {
- GDNativeExtensionScriptInstanceSet set_func;
- GDNativeExtensionScriptInstanceGet get_func;
- GDNativeExtensionScriptInstanceGetPropertyList get_property_list_func;
- GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
- GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
-
- GDNativeExtensionScriptInstancePropertyCanRevert property_can_revert_func;
- GDNativeExtensionScriptInstancePropertyGetRevert property_get_revert_func;
-
- GDNativeExtensionScriptInstanceGetOwner get_owner_func;
- GDNativeExtensionScriptInstanceGetPropertyState get_property_state_func;
-
- GDNativeExtensionScriptInstanceGetMethodList get_method_list_func;
- GDNativeExtensionScriptInstanceFreeMethodList free_method_list_func;
-
- GDNativeExtensionScriptInstanceHasMethod has_method_func;
-
- GDNativeExtensionScriptInstanceCall call_func;
- GDNativeExtensionScriptInstanceNotification notification_func;
-
- GDNativeExtensionScriptInstanceToString to_string_func;
-
- GDNativeExtensionScriptInstanceRefCountIncremented refcount_incremented_func;
- GDNativeExtensionScriptInstanceRefCountDecremented refcount_decremented_func;
-
- GDNativeExtensionScriptInstanceGetScript get_script_func;
-
- GDNativeExtensionScriptInstanceIsPlaceholder is_placeholder_func;
-
- GDNativeExtensionScriptInstanceSet set_fallback_func;
- GDNativeExtensionScriptInstanceGet get_fallback_func;
-
- GDNativeExtensionScriptInstanceGetLanguage get_language_func;
-
- GDNativeExtensionScriptInstanceFree free_func;
-
-} GDNativeExtensionScriptInstanceInfo;
-
-/* INTERFACE */
-
-typedef struct {
- uint32_t version_major;
- uint32_t version_minor;
- uint32_t version_patch;
- const char *version_string;
-
- /* GODOT CORE */
- void *(*mem_alloc)(size_t p_bytes);
- void *(*mem_realloc)(void *p_ptr, size_t p_bytes);
- void (*mem_free)(void *p_ptr);
-
- void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
- void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
- void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
-
- uint64_t (*get_native_struct_size)(const char *p_name);
-
- /* GODOT VARIANT */
-
- /* variant general */
- void (*variant_new_copy)(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src);
- void (*variant_new_nil)(GDNativeVariantPtr r_dest);
- void (*variant_destroy)(GDNativeVariantPtr p_self);
-
- /* variant type */
- void (*variant_call)(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
- void (*variant_call_static)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
- void (*variant_evaluate)(GDNativeVariantOperator p_op, const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_return, GDNativeBool *r_valid);
- void (*variant_set)(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid);
- void (*variant_set_named)(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid);
- void (*variant_set_keyed)(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid);
- void (*variant_set_indexed)(GDNativeVariantPtr p_self, GDNativeInt p_index, const GDNativeVariantPtr p_value, GDNativeBool *r_valid, GDNativeBool *r_oob);
- void (*variant_get)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
- void (*variant_get_named)(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
- void (*variant_get_keyed)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
- void (*variant_get_indexed)(const GDNativeVariantPtr p_self, GDNativeInt p_index, GDNativeVariantPtr r_ret, GDNativeBool *r_valid, GDNativeBool *r_oob);
- GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
- GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
- void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
- GDNativeInt (*variant_hash)(const GDNativeVariantPtr p_self);
- GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
- GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
- GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
- void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
- void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);
-
- GDNativeVariantType (*variant_get_type)(const GDNativeVariantPtr p_self);
- GDNativeBool (*variant_has_method)(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method);
- GDNativeBool (*variant_has_member)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member);
- GDNativeBool (*variant_has_key)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeBool *r_valid);
- void (*variant_get_type_name)(GDNativeVariantType p_type, GDNativeStringPtr r_name);
- GDNativeBool (*variant_can_convert)(GDNativeVariantType p_from, GDNativeVariantType p_to);
- GDNativeBool (*variant_can_convert_strict)(GDNativeVariantType p_from, GDNativeVariantType p_to);
-
- /* ptrcalls */
- GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type);
- GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type);
- GDNativePtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b);
- GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash);
- GDNativePtrConstructor (*variant_get_ptr_constructor)(GDNativeVariantType p_type, int32_t p_constructor);
- GDNativePtrDestructor (*variant_get_ptr_destructor)(GDNativeVariantType p_type);
- void (*variant_construct)(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error);
- GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const char *p_member);
- GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const char *p_member);
- GDNativePtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDNativeVariantType p_type);
- GDNativePtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDNativeVariantType p_type);
- GDNativePtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDNativeVariantType p_type);
- GDNativePtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDNativeVariantType p_type);
- GDNativePtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDNativeVariantType p_type);
- void (*variant_get_constant_value)(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret);
- GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const char *p_function, GDNativeInt p_hash);
-
- /* extra utilities */
-
- void (*string_new_with_latin1_chars)(GDNativeStringPtr r_dest, const char *p_contents);
- void (*string_new_with_utf8_chars)(GDNativeStringPtr r_dest, const char *p_contents);
- void (*string_new_with_utf16_chars)(GDNativeStringPtr r_dest, const char16_t *p_contents);
- void (*string_new_with_utf32_chars)(GDNativeStringPtr r_dest, const char32_t *p_contents);
- void (*string_new_with_wide_chars)(GDNativeStringPtr r_dest, const wchar_t *p_contents);
- void (*string_new_with_latin1_chars_and_len)(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size);
- void (*string_new_with_utf8_chars_and_len)(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size);
- void (*string_new_with_utf16_chars_and_len)(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size);
- void (*string_new_with_utf32_chars_and_len)(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size);
- void (*string_new_with_wide_chars_and_len)(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size);
- /* Information about the following functions:
- * - The return value is the resulting encoded string length.
- * - The length returned is in characters, not in bytes. It also does not include a trailing zero.
- * - These functions also do not write trailing zero, If you need it, write it yourself at the position indicated by the length (and make sure to allocate it).
- * - Passing NULL in r_text means only the length is computed (again, without including trailing zero).
- * - p_max_write_length argument is in characters, not bytes. It will be ignored if r_text is NULL.
- * - p_max_write_length argument does not affect the return value, it's only to cap write length.
- */
- GDNativeInt (*string_to_latin1_chars)(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length);
- GDNativeInt (*string_to_utf8_chars)(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length);
- GDNativeInt (*string_to_utf16_chars)(const GDNativeStringPtr p_self, char16_t *r_text, GDNativeInt p_max_write_length);
- GDNativeInt (*string_to_utf32_chars)(const GDNativeStringPtr p_self, char32_t *r_text, GDNativeInt p_max_write_length);
- GDNativeInt (*string_to_wide_chars)(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length);
- char32_t *(*string_operator_index)(GDNativeStringPtr p_self, GDNativeInt p_index);
- const char32_t *(*string_operator_index_const)(const GDNativeStringPtr p_self, GDNativeInt p_index);
-
- /* Packed array functions */
-
- uint8_t *(*packed_byte_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedByteArray
- const uint8_t *(*packed_byte_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedByteArray
-
- GDNativeTypePtr (*packed_color_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedColorArray, returns Color ptr
- GDNativeTypePtr (*packed_color_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedColorArray, returns Color ptr
-
- float *(*packed_float32_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedFloat32Array
- const float *(*packed_float32_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedFloat32Array
- double *(*packed_float64_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedFloat64Array
- const double *(*packed_float64_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedFloat64Array
-
- int32_t *(*packed_int32_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedInt32Array
- const int32_t *(*packed_int32_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedInt32Array
- int64_t *(*packed_int64_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedInt32Array
- const int64_t *(*packed_int64_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedInt32Array
-
- GDNativeStringPtr (*packed_string_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedStringArray
- GDNativeStringPtr (*packed_string_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedStringArray
-
- GDNativeTypePtr (*packed_vector2_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedVector2Array, returns Vector2 ptr
- GDNativeTypePtr (*packed_vector2_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedVector2Array, returns Vector2 ptr
- GDNativeTypePtr (*packed_vector3_array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedVector3Array, returns Vector3 ptr
- GDNativeTypePtr (*packed_vector3_array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be a PackedVector3Array, returns Vector3 ptr
-
- GDNativeVariantPtr (*array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be an Array ptr
- GDNativeVariantPtr (*array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be an Array ptr
-
- /* Dictionary functions */
-
- GDNativeVariantPtr (*dictionary_operator_index)(GDNativeTypePtr p_self, const GDNativeVariantPtr p_key); // p_self should be an Dictionary ptr
- GDNativeVariantPtr (*dictionary_operator_index_const)(const GDNativeTypePtr p_self, const GDNativeVariantPtr p_key); // p_self should be an Dictionary ptr
-
- /* OBJECT */
-
- void (*object_method_bind_call)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeVariantPtr *p_args, GDNativeInt p_arg_count, GDNativeVariantPtr r_ret, GDNativeCallError *r_error);
- void (*object_method_bind_ptrcall)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
- void (*object_destroy)(GDNativeObjectPtr p_o);
- GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
-
- void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
- void (*object_set_instance_binding)(GDNativeObjectPtr p_o, void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
-
- void (*object_set_instance)(GDNativeObjectPtr p_o, const char *p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
-
- GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
- GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
- GDObjectInstanceID (*object_get_instance_id)(const GDNativeObjectPtr p_object);
-
- /* SCRIPT INSTANCE */
-
- GDNativeScriptInstancePtr (*script_instance_create)(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data);
-
- /* CLASSDB */
- GDNativeObjectPtr (*classdb_construct_object)(const char *p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
- GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash);
- void *(*classdb_get_class_tag)(const char *p_classname);
-
- /* CLASSDB EXTENSION */
-
- void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
- void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
- void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
- void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
- void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
- void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
- void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
- void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
-
- void (*get_library_path)(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
-
-} GDNativeInterface;
-
-/* INITIALIZATION */
-
-typedef enum {
- GDNATIVE_INITIALIZATION_CORE,
- GDNATIVE_INITIALIZATION_SERVERS,
- GDNATIVE_INITIALIZATION_SCENE,
- GDNATIVE_INITIALIZATION_EDITOR,
- GDNATIVE_MAX_INITIALIZATION_LEVEL,
-} GDNativeInitializationLevel;
-
-typedef struct {
- /* Minimum initialization level required.
- * If Core or Servers, the extension needs editor or game restart to take effect */
- GDNativeInitializationLevel minimum_initialization_level;
- /* Up to the user to supply when initializing */
- void *userdata;
- /* This function will be called multiple times for each initialization level. */
- void (*initialize)(void *userdata, GDNativeInitializationLevel p_level);
- void (*deinitialize)(void *userdata, GDNativeInitializationLevel p_level);
-} GDNativeInitialization;
-
-/* Define a C function prototype that implements the function below and expose it to dlopen() (or similar).
- * It will be called on initialization. The name must be an unique one specified in the .gdextension config file.
- */
-
-typedef GDNativeBool (*GDNativeInitializationFunction)(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // GDNATIVE_INTERFACE_H
diff --git a/core/extension/make_interface_dumper.py b/core/extension/make_interface_dumper.py
new file mode 100644
index 0000000000..a8af0e9ff6
--- /dev/null
+++ b/core/extension/make_interface_dumper.py
@@ -0,0 +1,47 @@
+def run(target, source, env):
+ src = source[0]
+ dst = target[0]
+ f = open(src, "r", encoding="utf-8")
+ g = open(dst, "w", encoding="utf-8")
+
+ g.write(
+ """/* THIS FILE IS GENERATED DO NOT EDIT */
+#ifndef GDEXTENSION_INTERFACE_DUMP_H
+#define GDEXTENSION_INTERFACE_DUMP_H
+
+#ifdef TOOLS_ENABLED
+
+#include "core/io/file_access.h"
+#include "core/string/ustring.h"
+
+class GDExtensionInterfaceDump {
+ private:
+ static constexpr char const *gdextension_interface_dump ="""
+ )
+ for line in f:
+ g.write('"' + line.rstrip().replace('"', '\\"') + '\\n"\n')
+ g.write(";\n")
+
+ g.write(
+ """
+ public:
+ static void generate_gdextension_interface_file(const String &p_path) {
+ Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
+ CharString cs(gdextension_interface_dump);
+ fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
+ };
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // GDEXTENSION_INTERFACE_DUMP_H
+"""
+ )
+ g.close()
+ f.close()
+
+
+if __name__ == "__main__":
+ from platform_methods import subprocess_main
+
+ subprocess_main(globals())
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
deleted file mode 100644
index 6418da2235..0000000000
--- a/core/extension/native_extension.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-/*************************************************************************/
-/* native_extension.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#include "native_extension.h"
-#include "core/config/project_settings.h"
-#include "core/io/config_file.h"
-#include "core/object/class_db.h"
-#include "core/object/method_bind.h"
-#include "core/os/os.h"
-
-String NativeExtension::get_extension_list_config_file() {
- return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
-}
-
-class NativeExtensionMethodBind : public MethodBind {
- GDNativeExtensionClassMethodCall call_func;
- GDNativeExtensionClassMethodPtrCall ptrcall_func;
- GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
- GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func;
- GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
- void *method_userdata;
- bool vararg;
-
-protected:
- virtual Variant::Type _gen_argument_type(int p_arg) const override {
- return Variant::Type(get_argument_type_func(method_userdata, p_arg));
- }
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
- GDNativePropertyInfo pinfo;
- get_argument_info_func(method_userdata, p_arg, &pinfo);
- return PropertyInfo(pinfo);
- }
-
-public:
-#ifdef DEBUG_METHODS_ENABLED
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
- return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg));
- }
-#endif
-
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
- Variant ret;
- GDExtensionClassInstancePtr extension_instance = is_static() ? nullptr : p_object->_get_extension_instance();
- GDNativeCallError ce{ GDNATIVE_CALL_OK, 0, 0 };
- call_func(method_userdata, extension_instance, (const GDNativeVariantPtr *)p_args, p_arg_count, (GDNativeVariantPtr)&ret, &ce);
- r_error.error = Callable::CallError::Error(ce.error);
- r_error.argument = ce.argument;
- r_error.expected = ce.expected;
- return ret;
- }
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
- ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
- GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
- ptrcall_func(method_userdata, extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret);
- }
-
- virtual bool is_vararg() const override {
- return false;
- }
-
- explicit NativeExtensionMethodBind(const GDNativeExtensionClassMethodInfo *p_method_info) {
- method_userdata = p_method_info->method_userdata;
- call_func = p_method_info->call_func;
- ptrcall_func = p_method_info->ptrcall_func;
- get_argument_type_func = p_method_info->get_argument_type_func;
- get_argument_info_func = p_method_info->get_argument_info_func;
- get_argument_metadata_func = p_method_info->get_argument_metadata_func;
- set_name(p_method_info->name);
-
- set_hint_flags(p_method_info->method_flags);
-
- vararg = p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_VARARG;
- _set_returns(p_method_info->has_return_value);
- _set_const(p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_CONST);
- _set_static(p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_STATIC);
-#ifdef DEBUG_METHODS_ENABLED
- _generate_argument_types(p_method_info->argument_count);
-#endif
- set_argument_count(p_method_info->argument_count);
-
- Vector<Variant> defargs;
- defargs.resize(p_method_info->default_argument_count);
- for (uint32_t i = 0; i < p_method_info->default_argument_count; i++) {
- defargs.write[i] = *static_cast<Variant *>(p_method_info->default_arguments[i]);
- }
-
- set_default_arguments(defargs);
- }
-};
-
-static GDNativeInterface gdnative_interface;
-
-void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
- ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
-
- Extension *parent_extension = nullptr;
- StringName parent_class_name = p_parent_class_name;
-
- if (self->extension_classes.has(parent_class_name)) {
- parent_extension = &self->extension_classes[parent_class_name];
- } else if (ClassDB::class_exists(parent_class_name)) {
- if (ClassDB::get_api_type(parent_class_name) == ClassDB::API_EXTENSION || ClassDB::get_api_type(parent_class_name) == ClassDB::API_EDITOR_EXTENSION) {
- ERR_PRINT("Unimplemented yet");
- //inheriting from another extension
- } else {
- //inheriting from engine class
- }
- } else {
- ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'");
- }
-
- self->extension_classes[class_name] = Extension();
-
- Extension *extension = &self->extension_classes[class_name];
-
- if (parent_extension) {
- extension->native_extension.parent = &parent_extension->native_extension;
- parent_extension->native_extension.children.push_back(&extension->native_extension);
- }
-
- extension->native_extension.parent_class_name = parent_class_name;
- extension->native_extension.class_name = class_name;
- extension->native_extension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
- extension->native_extension.set = p_extension_funcs->set_func;
- extension->native_extension.get = p_extension_funcs->get_func;
- extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func;
- extension->native_extension.free_property_list = p_extension_funcs->free_property_list_func;
- extension->native_extension.property_can_revert = p_extension_funcs->property_can_revert_func;
- extension->native_extension.property_get_revert = p_extension_funcs->property_get_revert_func;
- extension->native_extension.notification = p_extension_funcs->notification_func;
- extension->native_extension.to_string = p_extension_funcs->to_string_func;
- extension->native_extension.reference = p_extension_funcs->reference_func;
- extension->native_extension.unreference = p_extension_funcs->unreference_func;
- extension->native_extension.class_userdata = p_extension_funcs->class_userdata;
- extension->native_extension.create_instance = p_extension_funcs->create_instance_func;
- extension->native_extension.free_instance = p_extension_funcs->free_instance_func;
- extension->native_extension.get_virtual = p_extension_funcs->get_virtual_func;
- extension->native_extension.get_rid = p_extension_funcs->get_rid_func;
-
- ClassDB::register_extension_class(&extension->native_extension);
-}
-void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- StringName method_name = p_method_info->name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
-
- //Extension *extension = &self->extension_classes[class_name];
-
- NativeExtensionMethodBind *method = memnew(NativeExtensionMethodBind(p_method_info));
- method->set_instance_class(class_name);
-
- ClassDB::bind_method_custom(class_name, method);
-}
-void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
-
- //Extension *extension = &self->extension_classes[class_name];
-
- ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value, p_is_bitfield);
-}
-
-void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- String property_name = p_info->name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'.");
-
- //Extension *extension = &self->extension_classes[class_name];
- PropertyInfo pinfo(*p_info);
-
- ClassDB::add_property(class_name, pinfo, p_setter, p_getter);
-}
-
-void NativeExtension::_register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + String(p_group_name) + "' for unexisting class '" + class_name + "'.");
-
- ClassDB::add_property_group(class_name, p_group_name, p_prefix);
-}
-
-void NativeExtension::_register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + String(p_subgroup_name) + "' for unexisting class '" + class_name + "'.");
-
- ClassDB::add_property_subgroup(class_name, p_subgroup_name, p_prefix);
-}
-
-void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
-
- MethodInfo s;
- s.name = p_signal_name;
- for (int i = 0; i < p_argument_count; i++) {
- PropertyInfo arg(p_argument_info[i]);
- s.arguments.push_back(arg);
- }
- ClassDB::add_signal(class_name, s);
-}
-
-void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
- Extension *ext = &self->extension_classes[class_name];
- ERR_FAIL_COND_MSG(ext->native_extension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
-
- ClassDB::unregister_extension_class(class_name);
- if (ext->native_extension.parent != nullptr) {
- ext->native_extension.parent->children.erase(&ext->native_extension);
- }
- self->extension_classes.erase(class_name);
-}
-
-void NativeExtension::_get_library_path(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path) {
- NativeExtension *self = static_cast<NativeExtension *>(p_library);
-
- *(String *)r_path = self->library_path;
-}
-
-Error NativeExtension::open_library(const String &p_path, const String &p_entry_symbol) {
- Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path);
- if (err != OK) {
- ERR_PRINT("GDExtension dynamic library not found: " + p_path);
- return err;
- }
-
- void *entry_funcptr = nullptr;
-
- err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false);
-
- if (err != OK) {
- ERR_PRINT("GDExtension entry point '" + p_entry_symbol + "' not found in library " + p_path);
- OS::get_singleton()->close_dynamic_library(library);
- return err;
- }
-
- GDNativeInitializationFunction initialization_function = (GDNativeInitializationFunction)entry_funcptr;
-
- if (initialization_function(&gdnative_interface, this, &initialization)) {
- level_initialized = -1;
- return OK;
- } else {
- ERR_PRINT("GDExtension initialization function '" + p_entry_symbol + "' returned an error.");
- return FAILED;
- }
-}
-
-void NativeExtension::close_library() {
- ERR_FAIL_COND(library == nullptr);
- OS::get_singleton()->close_dynamic_library(library);
-
- library = nullptr;
-}
-
-bool NativeExtension::is_library_open() const {
- return library != nullptr;
-}
-
-NativeExtension::InitializationLevel NativeExtension::get_minimum_library_initialization_level() const {
- ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE);
- return InitializationLevel(initialization.minimum_initialization_level);
-}
-
-void NativeExtension::initialize_library(InitializationLevel p_level) {
- ERR_FAIL_COND(library == nullptr);
- ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
-
- level_initialized = int32_t(p_level);
-
- ERR_FAIL_COND(initialization.initialize == nullptr);
-
- initialization.initialize(initialization.userdata, GDNativeInitializationLevel(p_level));
-}
-void NativeExtension::deinitialize_library(InitializationLevel p_level) {
- ERR_FAIL_COND(library == nullptr);
- ERR_FAIL_COND(p_level > int32_t(level_initialized));
-
- level_initialized = int32_t(p_level) - 1;
- initialization.deinitialize(initialization.userdata, GDNativeInitializationLevel(p_level));
-}
-
-void NativeExtension::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &NativeExtension::open_library);
- ClassDB::bind_method(D_METHOD("close_library"), &NativeExtension::close_library);
- ClassDB::bind_method(D_METHOD("is_library_open"), &NativeExtension::is_library_open);
-
- ClassDB::bind_method(D_METHOD("get_minimum_library_initialization_level"), &NativeExtension::get_minimum_library_initialization_level);
- ClassDB::bind_method(D_METHOD("initialize_library", "level"), &NativeExtension::initialize_library);
-
- BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_CORE);
- BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SERVERS);
- BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SCENE);
- BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_EDITOR);
-}
-
-NativeExtension::NativeExtension() {
-}
-
-NativeExtension::~NativeExtension() {
- if (library != nullptr) {
- close_library();
- }
-}
-
-extern void gdnative_setup_interface(GDNativeInterface *p_interface);
-
-void NativeExtension::initialize_native_extensions() {
- gdnative_setup_interface(&gdnative_interface);
-
- gdnative_interface.classdb_register_extension_class = _register_extension_class;
- gdnative_interface.classdb_register_extension_class_method = _register_extension_class_method;
- gdnative_interface.classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant;
- gdnative_interface.classdb_register_extension_class_property = _register_extension_class_property;
- gdnative_interface.classdb_register_extension_class_property_group = _register_extension_class_property_group;
- gdnative_interface.classdb_register_extension_class_property_subgroup = _register_extension_class_property_subgroup;
- gdnative_interface.classdb_register_extension_class_signal = _register_extension_class_signal;
- gdnative_interface.classdb_unregister_extension_class = _unregister_extension_class;
- gdnative_interface.get_library_path = _get_library_path;
-}
-
-Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<ConfigFile> config;
- config.instantiate();
-
- Error err = config->load(p_path);
-
- if (r_error) {
- *r_error = err;
- }
-
- if (err != OK) {
- ERR_PRINT("Error loading GDExtension configuration file: " + p_path);
- return Ref<Resource>();
- }
-
- if (!config->has_section_key("configuration", "entry_symbol")) {
- if (r_error) {
- *r_error = ERR_INVALID_DATA;
- }
- ERR_PRINT("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: " + p_path);
- return Ref<Resource>();
- }
-
- String entry_symbol = config->get_value("configuration", "entry_symbol");
-
- List<String> libraries;
-
- config->get_section_keys("libraries", &libraries);
-
- String library_path;
-
- for (const String &E : libraries) {
- Vector<String> tags = E.split(".");
- bool all_tags_met = true;
- for (int i = 0; i < tags.size(); i++) {
- String tag = tags[i].strip_edges();
- if (!OS::get_singleton()->has_feature(tag)) {
- all_tags_met = false;
- break;
- }
- }
-
- if (all_tags_met) {
- library_path = config->get_value("libraries", E);
- break;
- }
- }
-
- if (library_path.is_empty()) {
- if (r_error) {
- *r_error = ERR_FILE_NOT_FOUND;
- }
- const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
- ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
- return Ref<Resource>();
- }
-
- if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
- library_path = p_path.get_base_dir().path_join(library_path);
- }
-
- Ref<NativeExtension> lib;
- lib.instantiate();
- String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
- err = lib->open_library(abs_path, entry_symbol);
-
- if (r_error) {
- *r_error = err;
- }
-
- if (err != OK) {
- // Errors already logged in open_library()
- return Ref<Resource>();
- }
-
- return lib;
-}
-
-void NativeExtensionResourceLoader::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("gdextension");
-}
-
-bool NativeExtensionResourceLoader::handles_type(const String &p_type) const {
- return p_type == "NativeExtension";
-}
-
-String NativeExtensionResourceLoader::get_resource_type(const String &p_path) const {
- String el = p_path.get_extension().to_lower();
- if (el == "gdextension") {
- return "NativeExtension";
- }
- return "";
-}
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 774d1be6b5..dcb6aefb00 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -67,9 +67,11 @@
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,paddle1:b23,paddle2:b19,platform:Windows,
+03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001230000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
@@ -201,6 +203,7 @@
03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -296,7 +299,8 @@
030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,
+03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
+03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -369,6 +373,7 @@
030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,
+030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -377,8 +382,9 @@
03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
030000008f0e00001030000000000000,Mayflash Sega Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,
-0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
@@ -443,6 +449,7 @@
030000006f0e00008501000000000000,PDP Fightpad Pro,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows,
030000006f0e00000901000000000000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,
+03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
@@ -464,7 +471,6 @@
03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
-03000000666600006706000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
@@ -505,7 +511,8 @@
030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows,
03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -554,6 +561,7 @@
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows,
0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows,
@@ -741,9 +749,8 @@
03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
-03000000bc2000005060000000000000,Xiaomi XMGP01YM,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,-lefty:-a1,+lefty:+a2,rightx:a3,-righty:-a4,+righty:+a5,lefttrigger:b8,righttrigger:b9,platform:Windows,
-03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Windows,
-03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows,
03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
@@ -789,8 +796,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
-03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
-03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
@@ -817,10 +827,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle3:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Mac OS X,
03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
+03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X,
030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,
@@ -836,11 +848,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f0000aa00000072050000,Hori Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,
+03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X,
03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X,
03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,
03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,
@@ -858,10 +871,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X,
03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
@@ -886,8 +900,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X,
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
+030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,
030000006f0e00000901000002010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -899,8 +915,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -919,6 +937,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X,
030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -937,14 +956,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
-050000004e696d6275732b008b000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
-05000000556e6b6e6f776e2048494400,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
@@ -954,6 +972,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,
+03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,
@@ -965,6 +984,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -975,8 +995,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
-030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -1008,6 +1029,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@@ -1028,9 +1050,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
-03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
-05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
@@ -1069,10 +1095,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000bc2000004d50000011010000,BEITONG A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000666600006706000000010000,Boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1090,6 +1116,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1099,6 +1126,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux,
+190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux,
+190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux,
03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1113,6 +1143,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000632500002605000010010000,HJDX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,
030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1139,7 +1170,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f0000c100000011010000,Horipad S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
-030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,
+05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,
+03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux,
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1191,6 +1223,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
@@ -1240,6 +1273,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+030000009b2800008000000020020000,Nintendo Classic Controller,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,
060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -1268,7 +1302,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux,
03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
-03000000790000001c18000011010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1283,6 +1316,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000901000011010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
@@ -1326,10 +1360,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -1341,7 +1377,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -1356,9 +1391,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
+190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,
0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux,
+03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Linux,
030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1414,9 +1451,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,
+03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
@@ -1449,6 +1488,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1486,8 +1526,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000130b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
-050000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
@@ -1551,13 +1591,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
@@ -1580,7 +1620,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
-0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
@@ -1588,6 +1627,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b18,platform:Android,
31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android,
+62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android,
+31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android,
64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android,
532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android,
@@ -1604,6 +1647,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4~,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5~,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
@@ -1642,6 +1686,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android,
+536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android,
32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android,
050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1661,20 +1707,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-536f6e7920496e746572616374697665,PS4 Controller,a:b0,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-576972656c65737320436f6e74726f6c,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
-61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1686,6 +1733,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android,
38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b6,platform:Android,
+37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android,
+5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android,
+526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android,
+64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android,
33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android,
66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android,
32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
@@ -1706,6 +1757,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android,
35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android,
+54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1749,9 +1802,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,
4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
+050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS,
050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS,
+050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,
050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS,
+050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,
050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 889c2a92fa..cb65d2569c 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -519,6 +519,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
touch_event.instantiate();
touch_event->set_pressed(mb->is_pressed());
touch_event->set_position(mb->get_position());
+ touch_event->set_double_tap(mb->is_double_click());
event_dispatch_function(touch_event);
}
}
@@ -580,6 +581,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
button_event->set_global_position(st->get_position());
button_event->set_pressed(st->is_pressed());
button_event->set_button_index(MouseButton::LEFT);
+ button_event->set_double_click(st->is_double_tap());
if (st->is_pressed()) {
button_event->set_button_mask(MouseButton(mouse_button_mask | MouseButton::MASK_LEFT));
} else {
@@ -1308,7 +1310,7 @@ void Input::parse_mapping(String p_mapping) {
JoyButton output_button = _get_output_button(output);
JoyAxis output_axis = _get_output_axis(output);
ERR_CONTINUE_MSG(output_button == JoyButton::INVALID && output_axis == JoyAxis::INVALID,
- vformat("Unrecognised output string \"%s\" in mapping:\n%s", output, p_mapping));
+ vformat("Unrecognized output string \"%s\" in mapping:\n%s", output, p_mapping));
ERR_CONTINUE_MSG(output_button != JoyButton::INVALID && output_axis != JoyAxis::INVALID,
vformat("Output string \"%s\" matched both button and axis in mapping:\n%s", output, p_mapping));
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 38037eaf72..0a32b4bf68 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1162,6 +1162,13 @@ bool InputEventScreenTouch::is_pressed() const {
return pressed;
}
+void InputEventScreenTouch::set_double_tap(bool p_double_tap) {
+ double_tap = p_double_tap;
+}
+bool InputEventScreenTouch::is_double_tap() const {
+ return double_tap;
+}
+
Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
Ref<InputEventScreenTouch> st;
st.instantiate();
@@ -1170,6 +1177,7 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
st->set_index(index);
st->set_position(p_xform.xform(pos + p_local_ofs));
st->set_pressed(pressed);
+ st->set_double_tap(double_tap);
return st;
}
@@ -1182,7 +1190,8 @@ String InputEventScreenTouch::as_text() const {
String InputEventScreenTouch::to_string() {
String p = pressed ? "true" : "false";
- return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s)", index, p, String(get_position()));
+ String double_tap_string = double_tap ? "true" : "false";
+ return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s), double_tap=%s", index, p, String(get_position()), double_tap_string);
}
void InputEventScreenTouch::_bind_methods() {
@@ -1195,9 +1204,13 @@ void InputEventScreenTouch::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed);
//ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed);
+ ClassDB::bind_method(D_METHOD("set_double_tap", "double_tap"), &InputEventScreenTouch::set_double_tap);
+ ClassDB::bind_method(D_METHOD("is_double_tap"), &InputEventScreenTouch::is_double_tap);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "double_tap"), "set_double_tap", "is_double_tap");
}
///////////////////////////////////
@@ -1549,7 +1562,7 @@ String InputEventMIDI::as_text() const {
}
String InputEventMIDI::to_string() {
- return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d", channel, message, pitch, velocity, pressure);
+ return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d, controller_number=%d, controller_value=%d", channel, message, pitch, velocity, pressure, controller_number, controller_value);
}
void InputEventMIDI::_bind_methods() {
diff --git a/core/input/input_event.h b/core/input/input_event.h
index bc3ec3e7ac..adbcb7cf68 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -353,6 +353,7 @@ class InputEventScreenTouch : public InputEventFromWindow {
int index = 0;
Vector2 pos;
bool pressed = false;
+ bool double_tap = false;
protected:
static void _bind_methods();
@@ -367,6 +368,9 @@ public:
void set_pressed(bool p_pressed);
virtual bool is_pressed() const override;
+ void set_double_tap(bool p_double_tap);
+ bool is_double_tap() const;
+
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ce76d11b6e..1c7d71e309 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -257,7 +257,7 @@ void InputMap::load_from_project_settings() {
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
+ Dictionary action = GLOBAL_GET(pi.name);
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
Array events = action["events"];
@@ -331,12 +331,18 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
+ { "ui_text_caret_add_below", TTRC("Caret Add Below") },
+ { "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
+ { "ui_text_caret_add_above", TTRC("Caret Add Above") },
+ { "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
{ "ui_text_scroll_up", TTRC("Scroll Up") },
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
{ "ui_text_scroll_down", TTRC("Scroll Down") },
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
{ "ui_text_select_all", TTRC("Select All") },
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
+ { "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
+ { "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
{ "ui_text_submit", TTRC("Text Submitted") },
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
@@ -616,6 +622,24 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
+ // Text Caret Addition Below/Above
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_below", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_below.macos", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_above", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::O | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_above.macos", inputs);
+
// Text Scrolling
inputs = List<Ref<InputEvent>>();
@@ -641,10 +665,18 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_select_all", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
+ inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
+ default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs);
+
+ inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::INSERT));
default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
diff --git a/core/input/shortcut.cpp b/core/input/shortcut.cpp
index 9eeeb449ba..e74ccb11bb 100644
--- a/core/input/shortcut.cpp
+++ b/core/input/shortcut.cpp
@@ -107,7 +107,7 @@ void Shortcut::_bind_methods() {
ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event);
ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "events", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")), "set_events", "get_events");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "events", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("InputEvent")), "set_events", "get_events");
}
bool Shortcut::is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2) {
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index 79e7fa16e3..7eb50d2261 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -351,7 +351,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
const size_t copy_buffer_limit = 65536; // 64 KB
fsrc->seek_end(0);
- int size = fsrc->get_position();
+ uint64_t size = fsrc->get_position();
fsrc->seek(0);
err = OK;
size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit);
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index cb25564342..0ceb300f97 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -690,7 +690,7 @@ void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
_store_buffer(buff);
}
-Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
+Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) {
Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error);
if (f.is_null()) {
if (r_error) { // if error requested, do not throw error
@@ -706,7 +706,7 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err
String FileAccess::get_file_as_string(const String &p_path, Error *r_error) {
Error err;
- Vector<uint8_t> array = get_file_as_array(p_path, &err);
+ Vector<uint8_t> array = get_file_as_bytes(p_path, &err);
if (r_error) {
*r_error = err;
}
@@ -810,6 +810,9 @@ void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string);
+
ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush);
ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute);
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 8ca44306a0..54a0235333 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -192,9 +192,12 @@ public:
static String get_sha256(const String &p_file);
static String get_multiple_md5(const Vector<String> &p_file);
- static Vector<uint8_t> get_file_as_array(const String &p_path, Error *r_error = nullptr);
+ static Vector<uint8_t> get_file_as_bytes(const String &p_path, Error *r_error = nullptr);
static String get_file_as_string(const String &p_path, Error *r_error = nullptr);
+ static PackedByteArray _get_file_as_bytes(const String &p_path) { return get_file_as_bytes(p_path); }
+ static String _get_file_as_string(const String &p_path) { return get_file_as_string(p_path); };
+
template <class T>
static void make_default(AccessType p_access) {
create_func[p_access] = _create_builtin<T>;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 4be624a5a8..1b9538794a 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -982,7 +982,7 @@ void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
}
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
- ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use create() or create_from_data() first.");
+ ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use set_data() first.");
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
@@ -1017,7 +1017,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
bool interpolate_mipmaps = mipmap_aware && mip1 != mip2;
if (interpolate_mipmaps) {
- dst2.create(p_width, p_height, false, format);
+ dst2.initialize_data(p_width, p_height, false, format);
}
bool had_mipmaps = mipmaps;
@@ -1341,78 +1341,126 @@ void Image::crop(int p_width, int p_height) {
void Image::rotate_90(ClockDirection p_direction) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats.");
- ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels.");
- ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels.");
-
- int saved_width = height;
- int saved_height = width;
-
- if (width != height) {
- int n = MAX(width, height);
- resize(n, n, INTERPOLATE_NEAREST);
- }
+ ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels.");
+ ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels.");
bool used_mipmaps = has_mipmaps();
if (used_mipmaps) {
clear_mipmaps();
}
+ // In-place 90 degrees rotation by following the permutation cycles.
{
- uint8_t *w = data.ptrw();
- uint8_t src[16];
- uint8_t dst[16];
+ // Explanation by example (clockwise):
+ //
+ // abc da
+ // def -> eb
+ // fc
+ //
+ // In memory:
+ // 012345 012345
+ // abcdef -> daebfc
+ //
+ // Permutation cycles:
+ // (0 --a--> 1 --b--> 3 --d--> 0)
+ // (2 --c--> 5 --f--> 4 --e--> 2)
+ //
+ // Applying cycles (backwards):
+ // 0->s s=a (store)
+ // 3->0 abcdef -> dbcdef
+ // 1->3 dbcdef -> dbcbef
+ // s->1 dbcbef -> dacbef
+ //
+ // 2->s s=c
+ // 4->2 dacbef -> daebef
+ // 5->4 daebef -> daebff
+ // s->5 daebff -> daebfc
+
+ const int w = width;
+ const int h = height;
+ const int size = w * h;
+
+ uint8_t *data_ptr = data.ptrw();
uint32_t pixel_size = get_format_pixel_size(format);
- // Flip.
+ uint8_t single_pixel_buffer[16];
- if (p_direction == CLOCKWISE) {
- for (int y = 0; y < height / 2; y++) {
- for (int x = 0; x < width; x++) {
- _get_pixelb(x, y, pixel_size, w, src);
- _get_pixelb(x, height - y - 1, pixel_size, w, dst);
+#define PREV_INDEX_IN_CYCLE(index) (p_direction == CLOCKWISE) ? ((h - 1 - (index % h)) * w + (index / h)) : ((index % h) * w + (w - 1 - (index / h)))
- _put_pixelb(x, height - y - 1, pixel_size, w, src);
- _put_pixelb(x, y, pixel_size, w, dst);
+ if (w == h) { // Square case, 4-length cycles only (plus irrelevant thus skipped 1-length cycle in the middle for odd-sized squares).
+ for (int y = 0; y < h / 2; y++) {
+ for (int x = 0; x < (w + 1) / 2; x++) {
+ int current = y * w + x;
+ memcpy(single_pixel_buffer, data_ptr + current * pixel_size, pixel_size);
+ for (int i = 0; i < 3; i++) {
+ int prev = PREV_INDEX_IN_CYCLE(current);
+ memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size);
+ current = prev;
+ }
+ memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size);
}
}
- } else {
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width / 2; x++) {
- _get_pixelb(x, y, pixel_size, w, src);
- _get_pixelb(width - x - 1, y, pixel_size, w, dst);
+ } else { // Rectangular case (w != h), kinda unpredictable cycles.
+ int permuted_pixels_count = 0;
+
+ for (int i = 0; i < size; i++) {
+ int prev = PREV_INDEX_IN_CYCLE(i);
+ if (prev == i) {
+ // 1-length cycle, pixel remains at the same index.
+ permuted_pixels_count++;
+ continue;
+ }
- _put_pixelb(width - x - 1, y, pixel_size, w, src);
- _put_pixelb(x, y, pixel_size, w, dst);
+ // Check whether we already processed this cycle.
+ // We iterate over it and if we'll find an index smaller than `i` then we already
+ // processed this cycle because we always start at the smallest index in the cycle.
+ // TODO: Improve this naive approach, can be done better.
+ while (prev > i) {
+ prev = PREV_INDEX_IN_CYCLE(prev);
+ }
+ if (prev < i) {
+ continue;
}
- }
- }
- // Transpose.
+ // Save the in-cycle pixel with the smallest index (`i`).
+ memcpy(single_pixel_buffer, data_ptr + i * pixel_size, pixel_size);
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- if (x < y) {
- _get_pixelb(x, y, pixel_size, w, src);
- _get_pixelb(y, x, pixel_size, w, dst);
+ // Overwrite pixels one by one by the preceding pixel in the cycle.
+ int current = i;
+ prev = PREV_INDEX_IN_CYCLE(current);
+ while (prev != i) {
+ memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size);
+ permuted_pixels_count++;
- _put_pixelb(y, x, pixel_size, w, src);
- _put_pixelb(x, y, pixel_size, w, dst);
+ current = prev;
+ prev = PREV_INDEX_IN_CYCLE(current);
+ };
+
+ // Overwrite the remaining pixel in the cycle by the saved pixel with the smallest index.
+ memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size);
+ permuted_pixels_count++;
+
+ if (permuted_pixels_count == size) {
+ break;
}
}
+
+ width = h;
+ height = w;
}
+
+#undef PREV_INDEX_IN_CYCLE
}
- if (saved_width != saved_height) {
- resize(saved_width, saved_height, INTERPOLATE_NEAREST);
- } else if (used_mipmaps) {
+ if (used_mipmaps) {
generate_mipmaps();
}
}
void Image::rotate_180() {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats.");
- ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels.");
- ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels.");
+ ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels.");
+ ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels.");
bool used_mipmaps = has_mipmaps();
if (used_mipmaps) {
@@ -1420,19 +1468,21 @@ void Image::rotate_180() {
}
{
- uint8_t *w = data.ptrw();
- uint8_t src[16];
- uint8_t dst[16];
+ uint8_t *data_ptr = data.ptrw();
uint32_t pixel_size = get_format_pixel_size(format);
- for (int y = 0; y < height / 2; y++) {
- for (int x = 0; x < width; x++) {
- _get_pixelb(x, y, pixel_size, w, src);
- _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst);
+ uint8_t single_pixel_buffer[16];
- _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src);
- _put_pixelb(x, y, pixel_size, w, dst);
- }
+ uint8_t *from_begin_ptr = data_ptr;
+ uint8_t *from_end_ptr = data_ptr + (width * height - 1) * pixel_size;
+
+ while (from_begin_ptr < from_end_ptr) {
+ memcpy(single_pixel_buffer, from_begin_ptr, pixel_size);
+ memcpy(from_begin_ptr, from_end_ptr, pixel_size);
+ memcpy(from_end_ptr, single_pixel_buffer, pixel_size);
+
+ from_begin_ptr += pixel_size;
+ from_end_ptr -= pixel_size;
}
}
@@ -2016,9 +2066,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con
uint8_t* wr = imgdata.ptrw();
memcpy(wr.ptr(), ptr, size);
wr = uint8_t*();
- Ref<Image> im;
- im.instantiate();
- im->create(w, h, false, format, imgdata);
+ Ref<Image> im = Image::create_from_data(w, h, false, format, imgdata);
im->save_png("res://mipmap_" + itos(i) + ".png");
}
#endif
@@ -2051,7 +2099,25 @@ Vector<uint8_t> Image::get_data() const {
return data;
}
-void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+Ref<Image> Image::create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+ Ref<Image> image;
+ image.instantiate();
+ image->initialize_data(p_width, p_height, p_use_mipmaps, p_format);
+ return image;
+}
+
+Ref<Image> Image::create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ Ref<Image> image;
+ image.instantiate();
+ image->initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
+ return image;
+}
+
+void Image::set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
+}
+
+void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
@@ -2077,7 +2143,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
format = p_format;
}
-void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
@@ -2115,7 +2181,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
mipmaps = p_use_mipmaps;
}
-void Image::create(const char **p_xpm) {
+void Image::initialize_data(const char **p_xpm) {
int size_width = 0;
int size_height = 0;
int pixelchars = 0;
@@ -2230,7 +2296,7 @@ void Image::create(const char **p_xpm) {
}
if (line == colormap_size) {
status = READING_PIXELS;
- create(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
+ initialize_data(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
data_write = data.ptrw();
pixel_size = has_alpha ? 4 : 3;
}
@@ -2559,7 +2625,7 @@ Image::Image(const char **p_xpm) {
mipmaps = false;
format = FORMAT_L8;
- create(p_xpm);
+ initialize_data(p_xpm);
}
Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
@@ -2568,7 +2634,7 @@ Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
mipmaps = p_use_mipmaps;
format = FORMAT_L8;
- create(p_width, p_height, p_use_mipmaps, p_format);
+ initialize_data(p_width, p_height, p_use_mipmaps, p_format);
}
Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
@@ -2577,7 +2643,7 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const V
mipmaps = p_mipmaps;
format = FORMAT_L8;
- create(p_width, p_height, p_mipmaps, p_format, p_data);
+ initialize_data(p_width, p_height, p_mipmaps, p_format, p_data);
}
Rect2i Image::get_used_rect() const {
@@ -2620,9 +2686,9 @@ Rect2i Image::get_used_rect() const {
}
}
-Ref<Image> Image::get_rect(const Rect2i &p_area) const {
- Ref<Image> img = memnew(Image(p_area.size.x, p_area.size.y, mipmaps, format));
- img->blit_rect(Ref<Image>((Image *)this), p_area, Point2i(0, 0));
+Ref<Image> Image::get_region(const Rect2i &p_region) const {
+ Ref<Image> img = memnew(Image(p_region.size.x, p_region.size.y, mipmaps, format));
+ img->blit_rect(Ref<Image>((Image *)this), p_region, Point2i(0, 0));
return img;
}
@@ -2846,6 +2912,9 @@ void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_s
}
void Image::fill(const Color &p_color) {
+ if (data.size() == 0) {
+ return;
+ }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
uint8_t *dst_data_ptr = data.ptrw();
@@ -2859,6 +2928,9 @@ void Image::fill(const Color &p_color) {
}
void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
+ if (data.size() == 0) {
+ return;
+ }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
@@ -2931,7 +3003,7 @@ void Image::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(ddformat == FORMAT_MAX);
- create(dwidth, dheight, dmipmaps, ddformat, ddata);
+ initialize_data(dwidth, dheight, dmipmaps, ddformat, ddata);
}
Dictionary Image::_get_data() const {
@@ -3294,8 +3366,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
- ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
- ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
+ ClassDB::bind_static_method("Image", D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
+ ClassDB::bind_static_method("Image", D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
+ ClassDB::bind_method(D_METHOD("set_data", "width", "height", "use_mipmaps", "format", "data"), &Image::set_data);
ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
@@ -3339,7 +3412,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("fill_rect", "rect", "color"), &Image::fill_rect);
ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect);
- ClassDB::bind_method(D_METHOD("get_rect", "rect"), &Image::get_rect);
+ ClassDB::bind_method(D_METHOD("get_region", "region"), &Image::get_region);
ClassDB::bind_method(D_METHOD("copy_from", "src"), &Image::copy_internals_from);
@@ -3460,9 +3533,7 @@ Ref<Image> Image::rgbe_to_srgb() {
ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>());
- Ref<Image> new_image;
- new_image.instantiate();
- new_image->create(width, height, false, Image::FORMAT_RGB8);
+ Ref<Image> new_image = create_empty(width, height, false, Image::FORMAT_RGB8);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
@@ -3503,6 +3574,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
void Image::bump_map_to_normal_map(float bump_scale) {
ERR_FAIL_COND(!_can_modify(format));
+ clear_mipmaps();
convert(Image::FORMAT_RF);
Vector<uint8_t> result_image; //rgba output
@@ -3726,6 +3798,19 @@ void Image::convert_ra_rgba8_to_rg() {
}
}
+void Image::convert_rgba8_to_bgra8() {
+ ERR_FAIL_COND(format != FORMAT_RGBA8);
+ ERR_FAIL_COND(!data.size());
+
+ int s = data.size();
+ uint8_t *w = data.ptrw();
+ for (int i = 0; i < s; i += 4) {
+ uint8_t r = w[i];
+ w[i] = w[i + 2]; // Swap R to B
+ w[i + 2] = r; // Swap B to R
+ }
+}
+
Error Image::_load_from_buffer(const Vector<uint8_t> &p_array, ImageMemLoadFunc p_loader) {
int buffer_size = p_array.size();
diff --git a/core/io/image.h b/core/io/image.h
index fd264a7a38..ad5c0b4a04 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -279,12 +279,12 @@ public:
void normalize(); //for normal maps
/**
- * Create a new image of a given size and format. Current image will be lost
+ * Creates new internal image data of a given size and format. Current image will be lost.
*/
- void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
- void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
+ void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void initialize_data(const char **p_xpm);
- void create(const char **p_xpm);
/**
* returns true when the image is empty (0,0) in size
*/
@@ -303,13 +303,9 @@ public:
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
- void create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
- create(p_width, p_height, p_use_mipmaps, p_format);
- }
-
- void create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
- create(p_width, p_height, p_use_mipmaps, p_format, p_data);
- }
+ static Ref<Image> create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
+ static Ref<Image> create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
/**
* create an empty image
@@ -381,7 +377,7 @@ public:
void fill_rect(const Rect2i &p_rect, const Color &p_color);
Rect2i get_used_rect() const;
- Ref<Image> get_rect(const Rect2i &p_area) const;
+ Ref<Image> get_region(const Rect2i &p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels));
static void set_compress_bptc_func(void (*p_compress_func)(Image *, float, UsedChannels));
@@ -395,6 +391,7 @@ public:
void convert_rg_to_ra_rgba8();
void convert_ra_rgba8_to_rg();
+ void convert_rgba8_to_bgra8();
Image(const uint8_t *p_mem_png_jpg, int p_len = -1);
Image(const char **p_xpm);
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 397984a2ab..6c00ca4b67 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -52,10 +52,8 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
Error ImageFormatLoaderExtension::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Error err = ERR_UNAVAILABLE;
- if (GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err)) {
- return err;
- }
- return ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err);
+ return err;
}
void ImageFormatLoaderExtension::get_recognized_extensions(List<String> *p_extension) const {
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index 07045e62a6..4a5f244911 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -86,10 +86,10 @@ protected:
public:
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
- GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
+ GDVIRTUAL2R(Error, _get_packet, GDExtensionConstPtr<const uint8_t *>, GDExtensionPtr<int>);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int);
+ GDVIRTUAL2R(Error, _put_packet, GDExtensionConstPtr<const uint8_t>, int);
EXBIND0RC(int, get_available_packet_count);
EXBIND0RC(int, get_max_packet_size);
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index aa1b323db2..0556f45b0c 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -107,6 +107,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &
}
Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) {
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use.");
+
Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ);
if (f.is_null()) {
return ERR_FILE_CANT_OPEN;
@@ -118,7 +120,7 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr
pf.ofs = ofs;
pf.size = f->get_length();
- Vector<uint8_t> data = FileAccess::get_file_as_array(p_src);
+ Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_src);
{
unsigned char hash[16];
CryptoCore::md5(data.ptr(), data.size(), hash);
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index ab30fb1ca3..be75ad7e25 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -436,7 +436,7 @@ void Resource::_bind_methods() {
ADD_GROUP("Resource", "resource_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "resource_name"), "set_name", "get_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name");
MethodInfo get_rid_bind("_get_rid");
get_rid_bind.return_val.type = Variant::RID;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 2a79067e02..4611528db7 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1042,7 +1042,14 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
er.path = ResourceUID::get_singleton()->get_id_path(er.uid);
} else {
+#ifdef TOOLS_ENABLED
+ // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
+ if (ResourceLoader::get_resource_uid(res_path) != er.uid) {
+ WARN_PRINT(String(res_path + ": In external resource #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data());
+ }
+#else
WARN_PRINT(String(res_path + ": In external resource #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data());
+#endif
}
}
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index a018221b7f..20445a8b03 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -49,6 +49,11 @@ Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS];
int ResourceLoader::loader_count = 0;
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_recognize_path, p_path, p_for_type, ret)) {
+ return ret;
+ }
+
String extension = p_path.get_extension();
List<String> extensions;
@@ -69,11 +74,8 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_
bool ResourceFormatLoader::handles_type(const String &p_type) const {
bool success = false;
- if (GDVIRTUAL_CALL(_handles_type, p_type, success)) {
- return success;
- }
-
- return false;
+ GDVIRTUAL_CALL(_handles_type, p_type, success);
+ return success;
}
void ResourceFormatLoader::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
@@ -93,21 +95,14 @@ void ResourceFormatLoader::get_classes_used(const String &p_path, HashSet<String
String ResourceFormatLoader::get_resource_type(const String &p_path) const {
String ret;
-
- if (GDVIRTUAL_CALL(_get_resource_type, p_path, ret)) {
- return ret;
- }
-
- return "";
+ GDVIRTUAL_CALL(_get_resource_type, p_path, ret);
+ return ret;
}
ResourceUID::ID ResourceFormatLoader::get_resource_uid(const String &p_path) const {
int64_t uid = ResourceUID::INVALID_ID;
- if (GDVIRTUAL_CALL(_get_resource_uid, p_path, uid)) {
- return uid;
- }
-
- return ResourceUID::INVALID_ID;
+ GDVIRTUAL_CALL(_get_resource_uid, p_path, uid);
+ return uid;
}
void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
@@ -127,7 +122,7 @@ bool ResourceFormatLoader::exists(const String &p_path) const {
if (GDVIRTUAL_CALL(_exists, p_path, success)) {
return success;
}
- return FileAccess::exists(p_path); //by default just check file
+ return FileAccess::exists(p_path); // By default just check file.
}
void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const {
@@ -176,11 +171,8 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Hash
}
int64_t err = OK;
- if (GDVIRTUAL_CALL(_rename_dependencies, p_path, deps_dict, err)) {
- return (Error)err;
- }
-
- return OK;
+ GDVIRTUAL_CALL(_rename_dependencies, p_path, deps_dict, err);
+ return (Error)err;
}
void ResourceFormatLoader::_bind_methods() {
@@ -189,6 +181,7 @@ void ResourceFormatLoader::_bind_methods() {
BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_recognize_path, "path", "type");
GDVIRTUAL_BIND(_handles_type, "type");
GDVIRTUAL_BIND(_get_resource_type, "path");
GDVIRTUAL_BIND(_get_resource_uid, "path");
@@ -908,7 +901,7 @@ void ResourceLoader::load_translation_remaps() {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
List<Variant> keys;
remaps.get_key_list(&keys);
for (const Variant &E : keys) {
@@ -930,12 +923,41 @@ void ResourceLoader::clear_translation_remaps() {
}
}
+void ResourceLoader::clear_thread_load_tasks() {
+ thread_load_mutex->lock();
+
+ for (KeyValue<String, ResourceLoader::ThreadLoadTask> &E : thread_load_tasks) {
+ switch (E.value.status) {
+ case ResourceLoader::ThreadLoadStatus::THREAD_LOAD_LOADED: {
+ E.value.resource = Ref<Resource>();
+ } break;
+
+ case ResourceLoader::ThreadLoadStatus::THREAD_LOAD_IN_PROGRESS: {
+ if (E.value.thread != nullptr) {
+ E.value.thread->wait_to_finish();
+ memdelete(E.value.thread);
+ E.value.thread = nullptr;
+ }
+ E.value.resource = Ref<Resource>();
+ } break;
+
+ case ResourceLoader::ThreadLoadStatus::THREAD_LOAD_FAILED:
+ default: {
+ // do nothing
+ }
+ }
+ }
+ thread_load_tasks.clear();
+
+ thread_load_mutex->unlock();
+}
+
void ResourceLoader::load_path_remaps() {
if (!ProjectSettings::get_singleton()->has_setting("path_remap/remapped_paths")) {
return;
}
- Vector<String> remaps = ProjectSettings::get_singleton()->get("path_remap/remapped_paths");
+ Vector<String> remaps = GLOBAL_GET("path_remap/remapped_paths");
int rc = remaps.size();
ERR_FAIL_COND(rc & 1); //must be even
const String *r = remaps.ptr();
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 91ba930176..af10098bd8 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -51,6 +51,7 @@ protected:
static void _bind_methods();
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
+ GDVIRTUAL2RC(bool, _recognize_path, String, StringName)
GDVIRTUAL1RC(bool, _handles_type, StringName)
GDVIRTUAL1RC(String, _get_resource_type, String)
GDVIRTUAL1RC(ResourceUID::ID, _get_resource_uid, String)
@@ -218,6 +219,8 @@ public:
static void load_translation_remaps();
static void clear_translation_remaps();
+ static void clear_thread_load_tasks();
+
static void set_load_callback(ResourceLoadedCallback p_callback);
static ResourceLoaderImport import;
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 2f863baaac..710afc614f 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -43,20 +43,14 @@ ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;
Error ResourceFormatSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
int64_t res = ERR_METHOD_NOT_FOUND;
- if (GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res)) {
- return (Error)res;
- }
-
- return ERR_METHOD_NOT_FOUND;
+ GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res);
+ return (Error)res;
}
bool ResourceFormatSaver::recognize(const Ref<Resource> &p_resource) const {
bool success = false;
- if (GDVIRTUAL_CALL(_recognize, p_resource, success)) {
- return success;
- }
-
- return false;
+ GDVIRTUAL_CALL(_recognize, p_resource, success);
+ return success;
}
void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
@@ -69,10 +63,31 @@ void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resou
}
}
+bool ResourceFormatSaver::recognize_path(const Ref<Resource> &p_resource, const String &p_path) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_recognize_path, p_resource, p_path, ret)) {
+ return ret;
+ }
+
+ String extension = p_path.get_extension();
+
+ List<String> extensions;
+ get_recognized_extensions(p_resource, &extensions);
+
+ for (const String &E : extensions) {
+ if (E.nocasecmp_to(extension) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void ResourceFormatSaver::_bind_methods() {
GDVIRTUAL_BIND(_save, "resource", "path", "flags");
GDVIRTUAL_BIND(_recognize, "resource");
GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
+ GDVIRTUAL_BIND(_recognize_path, "resource", "path");
}
Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
@@ -90,17 +105,7 @@ Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path,
continue;
}
- List<String> extensions;
- bool recognized = false;
- saver[i]->get_recognized_extensions(p_resource, &extensions);
-
- for (const String &E : extensions) {
- if (E.nocasecmp_to(extension) == 0) {
- recognized = true;
- }
- }
-
- if (!recognized) {
+ if (!saver[i]->recognize_path(p_resource, path)) {
continue;
}
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 4fee2bcfd1..5e48ce88c3 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -44,11 +44,13 @@ protected:
GDVIRTUAL3R(int64_t, _save, Ref<Resource>, String, uint32_t)
GDVIRTUAL1RC(bool, _recognize, Ref<Resource>)
GDVIRTUAL1RC(Vector<String>, _get_recognized_extensions, Ref<Resource>)
+ GDVIRTUAL2RC(bool, _recognize_path, Ref<Resource>, String)
public:
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
virtual bool recognize(const Ref<Resource> &p_resource) const;
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize_path(const Ref<Resource> &p_resource, const String &p_path) const;
virtual ~ResourceFormatSaver() {}
};
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 108a8ce9d9..95cc655b45 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -105,16 +105,16 @@ protected:
public:
virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
- GDVIRTUAL3R(Error, _put_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
+ GDVIRTUAL3R(Error, _put_data, GDExtensionConstPtr<const uint8_t>, int, GDExtensionPtr<int>);
virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
- GDVIRTUAL3R(Error, _put_partial_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
+ GDVIRTUAL3R(Error, _put_partial_data, GDExtensionConstPtr<const uint8_t>, int, GDExtensionPtr<int>);
virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
- GDVIRTUAL3R(Error, _get_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
+ GDVIRTUAL3R(Error, _get_data, GDExtensionPtr<uint8_t>, int, GDExtensionPtr<int>);
virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
- GDVIRTUAL3R(Error, _get_partial_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
+ GDVIRTUAL3R(Error, _get_partial_data, GDExtensionPtr<uint8_t>, int, GDExtensionPtr<int>);
EXBIND0RC(int, get_available_bytes);
};
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index abae48fdd8..16b7f3a1f6 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -41,11 +41,11 @@ static inline bool _is_white_space(char c) {
}
//! sets the state that text was found. Returns true if set should be set
-bool XMLParser::_set_text(char *start, char *end) {
+bool XMLParser::_set_text(const char *start, const char *end) {
// check if text is more than 2 characters, and if not, check if there is
// only white space, so that this text won't be reported
if (end - start < 3) {
- char *p = start;
+ const char *p = start;
for (; p != end; ++p) {
if (!_is_white_space(*p)) {
break;
@@ -92,7 +92,7 @@ void XMLParser::_parse_closing_xml_element() {
void XMLParser::_ignore_definition() {
node_type = NODE_UNKNOWN;
- char *F = P;
+ const char *F = P;
// move until end marked with '>' reached
while (*P && *P != '>') {
next_char();
@@ -123,8 +123,8 @@ bool XMLParser::_parse_cdata() {
return true;
}
- char *cDataBegin = P;
- char *cDataEnd = nullptr;
+ const char *cDataBegin = P;
+ const char *cDataEnd = nullptr;
// find end of CDATA
while (*P && !cDataEnd) {
@@ -152,9 +152,9 @@ void XMLParser::_parse_comment() {
node_type = NODE_COMMENT;
P += 1;
- char *pEndOfInput = data + length;
- char *pCommentBegin;
- char *pCommentEnd;
+ const char *pEndOfInput = data + length;
+ const char *pCommentBegin;
+ const char *pCommentEnd;
if (P + 1 < pEndOfInput && P[0] == '-' && P[1] == '-') {
// Comment, use '-->' as end.
@@ -293,7 +293,7 @@ void XMLParser::_parse_opening_xml_element() {
}
void XMLParser::_parse_current_node() {
- char *start = P;
+ const char *start = P;
node_offset = P - data;
// more forward until '<' found
@@ -458,15 +458,36 @@ bool XMLParser::is_empty() const {
Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_V(p_buffer.size() == 0, ERR_INVALID_DATA);
- if (data) {
- memdelete_arr(data);
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
}
length = p_buffer.size();
- data = memnew_arr(char, length + 1);
- memcpy(data, p_buffer.ptr(), length);
- data[length] = 0;
+ data_copy = memnew_arr(char, length + 1);
+ memcpy(data_copy, p_buffer.ptr(), length);
+ data_copy[length] = 0;
+ data = data_copy;
+ P = data;
+ current_line = 0;
+
+ return OK;
+}
+
+Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) {
+ ERR_FAIL_COND_V(p_size == 0, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V(!p_buffer, ERR_INVALID_DATA);
+
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
+ }
+
+ length = p_size;
+ data = (const char *)p_buffer;
P = data;
+ current_line = 0;
+
return OK;
}
@@ -479,13 +500,15 @@ Error XMLParser::open(const String &p_path) {
length = file->get_length();
ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT);
- if (data) {
- memdelete_arr(data);
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
}
- data = memnew_arr(char, length + 1);
- file->get_buffer((uint8_t *)data, length);
- data[length] = 0;
+ data_copy = memnew_arr(char, length + 1);
+ file->get_buffer((uint8_t *)data_copy, length);
+ data_copy[length] = 0;
+ data = data_copy;
P = data;
current_line = 0;
@@ -512,8 +535,9 @@ void XMLParser::skip_section() {
}
void XMLParser::close() {
- if (data) {
+ if (data_copy) {
memdelete_arr(data);
+ data_copy = nullptr;
}
data = nullptr;
length = 0;
@@ -528,7 +552,8 @@ int XMLParser::get_current_line() const {
}
XMLParser::~XMLParser() {
- if (data) {
- memdelete_arr(data);
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
}
}
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index aea252ddc7..be44f771dc 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -65,8 +65,9 @@ public:
};
private:
- char *data = nullptr;
- char *P = nullptr;
+ char *data_copy = nullptr;
+ const char *data = nullptr;
+ const char *P = nullptr;
uint64_t length = 0;
uint64_t current_line = 0;
String node_name;
@@ -81,7 +82,7 @@ private:
Vector<Attribute> attributes;
- bool _set_text(char *start, char *end);
+ bool _set_text(const char *start, const char *end);
void _parse_closing_xml_element();
void _ignore_definition();
bool _parse_cdata();
@@ -118,6 +119,7 @@ public:
Error open(const String &p_path);
Error open_buffer(const Vector<uint8_t> &p_buffer);
+ Error _open_buffer(const uint8_t *p_buffer, size_t p_size);
void close();
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index e573e8de19..200e5f5e83 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -37,11 +37,17 @@ void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
String fname;
fname.parse_utf8(p_fname);
+ int file_access_mode = 0;
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
- (*fa) = FileAccess::open(fname, FileAccess::WRITE);
- } else {
- (*fa) = FileAccess::open(fname, FileAccess::READ);
+ file_access_mode |= FileAccess::WRITE;
}
+ if (mode & ZLIB_FILEFUNC_MODE_READ) {
+ file_access_mode |= FileAccess::READ;
+ }
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
+ file_access_mode |= FileAccess::WRITE_READ;
+ }
+ (*fa) = FileAccess::open(fname, file_access_mode);
if (fa->is_null()) {
return nullptr;
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 483b0d10ec..fcf245d2ad 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -30,7 +30,7 @@
#include "aabb.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "core/variant/variant.h"
real_t AABB::get_volume() const {
@@ -76,6 +76,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
}
+bool AABB::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
diff --git a/core/math/aabb.h b/core/math/aabb.h
index dfeb5b3291..9d5837ad37 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -31,7 +31,6 @@
#ifndef AABB_H
#define AABB_H
-#include "core/math/math_defs.h"
#include "core/math/plane.h"
#include "core/math/vector3.h"
@@ -64,6 +63,7 @@ struct _NO_DISCARD_ AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index 1a80faaa12..d06f9bef1e 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -34,7 +34,7 @@
#include "core/math/vector2.h"
#include "core/typedefs.h"
-static inline float undenormalise(volatile float f) {
+static inline float undenormalize(volatile float f) {
union {
uint32_t i;
float f;
@@ -101,9 +101,9 @@ struct AudioFrame {
r /= p_sample;
}
- _ALWAYS_INLINE_ void undenormalise() {
- l = ::undenormalise(l);
- r = ::undenormalise(r);
+ _ALWAYS_INLINE_ void undenormalize() {
+ l = ::undenormalize(l);
+ r = ::undenormalize(r);
}
_FORCE_INLINE_ AudioFrame lerp(const AudioFrame &p_b, float p_t) const {
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 743a206ae7..d7bb025b69 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -31,7 +31,7 @@
#include "basis.h"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#define cofac(row1, col1, row2, col2) \
(rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1])
@@ -453,7 +453,7 @@ void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) cons
Vector3 Basis::get_euler(EulerOrder p_order) const {
switch (p_order) {
- case EULER_ORDER_XYZ: {
+ case EulerOrder::XYZ: {
// Euler angles in XYZ convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -487,8 +487,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
euler.z = 0.0f;
}
return euler;
- } break;
- case EULER_ORDER_XZY: {
+ }
+ case EulerOrder::XZY: {
// Euler angles in XZY convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -516,8 +516,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
euler.z = -Math_PI / 2.0f;
}
return euler;
- } break;
- case EULER_ORDER_YXZ: {
+ }
+ case EulerOrder::YXZ: {
// Euler angles in YXZ convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -554,8 +554,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
- } break;
- case EULER_ORDER_YZX: {
+ }
+ case EulerOrder::YZX: {
// Euler angles in YZX convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -584,7 +584,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
} break;
- case EULER_ORDER_ZXY: {
+ case EulerOrder::ZXY: {
// Euler angles in ZXY convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -612,7 +612,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
} break;
- case EULER_ORDER_ZYX: {
+ case EulerOrder::ZYX: {
// Euler angles in ZYX convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -639,7 +639,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
euler.z = -Math::atan2(rows[0][1], rows[1][1]);
}
return euler;
- } break;
+ }
default: {
ERR_FAIL_V_MSG(Vector3(), "Invalid parameter for get_euler(order)");
}
@@ -663,22 +663,22 @@ void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) {
Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1);
switch (p_order) {
- case EULER_ORDER_XYZ: {
+ case EulerOrder::XYZ: {
*this = xmat * (ymat * zmat);
} break;
- case EULER_ORDER_XZY: {
+ case EulerOrder::XZY: {
*this = xmat * zmat * ymat;
} break;
- case EULER_ORDER_YXZ: {
+ case EulerOrder::YXZ: {
*this = ymat * xmat * zmat;
} break;
- case EULER_ORDER_YZX: {
+ case EulerOrder::YZX: {
*this = ymat * zmat * xmat;
} break;
- case EULER_ORDER_ZXY: {
+ case EulerOrder::ZXY: {
*this = zmat * xmat * ymat;
} break;
- case EULER_ORDER_ZYX: {
+ case EulerOrder::ZYX: {
*this = zmat * ymat * xmat;
} break;
default: {
@@ -691,6 +691,10 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
}
+bool Basis::is_finite() const {
+ return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite();
+}
+
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -811,7 +815,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
return;
}
// As we have reached here there are no singularities so we can handle normally.
- double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise.
+ double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalize.
if (Math::abs(s) < CMP_EPSILON) {
// Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above.
diff --git a/core/math/basis.h b/core/math/basis.h
index cc2924f5ff..a1d9fccef1 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -56,15 +56,6 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ real_t determinant() const;
- enum EulerOrder {
- EULER_ORDER_XYZ,
- EULER_ORDER_XZY,
- EULER_ORDER_YXZ,
- EULER_ORDER_YZX,
- EULER_ORDER_ZXY,
- EULER_ORDER_ZYX
- };
-
void from_z(const Vector3 &p_z);
void rotate(const Vector3 &p_axis, real_t p_angle);
@@ -73,13 +64,13 @@ struct _NO_DISCARD_ Basis {
void rotate_local(const Vector3 &p_axis, real_t p_angle);
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
- void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
- Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const;
+ void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
+ Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) const;
void rotate(const Quaternion &p_quaternion);
Basis rotated(const Quaternion &p_quaternion) const;
- Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
+ Vector3 get_euler_normalized(EulerOrder p_order = EulerOrder::YXZ) const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
Quaternion get_rotation_quaternion() const;
@@ -88,9 +79,9 @@ struct _NO_DISCARD_ Basis {
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
- Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
- void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
- static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
+ Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
+ void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
+ static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) {
Basis b;
b.set_euler(p_euler, p_order);
return b;
@@ -119,7 +110,7 @@ struct _NO_DISCARD_ Basis {
Vector3 get_scale_local() const;
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
- void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ);
+ void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ);
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
// transposed dot products
@@ -134,6 +125,7 @@ struct _NO_DISCARD_ Basis {
}
bool is_equal_approx(const Basis &p_basis) const;
+ bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
index 8291394b31..3836e92a83 100644
--- a/core/math/bvh_tree.h
+++ b/core/math/bvh_tree.h
@@ -43,7 +43,6 @@
#include "core/math/bvh_abb.h"
#include "core/math/geometry_3d.h"
#include "core/math/vector3.h"
-#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/pooled_list.h"
#include <limits.h>
diff --git a/core/math/color.cpp b/core/math/color.cpp
index 4bdeafd2f2..f223853f6b 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -32,85 +32,85 @@
#include "color_names.inc"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "core/templates/rb_map.h"
#include "thirdparty/misc/ok_color.h"
uint32_t Color::to_argb32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
+ uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
+ c |= (uint8_t)Math::round(r * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
return c;
}
uint32_t Color::to_abgr32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
+ uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
+ c |= (uint8_t)Math::round(r * 255.0f);
return c;
}
uint32_t Color::to_rgba32() const {
- uint32_t c = (uint8_t)Math::round(r * 255);
+ uint32_t c = (uint8_t)Math::round(r * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(a * 255);
+ c |= (uint8_t)Math::round(a * 255.0f);
return c;
}
uint64_t Color::to_abgr64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
+ uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
+ c |= (uint16_t)Math::round(r * 65535.0f);
return c;
}
uint64_t Color::to_argb64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
+ uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
+ c |= (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
return c;
}
uint64_t Color::to_rgba64() const {
- uint64_t c = (uint16_t)Math::round(r * 65535);
+ uint64_t c = (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(a * 65535);
+ c |= (uint16_t)Math::round(a * 65535.0f);
return c;
}
String _to_hex(float p_val) {
- int v = Math::round(p_val * 255);
+ int v = Math::round(p_val * 255.0f);
v = CLAMP(v, 0, 255);
String ret;
@@ -150,8 +150,8 @@ float Color::get_h() const {
float delta = max - min;
- if (delta == 0) {
- return 0;
+ if (delta == 0.0f) {
+ return 0.0f;
}
float h;
@@ -164,7 +164,7 @@ float Color::get_h() const {
}
h /= 6.0f;
- if (h < 0) {
+ if (h < 0.0f) {
h += 1.0f;
}
@@ -179,7 +179,7 @@ float Color::get_s() const {
float delta = max - min;
- return (max != 0) ? (delta / max) : 0;
+ return (max != 0.0f) ? (delta / max) : 0.0f;
}
float Color::get_v() const {
@@ -193,7 +193,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
float f, p, q, t;
a = p_alpha;
- if (p_s == 0) {
+ if (p_s == 0.0f) {
// Achromatic (grey)
r = g = b = p_v;
return;
@@ -204,9 +204,9 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
i = Math::floor(p_h);
f = p_h - i;
- p = p_v * (1 - p_s);
- q = p_v * (1 - p_s * f);
- t = p_v * (1 - p_s * (1 - f));
+ p = p_v * (1.0f - p_s);
+ q = p_v * (1.0f - p_s * f);
+ t = p_v * (1.0f - p_s * (1.0f - f));
switch (i) {
case 0: // Red is the dominant color
@@ -347,7 +347,7 @@ Color Color::html(const String &p_rgba) {
ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
}
- float r, g, b, a = 1.0;
+ float r, g, b, a = 1.0f;
if (is_shorthand) {
r = _parse_col4(color, 0) / 15.0f;
g = _parse_col4(color, 1) / 15.0f;
@@ -363,10 +363,10 @@ Color Color::html(const String &p_rgba) {
a = _parse_col8(color, 6) / 255.0f;
}
}
- ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(a < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
return Color(r, g, b, a);
}
@@ -474,7 +474,7 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) {
float g = (p_rgbe >> 9) & 0x1ff;
float b = (p_rgbe >> 18) & 0x1ff;
float e = (p_rgbe >> 27);
- float m = Math::pow(2, e - 15.0f - 9.0f);
+ float m = Math::pow(2.0f, e - 15.0f - 9.0f);
float rd = r * m;
float gd = g * m;
diff --git a/core/math/color.h b/core/math/color.h
index bb8aa9a529..5630539aa7 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -56,11 +56,11 @@ struct _NO_DISCARD_ Color {
float get_h() const;
float get_s() const;
float get_v() const;
- void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
+ void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
float get_ok_hsl_h() const;
float get_ok_hsl_s() const;
float get_ok_hsl_l() const;
- void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0);
+ void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f);
_FORCE_INLINE_ float &operator[](int p_idx) {
return components[p_idx];
@@ -105,12 +105,10 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const {
Color res = *this;
-
- res.r += (p_weight * (p_to.r - r));
- res.g += (p_weight * (p_to.g - g));
- res.b += (p_weight * (p_to.b - b));
- res.a += (p_weight * (p_to.a - a));
-
+ res.r = Math::lerp(res.r, p_to.r, p_weight);
+ res.g = Math::lerp(res.g, p_to.g, p_weight);
+ res.b = Math::lerp(res.b, p_to.b, p_weight);
+ res.a = Math::lerp(res.a, p_to.a, p_weight);
return res;
}
@@ -176,9 +174,9 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
- r < 0.04045f ? r * (1.0 / 12.92) : Math::pow((r + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
- g < 0.04045f ? g * (1.0 / 12.92) : Math::pow((g + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
- b < 0.04045f ? b * (1.0 / 12.92) : Math::pow((b + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
+ r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
a);
}
_FORCE_INLINE_ Color linear_to_srgb() const {
@@ -199,11 +197,11 @@ struct _NO_DISCARD_ Color {
static String get_named_color_name(int p_idx);
static Color get_named_color(int p_idx);
static Color from_string(const String &p_string, const Color &p_default);
- static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
- static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0);
+ static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
+ static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f);
static Color from_rgbe9995(uint32_t p_rgbe);
- _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys
+ _FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
operator String() const;
// For the binder.
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 996f4f4d67..561970d2ee 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -62,6 +62,7 @@ subject to the following restrictions:
#include "core/math/aabb.h"
#include "core/math/math_defs.h"
#include "core/os/memory.h"
+#include "core/templates/oa_hash_map.h"
#include "core/templates/paged_allocator.h"
#include <string.h>
@@ -2252,19 +2253,62 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
r_mesh.vertices = ch.vertices;
+ // Tag which face each edge belongs to
+ LocalVector<int32_t> edge_faces;
+ edge_faces.resize(ch.edges.size());
+
+ for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ edge_faces[i] = -1;
+ }
+
+ for (uint32_t i = 0; i < ch.faces.size(); i++) {
+ const Edge *e_start = &ch.edges[ch.faces[i]];
+ const Edge *e = e_start;
+ do {
+ int64_t ofs = e - ch.edges.ptr();
+ edge_faces[ofs] = i;
+
+ e = e->get_next_edge_of_face();
+ } while (e != e_start);
+ }
+
// Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them.
r_mesh.edges.resize(ch.edges.size() / 2);
+ OAHashMap<uint64_t, int32_t> edge_map;
+ edge_map.reserve(ch.edges.size() * 4); // The higher the capacity, the faster the insert
+
uint32_t edges_copied = 0;
for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ ERR_CONTINUE(edge_faces[i] == -1); // Sanity check
+
uint32_t a = (&ch.edges[i])->get_source_vertex();
uint32_t b = (&ch.edges[i])->get_target_vertex();
if (a < b) { // Copy only the "canonical" edge. For the reverse edge, this will be false.
ERR_BREAK(edges_copied >= (uint32_t)r_mesh.edges.size());
- r_mesh.edges.write[edges_copied].a = a;
- r_mesh.edges.write[edges_copied].b = b;
+ r_mesh.edges[edges_copied].vertex_a = a;
+ r_mesh.edges[edges_copied].vertex_b = b;
+ r_mesh.edges[edges_copied].face_a = edge_faces[i];
+ r_mesh.edges[edges_copied].face_b = -1;
+
+ uint64_t key = a;
+ key <<= 32;
+ key |= b;
+ edge_map.insert(key, edges_copied);
+
edges_copied++;
+ } else {
+ uint64_t key = b;
+ key <<= 32;
+ key |= a;
+ int32_t index;
+ if (!edge_map.lookup(key, index)) {
+ ERR_PRINT("Invalid edge");
+ } else {
+ r_mesh.edges[index].face_b = edge_faces[i];
+ }
}
}
+
if (edges_copied != (uint32_t)r_mesh.edges.size()) {
ERR_PRINT("Invalid edge count.");
}
@@ -2273,7 +2317,7 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
for (uint32_t i = 0; i < ch.faces.size(); i++) {
const Edge *e_start = &ch.edges[ch.faces[i]];
const Edge *e = e_start;
- Geometry3D::MeshData::Face &face = r_mesh.faces.write[i];
+ Geometry3D::MeshData::Face &face = r_mesh.faces[i];
do {
face.indices.push_back(e->get_target_vertex());
@@ -2284,8 +2328,8 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
// reverse indices: Godot wants clockwise, but this is counter-clockwise
if (face.indices.size() > 2) {
// reverse all but the first index.
- int *indices = face.indices.ptrw();
- for (int c = 0; c < (face.indices.size() - 1) / 2; c++) {
+ int *indices = face.indices.ptr();
+ for (uint32_t c = 0; c < (face.indices.size() - 1) / 2; c++) {
SWAP(indices[c + 1], indices[face.indices.size() - 1 - c]);
}
}
diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h
index cc41a794bd..ab6671a7d0 100644
--- a/core/math/convex_hull.h
+++ b/core/math/convex_hull.h
@@ -62,6 +62,10 @@ public:
friend class ConvexHullComputer;
public:
+ int32_t get_next_relative() const {
+ return next;
+ }
+
int32_t get_source_vertex() const {
return (this + reverse)->target_vertex;
}
@@ -86,7 +90,7 @@ public:
};
// Vertices of the output hull
- Vector<Vector3> vertices;
+ LocalVector<Vector3> vertices;
// Edges of the output hull
LocalVector<Edge> edges;
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 13d93d7f67..3f8fe09445 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -35,7 +35,6 @@
#include "core/math/aabb.h"
#include "core/math/projection.h"
#include "core/math/vector3.h"
-#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/vector.h"
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index dcec3929fe..26b809e7f2 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -1420,7 +1420,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
Callable::CallError ce;
Variant::call_utility_function(bifunc->func, &r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "Builtin Call Failed. " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce);
+ r_error_str = "Builtin call failed: " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce);
return true;
}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 9238293b48..548b9e4620 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -30,8 +30,6 @@
#include "geometry_3d.h"
-#include "core/string/print_string.h"
-
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
@@ -143,21 +141,21 @@ real_t Geometry3D::get_closest_distance_between_segments(const Vector3 &p_p0, co
void Geometry3D::MeshData::optimize_vertices() {
HashMap<int, int> vtx_remap;
- for (int i = 0; i < faces.size(); i++) {
- for (int j = 0; j < faces[i].indices.size(); j++) {
+ for (uint32_t i = 0; i < faces.size(); i++) {
+ for (uint32_t j = 0; j < faces[i].indices.size(); j++) {
int idx = faces[i].indices[j];
if (!vtx_remap.has(idx)) {
int ni = vtx_remap.size();
vtx_remap[idx] = ni;
}
- faces.write[i].indices.write[j] = vtx_remap[idx];
+ faces[i].indices[j] = vtx_remap[idx];
}
}
- for (int i = 0; i < edges.size(); i++) {
- int a = edges[i].a;
- int b = edges[i].b;
+ for (uint32_t i = 0; i < edges.size(); i++) {
+ int a = edges[i].vertex_a;
+ int b = edges[i].vertex_b;
if (!vtx_remap.has(a)) {
int ni = vtx_remap.size();
@@ -168,16 +166,16 @@ void Geometry3D::MeshData::optimize_vertices() {
vtx_remap[b] = ni;
}
- edges.write[i].a = vtx_remap[a];
- edges.write[i].b = vtx_remap[b];
+ edges[i].vertex_a = vtx_remap[a];
+ edges[i].vertex_b = vtx_remap[b];
}
- Vector<Vector3> new_vertices;
+ LocalVector<Vector3> new_vertices;
new_vertices.resize(vtx_remap.size());
- for (int i = 0; i < vertices.size(); i++) {
+ for (uint32_t i = 0; i < vertices.size(); i++) {
if (vtx_remap.has(i)) {
- new_vertices.write[vtx_remap[i]] = vertices[i];
+ new_vertices[vtx_remap[i]] = vertices[i];
}
}
vertices = new_vertices;
@@ -753,7 +751,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
Vector3 center = p.center();
// make a quad clockwise
- Vector<Vector3> vertices = {
+ LocalVector<Vector3> vertices = {
center - up * subplane_size + right * subplane_size,
center - up * subplane_size - right * subplane_size,
center + up * subplane_size - right * subplane_size,
@@ -765,7 +763,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
continue;
}
- Vector<Vector3> new_vertices;
+ LocalVector<Vector3> new_vertices;
Plane clip = p_planes[j];
if (clip.normal.dot(p.normal) > 0.95f) {
@@ -776,7 +774,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
break;
}
- for (int k = 0; k < vertices.size(); k++) {
+ for (uint32_t k = 0; k < vertices.size(); k++) {
int k_n = (k + 1) % vertices.size();
Vector3 edge0_A = vertices[k];
@@ -818,9 +816,9 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
MeshData::Face face;
// Add face indices.
- for (int j = 0; j < vertices.size(); j++) {
+ for (uint32_t j = 0; j < vertices.size(); j++) {
int idx = -1;
- for (int k = 0; k < mesh.vertices.size(); k++) {
+ for (uint32_t k = 0; k < mesh.vertices.size(); k++) {
if (mesh.vertices[k].distance_to(vertices[j]) < 0.001f) {
idx = k;
break;
@@ -839,28 +837,34 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
// Add edge.
- for (int j = 0; j < face.indices.size(); j++) {
+ for (uint32_t j = 0; j < face.indices.size(); j++) {
int a = face.indices[j];
int b = face.indices[(j + 1) % face.indices.size()];
bool found = false;
- for (int k = 0; k < mesh.edges.size(); k++) {
- if (mesh.edges[k].a == a && mesh.edges[k].b == b) {
+ int found_idx = -1;
+ for (uint32_t k = 0; k < mesh.edges.size(); k++) {
+ if (mesh.edges[k].vertex_a == a && mesh.edges[k].vertex_b == b) {
found = true;
+ found_idx = k;
break;
}
- if (mesh.edges[k].b == a && mesh.edges[k].a == b) {
+ if (mesh.edges[k].vertex_b == a && mesh.edges[k].vertex_a == b) {
found = true;
+ found_idx = k;
break;
}
}
if (found) {
+ mesh.edges[found_idx].face_b = j;
continue;
}
MeshData::Edge edge;
- edge.a = a;
- edge.b = b;
+ edge.vertex_a = a;
+ edge.vertex_b = b;
+ edge.face_a = j;
+ edge.face_b = -1;
mesh.edges.push_back(edge);
}
}
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index e5ace9db72..4b4c173a1e 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -33,6 +33,7 @@
#include "core/math/face3.h"
#include "core/object/object.h"
+#include "core/templates/local_vector.h"
#include "core/templates/vector.h"
class Geometry3D {
@@ -539,18 +540,19 @@ public:
struct MeshData {
struct Face {
Plane plane;
- Vector<int> indices;
+ LocalVector<int> indices;
};
- Vector<Face> faces;
+ LocalVector<Face> faces;
struct Edge {
- int a, b;
+ int vertex_a, vertex_b;
+ int face_a, face_b;
};
- Vector<Edge> edges;
+ LocalVector<Edge> edges;
- Vector<Vector3> vertices;
+ LocalVector<Vector3> vertices;
void optimize_vertices();
};
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index b8b82f2ff4..1058a47c1a 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -86,6 +86,7 @@ enum InlineAlignment {
// Image alignment points.
INLINE_ALIGNMENT_TOP_TO = 0b0000,
INLINE_ALIGNMENT_CENTER_TO = 0b0001,
+ INLINE_ALIGNMENT_BASELINE_TO = 0b0011,
INLINE_ALIGNMENT_BOTTOM_TO = 0b0010,
INLINE_ALIGNMENT_IMAGE_MASK = 0b0011,
@@ -116,6 +117,15 @@ enum Corner {
CORNER_BOTTOM_LEFT
};
+enum class EulerOrder {
+ XYZ,
+ XZY,
+ YXZ,
+ YZX,
+ ZXY,
+ ZYX
+};
+
/**
* The "Real" type is an abstract type used for real numbers, such as 1.5,
* in contrast to integer numbers. Precision can be controlled with the
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 7fa674a23d..8dff8e6e7e 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -184,6 +184,9 @@ public:
#endif
}
+ static _ALWAYS_INLINE_ bool is_finite(double p_val) { return isfinite(p_val); }
+ static _ALWAYS_INLINE_ bool is_finite(float p_val) { return isfinite(p_val); }
+
static _ALWAYS_INLINE_ double abs(double g) { return absd(g); }
static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
@@ -361,6 +364,26 @@ public:
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
}
+ static _ALWAYS_INLINE_ double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
+ /* Formula from Wikipedia article on Bezier curves. */
+ double omt = (1.0 - p_t);
+ double omt2 = omt * omt;
+ double t2 = p_t * p_t;
+
+ double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2;
+ return d;
+ }
+
+ static _ALWAYS_INLINE_ float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
+ /* Formula from Wikipedia article on Bezier curves. */
+ float omt = (1.0f - p_t);
+ float omt2 = omt * omt;
+ float t2 = p_t * p_t;
+
+ float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2;
+ return d;
+ }
+
static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) {
double difference = fmod(p_to - p_from, Math_TAU);
double distance = fmod(2.0 * difference, Math_TAU) - difference;
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 3b2eab4ae2..a5d2fe5628 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -176,6 +176,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
}
+bool Plane::is_finite() const {
+ return normal.is_finite() && Math::is_finite(d);
+}
+
Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 73babfa496..77da59fb27 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -74,6 +74,7 @@ struct _NO_DISCARD_ Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index 30c4f12795..c135e1946a 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -35,7 +35,7 @@
#include "core/math/plane.h"
#include "core/math/rect2.h"
#include "core/math/transform_3d.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
float Projection::determinant() const {
return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] -
@@ -134,7 +134,7 @@ Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intra
Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
Projection proj;
- proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar);
+ proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_znear, p_zfar);
return proj;
}
@@ -181,7 +181,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const {
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
- } break;
+ }
case PLANE_FAR: {
Plane new_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
@@ -191,7 +191,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const {
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
- } break;
+ }
case PLANE_LEFT: {
Plane new_plane = Plane(matrix[3] + matrix[0],
matrix[7] + matrix[4],
@@ -201,7 +201,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const {
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
- } break;
+ }
case PLANE_TOP: {
Plane new_plane = Plane(matrix[3] - matrix[1],
matrix[7] - matrix[5],
@@ -211,7 +211,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const {
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
- } break;
+ }
case PLANE_RIGHT: {
Plane new_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
@@ -221,7 +221,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const {
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
- } break;
+ }
case PLANE_BOTTOM: {
Plane new_plane = Plane(matrix[3] + matrix[1],
matrix[7] + matrix[5],
@@ -231,7 +231,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const {
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
- } break;
+ }
}
return Plane();
@@ -496,7 +496,10 @@ bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8point
for (int i = 0; i < 8; i++) {
Vector3 point;
- bool res = planes[intersections[i][0]].intersect_3(planes[intersections[i][1]], planes[intersections[i][2]], &point);
+ Plane a = planes[intersections[i][0]];
+ Plane b = planes[intersections[i][1]];
+ Plane c = planes[intersections[i][2]];
+ bool res = a.intersect_3(b, c, &point);
ERR_FAIL_COND_V(!res, false);
p_8points[i] = p_transform.xform(point);
}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index c836a82e37..942a0b766e 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -31,32 +31,18 @@
#include "quaternion.h"
#include "core/math/basis.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
real_t Quaternion::angle_to(const Quaternion &p_to) const {
real_t d = dot(p_to);
return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
}
-// get_euler_xyz returns a vector containing the Euler angles in the format
-// (ax,ay,az), where ax is the angle of rotation around x axis,
-// and similar for other axes.
-// This implementation uses XYZ convention (Z is the first rotation).
-Vector3 Quaternion::get_euler_xyz() const {
- Basis m(*this);
- return m.get_euler(Basis::EULER_ORDER_XYZ);
-}
-
-// get_euler_yxz returns a vector containing the Euler angles in the format
-// (ax,ay,az), where ax is the angle of rotation around x axis,
-// and similar for other axes.
-// This implementation uses YXZ convention (Z is the first rotation).
-Vector3 Quaternion::get_euler_yxz() const {
+Vector3 Quaternion::get_euler(EulerOrder p_order) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
#endif
- Basis m(*this);
- return m.get_euler(Basis::EULER_ORDER_YXZ);
+ return Basis(*this).get_euler(p_order);
}
void Quaternion::operator*=(const Quaternion &p_q) {
@@ -79,6 +65,10 @@ bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
}
+bool Quaternion::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}
@@ -326,7 +316,7 @@ Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
// (ax, ay, az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
-Quaternion::Quaternion(const Vector3 &p_euler) {
+Quaternion Quaternion::from_euler(const Vector3 &p_euler) {
real_t half_a1 = p_euler.y * 0.5f;
real_t half_a2 = p_euler.x * 0.5f;
real_t half_a3 = p_euler.z * 0.5f;
@@ -342,8 +332,9 @@ Quaternion::Quaternion(const Vector3 &p_euler) {
real_t cos_a3 = Math::cos(half_a3);
real_t sin_a3 = Math::sin(half_a3);
- x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
- y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
- z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
- w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
+ return Quaternion(
+ sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3,
+ sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3,
+ -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3,
+ sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3);
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 077fe5f189..c5af2121d9 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -55,6 +55,7 @@ struct _NO_DISCARD_ Quaternion {
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
@@ -65,9 +66,8 @@ struct _NO_DISCARD_ Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
- Vector3 get_euler_xyz() const;
- Vector3 get_euler_yxz() const;
- Vector3 get_euler() const { return get_euler_yxz(); };
+ Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
+ static Quaternion from_euler(const Vector3 &p_euler);
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
@@ -127,8 +127,6 @@ struct _NO_DISCARD_ Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
- Quaternion(const Vector3 &p_euler);
-
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -143,8 +141,7 @@ struct _NO_DISCARD_ Quaternion {
w = p_q.w;
}
- Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc
- {
+ Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index c7727a44a1..c194e1cc21 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -369,7 +369,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) {
Geometry3D::MeshData::Face &f = E->get();
- for (int i = 0; i < f.indices.size(); i++) {
+ for (uint32_t i = 0; i < f.indices.size(); i++) {
int a = E->get().indices[i];
int b = E->get().indices[(i + 1) % f.indices.size()];
Edge e(a, b);
@@ -436,17 +436,24 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
r_mesh.faces.clear();
r_mesh.faces.resize(ret_faces.size());
+ HashMap<List<Geometry3D::MeshData::Face>::Element *, int> face_indices;
+
int idx = 0;
- for (const Geometry3D::MeshData::Face &E : ret_faces) {
- r_mesh.faces.write[idx++] = E;
+ for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) {
+ face_indices[E] = idx;
+ r_mesh.faces[idx++] = E->get();
}
r_mesh.edges.resize(ret_edges.size());
idx = 0;
for (const KeyValue<Edge, RetFaceConnect> &E : ret_edges) {
Geometry3D::MeshData::Edge e;
- e.a = E.key.vertices[0];
- e.b = E.key.vertices[1];
- r_mesh.edges.write[idx++] = e;
+ e.vertex_a = E.key.vertices[0];
+ e.vertex_b = E.key.vertices[1];
+ ERR_CONTINUE(!face_indices.has(E.value.left));
+ ERR_CONTINUE(!face_indices.has(E.value.right));
+ e.face_a = face_indices[E.value.left];
+ e.face_b = face_indices[E.value.right];
+ r_mesh.edges[idx++] = e;
}
r_mesh.vertices = p_points;
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 9352bae0a6..bf67154cd6 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -57,7 +57,7 @@ public:
_FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); }
_FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); }
- RandomNumberGenerator() {}
+ RandomNumberGenerator() { randbase.randomize(); }
};
#endif // RANDOM_NUMBER_GENERATOR_H
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index 9e78ead816..facf4eb3c4 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -38,6 +38,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
}
+bool Rect2::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 5ed2f8236c..9863405d8e 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -178,7 +178,7 @@ struct _NO_DISCARD_ Rect2 {
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
- new_rect.size = new_rect.size - new_rect.position; //make relative again
+ new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
@@ -207,6 +207,7 @@ struct _NO_DISCARD_ Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
+ bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -253,7 +254,7 @@ struct _NO_DISCARD_ Rect2 {
return r;
}
- inline void expand_to(const Vector2 &p_vector) { //in place function for speed
+ inline void expand_to(const Vector2 &p_vector) { // In place function for speed.
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
@@ -311,7 +312,7 @@ struct _NO_DISCARD_ Rect2 {
continue;
}
- //check inside
+ // Check inside.
Vector2 tg = r.orthogonal();
float s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
@@ -320,7 +321,7 @@ struct _NO_DISCARD_ Rect2 {
side_minus++;
}
- //check ray box
+ // Check ray box.
r /= l;
Vector2 ir(1.0f / r.x, 1.0f / r.y);
@@ -341,7 +342,7 @@ struct _NO_DISCARD_ Rect2 {
}
if (side_plus * side_minus == 0) {
- return true; //all inside
+ return true; // All inside.
} else {
return false;
}
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index 2b58dcdd98..c92f2cae02 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -121,7 +121,7 @@ struct _NO_DISCARD_ Rect2i {
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
- new_rect.size = new_rect.size - new_rect.position; //make relative again
+ new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 226076029b..548a82d254 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -168,6 +168,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
+bool Transform2D::is_finite() const {
+ return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite();
+}
+
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target);
@@ -282,7 +286,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const
real_t dot = v1.dot(v2);
- dot = CLAMP(dot, -1.0f, 1.0f);
+ dot = CLAMP(dot, (real_t)-1.0, (real_t)1.0);
Vector2 v;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index f23f32867a..2b11f36535 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -98,6 +98,7 @@ struct _NO_DISCARD_ Transform2D {
void orthonormalize();
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
+ bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index 2de9e81b38..3285cbd664 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -31,7 +31,7 @@
#include "transform_3d.h"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
void Transform3D::affine_invert() {
basis.invert();
@@ -174,6 +174,10 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
}
+bool Transform3D::is_finite() const {
+ return basis.is_finite() && origin.is_finite();
+}
+
bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin);
}
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 44d6d826f3..cb347aa1c1 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -75,6 +75,7 @@ struct _NO_DISCARD_ Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
+ bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 56dbba393a..5366587126 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -186,6 +186,10 @@ bool Vector2::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y);
}
+bool Vector2::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y);
+}
+
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 75364f72f0..835c3d1ba6 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -112,6 +112,7 @@ struct _NO_DISCARD_ Vector2 {
_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
+ _FORCE_INLINE_ Vector2 bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;
@@ -121,6 +122,7 @@ struct _NO_DISCARD_ Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
@@ -241,10 +243,8 @@ _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
Vector2 Vector2::lerp(const Vector2 &p_to, const real_t p_weight) const {
Vector2 res = *this;
-
- res.x += (p_weight * (p_to.x - x));
- res.y += (p_weight * (p_to.y - y));
-
+ res.x = Math::lerp(res.x, p_to.x, p_weight);
+ res.y = Math::lerp(res.y, p_to.y, p_weight);
return res;
}
@@ -277,15 +277,16 @@ Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_
Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
Vector2 res = *this;
+ res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t);
+ res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t);
+ return res;
+}
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - p_t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = p_t * p_t;
- real_t t3 = t2 * p_t;
-
- return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
+Vector2 Vector2::bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
+ Vector2 res = *this;
+ res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t);
+ res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t);
+ return res;
}
Vector2 Vector2::direction_to(const Vector2 &p_to) const {
diff --git a/core/math/vector2i.cpp b/core/math/vector2i.cpp
index dfed42e4d6..ff8693ee5b 100644
--- a/core/math/vector2i.cpp
+++ b/core/math/vector2i.cpp
@@ -39,6 +39,12 @@ Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const {
CLAMP(y, p_min.y, p_max.y));
}
+Vector2i Vector2i::snapped(const Vector2i &p_step) const {
+ return Vector2i(
+ Math::snapped(x, p_step.x),
+ Math::snapped(y, p_step.y));
+}
+
int64_t Vector2i::length_squared() const {
return x * (int64_t)x + y * (int64_t)y;
}
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index e131bdea94..927be11030 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -119,6 +119,7 @@ struct _NO_DISCARD_ Vector2i {
Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); }
Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); }
Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
+ Vector2i snapped(const Vector2i &p_step) const;
operator String() const;
operator Vector2() const;
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 55ba509144..b106200c4a 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -139,6 +139,10 @@ bool Vector3::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
}
+bool Vector3::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z);
+}
+
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 62e810fb4d..dc74096690 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -100,6 +100,7 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
_FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
+ _FORCE_INLINE_ Vector3 bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;
@@ -136,6 +137,7 @@ struct _NO_DISCARD_ Vector3 {
bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
/* Operators */
@@ -207,10 +209,11 @@ Vector3 Vector3::round() const {
}
Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const {
- return Vector3(
- x + (p_weight * (p_to.x - x)),
- y + (p_weight * (p_to.y - y)),
- z + (p_weight * (p_to.z - z)));
+ Vector3 res = *this;
+ res.x = Math::lerp(res.x, p_to.x, p_weight);
+ res.y = Math::lerp(res.y, p_to.y, p_weight);
+ res.z = Math::lerp(res.z, p_to.z, p_weight);
+ return res;
}
Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const {
@@ -253,15 +256,18 @@ Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_
Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
Vector3 res = *this;
+ res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t);
+ res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t);
+ res.z = Math::bezier_interpolate(res.z, p_control_1.z, p_control_2.z, p_end.z, p_t);
+ return res;
+}
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - p_t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = p_t * p_t;
- real_t t3 = t2 * p_t;
-
- return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
+Vector3 Vector3::bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
+ Vector3 res = *this;
+ res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t);
+ res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t);
+ res.z = Math::bezier_derivative(res.z, p_control_1.z, p_control_2.z, p_end.z, p_t);
+ return res;
}
real_t Vector3::distance_to(const Vector3 &p_to) const {
diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp
index b248f35035..901f2b5a64 100644
--- a/core/math/vector3i.cpp
+++ b/core/math/vector3i.cpp
@@ -48,6 +48,13 @@ Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const {
CLAMP(z, p_min.z, p_max.z));
}
+Vector3i Vector3i::snapped(const Vector3i &p_step) const {
+ return Vector3i(
+ Math::snapped(x, p_step.x),
+ Math::snapped(y, p_step.y),
+ Math::snapped(z, p_step.z));
+}
+
Vector3i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")";
}
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 710fd96376..36bac3d8ae 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -77,6 +77,7 @@ struct _NO_DISCARD_ Vector3i {
_FORCE_INLINE_ Vector3i abs() const;
_FORCE_INLINE_ Vector3i sign() const;
Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const;
+ Vector3i snapped(const Vector3i &p_step) const;
/* Operators */
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index 55e51834df..5ddf2bb6f6 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -30,8 +30,7 @@
#include "vector4.h"
-#include "core/math/basis.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
Vector4::Axis Vector4::min_axis_index() const {
uint32_t min_index = 0;
@@ -65,6 +64,10 @@ bool Vector4::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
}
+bool Vector4::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
@@ -127,11 +130,12 @@ Vector4 Vector4::round() const {
}
Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const {
- return Vector4(
- x + (p_weight * (p_to.x - x)),
- y + (p_weight * (p_to.y - y)),
- z + (p_weight * (p_to.z - z)),
- w + (p_weight * (p_to.w - w)));
+ Vector4 res = *this;
+ res.x = Math::lerp(res.x, p_to.x, p_weight);
+ res.y = Math::lerp(res.y, p_to.y, p_weight);
+ res.z = Math::lerp(res.z, p_to.z, p_weight);
+ res.w = Math::lerp(res.w, p_to.w, p_weight);
+ return res;
}
Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const {
diff --git a/core/math/vector4.h b/core/math/vector4.h
index ac7b6c3aee..7c4bdc1788 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -71,6 +71,7 @@ struct _NO_DISCARD_ Vector4 {
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index 77f6fbd5b7..e906ab45ad 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -65,6 +65,14 @@ Vector4i Vector4i::clamp(const Vector4i &p_min, const Vector4i &p_max) const {
CLAMP(w, p_min.w, p_max.w));
}
+Vector4i Vector4i::snapped(const Vector4i &p_step) const {
+ return Vector4i(
+ Math::snapped(x, p_step.x),
+ Math::snapped(y, p_step.y),
+ Math::snapped(z, p_step.z),
+ Math::snapped(w, p_step.w));
+}
+
Vector4i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")";
}
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index a32414bb18..cb5a48daf9 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -79,6 +79,7 @@ struct _NO_DISCARD_ Vector4i {
_FORCE_INLINE_ Vector4i abs() const;
_FORCE_INLINE_ Vector4i sign() const;
Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const;
+ Vector4i snapped(const Vector4i &p_step) const;
/* Operators */
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index ca56add2ab..529d99ec9a 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -31,6 +31,7 @@
#include "class_db.h"
#include "core/config/engine.h"
+#include "core/object/script_language.h"
#include "core/os/mutex.h"
#include "core/version.h"
@@ -317,7 +318,7 @@ Object *ClassDB::instantiate(const StringName &p_class) {
{
OBJTYPE_RLOCK;
ti = classes.getptr(p_class);
- if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) {
+ if (!ti || ti->disabled || !ti->creation_func || (ti->gdextension && !ti->gdextension->create_instance)) {
if (compat_classes.has(p_class)) {
ti = classes.getptr(compat_classes[p_class]);
}
@@ -332,8 +333,8 @@ Object *ClassDB::instantiate(const StringName &p_class) {
return nullptr;
}
#endif
- if (ti->native_extension && ti->native_extension->create_instance) {
- return (Object *)ti->native_extension->create_instance(ti->native_extension->class_userdata);
+ if (ti->gdextension && ti->gdextension->create_instance) {
+ return (Object *)ti->gdextension->create_instance(ti->gdextension->class_userdata);
} else {
return ti->creation_func();
}
@@ -345,17 +346,17 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
{
OBJTYPE_RLOCK;
ti = classes.getptr(p_class);
- if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) {
+ if (!ti || ti->disabled || !ti->creation_func || (ti->gdextension && !ti->gdextension->create_instance)) {
if (compat_classes.has(p_class)) {
ti = classes.getptr(compat_classes[p_class]);
}
}
ERR_FAIL_COND_MSG(!ti, "Cannot get class '" + String(p_class) + "'.");
ERR_FAIL_COND_MSG(ti->disabled, "Class '" + String(p_class) + "' is disabled.");
- ERR_FAIL_COND_MSG(!ti->native_extension, "Class '" + String(p_class) + "' has no native extension.");
+ ERR_FAIL_COND_MSG(!ti->gdextension, "Class '" + String(p_class) + "' has no native extension.");
}
- p_object->_extension = ti->native_extension;
+ p_object->_extension = ti->gdextension;
p_object->_extension_instance = p_instance;
}
@@ -369,20 +370,25 @@ bool ClassDB::can_instantiate(const StringName &p_class) {
return false;
}
#endif
- return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance));
+ return (!ti->disabled && ti->creation_func != nullptr && !(ti->gdextension && !ti->gdextension->create_instance));
}
bool ClassDB::is_virtual(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ if (!ti) {
+ if (!ScriptServer::is_global_class(p_class)) {
+ ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
+ }
+ return false;
+ }
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
return false;
}
#endif
- return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance) && ti->is_virtual);
+ return (!ti->disabled && ti->creation_func != nullptr && !(ti->gdextension && !ti->gdextension->create_instance) && ti->is_virtual);
}
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
@@ -1454,7 +1460,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
if (Engine::get_singleton()->has_singleton(p_class)) {
c = Engine::get_singleton()->get_singleton_object(p_class);
cleanup_c = false;
- } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value.
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
@@ -1516,7 +1522,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
return var;
}
-void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
+void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
GLOBAL_LOCK_FUNCTION;
ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name));
@@ -1526,9 +1532,12 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
ClassInfo c;
c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
- c.native_extension = p_extension;
+ c.gdextension = p_extension;
c.name = p_extension->class_name;
- c.creation_func = parent->creation_func;
+ c.is_virtual = p_extension->is_virtual;
+ if (!p_extension->is_abstract) {
+ c.creation_func = parent->creation_func;
+ }
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 5fba52e23e..4b60079298 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -100,7 +100,7 @@ public:
ClassInfo *inherits_ptr = nullptr;
void *class_ptr = nullptr;
- ObjectNativeExtension *native_extension = nullptr;
+ ObjectGDExtension *gdextension = nullptr;
HashMap<StringName, MethodBind *> method_map;
HashMap<StringName, int64_t> constant_map;
@@ -203,7 +203,7 @@ public:
//nothing
}
- static void register_extension_class(ObjectNativeExtension *p_extension);
+ static void register_extension_class(ObjectGDExtension *p_extension);
static void unregister_extension_class(const StringName &p_class);
template <class T>
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 326a9277ff..0ee95835a6 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -2,7 +2,7 @@ proto = """
#define GDVIRTUAL$VER($RET m_name $ARG) \\
StringName _gdvirtual_##m_name##_sn = #m_name;\\
mutable bool _gdvirtual_##m_name##_initialized = false;\\
-mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
+mutable GDExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\
@@ -16,7 +16,8 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
} \\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ /* TODO: C-style cast because GDExtensionStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDExtensionStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
@@ -40,7 +41,8 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\
return _script_instance->has_method(_gdvirtual_##m_name##_sn);\\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ /* TODO: C-style cast because GDExtensionStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDExtensionStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
@@ -92,7 +94,7 @@ def generate_version(argcount, const=False, returns=False):
argtext += ", "
callsiargs = "Variant vargs[" + str(argcount) + "]={"
callsiargptrs = "\t\tconst Variant *vargptrs[" + str(argcount) + "]={"
- callptrargsptr = "\t\tconst GDNativeTypePtr argptrs[" + str(argcount) + "]={"
+ callptrargsptr = "\t\tGDExtensionConstTypePtr argptrs[" + str(argcount) + "]={"
callptrargs = ""
for i in range(argcount):
if i > 0:
@@ -119,7 +121,7 @@ def generate_version(argcount, const=False, returns=False):
s = s.replace("$CALLSIARGPASS", "(const Variant **)vargptrs," + str(argcount))
callptrargsptr += "};\\\n"
s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr)
- s = s.replace("$CALLPTRARGPASS", "(const GDNativeTypePtr*)argptrs")
+ s = s.replace("$CALLPTRARGPASS", "reinterpret_cast<GDExtensionConstTypePtr*>(argptrs)")
else:
s = s.replace("$CALLSIARGS", "")
s = s.replace("$CALLSIARGPASS", "nullptr, 0")
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index 0edc7a90c2..5381c596ce 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -63,7 +63,9 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo info = _gen_argument_type_info(p_argument);
#ifdef DEBUG_METHODS_ENABLED
- info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ if (info.name.is_empty()) {
+ info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ }
#endif
return info;
}
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 0d3e40f709..0f1366aefd 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -110,8 +110,8 @@ public:
_FORCE_INLINE_ int get_argument_count() const { return argument_count; };
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) = 0;
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) = 0;
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const = 0;
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const = 0;
StringName get_name() const;
void set_name(const StringName &p_name);
@@ -158,7 +158,7 @@ public:
}
#endif
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
ERR_FAIL(); // Can't call.
}
@@ -210,7 +210,7 @@ class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, v
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
public:
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
(static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)(p_args, p_arg_count, r_error);
return {};
}
@@ -246,7 +246,7 @@ public:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
}
#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
@@ -292,11 +292,6 @@ class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -304,9 +299,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -321,7 +313,7 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
#ifdef TYPED_METHOD_BIND
call_with_variant_args_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
#else
@@ -330,7 +322,7 @@ public:
return Variant();
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args);
#else
@@ -367,11 +359,6 @@ class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -379,9 +366,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -396,7 +380,7 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
#ifdef TYPED_METHOD_BIND
call_with_variant_argsc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
#else
@@ -405,7 +389,7 @@ public:
return Variant();
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args);
#else
@@ -444,11 +428,6 @@ class MethodBindTR : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -466,9 +445,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -481,7 +457,7 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
Variant ret;
#ifdef TYPED_METHOD_BIND
call_with_variant_args_ret_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
@@ -491,7 +467,7 @@ public:
return ret;
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
#else
@@ -531,11 +507,6 @@ class MethodBindTRC : public MethodBind {
(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -553,9 +524,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -568,7 +536,7 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
Variant ret;
#ifdef TYPED_METHOD_BIND
call_with_variant_args_retc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
@@ -578,7 +546,7 @@ public:
return ret;
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
#else
@@ -615,11 +583,6 @@ class MethodBindTS : public MethodBind {
void (*function)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -627,9 +590,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -644,13 +604,13 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
(void)p_object; // unused
call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
return Variant();
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
(void)p_object;
(void)r_ret;
call_with_ptr_args_static_method(function, p_args);
@@ -678,11 +638,6 @@ class MethodBindTRS : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -690,9 +645,6 @@ protected:
return GetTypeInfo<R>::VARIANT_TYPE;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
@@ -715,13 +667,13 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
Variant ret;
call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
return ret;
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) override {
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override {
(void)p_object;
call_with_ptr_args_static_method_ret(function, p_args, r_ret);
}
diff --git a/core/object/object.cpp b/core/object/object.cpp
index c275164b14..cfac36127c 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -233,7 +233,7 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
- if (_extension->set(_extension_instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value)) {
+ if (_extension->set(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (const GDExtensionVariantPtr)&p_value)) {
if (r_valid) {
*r_valid = true;
}
@@ -321,7 +321,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
- if (_extension->get(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
+ if (_extension->get(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
if (r_valid) {
*r_valid = true;
}
@@ -477,7 +477,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (_extension) {
- const ObjectNativeExtension *current_extension = _extension;
+ const ObjectGDExtension *current_extension = _extension;
while (current_extension) {
p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
@@ -487,7 +487,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (_extension && _extension->get_property_list) {
uint32_t pcount;
- const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
+ const GDExtensionPropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(pinfo[i]));
}
@@ -533,7 +533,7 @@ bool Object::property_can_revert(const StringName &p_name) const {
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
if (_extension && _extension->property_can_revert) {
- if (_extension->property_can_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name)) {
+ if (_extension->property_can_revert(_extension_instance, (const GDExtensionStringNamePtr)&p_name)) {
return true;
}
}
@@ -559,7 +559,7 @@ Variant Object::property_get_revert(const StringName &p_name) const {
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
if (_extension && _extension->property_get_revert) {
- if (_extension->property_get_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
+ if (_extension->property_get_revert(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
return ret;
}
}
@@ -808,7 +808,8 @@ String Object::to_string() {
}
if (_extension && _extension->to_string) {
String ret;
- _extension->to_string(_extension_instance, &ret);
+ GDExtensionBool is_valid;
+ _extension->to_string(_extension_instance, &is_valid, &ret);
return ret;
}
return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
@@ -1468,10 +1469,12 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
- ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind);
- ClassDB::bind_method(D_METHOD("get_indexed", "property"), &Object::_get_indexed_bind);
+ ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
+ ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
+ ClassDB::bind_method(D_METHOD("property_can_revert", "property"), &Object::property_can_revert);
+ ClassDB::bind_method(D_METHOD("property_get_revert", "property"), &Object::property_get_revert);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
ClassDB::bind_method(D_METHOD("to_string"), &Object::to_string);
ClassDB::bind_method(D_METHOD("get_instance_id"), &Object::get_instance_id);
@@ -1698,7 +1701,7 @@ uint32_t Object::get_edited_version() const {
}
#endif
-void Object::set_instance_binding(void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks) {
+void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
// This is only meant to be used on creation by the binder.
ERR_FAIL_COND(_instance_bindings != nullptr);
_instance_bindings = (InstanceBinding *)memalloc(sizeof(InstanceBinding));
@@ -1709,7 +1712,7 @@ void Object::set_instance_binding(void *p_token, void *p_binding, const GDNative
_instance_binding_count = 1;
}
-void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
+void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
void *binding = nullptr;
_instance_binding_mutex.lock();
for (uint32_t i = 0; i < _instance_binding_count; i++) {
@@ -1856,6 +1859,46 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
}
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ if (p_idx == 0) {
+ if (p_function == "connect" || p_function == "is_connected" || p_function == "disconnect" || p_function == "emit_signal" || p_function == "has_signal") {
+ List<MethodInfo> signals;
+ get_signal_list(&signals);
+ for (const MethodInfo &E : signals) {
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "call" || p_function == "call_deferred" || p_function == "callv" || p_function == "has_method") {
+ List<MethodInfo> methods;
+ get_method_list(&methods);
+ for (const MethodInfo &E : methods) {
+ if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
+ continue;
+ }
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "set" || p_function == "set_deferred" || p_function == "get") {
+ List<PropertyInfo> properties;
+ get_property_list(&properties);
+ for (const PropertyInfo &E : properties) {
+ if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
+ r_options->push_back(E.name.quote());
+ }
+ }
+ } else if (p_function == "set_meta" || p_function == "get_meta" || p_function == "has_meta" || p_function == "remove_meta") {
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ r_options->push_back(String(K.key).quote());
+ }
+ }
+ } else if (p_idx == 2) {
+ if (p_function == "connect") {
+ // Ideally, the constants should be inferred by the parameter.
+ // But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
+ List<StringName> constants;
+ ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
+ for (const StringName &E : constants) {
+ r_options->push_back(String(E));
+ }
+ }
+ }
}
SpinLock ObjectDB::spin_lock;
diff --git a/core/object/object.h b/core/object/object.h
index 5ba5453b31..d52cf7d62e 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -31,7 +31,7 @@
#ifndef OBJECT_H
#define OBJECT_H
-#include "core/extension/gdnative_interface.h"
+#include "core/extension/gdextension_interface.h"
#include "core/object/message_queue.h"
#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
@@ -71,8 +71,6 @@ enum PropertyHint {
PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines
PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties
PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
- PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
- PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
PROPERTY_HINT_OBJECT_ID,
PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose
PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts)
@@ -89,8 +87,8 @@ enum PropertyHint {
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_GLOBAL_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_INT_IS_OBJECTID,
- PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
+ PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_LOCALE_ID,
PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_NODE_TYPE, ///< a node object type
@@ -115,25 +113,24 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_RESTART_IF_CHANGED = 1 << 11,
PROPERTY_USAGE_SCRIPT_VARIABLE = 1 << 12,
PROPERTY_USAGE_STORE_IF_NULL = 1 << 13,
- PROPERTY_USAGE_ANIMATE_AS_TRIGGER = 1 << 14,
- PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 1 << 15,
- PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 16,
- PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 17,
- PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 18,
- PROPERTY_USAGE_INTERNAL = 1 << 19,
- PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE = 1 << 20, // If the object is duplicated also this property will be duplicated.
- PROPERTY_USAGE_HIGH_END_GFX = 1 << 21,
- PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 22,
- PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 23,
- PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 24, // Used in inspector to increment property when keyed in animation player.
- PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 25, // when loading, the resource for this property can be set at the end of loading.
- PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 26, // For Object properties, instantiate them when creating in editor.
- PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 27, //for project or editor settings, show when basic settings are selected.
- PROPERTY_USAGE_READ_ONLY = 1 << 28, // Mark a property as read-only in the inspector.
- PROPERTY_USAGE_ARRAY = 1 << 29, // Used in the inspector to group properties as elements of an array.
+ PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 1 << 14,
+ PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 15,
+ PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 16,
+ PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 17,
+ PROPERTY_USAGE_INTERNAL = 1 << 18,
+ PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE = 1 << 19, // If the object is duplicated also this property will be duplicated.
+ PROPERTY_USAGE_HIGH_END_GFX = 1 << 20,
+ PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 21,
+ PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 22,
+ PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 23, // Used in inspector to increment property when keyed in animation player.
+ PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 24, // when loading, the resource for this property can be set at the end of loading.
+ PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 25, // For Object properties, instantiate them when creating in editor.
+ PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 26, //for project or editor settings, show when basic settings are selected.
+ PROPERTY_USAGE_READ_ONLY = 1 << 27, // Mark a property as read-only in the inspector.
+ PROPERTY_USAGE_ARRAY = 1 << 28, // Used in the inspector to group properties as elements of an array.
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR,
- PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNATIONALIZED,
+ PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNATIONALIZED,
PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE,
};
@@ -151,6 +148,10 @@ enum PropertyUsageFlags {
#define ADD_ARRAY_COUNT_WITH_USAGE_FLAGS(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix, m_property_usage_flags) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix, m_property_usage_flags)
#define ADD_ARRAY(m_array_path, m_prefix) ClassDB::add_property_array(get_class_static(), m_array_path, m_prefix)
+// Helper macro to use with PROPERTY_HINT_ARRAY_TYPE for arrays of specific resources:
+// PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")
+#define MAKE_RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type)
+
struct PropertyInfo {
Variant::Type type = Variant::NIL;
String name;
@@ -190,12 +191,12 @@ struct PropertyInfo {
type(Variant::OBJECT),
class_name(p_class_name) {}
- explicit PropertyInfo(const GDNativePropertyInfo &pinfo) :
+ explicit PropertyInfo(const GDExtensionPropertyInfo &pinfo) :
type((Variant::Type)pinfo.type),
- name(pinfo.name),
- class_name(pinfo.class_name), // can be null
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ class_name(*reinterpret_cast<StringName *>(pinfo.class_name)),
hint((PropertyHint)pinfo.hint),
- hint_string(pinfo.hint_string), // can be null
+ hint_string(*reinterpret_cast<String *>(pinfo.hint_string)),
usage(pinfo.usage) {}
bool operator==(const PropertyInfo &p_info) const {
@@ -242,6 +243,20 @@ struct MethodInfo {
MethodInfo() {}
+ explicit MethodInfo(const GDExtensionMethodInfo &pinfo) :
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ return_val(PropertyInfo(pinfo.return_value)),
+ flags(pinfo.flags),
+ id(pinfo.id) {
+ for (uint32_t j = 0; j < pinfo.argument_count; j++) {
+ arguments.push_back(PropertyInfo(pinfo.arguments[j]));
+ }
+ const Variant *def_values = (const Variant *)pinfo.default_arguments;
+ for (uint32_t j = 0; j < pinfo.default_argument_count; j++) {
+ default_arguments.push_back(def_values[j]);
+ }
+ }
+
void _push_params(const PropertyInfo &p_param) {
arguments.push_back(p_param);
}
@@ -286,29 +301,31 @@ struct MethodInfo {
}
};
-// API used to extend in GDNative and other C compatible compiled languages.
+// API used to extend in GDExtension and other C compatible compiled languages.
class MethodBind;
-struct ObjectNativeExtension {
- ObjectNativeExtension *parent = nullptr;
- List<ObjectNativeExtension *> children;
+struct ObjectGDExtension {
+ ObjectGDExtension *parent = nullptr;
+ List<ObjectGDExtension *> children;
StringName parent_class_name;
StringName class_name;
bool editor_class = false;
- GDNativeExtensionClassSet set;
- GDNativeExtensionClassGet get;
- GDNativeExtensionClassGetPropertyList get_property_list;
- GDNativeExtensionClassFreePropertyList free_property_list;
- GDNativeExtensionClassPropertyCanRevert property_can_revert;
- GDNativeExtensionClassPropertyGetRevert property_get_revert;
- GDNativeExtensionClassNotification notification;
- GDNativeExtensionClassToString to_string;
- GDNativeExtensionClassReference reference;
- GDNativeExtensionClassReference unreference;
- GDNativeExtensionClassGetRID get_rid;
+ bool is_virtual = false;
+ bool is_abstract = false;
+ GDExtensionClassSet set;
+ GDExtensionClassGet get;
+ GDExtensionClassGetPropertyList get_property_list;
+ GDExtensionClassFreePropertyList free_property_list;
+ GDExtensionClassPropertyCanRevert property_can_revert;
+ GDExtensionClassPropertyGetRevert property_get_revert;
+ GDExtensionClassNotification notification;
+ GDExtensionClassToString to_string;
+ GDExtensionClassReference reference;
+ GDExtensionClassReference unreference;
+ GDExtensionClassGetRID get_rid;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
- const ObjectNativeExtension *e = this;
+ const ObjectGDExtension *e = this;
while (e) {
if (p_class == e->class_name.operator String()) {
return true;
@@ -319,9 +336,9 @@ struct ObjectNativeExtension {
}
void *class_userdata = nullptr;
- GDNativeExtensionClassCreateInstance create_instance;
- GDNativeExtensionClassFreeInstance free_instance;
- GDNativeExtensionClassGetVirtual get_virtual;
+ GDExtensionClassCreateInstance create_instance;
+ GDExtensionClassFreeInstance free_instance;
+ GDExtensionClassGetVirtual get_virtual;
};
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
@@ -539,6 +556,7 @@ public:
CONNECT_PERSIST = 2, // hint for scene to save this connection
CONNECT_ONE_SHOT = 4,
CONNECT_REFERENCE_COUNTED = 8,
+ CONNECT_INHERITED = 16, // Used in editor builds.
};
struct Connection {
@@ -561,7 +579,7 @@ private:
friend bool predelete_handler(Object *);
friend void postinitialize_handler(Object *);
- ObjectNativeExtension *_extension = nullptr;
+ ObjectGDExtension *_extension = nullptr;
GDExtensionClassInstancePtr _extension_instance = nullptr;
struct SignalData {
@@ -619,8 +637,8 @@ private:
struct InstanceBinding {
void *binding = nullptr;
void *token = nullptr;
- GDNativeInstanceBindingFreeCallback free_callback = nullptr;
- GDNativeInstanceBindingReferenceCallback reference_callback = nullptr;
+ GDExtensionInstanceBindingFreeCallback free_callback = nullptr;
+ GDExtensionInstanceBindingReferenceCallback reference_callback = nullptr;
};
InstanceBinding *_instance_bindings = nullptr;
uint32_t _instance_binding_count = 0;
@@ -644,8 +662,8 @@ protected:
return can_die;
}
- friend class NativeExtensionMethodBind;
- _ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; }
+ friend class GDExtensionMethodBind;
+ _ALWAYS_INLINE_ const ObjectGDExtension *_get_extension() const { return _extension; }
_ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; }
virtual void _initialize_classv() { initialize_class(); }
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
@@ -899,9 +917,9 @@ public:
#endif
// Used by script languages to store binding data.
- void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
+ void *get_instance_binding(void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks);
// Used on creation by binding only.
- void set_instance_binding(void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
+ void set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks);
bool has_instance_binding(void *p_token);
void clear_internal_resource_paths();
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 71790fb825..411c589739 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -253,12 +253,14 @@ public:
template <class T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
+ // p_ptr points to a RefCounted object
return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr)));
}
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
+ // p_ptr points to an EncodeT object which is a Ref<T> object.
*(const_cast<Ref<RefCounted> *>(reinterpret_cast<const Ref<RefCounted> *>(p_ptr))) = p_val;
}
};
@@ -268,6 +270,7 @@ struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
+ // p_ptr points to a RefCounted object
return Ref<T>((T *)p_ptr);
}
};
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 5a3413512d..36a0d03aaf 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -166,6 +166,7 @@ ScriptLanguage *ScriptServer::get_language(int p_idx) {
}
void ScriptServer::register_language(ScriptLanguage *p_language) {
+ ERR_FAIL_NULL(p_language);
ERR_FAIL_COND(_language_count >= MAX_LANGUAGES);
_languages[_language_count++] = p_language;
}
@@ -183,10 +184,10 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
}
void ScriptServer::init_languages() {
- { //load global classes
+ { // Load global classes.
global_classes_clear();
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
+ Array script_classes = GLOBAL_GET("_global_script_classes");
for (int i = 0; i < script_classes.size(); i++) {
Dictionary c = script_classes[i];
@@ -304,7 +305,7 @@ void ScriptServer::save_global_classes() {
Array old;
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ old = GLOBAL_GET("_global_script_classes");
}
if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
return;
@@ -408,7 +409,9 @@ bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_v
if (values.has(p_name)) {
Variant defval;
if (script->get_property_default_value(p_name, defval)) {
- if (defval == p_value) {
+ // The evaluate function ensures that a NIL variant is equal to e.g. an empty Resource.
+ // Simply doing defval == p_value does not do this.
+ if (Variant::evaluate(Variant::OP_EQUAL, defval, p_value)) {
values.erase(p_name);
return true;
}
@@ -418,7 +421,7 @@ bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_v
} else {
Variant defval;
if (script->get_property_default_value(p_name, defval)) {
- if (defval != p_value) {
+ if (Variant::evaluate(Variant::OP_NOT_EQUAL, defval, p_value)) {
values[p_name] = p_value;
}
return true;
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 7e74f6a2be..0ecd98152a 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -43,7 +43,7 @@ class ScriptExtension : public Script {
protected:
EXBIND0R(bool, editor_can_reload_from_file)
- GDVIRTUAL1(_placeholder_erased, GDNativePtr<void>)
+ GDVIRTUAL1(_placeholder_erased, GDExtensionPtr<void>)
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override {
GDVIRTUAL_CALL(_placeholder_erased, p_placeholder);
}
@@ -56,15 +56,15 @@ public:
EXBIND1RC(bool, inherits_script, const Ref<Script> &)
EXBIND0RC(StringName, get_instance_base_type)
- GDVIRTUAL1RC(GDNativePtr<void>, _instance_create, Object *)
+ GDVIRTUAL1RC(GDExtensionPtr<void>, _instance_create, Object *)
virtual ScriptInstance *instance_create(Object *p_this) override {
- GDNativePtr<void> ret = nullptr;
+ GDExtensionPtr<void> ret = nullptr;
GDVIRTUAL_REQUIRED_CALL(_instance_create, p_this, ret);
return reinterpret_cast<ScriptInstance *>(ret.operator void *());
}
- GDVIRTUAL1RC(GDNativePtr<void>, _placeholder_instance_create, Object *)
+ GDVIRTUAL1RC(GDExtensionPtr<void>, _placeholder_instance_create, Object *)
PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) override {
- GDNativePtr<void> ret = nullptr;
+ GDExtensionPtr<void> ret = nullptr;
GDVIRTUAL_REQUIRED_CALL(_placeholder_instance_create, p_this, ret);
return reinterpret_cast<PlaceHolderScriptInstance *>(ret.operator void *());
}
@@ -82,9 +82,10 @@ public:
GDVIRTUAL_REQUIRED_CALL(_get_documentation, doc);
Vector<DocData::ClassDoc> class_doc;
-#ifndef _MSC_VER
-#warning missing conversion from documentation to ClassDoc
-#endif
+ for (int i = 0; i < doc.size(); i++) {
+ class_doc.append(DocData::ClassDoc::from_dict(doc[i]));
+ }
+
return class_doc;
}
#endif // TOOLS_ENABLED
@@ -481,10 +482,10 @@ public:
}
}
}
- GDVIRTUAL1R(GDNativePtr<void>, _debug_get_stack_level_instance, int)
+ GDVIRTUAL1R(GDExtensionPtr<void>, _debug_get_stack_level_instance, int)
virtual ScriptInstance *debug_get_stack_level_instance(int p_level) override {
- GDNativePtr<void> ret = nullptr;
+ GDExtensionPtr<void> ret = nullptr;
GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_instance, p_level, ret);
return reinterpret_cast<ScriptInstance *>(ret.operator void *());
}
@@ -577,7 +578,7 @@ public:
EXBIND0(profiling_start)
EXBIND0(profiling_stop)
- GDVIRTUAL2R(int, _profiling_get_accumulated_data, GDNativePtr<ScriptLanguageExtensionProfilingInfo>, int)
+ GDVIRTUAL2R(int, _profiling_get_accumulated_data, GDExtensionPtr<ScriptLanguageExtensionProfilingInfo>, int)
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override {
int ret = 0;
@@ -585,7 +586,7 @@ public:
return ret;
}
- GDVIRTUAL2R(int, _profiling_get_frame_data, GDNativePtr<ScriptLanguageExtensionProfilingInfo>, int)
+ GDVIRTUAL2R(int, _profiling_get_frame_data, GDExtensionPtr<ScriptLanguageExtensionProfilingInfo>, int)
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override {
int ret = 0;
@@ -593,15 +594,15 @@ public:
return ret;
}
- GDVIRTUAL1R(GDNativePtr<void>, _alloc_instance_binding_data, Object *)
+ GDVIRTUAL1R(GDExtensionPtr<void>, _alloc_instance_binding_data, Object *)
virtual void *alloc_instance_binding_data(Object *p_object) override {
- GDNativePtr<void> ret = nullptr;
+ GDExtensionPtr<void> ret = nullptr;
GDVIRTUAL_REQUIRED_CALL(_alloc_instance_binding_data, p_object, ret);
return ret.operator void *();
}
- GDVIRTUAL1(_free_instance_binding_data, GDNativePtr<void>)
+ GDVIRTUAL1(_free_instance_binding_data, GDExtensionPtr<void>)
virtual void free_instance_binding_data(void *p_data) override {
GDVIRTUAL_REQUIRED_CALL(_free_instance_binding_data, p_data);
@@ -638,8 +639,8 @@ VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionLocation)
class ScriptInstanceExtension : public ScriptInstance {
public:
- const GDNativeExtensionScriptInstanceInfo *native_info;
- GDNativeExtensionScriptInstanceDataPtr instance = nullptr;
+ const GDExtensionScriptInstanceInfo *native_info;
+ GDExtensionScriptInstanceDataPtr instance = nullptr;
// There should not be warnings on explicit casts.
#if defined(__GNUC__) && !defined(__clang__)
@@ -649,20 +650,20 @@ public:
virtual bool set(const StringName &p_name, const Variant &p_value) override {
if (native_info->set_func) {
- return native_info->set_func(instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value);
+ return native_info->set_func(instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionConstVariantPtr)&p_value);
}
return false;
}
virtual bool get(const StringName &p_name, Variant &r_ret) const override {
if (native_info->get_func) {
- return native_info->get_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ return native_info->get_func(instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&r_ret);
}
return false;
}
virtual void get_property_list(List<PropertyInfo> *p_list) const override {
if (native_info->get_property_list_func) {
uint32_t pcount;
- const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount);
+ const GDExtensionPropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount);
#ifdef TOOLS_ENABLED
Ref<Script> script = get_script();
@@ -681,12 +682,11 @@ public:
}
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override {
if (native_info->get_property_type_func) {
- GDNativeBool is_valid = 0;
- GDNativeVariantType type = native_info->get_property_type_func(instance, (const GDNativeStringNamePtr)&p_name, &is_valid);
+ GDExtensionBool is_valid = 0;
+ GDExtensionVariantType type = native_info->get_property_type_func(instance, (GDExtensionConstStringNamePtr)&p_name, &is_valid);
if (r_is_valid) {
*r_is_valid = is_valid != 0;
}
-
return Variant::Type(type);
}
return Variant::NIL;
@@ -694,13 +694,13 @@ public:
virtual bool property_can_revert(const StringName &p_name) const override {
if (native_info->property_can_revert_func) {
- return native_info->property_can_revert_func(instance, (const GDNativeStringNamePtr)&p_name);
+ return native_info->property_can_revert_func(instance, (GDExtensionConstStringNamePtr)&p_name);
}
return false;
}
virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override {
if (native_info->property_get_revert_func) {
- return native_info->property_get_revert_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ return native_info->property_get_revert_func(instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&r_ret);
}
return false;
}
@@ -711,7 +711,7 @@ public:
}
return nullptr;
}
- static void _add_property_with_state(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata) {
+ static void _add_property_with_state(GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value, void *p_userdata) {
List<Pair<StringName, Variant>> *state = (List<Pair<StringName, Variant>> *)p_userdata;
state->push_back(Pair<StringName, Variant>(*(const StringName *)p_name, *(const Variant *)p_value));
}
@@ -724,21 +724,9 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const override {
if (native_info->get_method_list_func) {
uint32_t mcount;
- const GDNativeMethodInfo *minfo = native_info->get_method_list_func(instance, &mcount);
+ const GDExtensionMethodInfo *minfo = native_info->get_method_list_func(instance, &mcount);
for (uint32_t i = 0; i < mcount; i++) {
- MethodInfo m;
- m.name = minfo[i].name;
- m.flags = minfo[i].flags;
- m.id = minfo[i].id;
- m.return_val = PropertyInfo(minfo[i].return_value);
- for (uint32_t j = 0; j < minfo[i].argument_count; j++) {
- m.arguments.push_back(PropertyInfo(minfo[i].arguments[j]));
- }
- const Variant *def_values = (const Variant *)minfo[i].default_arguments;
- for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) {
- m.default_arguments.push_back(def_values[j]);
- }
- p_list->push_back(m);
+ p_list->push_back(MethodInfo(minfo[i]));
}
if (native_info->free_method_list_func) {
native_info->free_method_list_func(instance, minfo);
@@ -747,7 +735,7 @@ public:
}
virtual bool has_method(const StringName &p_method) const override {
if (native_info->has_method_func) {
- return native_info->has_method_func(instance, (GDNativeStringNamePtr)&p_method);
+ return native_info->has_method_func(instance, (GDExtensionStringNamePtr)&p_method);
}
return false;
}
@@ -755,8 +743,8 @@ public:
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
Variant ret;
if (native_info->call_func) {
- GDNativeCallError ce;
- native_info->call_func(instance, (const GDNativeStringNamePtr)&p_method, (const GDNativeVariantPtr *)p_args, p_argcount, (GDNativeVariantPtr)&ret, &ce);
+ GDExtensionCallError ce;
+ native_info->call_func(instance, (GDExtensionConstStringNamePtr)&p_method, (GDExtensionConstVariantPtr *)p_args, p_argcount, (GDExtensionVariantPtr)&ret, &ce);
r_error.error = Callable::CallError::Error(ce.error);
r_error.argument = ce.argument;
r_error.expected = ce.expected;
@@ -771,8 +759,9 @@ public:
}
virtual String to_string(bool *r_valid) override {
if (native_info->to_string_func) {
- GDNativeBool valid;
- String ret = native_info->to_string_func(instance, &valid);
+ GDExtensionBool valid;
+ String ret;
+ native_info->to_string_func(instance, &valid, reinterpret_cast<GDExtensionStringPtr>(&ret));
if (r_valid) {
*r_valid = valid != 0;
}
@@ -795,7 +784,7 @@ public:
virtual Ref<Script> get_script() const override {
if (native_info->get_script_func) {
- GDNativeObjectPtr script = native_info->get_script_func(instance);
+ GDExtensionObjectPtr script = native_info->get_script_func(instance);
return Ref<Script>(reinterpret_cast<Script *>(script));
}
return Ref<Script>();
@@ -810,7 +799,7 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) override {
if (native_info->set_fallback_func) {
- bool ret = native_info->set_fallback_func(instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value);
+ bool ret = native_info->set_fallback_func(instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionConstVariantPtr)&p_value);
if (r_valid) {
*r_valid = ret;
}
@@ -819,7 +808,7 @@ public:
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid) override {
Variant ret;
if (native_info->get_fallback_func) {
- bool valid = native_info->get_fallback_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret);
+ bool valid = native_info->get_fallback_func(instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret);
if (r_valid) {
*r_valid = valid;
}
@@ -829,7 +818,7 @@ public:
virtual ScriptLanguage *get_language() override {
if (native_info->get_language_func) {
- GDNativeExtensionScriptLanguagePtr lang = native_info->get_language_func(instance);
+ GDExtensionScriptLanguagePtr lang = native_info->get_language_func(instance);
return reinterpret_cast<ScriptLanguage *>(lang);
}
return nullptr;
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index aa66e86bc0..9f8a1de697 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -423,6 +423,10 @@ String UndoRedo::get_current_action_name() const {
return actions[current_action].name;
}
+int UndoRedo::get_action_level() const {
+ return action_level;
+}
+
bool UndoRedo::has_undo() const {
return current_action >= 0;
}
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index c7c58697c3..9c6d2d10ed 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -120,6 +120,7 @@ public:
bool redo();
bool undo();
String get_current_action_name() const;
+ int get_action_level() const;
int get_history_count();
int get_current_action();
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index 9b3dc6833e..0218a4c8f6 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -402,7 +402,9 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
}
}
- groups.erase(p_group); // Threads do not access this, so safe to erase here.
+ task_mutex.lock(); // This mutex is needed when Physics 2D and/or 3D is selected to run on a separate thread.
+ groups.erase(p_group);
+ task_mutex.unlock();
}
void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) {
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index a96e1989f9..c0504a174c 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -65,21 +65,15 @@ void MainLoop::initialize() {
}
bool MainLoop::physics_process(double p_time) {
- bool quit;
- if (GDVIRTUAL_CALL(_physics_process, p_time, quit)) {
- return quit;
- }
-
- return false;
+ bool quit = false;
+ GDVIRTUAL_CALL(_physics_process, p_time, quit);
+ return quit;
}
bool MainLoop::process(double p_time) {
- bool quit;
- if (GDVIRTUAL_CALL(_process, p_time, quit)) {
- return quit;
- }
-
- return false;
+ bool quit = false;
+ GDVIRTUAL_CALL(_process, p_time, quit);
+ return quit;
}
void MainLoop::finalize() {
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index 410b62068a..79eef95ef2 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -86,11 +86,6 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
if (length >= 2 + param_position) {
event->set_pitch(data[param_position]);
event->set_velocity(data[param_position + 1]);
-
- if (event->get_message() == MIDIMessage::NOTE_ON && event->get_velocity() == 0) {
- // https://www.midi.org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on
- event->set_message(MIDIMessage::NOTE_OFF);
- }
}
break;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index bbb2a94fe7..6b199e883f 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -155,10 +155,6 @@ int OS::get_process_id() const {
return -1;
}
-void OS::vibrate_handheld(int p_duration_ms) {
- WARN_PRINT("vibrate_handheld() only works with Android, iOS and Web");
-}
-
bool OS::is_stdout_verbose() const {
return _verbose_stdout;
}
@@ -353,20 +349,36 @@ bool OS::has_feature(const String &p_feature) {
if (p_feature == "debug") {
return true;
}
+#endif // DEBUG_ENABLED
+
+#ifdef TOOLS_ENABLED
+ if (p_feature == "editor") {
+ return true;
+ }
#else
- if (p_feature == "release") {
+ if (p_feature == "template") {
return true;
}
-#endif
-#ifdef TOOLS_ENABLED
- if (p_feature == "editor") {
+#ifdef DEBUG_ENABLED
+ if (p_feature == "template_debug") {
return true;
}
#else
- if (p_feature == "standalone") {
+ if (p_feature == "template_release" || p_feature == "release") {
return true;
}
-#endif
+#endif // DEBUG_ENABLED
+#endif // TOOLS_ENABLED
+
+#ifdef REAL_T_IS_DOUBLE
+ if (p_feature == "double") {
+ return true;
+ }
+#else
+ if (p_feature == "single") {
+ return true;
+ }
+#endif // REAL_T_IS_DOUBLE
if (sizeof(void *) == 8 && p_feature == "64") {
return true;
diff --git a/core/os/os.h b/core/os/os.h
index 1a5e45968d..07e9020a51 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -123,6 +123,8 @@ public:
int get_display_driver_id() const { return _display_driver_id; }
+ virtual Vector<String> get_video_adapter_driver_info() const = 0;
+
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR);
void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
@@ -148,7 +150,8 @@ public:
virtual int get_low_processor_usage_mode_sleep_usec() const;
virtual Vector<String> get_system_fonts() const { return Vector<String>(); };
- virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const { return String(); };
+ virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return String(); };
+ virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return Vector<String>(); };
virtual String get_executable_path() const;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0;
@@ -156,7 +159,7 @@ public:
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
virtual bool is_process_running(const ProcessID &p_pid) const = 0;
- virtual void vibrate_handheld(int p_duration_ms = 500);
+ virtual void vibrate_handheld(int p_duration_ms = 500) {}
virtual Error shell_open(String p_uri);
virtual Error set_cwd(const String &p_cwd);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 2e144a4c9a..7a7e45f752 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -38,8 +38,8 @@
#include "core/crypto/crypto.h"
#include "core/crypto/hashing_context.h"
#include "core/debugger/engine_profiler.h"
-#include "core/extension/native_extension.h"
-#include "core/extension/native_extension_manager.h"
+#include "core/extension/gdextension.h"
+#include "core/extension/gdextension_manager.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
#include "core/input/shortcut.h"
@@ -88,7 +88,7 @@ static Ref<ResourceFormatLoaderImage> resource_format_image;
static Ref<TranslationLoaderPO> resource_format_po;
static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto;
static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto;
-static Ref<NativeExtensionResourceLoader> resource_loader_native_extension;
+static Ref<GDExtensionResourceLoader> resource_loader_gdextension;
static Ref<ResourceFormatSaverJSON> resource_saver_json;
static Ref<ResourceFormatLoaderJSON> resource_loader_json;
@@ -109,7 +109,7 @@ static WorkerThreadPool *worker_thread_pool = nullptr;
extern Mutex _global_mutex;
-static NativeExtensionManager *native_extension_manager = nullptr;
+static GDExtensionManager *gdextension_manager = nullptr;
extern void register_global_constants();
extern void unregister_global_constants();
@@ -256,9 +256,9 @@ void register_core_types() {
GDREGISTER_CLASS(ImageFormatLoaderExtension);
GDREGISTER_ABSTRACT_CLASS(ResourceImporter);
- GDREGISTER_CLASS(NativeExtension);
+ GDREGISTER_CLASS(GDExtension);
- GDREGISTER_ABSTRACT_CLASS(NativeExtensionManager);
+ GDREGISTER_ABSTRACT_CLASS(GDExtensionManager);
GDREGISTER_ABSTRACT_CLASS(ResourceUID);
@@ -266,10 +266,10 @@ void register_core_types() {
resource_uid = memnew(ResourceUID);
- native_extension_manager = memnew(NativeExtensionManager);
+ gdextension_manager = memnew(GDExtensionManager);
- resource_loader_native_extension.instantiate();
- ResourceLoader::add_resource_format_loader(resource_loader_native_extension);
+ resource_loader_gdextension.instantiate();
+ ResourceLoader::add_resource_format_loader(resource_loader_gdextension);
ip = IP::create();
@@ -344,27 +344,27 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", core_bind::EngineDebugger::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("NativeExtensionManager", NativeExtensionManager::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("GDExtensionManager", GDExtensionManager::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceUID", ResourceUID::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("WorkerThreadPool", worker_thread_pool));
}
void register_core_extensions() {
// Hardcoded for now.
- NativeExtension::initialize_native_extensions();
- native_extension_manager->load_extensions();
- native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+ GDExtension::initialize_gdextensions();
+ gdextension_manager->load_extensions();
+ gdextension_manager->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_CORE);
_is_core_extensions_registered = true;
}
void unregister_core_extensions() {
if (_is_core_extensions_registered) {
- native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
+ gdextension_manager->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_CORE);
}
}
void unregister_core_types() {
- memdelete(native_extension_manager);
+ memdelete(gdextension_manager);
memdelete(resource_uid);
memdelete(_resource_loader);
@@ -410,8 +410,8 @@ void unregister_core_types() {
memdelete(ip);
}
- ResourceLoader::remove_resource_format_loader(resource_loader_native_extension);
- resource_loader_native_extension.unref();
+ ResourceLoader::remove_resource_format_loader(resource_loader_gdextension);
+ resource_loader_gdextension.unref();
ResourceLoader::finalize();
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index b130c2fc79..2fb3b54e27 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -267,6 +267,39 @@ StringName OptimizedTranslation::get_message(const StringName &p_src_text, const
}
}
+Vector<String> OptimizedTranslation::get_translated_message_list() const {
+ Vector<String> msgs;
+
+ const int *htr = hash_table.ptr();
+ const uint32_t *htptr = (const uint32_t *)&htr[0];
+ const int *btr = bucket_table.ptr();
+ const uint32_t *btptr = (const uint32_t *)&btr[0];
+ const uint8_t *sr = strings.ptr();
+ const char *sptr = (const char *)&sr[0];
+
+ for (int i = 0; i < hash_table.size(); i++) {
+ uint32_t p = htptr[i];
+ if (p != 0xFFFFFFFF) {
+ const Bucket &bucket = *(const Bucket *)&btptr[p];
+ for (int j = 0; j < bucket.size; j++) {
+ if (bucket.elem[j].comp_size == bucket.elem[j].uncomp_size) {
+ String rstr;
+ rstr.parse_utf8(&sptr[bucket.elem[j].str_offset], bucket.elem[j].uncomp_size);
+ msgs.push_back(rstr);
+ } else {
+ CharString uncomp;
+ uncomp.resize(bucket.elem[j].uncomp_size + 1);
+ smaz_decompress(&sptr[bucket.elem[j].str_offset], bucket.elem[j].comp_size, uncomp.ptrw(), bucket.elem[j].uncomp_size);
+ String rstr;
+ rstr.parse_utf8(uncomp.get_data());
+ msgs.push_back(rstr);
+ }
+ }
+ }
+ }
+ return msgs;
+}
+
StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
// The use of plurals translation is not yet supported in OptimizedTranslation.
return get_message(p_src_text, p_context);
diff --git a/core/string/optimized_translation.h b/core/string/optimized_translation.h
index f3dbfe8f5c..1cd12782d0 100644
--- a/core/string/optimized_translation.h
+++ b/core/string/optimized_translation.h
@@ -81,6 +81,7 @@ protected:
public:
virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
+ virtual Vector<String> get_translated_message_list() const override;
void generate(const Ref<Translation> &p_from);
OptimizedTranslation() {}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 9ee7f2b17b..d1ac91957a 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -59,6 +59,18 @@ Vector<String> Translation::_get_message_list() const {
return msgs;
}
+Vector<String> Translation::get_translated_message_list() const {
+ Vector<String> msgs;
+ msgs.resize(translation_map.size());
+ int idx = 0;
+ for (const KeyValue<StringName, StringName> &E : translation_map) {
+ msgs.set(idx, E.value);
+ idx += 1;
+ }
+
+ return msgs;
+}
+
void Translation::_set_messages(const Dictionary &p_messages) {
List<Variant> keys;
p_messages.get_key_list(&keys);
@@ -140,6 +152,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
+ ClassDB::bind_method(D_METHOD("get_translated_message_list"), &Translation::get_translated_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
ClassDB::bind_method(D_METHOD("_set_messages", "messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
@@ -293,6 +306,10 @@ void TranslationServer::init_locale_info() {
}
String TranslationServer::standardize_locale(const String &p_locale) const {
+ return _standardize_locale(p_locale, false);
+}
+
+String TranslationServer::_standardize_locale(const String &p_locale, bool p_add_defaults) const {
// Replaces '-' with '_' for macOS style locales.
String univ_locale = p_locale.replace("-", "_");
@@ -354,24 +371,26 @@ String TranslationServer::standardize_locale(const String &p_locale) const {
}
// Add script code base on language and country codes for some ambiguous cases.
- if (script_name.is_empty()) {
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang_name) {
- if (country_name.is_empty() || info.supported_countries.has(country_name)) {
- script_name = info.script;
- break;
+ if (p_add_defaults) {
+ if (script_name.is_empty()) {
+ for (int i = 0; i < locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = locale_script_info[i];
+ if (info.name == lang_name) {
+ if (country_name.is_empty() || info.supported_countries.has(country_name)) {
+ script_name = info.script;
+ break;
+ }
}
}
}
- }
- if (!script_name.is_empty() && country_name.is_empty()) {
- // Add conntry code based on script for some ambiguous cases.
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang_name && info.script == script_name) {
- country_name = info.default_country;
- break;
+ if (!script_name.is_empty() && country_name.is_empty()) {
+ // Add conntry code based on script for some ambiguous cases.
+ for (int i = 0; i < locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = locale_script_info[i];
+ if (info.name == lang_name && info.script == script_name) {
+ country_name = info.default_country;
+ break;
+ }
}
}
}
@@ -391,8 +410,8 @@ String TranslationServer::standardize_locale(const String &p_locale) const {
}
int TranslationServer::compare_locales(const String &p_locale_a, const String &p_locale_b) const {
- String locale_a = standardize_locale(p_locale_a);
- String locale_b = standardize_locale(p_locale_b);
+ String locale_a = _standardize_locale(p_locale_a, true);
+ String locale_b = _standardize_locale(p_locale_b, true);
if (locale_a == locale_b) {
// Exact match.
@@ -628,7 +647,7 @@ TranslationServer *TranslationServer::singleton = nullptr;
bool TranslationServer::_load_translations(const String &p_from) {
if (ProjectSettings::get_singleton()->has_setting(p_from)) {
- const Vector<String> &translation_names = ProjectSettings::get_singleton()->get(p_from);
+ const Vector<String> &translation_names = GLOBAL_GET(p_from);
int tcount = translation_names.size();
diff --git a/core/string/translation.h b/core/string/translation.h
index 3f97a8d4fc..5e8344baac 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -64,6 +64,7 @@ public:
virtual void erase_message(const StringName &p_src_text, const StringName &p_context = "");
virtual void get_message_list(List<StringName> *r_messages) const;
virtual int get_message_count() const;
+ virtual Vector<String> get_translated_message_list() const;
Translation() {}
};
@@ -102,6 +103,7 @@ class TranslationServer : public Object {
static TranslationServer *singleton;
bool _load_translations(const String &p_from);
+ String _standardize_locale(const String &p_locale, bool p_add_defaults) const;
StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const;
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index fa656b634d..724c1d42bc 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -103,6 +103,23 @@ void TranslationPO::_set_messages(const Dictionary &p_messages) {
}
}
+Vector<String> TranslationPO::get_translated_message_list() const {
+ Vector<String> msgs;
+ for (const KeyValue<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) {
+ if (E.key != StringName()) {
+ continue;
+ }
+
+ for (const KeyValue<StringName, Vector<StringName>> &E2 : E.value) {
+ for (const StringName &E3 : E2.value) {
+ msgs.push_back(E3);
+ }
+ }
+ }
+
+ return msgs;
+}
+
Vector<String> TranslationPO::_get_message_list() const {
// Return all keys in translation_map.
diff --git a/core/string/translation_po.h b/core/string/translation_po.h
index 7d63af2246..c50ea85744 100644
--- a/core/string/translation_po.h
+++ b/core/string/translation_po.h
@@ -70,6 +70,7 @@ protected:
static void _bind_methods();
public:
+ Vector<String> get_translated_message_list() const override;
void get_message_list(List<StringName> *r_messages) const override;
int get_message_count() const override;
void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "") override;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 6218c21cde..adab6d07c7 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -161,6 +161,18 @@ bool CharString::operator<(const CharString &p_right) const {
return is_str_less(get_data(), p_right.get_data());
}
+bool CharString::operator==(const CharString &p_right) const {
+ if (length() == 0) {
+ // True if both have length 0, false if only p_right has a length
+ return p_right.length() == 0;
+ } else if (p_right.length() == 0) {
+ // False due to unequal length
+ return false;
+ }
+
+ return strcmp(ptr(), p_right.ptr()) == 0;
+}
+
CharString &CharString::operator+=(char p_char) {
const int lhs_len = length();
resize(lhs_len + 2);
@@ -208,37 +220,6 @@ void CharString::copy_from(const char *p_cstr) {
/* String */
/*************************************************************************/
-//kind of poor should be rewritten properly
-String String::word_wrap(int p_chars_per_line) const {
- int from = 0;
- int last_space = 0;
- String ret;
- for (int i = 0; i < length(); i++) {
- if (i - from >= p_chars_per_line) {
- if (last_space == -1) {
- ret += substr(from, i - from + 1) + "\n";
- } else {
- ret += substr(from, last_space - from) + "\n";
- i = last_space; //rewind
- }
- from = i + 1;
- last_space = -1;
- } else if (operator[](i) == ' ' || operator[](i) == '\t') {
- last_space = i;
- } else if (operator[](i) == '\n') {
- ret += substr(from, i - from) + "\n";
- from = i + 1;
- last_space = -1;
- }
- }
-
- if (from < length()) {
- ret += substr(from, length());
- }
-
- return ret;
-}
-
Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const {
// Splits the URL into scheme, host, port, path. Strip credentials when present.
String base = *this;
@@ -1180,9 +1161,14 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
int len = length();
while (true) {
- int end = find(p_splitter, from);
- if (end < 0) {
- end = len;
+ int end;
+ if (p_splitter.is_empty()) {
+ end = from + 1;
+ } else {
+ end = find(p_splitter, from);
+ if (end < 0) {
+ end = len;
+ }
}
if (p_allow_empty || (end > from)) {
if (p_maxsplit <= 0) {
@@ -1223,7 +1209,15 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
break;
}
- int left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+ int left_edge;
+ if (p_splitter.is_empty()) {
+ left_edge = remaining_len - 1;
+ if (left_edge == 0) {
+ left_edge--; // Skip to the < 0 condition.
+ }
+ } else {
+ left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+ }
if (left_edge < 0) {
// no more splitters, we're done
@@ -1243,8 +1237,8 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
return ret;
}
-Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty) const {
- Vector<float> ret;
+Vector<double> String::split_floats(const String &p_splitter, bool p_allow_empty) const {
+ Vector<double> ret;
int from = 0;
int len = length();
@@ -1447,15 +1441,25 @@ String String::num(double p_num, int p_decimals) {
fmt[5] = 'f';
fmt[6] = 0;
}
- char buf[256];
+ // if we want to convert a double with as much decimal places as as
+ // DBL_MAX or DBL_MIN then we would theoretically need a buffer of at least
+ // DBL_MAX_10_EXP + 2 for DBL_MAX and DBL_MAX_10_EXP + 4 for DBL_MIN.
+ // BUT those values where still giving me exceptions, so I tested from
+ // DBL_MAX_10_EXP + 10 incrementing one by one and DBL_MAX_10_EXP + 17 (325)
+ // was the first buffer size not to throw an exception
+ char buf[325];
#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(buf, 256, fmt, p_num);
+ // PLEASE NOTE that, albeit vcrt online reference states that snprintf
+ // should safely truncate the output to the given buffer size, we have
+ // found a case where this is not true, so we should create a buffer
+ // as big as needed
+ snprintf(buf, 325, fmt, p_num);
#else
sprintf(buf, fmt, p_num);
#endif
- buf[255] = 0;
+ buf[324] = 0;
//destroy trailing zeroes
{
bool period = false;
@@ -1567,10 +1571,11 @@ String String::num_real(double p_num, bool p_trailing) {
#else
int decimals = 6;
#endif
- // We want to align the digits to the above sane default, so we only
- // need to subtract log10 for numbers with a positive power of ten.
- if (p_num > 10) {
- decimals -= (int)floor(log10(p_num));
+ // We want to align the digits to the above sane default, so we only need
+ // to subtract log10 for numbers with a positive power of ten magnitude.
+ double abs_num = Math::abs(p_num);
+ if (abs_num > 10) {
+ decimals -= (int)floor(log10(abs_num));
}
return num(p_num, decimals);
}
@@ -2815,7 +2820,7 @@ String String::substr(int p_from, int p_chars) const {
return String(*this);
}
- String s = String();
+ String s;
s.copy_from_unchecked(&get_data()[p_from], p_chars);
return s;
}
@@ -3667,29 +3672,43 @@ bool String::is_network_share_path() const {
String String::simplify_path() const {
String s = *this;
String drive;
- if (s.begins_with("local://")) {
- drive = "local://";
- s = s.substr(8, s.length());
- } else if (s.begins_with("res://")) {
- drive = "res://";
- s = s.substr(6, s.length());
- } else if (s.begins_with("user://")) {
- drive = "user://";
- s = s.substr(7, s.length());
- } else if (is_network_share_path()) {
- drive = s.substr(0, 2);
- s = s.substr(2, s.length() - 2);
- } else if (s.begins_with("/") || s.begins_with("\\")) {
- drive = s.substr(0, 1);
- s = s.substr(1, s.length() - 1);
- } else {
- int p = s.find(":/");
- if (p == -1) {
- p = s.find(":\\");
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = s.find("://");
+ bool found = false;
+ if (p > 0) {
+ bool only_chars = true;
+ for (int i = 0; i < p; i++) {
+ if (!is_ascii_alphanumeric_char(s[i])) {
+ only_chars = false;
+ break;
+ }
+ }
+ if (only_chars) {
+ found = true;
+ drive = s.substr(0, p + 3);
+ s = s.substr(p + 3);
}
- if (p != -1 && p < s.find("/")) {
- drive = s.substr(0, p + 2);
- s = s.substr(p + 2, s.length());
+ }
+ if (!found) {
+ if (is_network_share_path()) {
+ // Network path, beginning with // or \\.
+ drive = s.substr(0, 2);
+ s = s.substr(2);
+ } else if (s.begins_with("/") || s.begins_with("\\")) {
+ // Absolute path.
+ drive = s.substr(0, 1);
+ s = s.substr(1);
+ } else {
+ // Windows-style drive path, like C:/ or C:\.
+ p = s.find(":/");
+ if (p == -1) {
+ p = s.find(":\\");
+ }
+ if (p != -1 && p < s.find("/")) {
+ drive = s.substr(0, p + 2);
+ s = s.substr(p + 2);
+ }
}
}
@@ -3884,7 +3903,6 @@ String String::c_unescape() const {
escaped = escaped.replace("\\v", "\v");
escaped = escaped.replace("\\'", "\'");
escaped = escaped.replace("\\\"", "\"");
- escaped = escaped.replace("\\?", "\?");
escaped = escaped.replace("\\\\", "\\");
return escaped;
@@ -3901,7 +3919,6 @@ String String::c_escape() const {
escaped = escaped.replace("\t", "\\t");
escaped = escaped.replace("\v", "\\v");
escaped = escaped.replace("\'", "\\'");
- escaped = escaped.replace("\?", "\\?");
escaped = escaped.replace("\"", "\\\"");
return escaped;
@@ -4651,10 +4668,10 @@ String String::sprintf(const Array &values, bool *error) const {
double value = values[value_index];
bool is_negative = (value < 0);
String str = String::num(ABS(value), min_decimals);
- bool not_numeric = isinf(value) || isnan(value);
+ const bool is_finite = Math::is_finite(value);
// Pad decimals out.
- if (!not_numeric) {
+ if (is_finite) {
str = str.pad_decimals(min_decimals);
}
@@ -4662,7 +4679,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars;
- String pad_char = (pad_with_zeros && !not_numeric) ? String("0") : String(" "); // Never pad NaN or inf with zeros
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
str = str.rpad(pad_chars_count, pad_char);
} else {
@@ -4713,10 +4730,10 @@ String String::sprintf(const Array &values, bool *error) const {
for (int i = 0; i < count; i++) {
double val = vec[i];
String number_str = String::num(ABS(val), min_decimals);
- bool not_numeric = isinf(val) || isnan(val);
+ const bool is_finite = Math::is_finite(val);
// Pad decimals out.
- if (!not_numeric) {
+ if (is_finite) {
number_str = number_str.pad_decimals(min_decimals);
}
@@ -4724,7 +4741,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
- String pad_char = (pad_with_zeros && !not_numeric) ? String("0") : String(" "); // Never pad NaN or inf with zeros
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
number_str = number_str.rpad(pad_chars_count, pad_char);
} else {
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 4b6568a502..559f679f0f 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -156,6 +156,7 @@ public:
void operator=(const char *p_cstr);
bool operator<(const CharString &p_right) const;
+ bool operator==(const CharString &p_right) const;
CharString &operator+=(char p_char);
int length() const { return size() ? size() - 1 : 0; }
const char *get_data() const;
@@ -345,10 +346,10 @@ public:
String get_slice(String p_splitter, int p_slice) const;
String get_slicec(char32_t p_splitter, int p_slice) const;
- Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
- Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> split_spaces() const;
- Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
+ Vector<double> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
Vector<int> split_ints(const String &p_splitter, bool p_allow_empty = true) const;
Vector<int> split_ints_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
@@ -424,7 +425,6 @@ public:
String c_escape_multiline() const;
String c_unescape() const;
String json_escape() const;
- String word_wrap(int p_chars_per_line) const;
Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const;
String property_name_encode() const;
diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h
index 456a7b01ed..059f30df38 100644
--- a/core/templates/hashfuncs.h
+++ b/core/templates/hashfuncs.h
@@ -310,6 +310,7 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
+ static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.ptr()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index c1bdd6a6bc..53891a9823 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -31,12 +31,14 @@
#include "array.h"
#include "container_type_validate.h"
+#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/search_array.h"
#include "core/templates/vector.h"
#include "core/variant/callable.h"
+#include "core/variant/dictionary.h"
#include "core/variant/variant.h"
class ArrayPrivate {
@@ -200,16 +202,21 @@ uint32_t Array::recursive_hash(int recursion_count) const {
}
bool Array::_assign(const Array &p_array) {
+ bool can_convert = p_array._p->typed.type == Variant::NIL;
+ can_convert |= _p->typed.type == Variant::STRING && p_array._p->typed.type == Variant::STRING_NAME;
+ can_convert |= _p->typed.type == Variant::STRING_NAME && p_array._p->typed.type == Variant::STRING;
+
if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {
//same type or untyped, just reference, should be fine
_ref(p_array);
} else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway
_p->array = p_array._p->array;
- } else if (p_array._p->typed.type == Variant::NIL) { //from untyped to typed, must try to check if they are all valid
+ } else if (can_convert) { //from untyped to typed, must try to check if they are all valid
if (_p->typed.type == Variant::OBJECT) {
//for objects, it needs full validation, either can be converted or fail
for (int i = 0; i < p_array._p->array.size(); i++) {
- if (!_p->typed.validate(p_array._p->array[i], "assign")) {
+ const Variant &element = p_array._p->array[i];
+ if (element.get_type() != Variant::OBJECT || !_p->typed.validate_object(element, "assign")) {
return false;
}
}
@@ -254,16 +261,20 @@ void Array::operator=(const Array &p_array) {
void Array::push_back(const Variant &p_value) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
- ERR_FAIL_COND(!_p->typed.validate(p_value, "push_back"));
- _p->array.push_back(p_value);
+ Variant value = p_value;
+ ERR_FAIL_COND(!_p->typed.validate(value, "push_back"));
+ _p->array.push_back(value);
}
void Array::append_array(const Array &p_array) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
- for (int i = 0; i < p_array.size(); ++i) {
- ERR_FAIL_COND(!_p->typed.validate(p_array[i], "append_array"));
+
+ Vector<Variant> validated_array = p_array._p->array;
+ for (int i = 0; i < validated_array.size(); ++i) {
+ ERR_FAIL_COND(!_p->typed.validate(validated_array.write[i], "append_array"));
}
- _p->array.append_array(p_array._p->array);
+
+ _p->array.append_array(validated_array);
}
Error Array::resize(int p_new_size) {
@@ -273,20 +284,23 @@ Error Array::resize(int p_new_size) {
Error Array::insert(int p_pos, const Variant &p_value) {
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "insert"), ERR_INVALID_PARAMETER);
- return _p->array.insert(p_pos, p_value);
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "insert"), ERR_INVALID_PARAMETER);
+ return _p->array.insert(p_pos, value);
}
void Array::fill(const Variant &p_value) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
- ERR_FAIL_COND(!_p->typed.validate(p_value, "fill"));
- _p->array.fill(p_value);
+ Variant value = p_value;
+ ERR_FAIL_COND(!_p->typed.validate(value, "fill"));
+ _p->array.fill(value);
}
void Array::erase(const Variant &p_value) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
- ERR_FAIL_COND(!_p->typed.validate(p_value, "erase"));
- _p->array.erase(p_value);
+ Variant value = p_value;
+ ERR_FAIL_COND(!_p->typed.validate(value, "erase"));
+ _p->array.erase(value);
}
Variant Array::front() const {
@@ -299,16 +313,40 @@ Variant Array::back() const {
return operator[](_p->array.size() - 1);
}
+Variant Array::pick_random() const {
+ ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
+ return operator[](Math::rand() % _p->array.size());
+}
+
int Array::find(const Variant &p_value, int p_from) const {
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);
- return _p->array.find(p_value, p_from);
+ if (_p->array.size() == 0) {
+ return -1;
+ }
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "find"), -1);
+
+ int ret = -1;
+
+ if (p_from < 0 || size() == 0) {
+ return ret;
+ }
+
+ for (int i = p_from; i < size(); i++) {
+ if (StringLikeVariantComparator::compare(_p->array[i], value)) {
+ ret = i;
+ break;
+ }
+ }
+
+ return ret;
}
int Array::rfind(const Variant &p_value, int p_from) const {
if (_p->array.size() == 0) {
return -1;
}
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "rfind"), -1);
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "rfind"), -1);
if (p_from < 0) {
// Relative offset from the end
@@ -320,7 +358,7 @@ int Array::rfind(const Variant &p_value, int p_from) const {
}
for (int i = p_from; i >= 0; i--) {
- if (_p->array[i] == p_value) {
+ if (StringLikeVariantComparator::compare(_p->array[i], value)) {
return i;
}
}
@@ -328,20 +366,16 @@ int Array::rfind(const Variant &p_value, int p_from) const {
return -1;
}
-int Array::find_last(const Variant &p_value) const {
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find_last"), -1);
- return rfind(p_value);
-}
-
int Array::count(const Variant &p_value) const {
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "count"), 0);
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0);
if (_p->array.size() == 0) {
return 0;
}
int amount = 0;
for (int i = 0; i < _p->array.size(); i++) {
- if (_p->array[i] == p_value) {
+ if (StringLikeVariantComparator::compare(_p->array[i], value)) {
amount++;
}
}
@@ -350,9 +384,10 @@ int Array::count(const Variant &p_value) const {
}
bool Array::has(const Variant &p_value) const {
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "use 'has'"), false);
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "use 'has'"), false);
- return _p->array.find(p_value, 0) != -1;
+ return find(value) != -1;
}
void Array::remove_at(int p_pos) {
@@ -362,9 +397,10 @@ void Array::remove_at(int p_pos) {
void Array::set(int p_idx, const Variant &p_value) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
- ERR_FAIL_COND(!_p->typed.validate(p_value, "set"));
+ Variant value = p_value;
+ ERR_FAIL_COND(!_p->typed.validate(value, "set"));
- operator[](p_idx) = p_value;
+ operator[](p_idx) = value;
}
const Variant &Array::get(int p_idx) const {
@@ -402,6 +438,7 @@ Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {
Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
Array result;
+ result._p->typed = _p->typed;
ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");
@@ -433,6 +470,7 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
Array Array::filter(const Callable &p_callable) const {
Array new_arr;
new_arr.resize(size());
+ new_arr._p->typed = _p->typed;
int accepted_count = 0;
const Variant *argptrs[1];
@@ -585,15 +623,17 @@ void Array::shuffle() {
}
int Array::bsearch(const Variant &p_value, bool p_before) {
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "binary search"), -1);
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "binary search"), -1);
SearchArray<Variant, _ArrayVariantSort> avs;
- return avs.bisect(_p->array.ptrw(), _p->array.size(), p_value, p_before);
+ return avs.bisect(_p->array.ptrw(), _p->array.size(), value, p_before);
}
int Array::bsearch_custom(const Variant &p_value, const Callable &p_callable, bool p_before) {
- ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1);
+ Variant value = p_value;
+ ERR_FAIL_COND_V(!_p->typed.validate(value, "custom binary search"), -1);
- return _p->array.bsearch_custom<CallableComparator>(p_value, p_before, p_callable);
+ return _p->array.bsearch_custom<CallableComparator>(value, p_before, p_callable);
}
void Array::reverse() {
@@ -603,8 +643,9 @@ void Array::reverse() {
void Array::push_front(const Variant &p_value) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
- ERR_FAIL_COND(!_p->typed.validate(p_value, "push_front"));
- _p->array.insert(0, p_value);
+ Variant value = p_value;
+ ERR_FAIL_COND(!_p->typed.validate(value, "push_front"));
+ _p->array.insert(0, value);
}
Variant Array::pop_back() {
diff --git a/core/variant/array.h b/core/variant/array.h
index 3d9a794969..2dd3dde2d1 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -79,6 +79,7 @@ public:
Variant front() const;
Variant back() const;
+ Variant pick_random() const;
void sort();
void sort_custom(const Callable &p_callable);
@@ -89,7 +90,6 @@ public:
int find(const Variant &p_value, int p_from = 0) const;
int rfind(const Variant &p_value, int p_from = -1) const;
- int find_last(const Variant &p_value) const;
int count(const Variant &p_value) const;
bool has(const Variant &p_value) const;
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index f0c3b1ce38..696b27f9f2 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -138,7 +138,7 @@ VARIANT_ENUM_CAST(Vector3::Axis);
VARIANT_ENUM_CAST(Vector3i::Axis);
VARIANT_ENUM_CAST(Vector4::Axis);
VARIANT_ENUM_CAST(Vector4i::Axis);
-VARIANT_ENUM_CAST(Basis::EulerOrder);
+VARIANT_ENUM_CAST(EulerOrder);
VARIANT_ENUM_CAST(Projection::Planes);
VARIANT_ENUM_CAST(Error);
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 0305dc55c3..32770bd663 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -73,6 +73,16 @@ public:
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
Variant callv(const Array &p_arguments) const;
+ template <typename... VarArgs>
+ void call_deferred(VarArgs... p_args) const {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., 0 }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return call_deferredp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
_FORCE_INLINE_ bool is_null() const {
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index 6171c8c88f..9976fce47f 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -74,23 +74,41 @@ struct ContainerTypeValidate {
return true;
}
- _FORCE_INLINE_ bool validate(const Variant &p_variant, const char *p_operation = "use") {
+ // Coerces String and StringName into each other when needed.
+ _FORCE_INLINE_ bool validate(Variant &inout_variant, const char *p_operation = "use") {
if (type == Variant::NIL) {
return true;
}
- ERR_FAIL_COND_V_MSG(type != p_variant.get_type(), false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
- if (type != p_variant.get_type()) {
- return false;
+ if (type != inout_variant.get_type()) {
+ if (inout_variant.get_type() == Variant::NIL && type == Variant::OBJECT) {
+ return true;
+ }
+ if (type == Variant::STRING && inout_variant.get_type() == Variant::STRING_NAME) {
+ inout_variant = String(inout_variant);
+ return true;
+ } else if (type == Variant::STRING_NAME && inout_variant.get_type() == Variant::STRING) {
+ inout_variant = StringName(inout_variant);
+ return true;
+ }
+
+ ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(inout_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
}
if (type != Variant::OBJECT) {
return true;
}
+
+ return validate_object(inout_variant, p_operation);
+ }
+
+ _FORCE_INLINE_ bool validate_object(const Variant &p_variant, const char *p_operation = "use") {
+ ERR_FAIL_COND_V(p_variant.get_type() != Variant::OBJECT, false);
+
#ifdef DEBUG_ENABLED
ObjectID object_id = p_variant;
if (object_id == ObjectID()) {
- return true; //fine its null;
+ return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
@@ -101,7 +119,7 @@ struct ContainerTypeValidate {
}
#endif
if (class_name == StringName()) {
- return true; //all good, no class type requested
+ return true; // All good, no class type requested.
}
StringName obj_class = object->get_class_name();
@@ -110,12 +128,12 @@ struct ContainerTypeValidate {
}
if (script.is_null()) {
- return true; //all good
+ return true; // All good, no script requested.
}
Ref<Script> other_script = object->get_script();
- //check base script..
+ // Check base script..
ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index c1cb782a57..77d9fb0bc2 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -42,7 +42,7 @@
struct DictionaryPrivate {
SafeRefCount refcount;
Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
- HashMap<Variant, Variant, VariantHasher, VariantComparator> variant_map;
+ HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator> variant_map;
};
void Dictionary::get_key_list(List<Variant> *p_keys) const {
@@ -100,24 +100,12 @@ Variant &Dictionary::operator[](const Variant &p_key) {
}
const Variant &Dictionary::operator[](const Variant &p_key) const {
- if (p_key.get_type() == Variant::STRING_NAME) {
- const StringName *sn = VariantInternal::get_string_name(&p_key);
- return _p->variant_map[sn->operator String()];
- } else {
- return _p->variant_map[p_key];
- }
+ // Will not insert key, so no conversion is necessary.
+ return _p->variant_map[p_key];
}
const Variant *Dictionary::getptr(const Variant &p_key) const {
- HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E;
-
- if (p_key.get_type() == Variant::STRING_NAME) {
- const StringName *sn = VariantInternal::get_string_name(&p_key);
- E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
- } else {
- E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
- }
-
+ HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(p_key));
if (!E) {
return nullptr;
}
@@ -125,14 +113,7 @@ const Variant *Dictionary::getptr(const Variant &p_key) const {
}
Variant *Dictionary::getptr(const Variant &p_key) {
- HashMap<Variant, Variant, VariantHasher, VariantComparator>::Iterator E;
-
- if (p_key.get_type() == Variant::STRING_NAME) {
- const StringName *sn = VariantInternal::get_string_name(&p_key);
- E = ((HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
- } else {
- E = ((HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
- }
+ HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E(_p->variant_map.find(p_key));
if (!E) {
return nullptr;
}
@@ -145,14 +126,7 @@ Variant *Dictionary::getptr(const Variant &p_key) {
}
Variant Dictionary::get_valid(const Variant &p_key) const {
- HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E;
-
- if (p_key.get_type() == Variant::STRING_NAME) {
- const StringName *sn = VariantInternal::get_string_name(&p_key);
- E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
- } else {
- E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
- }
+ HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(p_key));
if (!E) {
return Variant();
@@ -178,12 +152,7 @@ bool Dictionary::is_empty() const {
}
bool Dictionary::has(const Variant &p_key) const {
- if (p_key.get_type() == Variant::STRING_NAME) {
- const StringName *sn = VariantInternal::get_string_name(&p_key);
- return _p->variant_map.has(sn->operator String());
- } else {
- return _p->variant_map.has(p_key);
- }
+ return _p->variant_map.has(p_key);
}
bool Dictionary::has_all(const Array &p_keys) const {
@@ -206,12 +175,7 @@ Variant Dictionary::find_key(const Variant &p_value) const {
bool Dictionary::erase(const Variant &p_key) {
ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
- if (p_key.get_type() == Variant::STRING_NAME) {
- const StringName *sn = VariantInternal::get_string_name(&p_key);
- return _p->variant_map.erase(sn->operator String());
- } else {
- return _p->variant_map.erase(p_key);
- }
+ return _p->variant_map.erase(p_key);
}
bool Dictionary::operator==(const Dictionary &p_dictionary) const {
@@ -238,7 +202,7 @@ bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_c
}
recursion_count++;
for (const KeyValue<Variant, Variant> &this_E : _p->variant_map) {
- HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator other_E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&p_dictionary._p->variant_map)->find(this_E.key);
+ HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator other_E(p_dictionary._p->variant_map.find(this_E.key));
if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count)) {
return false;
}
@@ -360,7 +324,7 @@ const Variant *Dictionary::next(const Variant *p_key) const {
}
return nullptr;
}
- HashMap<Variant, Variant, VariantHasher, VariantComparator>::Iterator E = _p->variant_map.find(*p_key);
+ HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E = _p->variant_map.find(*p_key);
if (!E) {
return nullptr;
diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h
index ed68e0f6c9..18670310b0 100644
--- a/core/variant/native_ptr.h
+++ b/core/variant/native_ptr.h
@@ -36,90 +36,90 @@
#include "core/variant/type_info.h"
template <class T>
-struct GDNativeConstPtr {
+struct GDExtensionConstPtr {
const T *data = nullptr;
- GDNativeConstPtr(const T *p_assign) { data = p_assign; }
+ GDExtensionConstPtr(const T *p_assign) { data = p_assign; }
static const char *get_name() { return "const void"; }
operator const T *() const { return data; }
operator Variant() const { return uint64_t(data); }
};
template <class T>
-struct GDNativePtr {
+struct GDExtensionPtr {
T *data = nullptr;
- GDNativePtr(T *p_assign) { data = p_assign; }
+ GDExtensionPtr(T *p_assign) { data = p_assign; }
static const char *get_name() { return "void"; }
operator T *() const { return data; }
operator Variant() const { return uint64_t(data); }
};
-#define GDVIRTUAL_NATIVE_PTR(m_type) \
- template <> \
- struct GDNativeConstPtr<const m_type> { \
- const m_type *data = nullptr; \
- GDNativeConstPtr() {} \
- GDNativeConstPtr(const m_type *p_assign) { data = p_assign; } \
- static const char *get_name() { return "const " #m_type; } \
- operator const m_type *() const { return data; } \
- operator Variant() const { return uint64_t(data); } \
- }; \
- template <> \
- struct VariantCaster<GDNativeConstPtr<const m_type>> { \
- static _FORCE_INLINE_ GDNativeConstPtr<const m_type> cast(const Variant &p_variant) { \
- return GDNativeConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
- } \
- }; \
- template <> \
- struct GDNativePtr<m_type> { \
- m_type *data = nullptr; \
- GDNativePtr() {} \
- GDNativePtr(m_type *p_assign) { data = p_assign; } \
- static const char *get_name() { return #m_type; } \
- operator m_type *() const { return data; } \
- operator Variant() const { return uint64_t(data); } \
- }; \
- template <> \
- struct VariantCaster<GDNativePtr<m_type>> { \
- static _FORCE_INLINE_ GDNativePtr<m_type> cast(const Variant &p_variant) { \
- return GDNativePtr<m_type>((m_type *)p_variant.operator uint64_t()); \
- } \
+#define GDVIRTUAL_NATIVE_PTR(m_type) \
+ template <> \
+ struct GDExtensionConstPtr<const m_type> { \
+ const m_type *data = nullptr; \
+ GDExtensionConstPtr() {} \
+ GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \
+ static const char *get_name() { return "const " #m_type; } \
+ operator const m_type *() const { return data; } \
+ operator Variant() const { return uint64_t(data); } \
+ }; \
+ template <> \
+ struct VariantCaster<GDExtensionConstPtr<const m_type>> { \
+ static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \
+ return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
+ } \
+ }; \
+ template <> \
+ struct GDExtensionPtr<m_type> { \
+ m_type *data = nullptr; \
+ GDExtensionPtr() {} \
+ GDExtensionPtr(m_type *p_assign) { data = p_assign; } \
+ static const char *get_name() { return #m_type; } \
+ operator m_type *() const { return data; } \
+ operator Variant() const { return uint64_t(data); } \
+ }; \
+ template <> \
+ struct VariantCaster<GDExtensionPtr<m_type>> { \
+ static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \
+ return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \
+ } \
};
template <class T>
-struct GetTypeInfo<GDNativeConstPtr<T>> {
+struct GetTypeInfo<GDExtensionConstPtr<T>> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
- return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDNativeConstPtr<T>::get_name());
+ return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDExtensionConstPtr<T>::get_name());
}
};
template <class T>
-struct GetTypeInfo<GDNativePtr<T>> {
+struct GetTypeInfo<GDExtensionPtr<T>> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
- return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDNativePtr<T>::get_name());
+ return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDExtensionPtr<T>::get_name());
}
};
template <class T>
-struct PtrToArg<GDNativeConstPtr<T>> {
- _FORCE_INLINE_ static GDNativeConstPtr<T> convert(const void *p_ptr) {
- return GDNativeConstPtr<T>(reinterpret_cast<const T *>(p_ptr));
+struct PtrToArg<GDExtensionConstPtr<T>> {
+ _FORCE_INLINE_ static GDExtensionConstPtr<T> convert(const void *p_ptr) {
+ return GDExtensionConstPtr<T>(reinterpret_cast<const T *>(p_ptr));
}
typedef const T *EncodeT;
- _FORCE_INLINE_ static void encode(GDNativeConstPtr<T> p_val, void *p_ptr) {
+ _FORCE_INLINE_ static void encode(GDExtensionConstPtr<T> p_val, void *p_ptr) {
*((const T **)p_ptr) = p_val.data;
}
};
template <class T>
-struct PtrToArg<GDNativePtr<T>> {
- _FORCE_INLINE_ static GDNativePtr<T> convert(const void *p_ptr) {
- return GDNativePtr<T>(reinterpret_cast<const T *>(p_ptr));
+struct PtrToArg<GDExtensionPtr<T>> {
+ _FORCE_INLINE_ static GDExtensionPtr<T> convert(const void *p_ptr) {
+ return GDExtensionPtr<T>(reinterpret_cast<const T *>(p_ptr));
}
typedef T *EncodeT;
- _FORCE_INLINE_ static void encode(GDNativePtr<T> p_val, void *p_ptr) {
+ _FORCE_INLINE_ static void encode(GDExtensionPtr<T> p_val, void *p_ptr) {
*((T **)p_ptr) = p_val.data;
}
};
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index e355053296..8e2d150430 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -290,6 +290,7 @@ public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
+ _FORCE_INLINE_ BitField() = default;
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index fbce337359..39b7cbee0d 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -47,146 +47,126 @@ String Variant::get_type_name(Variant::Type p_type) {
switch (p_type) {
case NIL: {
return "Nil";
- } break;
+ }
- // atomic types
+ // Atomic types.
case BOOL: {
return "bool";
- } break;
+ }
case INT: {
return "int";
-
- } break;
+ }
case FLOAT: {
return "float";
-
- } break;
+ }
case STRING: {
return "String";
- } break;
+ }
- // math types
+ // Math types.
case VECTOR2: {
return "Vector2";
- } break;
+ }
case VECTOR2I: {
return "Vector2i";
- } break;
+ }
case RECT2: {
return "Rect2";
- } break;
+ }
case RECT2I: {
return "Rect2i";
- } break;
+ }
case TRANSFORM2D: {
return "Transform2D";
- } break;
+ }
case VECTOR3: {
return "Vector3";
- } break;
+ }
case VECTOR3I: {
return "Vector3i";
- } break;
+ }
case VECTOR4: {
return "Vector4";
- } break;
+ }
case VECTOR4I: {
return "Vector4i";
- } break;
+ }
case PLANE: {
return "Plane";
-
- } break;
+ }
case AABB: {
return "AABB";
- } break;
+ }
case QUATERNION: {
return "Quaternion";
-
- } break;
+ }
case BASIS: {
return "Basis";
-
- } break;
+ }
case TRANSFORM3D: {
return "Transform3D";
-
- } break;
+ }
case PROJECTION: {
return "Projection";
+ }
- } break;
-
- // misc types
+ // Miscellaneous types.
case COLOR: {
return "Color";
-
- } break;
+ }
case RID: {
return "RID";
- } break;
+ }
case OBJECT: {
return "Object";
- } break;
+ }
case CALLABLE: {
return "Callable";
- } break;
+ }
case SIGNAL: {
return "Signal";
- } break;
+ }
case STRING_NAME: {
return "StringName";
-
- } break;
+ }
case NODE_PATH: {
return "NodePath";
-
- } break;
+ }
case DICTIONARY: {
return "Dictionary";
-
- } break;
+ }
case ARRAY: {
return "Array";
+ }
- } break;
-
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
return "PackedByteArray";
-
- } break;
+ }
case PACKED_INT32_ARRAY: {
return "PackedInt32Array";
-
- } break;
+ }
case PACKED_INT64_ARRAY: {
return "PackedInt64Array";
-
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return "PackedFloat32Array";
-
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return "PackedFloat64Array";
-
- } break;
+ }
case PACKED_STRING_ARRAY: {
return "PackedStringArray";
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return "PackedVector2Array";
-
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return "PackedVector3Array";
-
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return "PackedColorArray";
-
- } break;
+ }
default: {
}
}
@@ -880,157 +860,126 @@ bool Variant::is_zero() const {
switch (type) {
case NIL: {
return true;
- } break;
+ }
- // atomic types
+ // Atomic types.
case BOOL: {
return !(_data._bool);
- } break;
+ }
case INT: {
return _data._int == 0;
-
- } break;
+ }
case FLOAT: {
return _data._float == 0;
-
- } break;
+ }
case STRING: {
return *reinterpret_cast<const String *>(_data._mem) == String();
+ }
- } break;
-
- // math types
+ // Math types.
case VECTOR2: {
return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2();
-
- } break;
+ }
case VECTOR2I: {
return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i();
-
- } break;
+ }
case RECT2: {
return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2();
-
- } break;
+ }
case RECT2I: {
return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i();
-
- } break;
+ }
case TRANSFORM2D: {
return *_data._transform2d == Transform2D();
-
- } break;
+ }
case VECTOR3: {
return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3();
-
- } break;
+ }
case VECTOR3I: {
return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i();
-
- } break;
+ }
case VECTOR4: {
return *reinterpret_cast<const Vector4 *>(_data._mem) == Vector4();
-
- } break;
+ }
case VECTOR4I: {
return *reinterpret_cast<const Vector4i *>(_data._mem) == Vector4i();
-
- } break;
+ }
case PLANE: {
return *reinterpret_cast<const Plane *>(_data._mem) == Plane();
-
- } break;
+ }
case AABB: {
return *_data._aabb == ::AABB();
- } break;
+ }
case QUATERNION: {
return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion();
-
- } break;
+ }
case BASIS: {
return *_data._basis == Basis();
-
- } break;
+ }
case TRANSFORM3D: {
return *_data._transform3d == Transform3D();
-
- } break;
+ }
case PROJECTION: {
return *_data._projection == Projection();
+ }
- } break;
-
- // misc types
+ // Miscellaneous types.
case COLOR: {
return *reinterpret_cast<const Color *>(_data._mem) == Color();
-
- } break;
+ }
case RID: {
return *reinterpret_cast<const ::RID *>(_data._mem) == ::RID();
- } break;
+ }
case OBJECT: {
return _get_obj().obj == nullptr;
- } break;
+ }
case CALLABLE: {
return reinterpret_cast<const Callable *>(_data._mem)->is_null();
- } break;
+ }
case SIGNAL: {
return reinterpret_cast<const Signal *>(_data._mem)->is_null();
- } break;
+ }
case STRING_NAME: {
- return *reinterpret_cast<const StringName *>(_data._mem) != StringName();
-
- } break;
+ return *reinterpret_cast<const StringName *>(_data._mem) == StringName();
+ }
case NODE_PATH: {
return reinterpret_cast<const NodePath *>(_data._mem)->is_empty();
-
- } break;
+ }
case DICTIONARY: {
return reinterpret_cast<const Dictionary *>(_data._mem)->is_empty();
-
- } break;
+ }
case ARRAY: {
return reinterpret_cast<const Array *>(_data._mem)->is_empty();
+ }
- } break;
-
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
return PackedArrayRef<uint8_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_INT32_ARRAY: {
return PackedArrayRef<int32_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_INT64_ARRAY: {
return PackedArrayRef<int64_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return PackedArrayRef<float>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return PackedArrayRef<double>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_STRING_ARRAY: {
return PackedArrayRef<String>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return PackedArrayRef<Vector2>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return PackedArrayRef<Vector3>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return PackedArrayRef<Color>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
default: {
}
}
@@ -1042,60 +991,49 @@ bool Variant::is_one() const {
switch (type) {
case NIL: {
return true;
- } break;
+ }
- // atomic types
case BOOL: {
return _data._bool;
- } break;
+ }
case INT: {
return _data._int == 1;
-
- } break;
+ }
case FLOAT: {
return _data._float == 1;
+ }
- } break;
case VECTOR2: {
return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2(1, 1);
-
- } break;
+ }
case VECTOR2I: {
return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i(1, 1);
-
- } break;
+ }
case RECT2: {
return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2(1, 1, 1, 1);
-
- } break;
+ }
case RECT2I: {
return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i(1, 1, 1, 1);
-
- } break;
+ }
case VECTOR3: {
return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3(1, 1, 1);
-
- } break;
+ }
case VECTOR3I: {
return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i(1, 1, 1);
-
- } break;
+ }
case VECTOR4: {
return *reinterpret_cast<const Vector4 *>(_data._mem) == Vector4(1, 1, 1, 1);
-
- } break;
+ }
case VECTOR4I: {
return *reinterpret_cast<const Vector4i *>(_data._mem) == Vector4i(1, 1, 1, 1);
-
- } break;
+ }
case PLANE: {
return *reinterpret_cast<const Plane *>(_data._mem) == Plane(1, 1, 1, 1);
+ }
- } break;
case COLOR: {
return *reinterpret_cast<const Color *>(_data._mem) == Color(1, 1, 1, 1);
-
- } break;
+ }
default: {
return !is_zero();
@@ -1133,10 +1071,10 @@ void Variant::reference(const Variant &p_variant) {
switch (p_variant.type) {
case NIL: {
- // none
+ // None.
} break;
- // atomic types
+ // Atomic types.
case BOOL: {
_data._bool = p_variant._data._bool;
} break;
@@ -1150,7 +1088,7 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, String(*reinterpret_cast<const String *>(p_variant._data._mem)));
} break;
- // math types
+ // Math types.
case VECTOR2: {
memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem)));
} break;
@@ -1202,10 +1140,9 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._projection, Projection(*p_variant._data._projection));
} break;
- // misc types
+ // Miscellaneous types.
case COLOR: {
memnew_placement(_data._mem, Color(*reinterpret_cast<const Color *>(p_variant._data._mem)));
-
} break;
case RID: {
memnew_placement(_data._mem, ::RID(*reinterpret_cast<const ::RID *>(p_variant._data._mem)));
@@ -1224,7 +1161,6 @@ void Variant::reference(const Variant &p_variant) {
_get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
_get_obj().id = p_variant._get_obj().id;
-
} break;
case CALLABLE: {
memnew_placement(_data._mem, Callable(*reinterpret_cast<const Callable *>(p_variant._data._mem)));
@@ -1234,84 +1170,71 @@ void Variant::reference(const Variant &p_variant) {
} break;
case STRING_NAME: {
memnew_placement(_data._mem, StringName(*reinterpret_cast<const StringName *>(p_variant._data._mem)));
-
} break;
case NODE_PATH: {
memnew_placement(_data._mem, NodePath(*reinterpret_cast<const NodePath *>(p_variant._data._mem)));
-
} break;
case DICTIONARY: {
memnew_placement(_data._mem, Dictionary(*reinterpret_cast<const Dictionary *>(p_variant._data._mem)));
-
} break;
case ARRAY: {
memnew_placement(_data._mem, Array(*reinterpret_cast<const Array *>(p_variant._data._mem)));
-
} break;
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<uint8_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<uint8_t>::create();
}
-
} break;
case PACKED_INT32_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<int32_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<int32_t>::create();
}
-
} break;
case PACKED_INT64_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<int64_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<int64_t>::create();
}
-
} break;
case PACKED_FLOAT32_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<float> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<float>::create();
}
-
} break;
case PACKED_FLOAT64_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<double> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<double>::create();
}
-
} break;
case PACKED_STRING_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<String> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<String>::create();
}
-
} break;
case PACKED_VECTOR2_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Vector2> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Vector2>::create();
}
-
} break;
case PACKED_VECTOR3_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Vector3> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Vector3>::create();
}
-
} break;
case PACKED_COLOR_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Color> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Color>::create();
}
-
} break;
default: {
}
@@ -1331,6 +1254,7 @@ void Variant::zero() {
case FLOAT:
this->_data._float = 0;
break;
+
case VECTOR2:
*reinterpret_cast<Vector2 *>(this->_data._mem) = Vector2();
break;
@@ -1361,9 +1285,11 @@ void Variant::zero() {
case QUATERNION:
*reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion();
break;
+
case COLOR:
*reinterpret_cast<Color *>(this->_data._mem) = Color();
break;
+
default:
this->clear();
break;
@@ -1375,15 +1301,8 @@ void Variant::_clear_internal() {
case STRING: {
reinterpret_cast<String *>(_data._mem)->~String();
} break;
- /*
- // no point, they don't allocate memory
- VECTOR3,
- PLANE,
- QUATERNION,
- COLOR,
- VECTOR2,
- RECT2
- */
+
+ // Math types.
case TRANSFORM2D: {
if (_data._transform2d) {
_data._transform2d->~Transform2D();
@@ -1419,7 +1338,8 @@ void Variant::_clear_internal() {
_data._projection = nullptr;
}
} break;
- // misc types
+
+ // Miscellaneous types.
case STRING_NAME: {
reinterpret_cast<StringName *>(_data._mem)->~StringName();
} break;
@@ -1428,7 +1348,7 @@ void Variant::_clear_internal() {
} break;
case OBJECT: {
if (_get_obj().id.is_ref_counted()) {
- //we are safe that there is a reference here
+ // We are safe that there is a reference here.
RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
if (ref_counted->unreference()) {
memdelete(ref_counted);
@@ -1438,8 +1358,8 @@ void Variant::_clear_internal() {
_get_obj().id = ObjectID();
} break;
case RID: {
- // not much need probably
- // Can't seem to use destructor + scoping operator, so hack.
+ // Not much need probably.
+ // HACK: Can't seem to use destructor + scoping operator, so hack.
typedef ::RID RID_Class;
reinterpret_cast<RID_Class *>(_data._mem)->~RID_Class();
} break;
@@ -1455,7 +1375,8 @@ void Variant::_clear_internal() {
case ARRAY: {
reinterpret_cast<Array *>(_data._mem)->~Array();
} break;
- // arrays
+
+ // Arrays.
case PACKED_BYTE_ARRAY: {
PackedArrayRefBase::destroy(_data.packed_array);
} break;
@@ -1484,7 +1405,9 @@ void Variant::_clear_internal() {
PackedArrayRefBase::destroy(_data.packed_array);
} break;
default: {
- } /* not needed */
+ // Not needed, there is no point. The following do not allocate memory:
+ // VECTOR2, VECTOR3, RECT2, PLANE, QUATERNION, COLOR.
+ }
}
}
@@ -1863,34 +1786,34 @@ String Variant::stringify(int recursion_count) const {
str += " }";
return str;
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return stringify_vector(operator Vector<Vector2>(), recursion_count);
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return stringify_vector(operator Vector<Vector3>(), recursion_count);
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return stringify_vector(operator Vector<Color>(), recursion_count);
- } break;
+ }
case PACKED_STRING_ARRAY: {
return stringify_vector(operator Vector<String>(), recursion_count);
- } break;
+ }
case PACKED_BYTE_ARRAY: {
return stringify_vector(operator Vector<uint8_t>(), recursion_count);
- } break;
+ }
case PACKED_INT32_ARRAY: {
return stringify_vector(operator Vector<int32_t>(), recursion_count);
- } break;
+ }
case PACKED_INT64_ARRAY: {
return stringify_vector(operator Vector<int64_t>(), recursion_count);
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return stringify_vector(operator Vector<float>(), recursion_count);
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return stringify_vector(operator Vector<double>(), recursion_count);
- } break;
+ }
case ARRAY: {
Array arr = operator Array();
if (recursion_count > MAX_RECURSION) {
@@ -1899,8 +1822,7 @@ String Variant::stringify(int recursion_count) const {
}
return stringify_vector(arr, recursion_count);
-
- } break;
+ }
case OBJECT: {
if (_get_obj().obj) {
if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
@@ -1911,31 +1833,27 @@ String Variant::stringify(int recursion_count) const {
} else {
return "<Object#null>";
}
-
- } break;
+ }
case CALLABLE: {
const Callable &c = *reinterpret_cast<const Callable *>(_data._mem);
return c;
- } break;
+ }
case SIGNAL: {
const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
return s;
- } break;
+ }
case RID: {
const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
return "RID(" + itos(s.get_id()) + ")";
- } break;
+ }
default: {
return "<" + get_type_name(type) + ">";
}
}
-
- return "";
}
String Variant::to_json_string() const {
- JSON json;
- return json.stringify(*this);
+ return JSON::stringify(*this);
}
Variant::operator Vector2() const {
@@ -3573,6 +3491,19 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
}
}
+bool StringLikeVariantComparator::compare(const Variant &p_lhs, const Variant &p_rhs) {
+ if (p_lhs.hash_compare(p_rhs)) {
+ return true;
+ }
+ if (p_lhs.get_type() == Variant::STRING && p_rhs.get_type() == Variant::STRING_NAME) {
+ return *VariantInternal::get_string(&p_lhs) == *VariantInternal::get_string_name(&p_rhs);
+ }
+ if (p_lhs.get_type() == Variant::STRING_NAME && p_rhs.get_type() == Variant::STRING) {
+ return *VariantInternal::get_string_name(&p_lhs) == *VariantInternal::get_string(&p_rhs);
+ }
+ return false;
+}
+
bool Variant::is_ref_counted() const {
return type == OBJECT && _get_obj().id.is_ref_counted();
}
@@ -3691,16 +3622,16 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = ce.argument;
if (p_argptrs) {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected));
} else {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected));
}
} else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount);
} else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount);
} else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text = "Method not found.";
+ err_text = "Method not found";
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text = "Instance is null";
} else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index b0738e7d44..f7221e206f 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -490,6 +490,7 @@ public:
}
// Only enum classes that need to be bound need this to be defined.
+ VARIANT_ENUM_CLASS_CONSTRUCTOR(EulerOrder)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton)
VARIANT_ENUM_CLASS_CONSTRUCTOR(Key)
@@ -796,6 +797,10 @@ struct VariantComparator {
static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
};
+struct StringLikeVariantComparator {
+ static bool compare(const Variant &p_lhs, const Variant &p_rhs);
+};
+
Variant::ObjData &Variant::_get_obj() {
return *reinterpret_cast<ObjData *>(&_data._mem[0]);
}
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 1831f7b72a..ac569941bf 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -73,6 +73,30 @@ static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant
call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
}
+template <class From, class R, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_variant_args_ret_dv(&converted, method, p_args, p_argcount, r_ret, r_error, p_defvals);
+}
+
+template <class From, class R, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_method_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_variant_args_retc_dv(&converted, method, p_args, p_argcount, r_ret, r_error, p_defvals);
+}
+
+template <class From, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_variant_args_dv(&converted, method, p_args, p_argcount, r_error, p_defvals);
+}
+
+template <class From, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_variant_argsc_dv(&converted, method, p_args, p_argcount, r_error, p_defvals);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_method_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, p_defvals, r_error);
@@ -102,6 +126,29 @@ static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Vari
call_with_validated_variant_argsc(base, method, p_args);
}
+template <class From, class R, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_validated_variant_args_ret_helper<T, R, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class From, class R, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_validated_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_validated_variant_args_retc_helper<T, R, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+template <class From, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_validated_call(void (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_validated_variant_args_helper<T, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class From, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_validated_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
+ T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
+ call_with_validated_variant_argsc_helper<T, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_validated_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_retc(base, method, p_args, r_ret);
@@ -142,6 +189,30 @@ static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_bas
call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args);
}
+template <class From, class R, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
+ T converted(*reinterpret_cast<From *>(p_base));
+ call_with_ptr_args_ret(&converted, method, p_args, r_ret);
+}
+
+template <class From, class R, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
+ T converted(*reinterpret_cast<From *>(p_base));
+ call_with_ptr_args_retc(&converted, method, p_args, r_ret);
+}
+
+template <class From, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
+ T converted(*reinterpret_cast<From *>(p_base));
+ call_with_ptr_args(&converted, method, p_args);
+}
+
+template <class From, class T, class... P>
+static _FORCE_INLINE_ void vc_convert_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
+ T converted(*reinterpret_cast<From *>(p_base));
+ call_with_ptr_argsc(&converted, method, p_args);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...)) {
return sizeof...(P);
@@ -337,6 +408,46 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
} \
};
+#define CONVERT_METHOD_CLASS(m_class, m_method_name, m_method_ptr) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ vc_convert_method_call<m_class>(m_method_ptr, base, p_args, p_argcount, r_ret, p_defvals, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ vc_convert_validated_call<m_class>(m_method_ptr, base, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_convert_ptrcall<m_class>(m_method_ptr, p_base, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type(m_method_ptr, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return vc_get_return_type(m_method_ptr); \
+ } \
+ static bool has_return_type() { \
+ return vc_has_return_type(m_method_ptr); \
+ } \
+ static bool is_const() { \
+ return vc_is_const(m_method_ptr); \
+ } \
+ static bool is_static() { \
+ return false; \
+ } \
+ static bool is_vararg() { \
+ return false; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
template <class R, class... P>
static _FORCE_INLINE_ void vc_static_ptrcall(R (*method)(P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_method_ret<R, P...>(method, p_args, r_ret);
@@ -1422,6 +1533,16 @@ int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, String
#endif
#ifdef DEBUG_METHODS_ENABLED
+#define bind_convert_method(m_type_from, m_type_to, m_method, m_arg_names, m_default_args) \
+ CONVERT_METHOD_CLASS(m_type_from, m_method, &m_type_to::m_method); \
+ register_builtin_method<Method_##m_type_from##_##m_method>(m_arg_names, m_default_args);
+#else
+#define bind_convert_method(m_type_from, m_type_to, m_method, m_arg_names, m_default_args) \
+ CONVERT_METHOD_CLASS(m_type_from, m_method, &m_type_to ::m_method); \
+ register_builtin_method<Method_##m_type_from##_##m_method>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
#define bind_static_method(m_type, m_method, m_arg_names, m_default_args) \
STATIC_METHOD_CLASS(m_type, m_method, m_type::m_method); \
register_builtin_method<Method_##m_type##_##m_method>(m_arg_names, m_default_args);
@@ -1442,6 +1563,16 @@ int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, String
#endif
#ifdef DEBUG_METHODS_ENABLED
+#define bind_convert_methodv(m_type_from, m_type_to, m_name, m_method, m_arg_names, m_default_args) \
+ CONVERT_METHOD_CLASS(m_type_from, m_name, m_method); \
+ register_builtin_method<Method_##m_type_from##_##m_name>(m_arg_names, m_default_args);
+#else
+#define bind_convert_methodv(m_type_from, m_type_to, m_name, m_method, m_arg_names, m_default_args) \
+ CONVERT_METHOD_CLASS(m_type_from, m_name, m_method); \
+ register_builtin_method<Method_##m_type_from##_##m_name>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
FUNCTION_CLASS(m_type, m_name, m_method, true); \
register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
@@ -1461,6 +1592,14 @@ int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, String
register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
#endif
+#define bind_string_method(m_method, m_arg_names, m_default_args) \
+ bind_method(String, m_method, m_arg_names, m_default_args); \
+ bind_convert_method(StringName, String, m_method, m_arg_names, m_default_args);
+
+#define bind_string_methodv(m_name, m_method, m_arg_names, m_default_args) \
+ bind_methodv(String, m_name, m_method, m_arg_names, m_default_args); \
+ bind_convert_methodv(StringName, String, m_name, m_method, m_arg_names, m_default_args);
+
#define bind_custom(m_type, m_name, m_method, m_has_return, m_ret_type) \
VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \
register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>());
@@ -1477,108 +1616,108 @@ static void _register_variant_builtin_methods() {
/* String */
- bind_method(String, casecmp_to, sarray("to"), varray());
- bind_method(String, nocasecmp_to, sarray("to"), varray());
- bind_method(String, naturalnocasecmp_to, sarray("to"), varray());
- bind_method(String, length, sarray(), varray());
- bind_method(String, substr, sarray("from", "len"), varray(-1));
- bind_method(String, get_slice, sarray("delimiter", "slice"), varray());
- bind_method(String, get_slicec, sarray("delimiter", "slice"), varray());
- bind_method(String, get_slice_count, sarray("delimiter"), varray());
- bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
- bind_method(String, count, sarray("what", "from", "to"), varray(0, 0));
- bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0));
- bind_method(String, findn, sarray("what", "from"), varray(0));
- bind_method(String, rfind, sarray("what", "from"), varray(-1));
- bind_method(String, rfindn, sarray("what", "from"), varray(-1));
- bind_method(String, match, sarray("expr"), varray());
- bind_method(String, matchn, sarray("expr"), varray());
- bind_methodv(String, begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray());
- bind_method(String, ends_with, sarray("text"), varray());
- bind_method(String, is_subsequence_of, sarray("text"), varray());
- bind_method(String, is_subsequence_ofn, sarray("text"), varray());
- bind_method(String, bigrams, sarray(), varray());
- bind_method(String, similarity, sarray("text"), varray());
-
- bind_method(String, format, sarray("values", "placeholder"), varray("{_}"));
- bind_methodv(String, replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
- bind_method(String, replacen, sarray("what", "forwhat"), varray());
- bind_method(String, repeat, sarray("count"), varray());
- bind_method(String, insert, sarray("position", "what"), varray());
- bind_method(String, capitalize, sarray(), varray());
- bind_method(String, to_camel_case, sarray(), varray());
- bind_method(String, to_pascal_case, sarray(), varray());
- bind_method(String, to_snake_case, sarray(), varray());
- bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
- bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
- bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
- bind_method(String, join, sarray("parts"), varray());
-
- bind_method(String, to_upper, sarray(), varray());
- bind_method(String, to_lower, sarray(), varray());
-
- bind_method(String, left, sarray("length"), varray());
- bind_method(String, right, sarray("length"), varray());
-
- bind_method(String, strip_edges, sarray("left", "right"), varray(true, true));
- bind_method(String, strip_escapes, sarray(), varray());
- bind_method(String, lstrip, sarray("chars"), varray());
- bind_method(String, rstrip, sarray("chars"), varray());
- bind_method(String, get_extension, sarray(), varray());
- bind_method(String, get_basename, sarray(), varray());
- bind_method(String, path_join, sarray("file"), varray());
- bind_method(String, unicode_at, sarray("at"), varray());
- bind_method(String, indent, sarray("prefix"), varray());
- bind_method(String, dedent, sarray(), varray());
+ bind_string_method(casecmp_to, sarray("to"), varray());
+ bind_string_method(nocasecmp_to, sarray("to"), varray());
+ bind_string_method(naturalnocasecmp_to, sarray("to"), varray());
+ bind_string_method(length, sarray(), varray());
+ bind_string_method(substr, sarray("from", "len"), varray(-1));
+ bind_string_method(get_slice, sarray("delimiter", "slice"), varray());
+ bind_string_method(get_slicec, sarray("delimiter", "slice"), varray());
+ bind_string_method(get_slice_count, sarray("delimiter"), varray());
+ bind_string_methodv(find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
+ bind_string_method(count, sarray("what", "from", "to"), varray(0, 0));
+ bind_string_method(countn, sarray("what", "from", "to"), varray(0, 0));
+ bind_string_method(findn, sarray("what", "from"), varray(0));
+ bind_string_method(rfind, sarray("what", "from"), varray(-1));
+ bind_string_method(rfindn, sarray("what", "from"), varray(-1));
+ bind_string_method(match, sarray("expr"), varray());
+ bind_string_method(matchn, sarray("expr"), varray());
+ bind_string_methodv(begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray());
+ bind_string_method(ends_with, sarray("text"), varray());
+ bind_string_method(is_subsequence_of, sarray("text"), varray());
+ bind_string_method(is_subsequence_ofn, sarray("text"), varray());
+ bind_string_method(bigrams, sarray(), varray());
+ bind_string_method(similarity, sarray("text"), varray());
+
+ bind_string_method(format, sarray("values", "placeholder"), varray("{_}"));
+ 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(insert, sarray("position", "what"), varray());
+ bind_string_method(capitalize, sarray(), varray());
+ bind_string_method(to_camel_case, sarray(), varray());
+ bind_string_method(to_pascal_case, sarray(), varray());
+ bind_string_method(to_snake_case, sarray(), varray());
+ bind_string_method(split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
+ bind_string_method(rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
+ bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true));
+ bind_string_method(join, sarray("parts"), varray());
+
+ bind_string_method(to_upper, sarray(), varray());
+ bind_string_method(to_lower, sarray(), varray());
+
+ bind_string_method(left, sarray("length"), varray());
+ bind_string_method(right, sarray("length"), varray());
+
+ bind_string_method(strip_edges, sarray("left", "right"), varray(true, true));
+ bind_string_method(strip_escapes, sarray(), varray());
+ bind_string_method(lstrip, sarray("chars"), varray());
+ bind_string_method(rstrip, sarray("chars"), varray());
+ bind_string_method(get_extension, sarray(), varray());
+ bind_string_method(get_basename, sarray(), varray());
+ bind_string_method(path_join, sarray("file"), varray());
+ bind_string_method(unicode_at, sarray("at"), varray());
+ bind_string_method(indent, sarray("prefix"), varray());
+ bind_string_method(dedent, sarray(), varray());
bind_method(String, hash, sarray(), varray());
- bind_method(String, md5_text, sarray(), varray());
- bind_method(String, sha1_text, sarray(), varray());
- bind_method(String, sha256_text, sarray(), varray());
- bind_method(String, md5_buffer, sarray(), varray());
- bind_method(String, sha1_buffer, sarray(), varray());
- bind_method(String, sha256_buffer, sarray(), varray());
- bind_method(String, is_empty, sarray(), varray());
- bind_methodv(String, contains, static_cast<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray());
-
- bind_method(String, is_absolute_path, sarray(), varray());
- bind_method(String, is_relative_path, sarray(), varray());
- bind_method(String, simplify_path, sarray(), varray());
- bind_method(String, get_base_dir, sarray(), varray());
- bind_method(String, get_file, sarray(), varray());
- bind_method(String, xml_escape, sarray("escape_quotes"), varray(false));
- bind_method(String, xml_unescape, sarray(), varray());
- bind_method(String, uri_encode, sarray(), varray());
- bind_method(String, uri_decode, sarray(), varray());
- bind_method(String, c_escape, sarray(), varray());
- bind_method(String, c_unescape, sarray(), varray());
- bind_method(String, json_escape, sarray(), varray());
-
- bind_method(String, validate_node_name, sarray(), varray());
-
- bind_method(String, is_valid_identifier, sarray(), varray());
- bind_method(String, is_valid_int, sarray(), varray());
- bind_method(String, is_valid_float, sarray(), varray());
- bind_method(String, is_valid_hex_number, sarray("with_prefix"), varray(false));
- bind_method(String, is_valid_html_color, sarray(), varray());
- bind_method(String, is_valid_ip_address, sarray(), varray());
- bind_method(String, is_valid_filename, sarray(), varray());
-
- bind_method(String, to_int, sarray(), varray());
- bind_method(String, to_float, sarray(), varray());
- bind_method(String, hex_to_int, sarray(), varray());
- bind_method(String, bin_to_int, sarray(), varray());
-
- bind_method(String, lpad, sarray("min_length", "character"), varray(" "));
- bind_method(String, rpad, sarray("min_length", "character"), varray(" "));
- bind_method(String, pad_decimals, sarray("digits"), varray());
- bind_method(String, pad_zeros, sarray("digits"), varray());
- bind_method(String, trim_prefix, sarray("prefix"), varray());
- bind_method(String, trim_suffix, sarray("suffix"), varray());
-
- bind_method(String, to_ascii_buffer, sarray(), varray());
- bind_method(String, to_utf8_buffer, sarray(), varray());
- bind_method(String, to_utf16_buffer, sarray(), varray());
- bind_method(String, to_utf32_buffer, sarray(), varray());
+ bind_string_method(md5_text, sarray(), varray());
+ bind_string_method(sha1_text, sarray(), varray());
+ bind_string_method(sha256_text, sarray(), varray());
+ bind_string_method(md5_buffer, sarray(), varray());
+ bind_string_method(sha1_buffer, sarray(), varray());
+ bind_string_method(sha256_buffer, sarray(), varray());
+ bind_string_method(is_empty, sarray(), varray());
+ bind_string_methodv(contains, static_cast<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray());
+
+ bind_string_method(is_absolute_path, sarray(), varray());
+ bind_string_method(is_relative_path, sarray(), varray());
+ bind_string_method(simplify_path, sarray(), varray());
+ bind_string_method(get_base_dir, sarray(), varray());
+ bind_string_method(get_file, sarray(), varray());
+ bind_string_method(xml_escape, sarray("escape_quotes"), varray(false));
+ bind_string_method(xml_unescape, sarray(), varray());
+ bind_string_method(uri_encode, sarray(), varray());
+ bind_string_method(uri_decode, sarray(), varray());
+ bind_string_method(c_escape, sarray(), varray());
+ bind_string_method(c_unescape, sarray(), varray());
+ bind_string_method(json_escape, sarray(), varray());
+
+ bind_string_method(validate_node_name, sarray(), varray());
+
+ bind_string_method(is_valid_identifier, sarray(), varray());
+ bind_string_method(is_valid_int, sarray(), varray());
+ bind_string_method(is_valid_float, sarray(), varray());
+ bind_string_method(is_valid_hex_number, sarray("with_prefix"), varray(false));
+ bind_string_method(is_valid_html_color, sarray(), varray());
+ bind_string_method(is_valid_ip_address, sarray(), varray());
+ bind_string_method(is_valid_filename, sarray(), varray());
+
+ bind_string_method(to_int, sarray(), varray());
+ bind_string_method(to_float, sarray(), varray());
+ bind_string_method(hex_to_int, sarray(), varray());
+ bind_string_method(bin_to_int, sarray(), varray());
+
+ bind_string_method(lpad, sarray("min_length", "character"), varray(" "));
+ bind_string_method(rpad, sarray("min_length", "character"), varray(" "));
+ bind_string_method(pad_decimals, sarray("digits"), varray());
+ bind_string_method(pad_zeros, sarray("digits"), varray());
+ bind_string_method(trim_prefix, sarray("prefix"), varray());
+ bind_string_method(trim_suffix, sarray("suffix"), varray());
+
+ bind_string_method(to_ascii_buffer, sarray(), varray());
+ bind_string_method(to_utf8_buffer, sarray(), varray());
+ bind_string_method(to_utf16_buffer, sarray(), varray());
+ bind_string_method(to_utf32_buffer, sarray(), varray());
bind_static_method(String, num_scientific, sarray("number"), varray());
bind_static_method(String, num, sarray("number", "decimals"), varray(-1));
@@ -1606,6 +1745,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
bind_method(Vector2, is_zero_approx, sarray(), varray());
+ bind_method(Vector2, is_finite, sarray(), varray());
bind_method(Vector2, posmod, sarray("mod"), varray());
bind_method(Vector2, posmodv, sarray("modv"), varray());
bind_method(Vector2, project, sarray("b"), varray());
@@ -1614,6 +1754,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Vector2, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector2, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
+ bind_method(Vector2, bezier_derivative, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector2, max_axis_index, sarray(), varray());
bind_method(Vector2, min_axis_index, sarray(), varray());
bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
@@ -1645,6 +1786,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2i, sign, sarray(), varray());
bind_method(Vector2i, abs, sarray(), varray());
bind_method(Vector2i, clamp, sarray("min", "max"), varray());
+ bind_method(Vector2i, snapped, sarray("step"), varray());
/* Rect2 */
@@ -1653,6 +1795,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, has_area, sarray(), varray());
bind_method(Rect2, has_point, sarray("point"), varray());
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
+ bind_method(Rect2, is_finite, sarray(), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
bind_method(Rect2, encloses, sarray("b"), varray());
bind_method(Rect2, intersection, sarray("b"), varray());
@@ -1695,6 +1838,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
bind_method(Vector3, is_zero_approx, sarray(), varray());
+ bind_method(Vector3, is_finite, sarray(), varray());
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1704,6 +1848,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Vector3, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
+ bind_method(Vector3, bezier_derivative, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
bind_method(Vector3, dot, sarray("with"), varray());
bind_method(Vector3, cross, sarray("with"), varray());
@@ -1731,6 +1876,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3i, sign, sarray(), varray());
bind_method(Vector3i, abs, sarray(), varray());
bind_method(Vector3i, clamp, sarray("min", "max"), varray());
+ bind_method(Vector3i, snapped, sarray("step"), varray());
/* Vector4 */
@@ -1759,6 +1905,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
bind_method(Vector4, is_zero_approx, sarray(), varray());
+ bind_method(Vector4, is_finite, sarray(), varray());
/* Vector4i */
@@ -1769,12 +1916,14 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4i, sign, sarray(), varray());
bind_method(Vector4i, abs, sarray(), varray());
bind_method(Vector4i, clamp, sarray("min", "max"), varray());
+ bind_method(Vector4i, snapped, sarray("step"), varray());
/* Plane */
bind_method(Plane, normalized, sarray(), varray());
bind_method(Plane, center, sarray(), varray());
bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
+ bind_method(Plane, is_finite, sarray(), varray());
bind_method(Plane, is_point_over, sarray("point"), varray());
bind_method(Plane, distance_to, sarray("point"), varray());
bind_method(Plane, has_point, sarray("point", "tolerance"), varray(CMP_EPSILON));
@@ -1790,6 +1939,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, normalized, sarray(), varray());
bind_method(Quaternion, is_normalized, sarray(), varray());
bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
+ bind_method(Quaternion, is_finite, sarray(), varray());
bind_method(Quaternion, inverse, sarray(), varray());
bind_method(Quaternion, log, sarray(), varray());
bind_method(Quaternion, exp, sarray(), varray());
@@ -1799,7 +1949,8 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, slerpni, sarray("to", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
- bind_method(Quaternion, get_euler, sarray(), varray());
+ bind_method(Quaternion, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
+ bind_static_method(Quaternion, from_euler, sarray("euler"), varray());
bind_method(Quaternion, get_axis, sarray(), varray());
bind_method(Quaternion, get_angle, sarray(), varray());
@@ -1829,10 +1980,6 @@ static void _register_variant_builtin_methods() {
bind_static_method(Color, hex64, sarray("hex"), varray());
bind_static_method(Color, html, sarray("rgba"), varray());
bind_static_method(Color, html_is_valid, sarray("color"), varray());
- bind_static_method(Color, find_named_color, sarray("name"), varray());
- bind_static_method(Color, get_named_color_count, sarray(), varray());
- bind_static_method(Color, get_named_color_name, sarray("idx"), varray());
- bind_static_method(Color, get_named_color, sarray("idx"), varray());
bind_static_method(Color, from_string, sarray("str", "default"), varray());
bind_static_method(Color, from_hsv, sarray("h", "s", "v", "alpha"), varray(1.0));
bind_static_method(Color, from_ok_hsl, sarray("h", "s", "l", "alpha"), varray(1.0));
@@ -1909,6 +2056,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform2D, is_finite, sarray(), varray());
bind_method(Transform2D, set_rotation, sarray("rotation"), varray());
bind_method(Transform2D, set_scale, sarray("scale"), varray());
bind_method(Transform2D, set_skew, sarray("skew"), varray());
@@ -1923,16 +2071,17 @@ static void _register_variant_builtin_methods() {
bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "angle"), varray());
bind_method(Basis, scaled, sarray("scale"), varray());
bind_method(Basis, get_scale, sarray(), varray());
- bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ));
+ bind_method(Basis, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
bind_method(Basis, tdotx, sarray("with"), varray());
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
+ bind_method(Basis, is_finite, sarray(), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_static_method(Basis, from_scale, sarray("scale"), varray());
- bind_static_method(Basis, from_euler, sarray("euler", "order"), varray(Basis::EULER_ORDER_YXZ));
+ bind_static_method(Basis, from_euler, sarray("euler", "order"), varray((int64_t)EulerOrder::YXZ));
/* AABB */
@@ -1943,6 +2092,7 @@ static void _register_variant_builtin_methods() {
bind_method(AABB, has_surface, sarray(), varray());
bind_method(AABB, has_point, sarray("point"), varray());
bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
+ bind_method(AABB, is_finite, sarray(), varray());
bind_method(AABB, intersects, sarray("with"), varray());
bind_method(AABB, encloses, sarray("with"), varray());
bind_method(AABB, intersects_plane, sarray("plane"), varray());
@@ -1975,6 +2125,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform3D, is_finite, sarray(), varray());
/* Projection */
@@ -2043,9 +2194,9 @@ static void _register_variant_builtin_methods() {
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
bind_method(Array, back, sarray(), varray());
+ bind_method(Array, pick_random, sarray(), varray());
bind_method(Array, find, sarray("what", "from"), varray(0));
bind_method(Array, rfind, sarray("what", "from"), varray(-1));
- bind_method(Array, find_last, sarray("value"), varray());
bind_method(Array, count, sarray("value"), varray());
bind_method(Array, has, sarray("value"), varray());
bind_method(Array, pop_back, sarray(), varray());
@@ -2426,25 +2577,11 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1));
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX);
-
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX);
-
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D());
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
- Transform3D identity_transform = Transform3D();
+ Transform3D identity_transform;
Transform3D flip_x_transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
Transform3D flip_y_transform = Transform3D(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
Transform3D flip_z_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
@@ -2453,7 +2590,7 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Y", flip_y_transform);
_VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Z", flip_z_transform);
- Basis identity_basis = Basis();
+ Basis identity_basis;
Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
Basis flip_y_basis = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
Basis flip_z_basis = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3b88dc11ca..624a6f5e06 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -68,11 +68,13 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructor<int64_t, int64_t>>(sarray("from"));
add_constructor<VariantConstructor<int64_t, double>>(sarray("from"));
add_constructor<VariantConstructor<int64_t, bool>>(sarray("from"));
+ add_constructor<VariantConstructorFromString<int64_t>>(sarray("from"));
add_constructor<VariantConstructNoArgs<double>>(sarray());
add_constructor<VariantConstructor<double, double>>(sarray("from"));
add_constructor<VariantConstructor<double, int64_t>>(sarray("from"));
add_constructor<VariantConstructor<double, bool>>(sarray("from"));
+ add_constructor<VariantConstructorFromString<double>>(sarray("from"));
add_constructor<VariantConstructNoArgs<String>>(sarray());
add_constructor<VariantConstructor<String, String>>(sarray("from"));
@@ -141,7 +143,6 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle"));
add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w"));
- add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler_yxz"));
add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 34d228f4d2..f52cc43914 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -222,6 +222,64 @@ public:
}
};
+template <class T>
+class VariantConstructorFromString {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ return;
+ }
+
+ VariantTypeChanger<T>::change(&r_ret);
+ const String &src_str = *VariantGetInternalPtr<String>::get_ptr(p_args[0]);
+
+ if (r_ret.get_type() == Variant::Type::INT) {
+ r_ret = src_str.to_int();
+ } else if (r_ret.get_type() == Variant::Type::FLOAT) {
+ r_ret = src_str.to_float();
+ }
+ }
+
+ static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(r_ret);
+ const String &src_str = *VariantGetInternalPtr<String>::get_ptr(p_args[0]);
+ T ret = Variant();
+ if (r_ret->get_type() == Variant::Type::INT) {
+ ret = src_str.to_int();
+ } else if (r_ret->get_type() == Variant::Type::FLOAT) {
+ ret = src_str.to_float();
+ }
+ *r_ret = ret;
+ }
+
+ static void ptr_construct(void *base, const void **p_args) {
+ String src_str = PtrToArg<String>::convert(p_args[0]);
+ T dst_var = Variant();
+ Variant type_test = Variant(dst_var);
+ if (type_test.get_type() == Variant::Type::INT) {
+ dst_var = src_str.to_int();
+ } else if (type_test.get_type() == Variant::Type::FLOAT) {
+ dst_var = src_str.to_float();
+ }
+ PtrConstruct<T>::construct(dst_var, base);
+ }
+
+ static int get_argument_count() {
+ return 1;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::STRING;
+ }
+
+ static Variant::Type get_base_type() {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+ }
+};
+
class VariantConstructorCallableArgs {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
diff --git a/core/variant/variant_destruct.cpp b/core/variant/variant_destruct.cpp
index ab8303f3ae..5117c33e2b 100644
--- a/core/variant/variant_destruct.cpp
+++ b/core/variant/variant_destruct.cpp
@@ -41,13 +41,8 @@ static void add_destructor() {
void Variant::_register_variant_destructors() {
add_destructor<VariantDestruct<String>>();
- add_destructor<VariantDestruct<Transform2D>>();
- add_destructor<VariantDestruct<::AABB>>();
- add_destructor<VariantDestruct<Basis>>();
- add_destructor<VariantDestruct<Transform3D>>();
add_destructor<VariantDestruct<StringName>>();
add_destructor<VariantDestruct<NodePath>>();
- add_destructor<VariantDestruct<::RID>>();
add_destructor<VariantDestruct<Callable>>();
add_destructor<VariantDestruct<Signal>>();
add_destructor<VariantDestruct<Dictionary>>();
diff --git a/core/variant/variant_destruct.h b/core/variant/variant_destruct.h
index 5e3478635d..2730110c0f 100644
--- a/core/variant/variant_destruct.h
+++ b/core/variant/variant_destruct.h
@@ -50,13 +50,8 @@ struct VariantDestruct {};
}
MAKE_PTRDESTRUCT(String);
-MAKE_PTRDESTRUCT(Transform2D);
-MAKE_PTRDESTRUCT(AABB);
-MAKE_PTRDESTRUCT(Basis);
-MAKE_PTRDESTRUCT(Transform3D);
MAKE_PTRDESTRUCT(StringName);
MAKE_PTRDESTRUCT(NodePath);
-MAKE_PTRDESTRUCT(RID);
MAKE_PTRDESTRUCT(Callable);
MAKE_PTRDESTRUCT(Signal);
MAKE_PTRDESTRUCT(Dictionary);
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 874a183d29..684baff348 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -824,9 +824,9 @@ VARIANT_ACCESSOR_NUMBER(Vector4i::Axis)
VARIANT_ACCESSOR_NUMBER(Projection::Planes)
template <>
-struct VariantInternalAccessor<Basis::EulerOrder> {
- static _FORCE_INLINE_ Basis::EulerOrder get(const Variant *v) { return Basis::EulerOrder(*VariantInternal::get_int(v)); }
- static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = p_value; }
+struct VariantInternalAccessor<EulerOrder> {
+ static _FORCE_INLINE_ EulerOrder get(const Variant *v) { return EulerOrder(*VariantInternal::get_int(v)); }
+ static _FORCE_INLINE_ void set(Variant *v, EulerOrder p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; }
};
template <>
@@ -1047,7 +1047,7 @@ struct VariantInternalAccessor<PackedColorArray> {
template <>
struct VariantInternalAccessor<Object *> {
static _FORCE_INLINE_ Object *get(const Variant *v) { return const_cast<Object *>(*VariantInternal::get_object(v)); }
- static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { *VariantInternal::get_object(v) = const_cast<Object *>(p_value); }
+ static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { VariantInternal::object_assign(v, p_value); }
};
template <>
@@ -1517,7 +1517,7 @@ struct VariantTypeAdjust<Object *> {
}
};
-// GDNative extension helpers.
+// GDExtension helpers.
template <class T>
struct VariantTypeConstructor {
@@ -1532,27 +1532,4 @@ struct VariantTypeConstructor {
}
};
-template <>
-struct VariantTypeConstructor<Object *> {
- _FORCE_INLINE_ static void variant_from_type(void *p_variant, void *p_value) {
- Variant *variant = reinterpret_cast<Variant *>(p_variant);
- VariantInitializer<Object *>::init(variant);
- Object *object = *(reinterpret_cast<Object **>(p_value));
- if (object) {
- if (object->is_ref_counted()) {
- if (!VariantInternal::initialize_ref(object)) {
- return;
- }
- }
- VariantInternalAccessor<Object *>::set(variant, object);
- VariantInternalAccessor<ObjectID>::set(variant, object->get_instance_id());
- }
- }
-
- _FORCE_INLINE_ static void type_from_variant(void *p_value, void *p_variant) {
- Object **value = reinterpret_cast<Object **>(p_value);
- *value = VariantInternalAccessor<Object *>::get(reinterpret_cast<Variant *>(p_variant));
- }
-};
-
#endif // VARIANT_INTERNAL_H
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 6cca7955ae..d4e6dfb4d1 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -229,6 +229,20 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<Vector4>::VARIANT_TYPE; }
};
+#define register_string_op(m_op_type, m_op_code) \
+ do { \
+ register_op<m_op_type<String, String>>(m_op_code, Variant::STRING, Variant::STRING); \
+ register_op<m_op_type<String, StringName>>(m_op_code, Variant::STRING, Variant::STRING_NAME); \
+ register_op<m_op_type<StringName, String>>(m_op_code, Variant::STRING_NAME, Variant::STRING); \
+ register_op<m_op_type<StringName, StringName>>(m_op_code, Variant::STRING_NAME, Variant::STRING_NAME); \
+ } while (false)
+
+#define register_string_modulo_op(m_class, m_type) \
+ do { \
+ register_op<OperatorEvaluatorStringFormat<String, m_class>>(Variant::OP_MODULE, Variant::STRING, m_type); \
+ register_op<OperatorEvaluatorStringFormat<StringName, m_class>>(Variant::OP_MODULE, Variant::STRING_NAME, m_type); \
+ } while (false)
+
void Variant::_register_variant_operators() {
memset(operator_return_type_table, 0, sizeof(operator_return_type_table));
memset(operator_evaluator_table, 0, sizeof(operator_evaluator_table));
@@ -239,9 +253,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAdd<double, int64_t, double>>(Variant::OP_ADD, Variant::INT, Variant::FLOAT);
register_op<OperatorEvaluatorAdd<double, double, int64_t>>(Variant::OP_ADD, Variant::FLOAT, Variant::INT);
register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT);
- register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING);
- register_op<OperatorEvaluatorAdd<String, char32_t, String>>(Variant::OP_ADD, Variant::INT, Variant::STRING);
- register_op<OperatorEvaluatorAdd<String, String, char32_t>>(Variant::OP_ADD, Variant::STRING, Variant::INT);
+ register_string_op(OperatorEvaluatorStringConcat, Variant::OP_ADD);
register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
@@ -384,10 +396,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorDivNZ<Vector2, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT);
register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
-
register_op<OperatorEvaluatorDiv<Vector3, Vector3, Vector3>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::VECTOR3);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, double>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::FLOAT);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT);
@@ -421,46 +429,46 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorModNZ<Vector4i, Vector4i, Vector4i>>(Variant::OP_MODULE, Variant::VECTOR4I, Variant::VECTOR4I);
register_op<OperatorEvaluatorModNZ<Vector4i, Vector4i, int64_t>>(Variant::OP_MODULE, Variant::VECTOR4I, Variant::INT);
- register_op<OperatorEvaluatorStringModNil>(Variant::OP_MODULE, Variant::STRING, Variant::NIL);
-
- register_op<OperatorEvaluatorStringModT<bool>>(Variant::OP_MODULE, Variant::STRING, Variant::BOOL);
- register_op<OperatorEvaluatorStringModT<int64_t>>(Variant::OP_MODULE, Variant::STRING, Variant::INT);
- register_op<OperatorEvaluatorStringModT<double>>(Variant::OP_MODULE, Variant::STRING, Variant::FLOAT);
- register_op<OperatorEvaluatorStringModT<String>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING);
- register_op<OperatorEvaluatorStringModT<Vector2>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2);
- register_op<OperatorEvaluatorStringModT<Vector2i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2I);
- register_op<OperatorEvaluatorStringModT<Rect2>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2);
- register_op<OperatorEvaluatorStringModT<Rect2i>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2I);
- register_op<OperatorEvaluatorStringModT<Vector3>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3);
- register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I);
- register_op<OperatorEvaluatorStringModT<Vector4>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR4);
- register_op<OperatorEvaluatorStringModT<Vector4i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR4I);
- register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D);
- register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE);
- register_op<OperatorEvaluatorStringModT<Quaternion>>(Variant::OP_MODULE, Variant::STRING, Variant::QUATERNION);
- register_op<OperatorEvaluatorStringModT<::AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB);
- register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS);
- register_op<OperatorEvaluatorStringModT<Transform3D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM3D);
- register_op<OperatorEvaluatorStringModT<Projection>>(Variant::OP_MODULE, Variant::STRING, Variant::PROJECTION);
-
- register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR);
- register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME);
- register_op<OperatorEvaluatorStringModT<NodePath>>(Variant::OP_MODULE, Variant::STRING, Variant::NODE_PATH);
- register_op<OperatorEvaluatorStringModObject>(Variant::OP_MODULE, Variant::STRING, Variant::OBJECT);
- register_op<OperatorEvaluatorStringModT<Callable>>(Variant::OP_MODULE, Variant::STRING, Variant::CALLABLE);
- register_op<OperatorEvaluatorStringModT<Signal>>(Variant::OP_MODULE, Variant::STRING, Variant::SIGNAL);
- register_op<OperatorEvaluatorStringModT<Dictionary>>(Variant::OP_MODULE, Variant::STRING, Variant::DICTIONARY);
- register_op<OperatorEvaluatorStringModArray>(Variant::OP_MODULE, Variant::STRING, Variant::ARRAY);
-
- register_op<OperatorEvaluatorStringModT<PackedByteArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_BYTE_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedInt32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT32_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedInt64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT64_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedFloat32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT32_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedFloat64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT64_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedStringArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_STRING_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedVector2Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR2_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedVector3Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR3_ARRAY);
- register_op<OperatorEvaluatorStringModT<PackedColorArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_COLOR_ARRAY);
+ register_string_modulo_op(void, Variant::NIL);
+
+ register_string_modulo_op(bool, Variant::BOOL);
+ register_string_modulo_op(int64_t, Variant::INT);
+ register_string_modulo_op(double, Variant::FLOAT);
+ register_string_modulo_op(String, Variant::STRING);
+ register_string_modulo_op(Vector2, Variant::VECTOR2);
+ register_string_modulo_op(Vector2i, Variant::VECTOR2I);
+ register_string_modulo_op(Rect2, Variant::RECT2);
+ register_string_modulo_op(Rect2i, Variant::RECT2I);
+ register_string_modulo_op(Vector3, Variant::VECTOR3);
+ register_string_modulo_op(Vector3i, Variant::VECTOR3I);
+ register_string_modulo_op(Vector4, Variant::VECTOR4);
+ register_string_modulo_op(Vector4i, Variant::VECTOR4I);
+ register_string_modulo_op(Transform2D, Variant::TRANSFORM2D);
+ register_string_modulo_op(Plane, Variant::PLANE);
+ register_string_modulo_op(Quaternion, Variant::QUATERNION);
+ register_string_modulo_op(::AABB, Variant::AABB);
+ register_string_modulo_op(Basis, Variant::BASIS);
+ register_string_modulo_op(Transform3D, Variant::TRANSFORM3D);
+ register_string_modulo_op(Projection, Variant::PROJECTION);
+
+ register_string_modulo_op(Color, Variant::COLOR);
+ register_string_modulo_op(StringName, Variant::STRING_NAME);
+ register_string_modulo_op(NodePath, Variant::NODE_PATH);
+ register_string_modulo_op(Object, Variant::OBJECT);
+ register_string_modulo_op(Callable, Variant::CALLABLE);
+ register_string_modulo_op(Signal, Variant::SIGNAL);
+ register_string_modulo_op(Dictionary, Variant::DICTIONARY);
+ register_string_modulo_op(Array, Variant::ARRAY);
+
+ register_string_modulo_op(PackedByteArray, Variant::PACKED_BYTE_ARRAY);
+ register_string_modulo_op(PackedInt32Array, Variant::PACKED_INT32_ARRAY);
+ register_string_modulo_op(PackedInt64Array, Variant::PACKED_INT64_ARRAY);
+ register_string_modulo_op(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY);
+ register_string_modulo_op(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY);
+ register_string_modulo_op(PackedStringArray, Variant::PACKED_STRING_ARRAY);
+ register_string_modulo_op(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY);
+ register_string_modulo_op(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY);
+ register_string_modulo_op(PackedColorArray, Variant::PACKED_COLOR_ARRAY);
register_op<OperatorEvaluatorPow<int64_t, int64_t, int64_t>>(Variant::OP_POWER, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorPow<double, int64_t, double>>(Variant::OP_POWER, Variant::INT, Variant::FLOAT);
@@ -498,15 +506,13 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorBitXor<int64_t, int64_t, int64_t>>(Variant::OP_BIT_XOR, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
- register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
-
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_EQUAL, Variant::NIL, Variant::NIL);
register_op<OperatorEvaluatorEqual<bool, bool>>(Variant::OP_EQUAL, Variant::BOOL, Variant::BOOL);
register_op<OperatorEvaluatorEqual<int64_t, int64_t>>(Variant::OP_EQUAL, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorEqual<int64_t, double>>(Variant::OP_EQUAL, Variant::INT, Variant::FLOAT);
register_op<OperatorEvaluatorEqual<double, int64_t>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::INT);
register_op<OperatorEvaluatorEqual<double, double>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::FLOAT);
- register_op<OperatorEvaluatorEqual<String, String>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING);
+ register_string_op(OperatorEvaluatorEqual, Variant::OP_EQUAL);
register_op<OperatorEvaluatorEqual<Vector2, Vector2>>(Variant::OP_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorEqual<Vector2i, Vector2i>>(Variant::OP_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorEqual<Rect2, Rect2>>(Variant::OP_EQUAL, Variant::RECT2, Variant::RECT2);
@@ -524,10 +530,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorEqual<Projection, Projection>>(Variant::OP_EQUAL, Variant::PROJECTION, Variant::PROJECTION);
register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR);
- register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING);
- register_op<OperatorEvaluatorEqual<String, StringName>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING_NAME);
- register_op<OperatorEvaluatorEqual<StringName, StringName>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME);
-
register_op<OperatorEvaluatorEqual<NodePath, NodePath>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH);
register_op<OperatorEvaluatorEqual<::RID, ::RID>>(Variant::OP_EQUAL, Variant::RID, Variant::RID);
@@ -567,6 +569,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::AABB, Variant::NIL>>(Variant::OP_EQUAL, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::BASIS, Variant::NIL>>(Variant::OP_EQUAL, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::NIL>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::PROJECTION, Variant::NIL>>(Variant::OP_EQUAL, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::COLOR, Variant::NIL>>(Variant::OP_EQUAL, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::STRING_NAME, Variant::NIL>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NIL>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NIL);
@@ -603,6 +606,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::AABB>>(Variant::OP_EQUAL, Variant::NIL, Variant::AABB);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::BASIS>>(Variant::OP_EQUAL, Variant::NIL, Variant::BASIS);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::TRANSFORM3D>>(Variant::OP_EQUAL, Variant::NIL, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::PROJECTION>>(Variant::OP_EQUAL, Variant::NIL, Variant::PROJECTION);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::COLOR>>(Variant::OP_EQUAL, Variant::NIL, Variant::COLOR);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::STRING_NAME>>(Variant::OP_EQUAL, Variant::NIL, Variant::STRING_NAME);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::NODE_PATH>>(Variant::OP_EQUAL, Variant::NIL, Variant::NODE_PATH);
@@ -627,7 +631,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotEqual<int64_t, double>>(Variant::OP_NOT_EQUAL, Variant::INT, Variant::FLOAT);
register_op<OperatorEvaluatorNotEqual<double, int64_t>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::INT);
register_op<OperatorEvaluatorNotEqual<double, double>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::FLOAT);
- register_op<OperatorEvaluatorNotEqual<String, String>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING);
+ register_string_op(OperatorEvaluatorNotEqual, Variant::OP_NOT_EQUAL);
register_op<OperatorEvaluatorNotEqual<Vector2, Vector2>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorNotEqual<Vector2i, Vector2i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorNotEqual<Rect2, Rect2>>(Variant::OP_NOT_EQUAL, Variant::RECT2, Variant::RECT2);
@@ -645,10 +649,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotEqual<Projection, Projection>>(Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::PROJECTION);
register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR);
- register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING);
- register_op<OperatorEvaluatorNotEqual<String, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING_NAME);
- register_op<OperatorEvaluatorNotEqual<StringName, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME);
-
register_op<OperatorEvaluatorNotEqual<NodePath, NodePath>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH);
register_op<OperatorEvaluatorNotEqual<::RID, ::RID>>(Variant::OP_NOT_EQUAL, Variant::RID, Variant::RID);
@@ -688,6 +688,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::AABB, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NIL);
@@ -724,6 +725,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::AABB>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::AABB);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::BASIS>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::BASIS);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::TRANSFORM3D>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::PROJECTION>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::PROJECTION);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::COLOR>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::COLOR);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::STRING_NAME>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::STRING_NAME);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NODE_PATH>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NODE_PATH);
@@ -899,10 +901,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL);
register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL);
- register_op<OperatorEvaluatorInStringFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING);
- register_op<OperatorEvaluatorInStringFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING);
- register_op<OperatorEvaluatorInStringNameFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING_NAME);
- register_op<OperatorEvaluatorInStringNameFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING_NAME);
+ register_string_op(OperatorEvaluatorInStringFind, Variant::OP_IN);
register_op<OperatorEvaluatorInDictionaryHasNil>(Variant::OP_IN, Variant::NIL, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<bool>>(Variant::OP_IN, Variant::BOOL, Variant::DICTIONARY);
@@ -1000,6 +999,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorInArrayFind<float, PackedFloat64Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_FLOAT64_ARRAY);
register_op<OperatorEvaluatorInArrayFind<String, PackedStringArray>>(Variant::OP_IN, Variant::STRING, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<StringName, PackedStringArray>>(Variant::OP_IN, Variant::STRING_NAME, Variant::PACKED_STRING_ARRAY);
register_op<OperatorEvaluatorInArrayFind<Vector2, PackedVector2Array>>(Variant::OP_IN, Variant::VECTOR2, Variant::PACKED_VECTOR2_ARRAY);
register_op<OperatorEvaluatorInArrayFind<Vector3, PackedVector3Array>>(Variant::OP_IN, Variant::VECTOR3, Variant::PACKED_VECTOR3_ARRAY);
@@ -1010,6 +1010,9 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorObjectHasPropertyStringName>(Variant::OP_IN, Variant::STRING_NAME, Variant::OBJECT);
}
+#undef register_string_op
+#undef register_string_modulo_op
+
void Variant::_unregister_variant_operators() {
}
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index ec1ce67445..ea4216322c 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -875,7 +875,33 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; }
};
-class OperatorEvaluatorStringModNil {
+template <class Left, class Right>
+class OperatorEvaluatorStringConcat {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String a(*VariantGetInternalPtr<Left>::get_ptr(&p_left));
+ const String b(*VariantGetInternalPtr<Right>::get_ptr(&p_right));
+ *r_ret = a + b;
+ r_valid = true;
+ }
+ static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const String a(*VariantGetInternalPtr<Left>::get_ptr(left));
+ const String b(*VariantGetInternalPtr<Right>::get_ptr(right));
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = a + b;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ const String a(PtrToArg<Left>::convert(left));
+ const String b(PtrToArg<Right>::convert(right));
+ PtrToArg<String>::encode(a + b, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+template <class S, class T>
+class OperatorEvaluatorStringFormat;
+
+template <class S>
+class OperatorEvaluatorStringFormat<S, void> {
public:
_FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) {
Array values;
@@ -888,20 +914,22 @@ public:
return a;
}
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
- const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
- *r_ret = do_mod(a, &r_valid);
- r_valid = true;
+ *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), &r_valid);
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
- *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr);
+ bool valid = true;
+ String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), &valid);
+ ERR_FAIL_COND_MSG(!valid, result);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = result;
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
- PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), nullptr), r_ret);
+ PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), nullptr), r_ret);
}
static Variant::Type get_return_type() { return Variant::STRING; }
};
-class OperatorEvaluatorStringModArray {
+template <class S>
+class OperatorEvaluatorStringFormat<S, Array> {
public:
_FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) {
String a = s.sprintf(p_values, r_valid);
@@ -911,20 +939,22 @@ public:
return a;
}
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
- const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
- *r_ret = do_mod(a, *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid);
- r_valid = true;
+ *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid);
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
- *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr);
+ bool valid = true;
+ String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), &valid);
+ ERR_FAIL_COND_MSG(!valid, result);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = result;
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
- PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret);
+ PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret);
}
static Variant::Type get_return_type() { return Variant::STRING; }
};
-class OperatorEvaluatorStringModObject {
+template <class S>
+class OperatorEvaluatorStringFormat<S, Object> {
public:
_FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) {
Array values;
@@ -937,21 +967,22 @@ public:
return a;
}
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
- const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
- *r_ret = do_mod(a, p_right.get_validated_object(), &r_valid);
- r_valid = true;
+ *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), p_right.get_validated_object(), &r_valid);
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
- *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr);
+ bool valid = true;
+ String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), right->get_validated_object(), &valid);
+ ERR_FAIL_COND_MSG(!valid, result);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = result;
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
- PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret);
+ PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret);
}
static Variant::Type get_return_type() { return Variant::STRING; }
};
-template <class T>
-class OperatorEvaluatorStringModT {
+template <class S, class T>
+class OperatorEvaluatorStringFormat {
public:
_FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) {
Array values;
@@ -963,15 +994,16 @@ public:
return a;
}
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
- const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
- *r_ret = do_mod(a, *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid);
- r_valid = true;
+ *r_ret = do_mod(*VariantGetInternalPtr<S>::get_ptr(&p_left), *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid);
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
- *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr);
+ bool valid = true;
+ String result = do_mod(*VariantGetInternalPtr<S>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), &valid);
+ ERR_FAIL_COND_MSG(!valid, result);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = result;
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
- PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret);
+ PtrToArg<String>::encode(do_mod(PtrToArg<S>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret);
}
static Variant::Type get_return_type() { return Variant::STRING; }
};
@@ -1280,8 +1312,11 @@ public:
////
+template <class Left, class Right>
+class OperatorEvaluatorInStringFind;
+
template <class Left>
-class OperatorEvaluatorInStringFind {
+class OperatorEvaluatorInStringFind<Left, String> {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left);
@@ -1302,7 +1337,7 @@ public:
};
template <class Left>
-class OperatorEvaluatorInStringNameFind {
+class OperatorEvaluatorInStringFind<Left, StringName> {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index d2e4d752a4..f122ed5f8f 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -35,39 +35,93 @@
#include "core/os/keyboard.h"
#include "core/string/string_buffer.h"
-char32_t VariantParser::StreamFile::get_char() {
- return f->get_8();
+char32_t VariantParser::Stream::get_char() {
+ // is within buffer?
+ if (readahead_pointer < readahead_filled) {
+ return readahead_buffer[readahead_pointer++];
+ }
+
+ // attempt to readahead
+ readahead_filled = _read_buffer(readahead_buffer, readahead_enabled ? READAHEAD_SIZE : 1);
+ if (readahead_filled) {
+ readahead_pointer = 0;
+ } else {
+ // EOF
+ readahead_pointer = 1;
+ eof = true;
+ return 0;
+ }
+ return get_char();
+}
+
+bool VariantParser::Stream::is_eof() const {
+ if (readahead_enabled) {
+ return eof;
+ }
+ return _is_eof();
}
bool VariantParser::StreamFile::is_utf8() const {
return true;
}
-bool VariantParser::StreamFile::is_eof() const {
+bool VariantParser::StreamFile::_is_eof() const {
return f->eof_reached();
}
-char32_t VariantParser::StreamString::get_char() {
- if (pos > s.length()) {
- return 0;
- } else if (pos == s.length()) {
- // You need to try to read again when you have reached the end for EOF to be reported,
- // so this works the same as files (like StreamFile does)
- pos++;
- return 0;
- } else {
- return s[pos++];
+uint32_t VariantParser::StreamFile::_read_buffer(char32_t *p_buffer, uint32_t p_num_chars) {
+ // The buffer is assumed to include at least one character (for null terminator)
+ ERR_FAIL_COND_V(!p_num_chars, 0);
+
+ uint8_t *temp = (uint8_t *)alloca(p_num_chars);
+ uint64_t num_read = f->get_buffer(temp, p_num_chars);
+ ERR_FAIL_COND_V(num_read == UINT64_MAX, 0);
+
+ // translate to wchar
+ for (uint32_t n = 0; n < num_read; n++) {
+ p_buffer[n] = temp[n];
}
+
+ // could be less than p_num_chars, or zero
+ return num_read;
}
bool VariantParser::StreamString::is_utf8() const {
return false;
}
-bool VariantParser::StreamString::is_eof() const {
+bool VariantParser::StreamString::_is_eof() const {
return pos > s.length();
}
+uint32_t VariantParser::StreamString::_read_buffer(char32_t *p_buffer, uint32_t p_num_chars) {
+ // The buffer is assumed to include at least one character (for null terminator)
+ ERR_FAIL_COND_V(!p_num_chars, 0);
+
+ int available = MAX(s.length() - pos, 0);
+ if (available >= (int)p_num_chars) {
+ const char32_t *src = s.ptr();
+ src += pos;
+ memcpy(p_buffer, src, p_num_chars * sizeof(char32_t));
+ pos += p_num_chars;
+
+ return p_num_chars;
+ }
+
+ // going to reach EOF
+ if (available) {
+ const char32_t *src = s.ptr();
+ src += pos;
+ memcpy(p_buffer, src, available * sizeof(char32_t));
+ pos += available;
+ }
+
+ // add a zero
+ p_buffer[available] = 0;
+
+ return available;
+}
+
/////////////////////////////////////////////////////////////////////////////////////////////////
const char *VariantParser::tk_name[TK_MAX] = {
@@ -1283,7 +1337,7 @@ Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int
Variant v;
err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser);
- if (err) {
+ if (err && err != ERR_FILE_MISSING_DEPENDENCIES) {
return err;
}
object[key] = v;
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index 56b484c8bc..fdea355c4b 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -38,35 +38,55 @@
class VariantParser {
public:
struct Stream {
- virtual char32_t get_char() = 0;
- virtual bool is_utf8() const = 0;
- virtual bool is_eof() const = 0;
-
+ private:
+ enum { READAHEAD_SIZE = 2048 };
+ char32_t readahead_buffer[READAHEAD_SIZE];
+ uint32_t readahead_pointer = 0;
+ uint32_t readahead_filled = 0;
+ bool eof = false;
+
+ protected:
+ bool readahead_enabled = true;
+ virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) = 0;
+ virtual bool _is_eof() const = 0;
+
+ public:
char32_t saved = 0;
+ char32_t get_char();
+ virtual bool is_utf8() const = 0;
+ bool is_eof() const;
+
Stream() {}
virtual ~Stream() {}
};
struct StreamFile : public Stream {
+ protected:
+ virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) override;
+ virtual bool _is_eof() const override;
+
+ public:
Ref<FileAccess> f;
- virtual char32_t get_char() override;
virtual bool is_utf8() const override;
- virtual bool is_eof() const override;
- StreamFile() {}
+ StreamFile(bool p_readahead_enabled = true) { readahead_enabled = p_readahead_enabled; }
};
struct StreamString : public Stream {
String s;
+
+ private:
int pos = 0;
- virtual char32_t get_char() override;
- virtual bool is_utf8() const override;
- virtual bool is_eof() const override;
+ protected:
+ virtual uint32_t _read_buffer(char32_t *p_buffer, uint32_t p_num_chars) override;
+ virtual bool _is_eof() const override;
- StreamString() {}
+ public:
+ virtual bool is_utf8() const override;
+ StreamString(bool p_readahead_enabled = true) { readahead_enabled = p_readahead_enabled; }
};
typedef Error (*ParseResourceFunc)(void *p_self, Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 670b66d53e..4b82981fa9 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -310,6 +310,10 @@ struct VariantUtilityFunctions {
return Math::is_zero_approx(x);
}
+ static inline bool is_finite(double x) {
+ return Math::is_finite(x);
+ }
+
static inline double ease(float x, float curve) {
return Math::ease(x, curve);
}
@@ -318,8 +322,52 @@ struct VariantUtilityFunctions {
return Math::step_decimals(step);
}
- static inline double snapped(double value, double step) {
- return Math::snapped(value, 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;
+ 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);
+ }
+
+ static inline int64_t 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) {
@@ -331,6 +379,9 @@ struct VariantUtilityFunctions {
}
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;
@@ -385,6 +436,10 @@ struct VariantUtilityFunctions {
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);
+ }
+
static inline double lerp_angle(double from, double to, double weight) {
return Math::lerp_angle(from, to, weight);
}
@@ -1128,6 +1183,40 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) {
}; \
register_utility_function<Func_##m_func>(#m_func, m_args)
+#define FUNCBINDVR2(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ r_error.error = Callable::CallError::CALL_OK; \
+ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ Callable::CallError ce; \
+ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], ce); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ Callable::CallError ce; \
+ Variant r; \
+ r = VariantUtilityFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), PtrToArg<Variant>::convert(p_args[1]), ce); \
+ PtrToArg<Variant>::encode(r, ret); \
+ } \
+ static int get_argument_count() { \
+ return 2; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_vararg() { return false; } \
+ static Variant::UtilityFunctionType get_type() { return m_category; } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
#define FUNCBINDVR3(m_func, m_args, m_category) \
class Func_##m_func { \
public: \
@@ -1411,6 +1500,10 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(signf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(signi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDVR2(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(snappedf, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(snappedi, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
+
FUNCBINDR(pow, sarray("base", "exp"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(log, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(exp, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1420,10 +1513,10 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(is_finite, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVR3(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerpf, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1432,6 +1525,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(bezier_derivative, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);