diff options
Diffstat (limited to 'core')
181 files changed, 9571 insertions, 5329 deletions
diff --git a/core/SCsub b/core/SCsub index e3ba46be02..d9167b8f83 100644 --- a/core/SCsub +++ b/core/SCsub @@ -186,6 +186,7 @@ SConscript("io/SCsub") SConscript("debugger/SCsub") SConscript("input/SCsub") SConscript("variant/SCsub") +SConscript("extension/SCsub") SConscript("object/SCsub") SConscript("templates/SCsub") SConscript("string/SCsub") diff --git a/core/config/engine.cpp b/core/config/engine.cpp index c43e32868c..ad31966a65 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -190,6 +190,14 @@ bool Engine::is_validation_layers_enabled() const { return use_validation_layers; } +void Engine::set_print_error_messages(bool p_enabled) { + _print_error_enabled = p_enabled; +} + +bool Engine::is_printing_error_messages() const { + return _print_error_enabled; +} + void Engine::add_singleton(const Singleton &p_singleton) { singletons.push_back(p_singleton); singleton_ptrs[p_singleton.name] = p_singleton.ptr; @@ -228,13 +236,14 @@ Engine::Engine() { singleton = this; } -Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) : +Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) : name(p_name), - ptr(p_ptr) { + ptr(p_ptr), + class_name(p_class_name) { #ifdef DEBUG_ENABLED - Reference *ref = Object::cast_to<Reference>(p_ptr); - if (ref && !ref->is_referenced()) { - WARN_PRINT("You must use Ref<> to ensure the lifetime of a Reference object intended to be used as a singleton."); + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); + if (rc && !rc->is_referenced()) { + WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton."); } #endif } diff --git a/core/config/engine.h b/core/config/engine.h index 276da1c7ea..970cfb03e8 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -41,7 +41,8 @@ public: struct Singleton { StringName name; Object *ptr; - Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr); + StringName class_name; //used for binding generation hinting + Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName()); }; private: @@ -100,6 +101,9 @@ public: void set_time_scale(float p_scale); float get_time_scale() const; + void set_print_error_messages(bool p_enabled); + bool is_printing_error_messages() const; + void set_frame_delay(uint32_t p_msec); uint32_t get_frame_delay() const; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 53d13f7429..ac4e0db5b7 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -33,11 +33,11 @@ #include "core/core_bind.h" #include "core/core_string_names.h" #include "core/input/input_map.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_network.h" #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" @@ -62,7 +62,7 @@ String ProjectSettings::localize_path(const String &p_path) const { } if (p_path.begins_with("res://") || p_path.begins_with("user://") || - (p_path.is_abs_path() && !p_path.begins_with(resource_path))) { + (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) { return p_path.simplify_path(); } @@ -248,7 +248,7 @@ struct _VCSort { String name; Variant::Type type; int order; - int flags; + uint32_t flags; bool operator<(const _VCSort &p_vcs) const { return order == p_vcs.order ? name < p_vcs.name : order < p_vcs.order; } }; @@ -711,8 +711,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str file->store_32(count + 1); //store how many properties are saved, add one for custom featuers, which must always go first String key = CoreStringNames::get_singleton()->_custom_features; - file->store_32(key.length()); - file->store_string(key); + file->store_pascal_string(key); int len; err = encode_variant(p_custom_features, nullptr, len, false); @@ -749,8 +748,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str value = get(key); } - file->store_32(key.length()); - file->store_string(key); + file->store_pascal_string(key); int len; err = encode_variant(value, nullptr, len, true); @@ -1102,7 +1100,7 @@ ProjectSettings::ProjectSettings() { if (Engine::get_singleton()->has_singleton("GodotSharp")) { extensions.push_back("cs"); } - extensions.push_back("shader"); + extensions.push_back("gdshader"); GLOBAL_DEF("editor/run/main_run_args", ""); @@ -1116,6 +1114,8 @@ ProjectSettings::ProjectSettings() { // Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum. custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"); + // Keep the enum values in sync with the `DisplayServer::VSyncMode` enum. + custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox"); custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); GLOBAL_DEF("physics/2d/run_on_thread", false); GLOBAL_DEF("physics/3d/run_on_thread", false); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index ed4387a1b9..a3349444c4 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -35,35 +35,12 @@ #include "core/debugger/engine_debugger.h" #include "core/io/file_access_compressed.h" #include "core/io/file_access_encrypted.h" -#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" #include "core/os/keyboard.h" #include "core/os/os.h" -/** - * Time constants borrowed from loc_time.h - */ -#define EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */ -#define SECS_DAY (24L * 60L * 60L) -#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) -#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) -#define SECOND_KEY "second" -#define MINUTE_KEY "minute" -#define HOUR_KEY "hour" -#define DAY_KEY "day" -#define MONTH_KEY "month" -#define YEAR_KEY "year" -#define WEEKDAY_KEY "weekday" -#define DST_KEY "dst" - -/// Table of number of days in each month (for regular year and leap year) -static const unsigned int MONTH_DAYS_TABLE[2][12] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - ////// _ResourceLoader ////// _ResourceLoader *_ResourceLoader::singleton = nullptr; @@ -322,197 +299,6 @@ uint64_t _OS::get_static_memory_peak_usage() const { return OS::get_singleton()->get_static_memory_peak_usage(); } -/** - * Get current datetime with consideration for utc and - * dst - */ -Dictionary _OS::get_datetime(bool utc) const { - Dictionary dated = get_date(utc); - Dictionary timed = get_time(utc); - - List<Variant> keys; - timed.get_key_list(&keys); - - for (int i = 0; i < keys.size(); i++) { - dated[keys[i]] = timed[keys[i]]; - } - - return dated; -} - -Dictionary _OS::get_date(bool utc) const { - OS::Date date = OS::get_singleton()->get_date(utc); - Dictionary dated; - dated[YEAR_KEY] = date.year; - dated[MONTH_KEY] = date.month; - dated[DAY_KEY] = date.day; - dated[WEEKDAY_KEY] = date.weekday; - dated[DST_KEY] = date.dst; - return dated; -} - -Dictionary _OS::get_time(bool utc) const { - OS::Time time = OS::get_singleton()->get_time(utc); - Dictionary timed; - timed[HOUR_KEY] = time.hour; - timed[MINUTE_KEY] = time.min; - timed[SECOND_KEY] = time.sec; - return timed; -} - -/** - * Get an epoch time value from a dictionary of time values - * @p datetime must be populated with the following keys: - * day, hour, minute, month, second, year. (dst is ignored). - * - * You can pass the output from - * get_datetime_from_unix_time directly into this function - * - * @param datetime dictionary of date and time values to convert - * - * @return epoch calculated - */ -int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { - // if datetime is an empty Dictionary throws an error - ERR_FAIL_COND_V_MSG(datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); - - // Bunch of conversion constants - static const unsigned int SECONDS_PER_MINUTE = 60; - static const unsigned int MINUTES_PER_HOUR = 60; - static const unsigned int HOURS_PER_DAY = 24; - static const unsigned int SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE; - static const unsigned int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; - - // Get all time values from the dictionary, set to zero if it doesn't exist. - // Risk incorrect calculation over throwing errors - unsigned int second = ((datetime.has(SECOND_KEY)) ? static_cast<unsigned int>(datetime[SECOND_KEY]) : 0); - unsigned int minute = ((datetime.has(MINUTE_KEY)) ? static_cast<unsigned int>(datetime[MINUTE_KEY]) : 0); - unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast<unsigned int>(datetime[HOUR_KEY]) : 0); - unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 1); - unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) : 1); - unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast<unsigned int>(datetime[YEAR_KEY]) : 1970); - - /// How many days come before each month (0-12) - static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - - ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + "."); - ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); - ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); - ERR_FAIL_COND_V_MSG(year == 0, 0, "Years before 1 AD are not supported. Value passed: " + itos(year) + "."); - ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + "."); - // Do this check after month is tested as valid - unsigned int days_in_month = MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]; - ERR_FAIL_COND_V_MSG(day == 0 || day > days_in_month, 0, "Invalid day value of: " + itos(day) + ". It should be comprised between 1 and " + itos(days_in_month) + " for month " + itos(month) + "."); - - // Calculate all the seconds from months past in this year - uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; - - int64_t SECONDS_FROM_YEARS_PAST = 0; - if (year >= EPOCH_YR) { - for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { - SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; - } - } else { - for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) { - SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY; - } - } - - int64_t epoch = - second + - minute * SECONDS_PER_MINUTE + - hour * SECONDS_PER_HOUR + - // Subtract 1 from day, since the current day isn't over yet - // and we cannot count all 24 hours. - (day - 1) * SECONDS_PER_DAY + - SECONDS_FROM_MONTHS_PAST_THIS_YEAR + - SECONDS_FROM_YEARS_PAST; - return epoch; -} - -/** - * Get a dictionary of time values when given epoch time - * - * Dictionary Time values will be a union if values from #get_time - * and #get_date dictionaries (with the exception of dst = - * day light standard time, as it cannot be determined from epoch) - * - * @param unix_time_val epoch time to convert - * - * @return dictionary of date and time values - */ -Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { - OS::Date date; - OS::Time time; - - long dayclock, dayno; - int year = EPOCH_YR; - - if (unix_time_val >= 0) { - dayno = unix_time_val / SECS_DAY; - dayclock = unix_time_val % SECS_DAY; - /* day 0 was a thursday */ - date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); - while (dayno >= YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - } else { - dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; - dayclock = unix_time_val - dayno * SECS_DAY; - date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7); - do { - year--; - dayno += YEARSIZE(year); - } while (dayno < 0); - } - - time.sec = dayclock % 60; - time.min = (dayclock % 3600) / 60; - time.hour = dayclock / 3600; - date.year = year; - - size_t imonth = 0; - - while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) { - dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]; - imonth++; - } - - /// Add 1 to month to make sure months are indexed starting at 1 - date.month = static_cast<OS::Month>(imonth + 1); - - date.day = dayno + 1; - - Dictionary timed; - timed[HOUR_KEY] = time.hour; - timed[MINUTE_KEY] = time.min; - timed[SECOND_KEY] = time.sec; - timed[YEAR_KEY] = date.year; - timed[MONTH_KEY] = date.month; - timed[DAY_KEY] = date.day; - timed[WEEKDAY_KEY] = date.weekday; - - return timed; -} - -Dictionary _OS::get_time_zone_info() const { - OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info(); - Dictionary infod; - infod["bias"] = info.bias; - infod["name"] = info.name; - return infod; -} - -double _OS::get_unix_time() const { - return OS::get_singleton()->get_unix_time(); -} - /** This method uses a signed argument for better error reporting as it's used from the scripting API. */ void _OS::delay_usec(int p_usec) const { ERR_FAIL_COND_MSG( @@ -529,14 +315,6 @@ void _OS::delay_msec(int p_msec) const { OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000); } -uint32_t _OS::get_ticks_msec() const { - return OS::get_singleton()->get_ticks_msec(); -} - -uint64_t _OS::get_ticks_usec() const { - return OS::get_singleton()->get_ticks_usec(); -} - bool _OS::can_use_threads() const { return OS::get_singleton()->can_use_threads(); } @@ -643,6 +421,25 @@ String _OS::get_user_data_dir() const { return OS::get_singleton()->get_user_data_dir(); } +String _OS::get_external_data_dir() const { + return OS::get_singleton()->get_external_data_dir(); +} + +String _OS::get_config_dir() const { + // Exposed as `get_config_dir()` instead of `get_config_path()` for consistency with other exposed OS methods. + return OS::get_singleton()->get_config_path(); +} + +String _OS::get_data_dir() const { + // Exposed as `get_data_dir()` instead of `get_data_path()` for consistency with other exposed OS methods. + return OS::get_singleton()->get_data_path(); +} + +String _OS::get_cache_dir() const { + // Exposed as `get_cache_dir()` instead of `get_cache_path()` for consistency with other exposed OS methods. + return OS::get_singleton()->get_cache_path(); +} + bool _OS::is_debug_build() const { #ifdef DEBUG_ENABLED return true; @@ -712,18 +509,8 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name); ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args); - ClassDB::bind_method(D_METHOD("get_datetime", "utc"), &_OS::get_datetime, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_date", "utc"), &_OS::get_date, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_time", "utc"), &_OS::get_time, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_time_zone_info"), &_OS::get_time_zone_info); - ClassDB::bind_method(D_METHOD("get_unix_time"), &_OS::get_unix_time); - ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time); - ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime); - ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec); ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec); - ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec); - ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec); ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale); ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name); @@ -743,7 +530,11 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &_OS::get_static_memory_peak_usage); ClassDB::bind_method(D_METHOD("get_user_data_dir"), &_OS::get_user_data_dir); + ClassDB::bind_method(D_METHOD("get_external_data_dir"), &_OS::get_external_data_dir); ClassDB::bind_method(D_METHOD("get_system_dir", "dir"), &_OS::get_system_dir); + ClassDB::bind_method(D_METHOD("get_config_dir"), &_OS::get_config_dir); + ClassDB::bind_method(D_METHOD("get_data_dir"), &_OS::get_data_dir); + ClassDB::bind_method(D_METHOD("get_cache_dir"), &_OS::get_cache_dir); ClassDB::bind_method(D_METHOD("get_unique_id"), &_OS::get_unique_id); ClassDB::bind_method(D_METHOD("print_all_textures_by_size"), &_OS::print_all_textures_by_size); @@ -2059,17 +1850,17 @@ bool _ClassDB::is_parent_class(const StringName &p_class, const StringName &p_in return ClassDB::is_parent_class(p_class, p_inherits); } -bool _ClassDB::can_instance(const StringName &p_class) const { - return ClassDB::can_instance(p_class); +bool _ClassDB::can_instantiate(const StringName &p_class) const { + return ClassDB::can_instantiate(p_class); } -Variant _ClassDB::instance(const StringName &p_class) const { - Object *obj = ClassDB::instance(p_class); +Variant _ClassDB::instantiate(const StringName &p_class) const { + Object *obj = ClassDB::instantiate(p_class); if (!obj) { return Variant(); } - Reference *r = Object::cast_to<Reference>(obj); + RefCounted *r = Object::cast_to<RefCounted>(obj); if (r) { return REF(r); } else { @@ -2193,8 +1984,8 @@ void _ClassDB::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parent_class", "class"), &_ClassDB::get_parent_class); ClassDB::bind_method(D_METHOD("class_exists", "class"), &_ClassDB::class_exists); ClassDB::bind_method(D_METHOD("is_parent_class", "class", "inherits"), &_ClassDB::is_parent_class); - ClassDB::bind_method(D_METHOD("can_instance", "class"), &_ClassDB::can_instance); - ClassDB::bind_method(D_METHOD("instance", "class"), &_ClassDB::instance); + ClassDB::bind_method(D_METHOD("can_instantiate", "class"), &_ClassDB::can_instantiate); + ClassDB::bind_method(D_METHOD("instantiate", "class"), &_ClassDB::instantiate); ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &_ClassDB::has_signal); ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &_ClassDB::get_signal); @@ -2320,6 +2111,14 @@ bool _Engine::is_editor_hint() const { return Engine::get_singleton()->is_editor_hint(); } +void _Engine::set_print_error_messages(bool p_enabled) { + Engine::get_singleton()->set_print_error_messages(p_enabled); +} + +bool _Engine::is_printing_error_messages() const { + return Engine::get_singleton()->is_printing_error_messages(); +} + void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_iterations_per_second", "iterations_per_second"), &_Engine::set_iterations_per_second); ClassDB::bind_method(D_METHOD("get_iterations_per_second"), &_Engine::get_iterations_per_second); @@ -2354,7 +2153,11 @@ void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editor_hint", "enabled"), &_Engine::set_editor_hint); ClassDB::bind_method(D_METHOD("is_editor_hint"), &_Engine::is_editor_hint); + ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &_Engine::set_print_error_messages); + ClassDB::bind_method(D_METHOD("is_printing_error_messages"), &_Engine::is_printing_error_messages); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_hint"), "set_editor_hint", "is_editor_hint"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages"); ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations_per_second"), "set_iterations_per_second", "get_iterations_per_second"); ADD_PROPERTY(PropertyInfo(Variant::INT, "target_fps"), "set_target_fps", "get_target_fps"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale"); @@ -2363,80 +2166,6 @@ void _Engine::_bind_methods() { _Engine *_Engine::singleton = nullptr; -////// _JSON ////// - -void JSONParseResult::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_error"), &JSONParseResult::get_error); - ClassDB::bind_method(D_METHOD("get_error_string"), &JSONParseResult::get_error_string); - ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParseResult::get_error_line); - ClassDB::bind_method(D_METHOD("get_result"), &JSONParseResult::get_result); - - ClassDB::bind_method(D_METHOD("set_error", "error"), &JSONParseResult::set_error); - ClassDB::bind_method(D_METHOD("set_error_string", "error_string"), &JSONParseResult::set_error_string); - ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line); - ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result"); -} - -void JSONParseResult::set_error(Error p_error) { - error = p_error; -} - -Error JSONParseResult::get_error() const { - return error; -} - -void JSONParseResult::set_error_string(const String &p_error_string) { - error_string = p_error_string; -} - -String JSONParseResult::get_error_string() const { - return error_string; -} - -void JSONParseResult::set_error_line(int p_error_line) { - error_line = p_error_line; -} - -int JSONParseResult::get_error_line() const { - return error_line; -} - -void JSONParseResult::set_result(const Variant &p_result) { - result = p_result; -} - -Variant JSONParseResult::get_result() const { - return result; -} - -void _JSON::_bind_methods() { - ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys"), &_JSON::print, DEFVAL(String()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse); -} - -String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys) { - return JSON::print(p_value, p_indent, p_sort_keys); -} - -Ref<JSONParseResult> _JSON::parse(const String &p_json) { - Ref<JSONParseResult> result; - result.instance(); - - result->error = JSON::parse(p_json, result->result, result->error_string, result->error_line); - - if (result->error != OK) { - ERR_PRINT(vformat("Error parsing JSON at line %s: %s", result->error_line, result->error_string)); - } - return result; -} - -_JSON *_JSON::singleton = nullptr; - ////// _EngineDebugger ////// void _EngineDebugger::_bind_methods() { diff --git a/core/core_bind.h b/core/core_bind.h index d05353bf0f..673dbe32c4 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -32,11 +32,11 @@ #define CORE_BIND_H #include "core/io/compression.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/os/semaphore.h" #include "core/os/thread.h" @@ -199,14 +199,6 @@ public: void set_use_file_access_save_and_swap(bool p_enable); - Dictionary get_date(bool utc) const; - Dictionary get_time(bool utc) const; - Dictionary get_datetime(bool utc) const; - Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const; - int64_t get_unix_time_from_datetime(Dictionary datetime) const; - Dictionary get_time_zone_info() const; - double get_unix_time() const; - uint64_t get_static_memory_usage() const; uint64_t get_static_memory_peak_usage() const; @@ -237,6 +229,10 @@ public: String get_system_dir(SystemDir p_dir) const; String get_user_data_dir() const; + String get_external_data_dir() const; + String get_config_dir() const; + String get_data_dir() const; + String get_cache_dir() const; Error set_thread_name(const String &p_name); Thread::ID get_thread_caller_id() const; @@ -352,8 +348,8 @@ public: _Geometry3D() { singleton = this; } }; -class _File : public Reference { - GDCLASS(_File, Reference); +class _File : public RefCounted { + GDCLASS(_File, RefCounted); FileAccess *f = nullptr; bool big_endian = false; @@ -454,8 +450,8 @@ public: VARIANT_ENUM_CAST(_File::ModeFlags); VARIANT_ENUM_CAST(_File::CompressionMode); -class _Directory : public Reference { - GDCLASS(_Directory, Reference); +class _Directory : public RefCounted { + GDCLASS(_Directory, RefCounted); DirAccess *d; bool dir_open = false; @@ -524,8 +520,8 @@ public: ~_Marshalls() { singleton = nullptr; } }; -class _Mutex : public Reference { - GDCLASS(_Mutex, Reference); +class _Mutex : public RefCounted { + GDCLASS(_Mutex, RefCounted); Mutex mutex; static void _bind_methods(); @@ -536,8 +532,8 @@ public: void unlock(); }; -class _Semaphore : public Reference { - GDCLASS(_Semaphore, Reference); +class _Semaphore : public RefCounted { + GDCLASS(_Semaphore, RefCounted); Semaphore semaphore; static void _bind_methods(); @@ -548,8 +544,8 @@ public: void post(); }; -class _Thread : public Reference { - GDCLASS(_Thread, Reference); +class _Thread : public RefCounted { + GDCLASS(_Thread, RefCounted); protected: Variant ret; @@ -589,8 +585,8 @@ public: StringName get_parent_class(const StringName &p_class) const; bool class_exists(const StringName &p_class) const; bool is_parent_class(const StringName &p_class, const StringName &p_inherits) const; - bool can_instance(const StringName &p_class) const; - Variant instance(const StringName &p_class) const; + bool can_instantiate(const StringName &p_class) const; + Variant instantiate(const StringName &p_class) const; bool has_signal(StringName p_class, StringName p_signal) const; Dictionary get_signal(StringName p_class, StringName p_signal) const; @@ -660,55 +656,10 @@ public: void set_editor_hint(bool p_enabled); bool is_editor_hint() const; - _Engine() { singleton = this; } -}; - -class _JSON; - -class JSONParseResult : public Reference { - GDCLASS(JSONParseResult, Reference); - - friend class _JSON; - - Error error; - String error_string; - int error_line = -1; - - Variant result; - -protected: - static void _bind_methods(); - -public: - void set_error(Error p_error); - Error get_error() const; - - void set_error_string(const String &p_error_string); - String get_error_string() const; - - void set_error_line(int p_error_line); - int get_error_line() const; + void set_print_error_messages(bool p_enabled); + bool is_printing_error_messages() const; - void set_result(const Variant &p_result); - Variant get_result() const; - - JSONParseResult() {} -}; - -class _JSON : public Object { - GDCLASS(_JSON, Object); - -protected: - static void _bind_methods(); - static _JSON *singleton; - -public: - static _JSON *get_singleton() { return singleton; } - - String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false); - Ref<JSONParseResult> parse(const String &p_json); - - _JSON() { singleton = this; } + _Engine() { singleton = this; } }; class _EngineDebugger : public Object { diff --git a/core/core_constants.cpp b/core/core_constants.cpp index a0a41015dc..0aad21276a 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -106,10 +106,6 @@ static Vector<_CoreConstant> _global_constants; VARIANT_ENUM_CAST(Key); VARIANT_ENUM_CAST(KeyModifierMask); -VARIANT_ENUM_CAST(MouseButton); -VARIANT_ENUM_CAST(JoyButton); -VARIANT_ENUM_CAST(JoyAxis); -VARIANT_ENUM_CAST(MIDIMessage); void register_global_constants() { BIND_CORE_ENUM_CONSTANT(SIDE_LEFT); @@ -512,7 +508,6 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE); - BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_RANGE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LENGTH); @@ -580,10 +575,10 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE); - BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUAT", Variant::QUAT); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS); - BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH); diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h index cc00b18fd2..2f8422f537 100644 --- a/core/crypto/aes_context.h +++ b/core/crypto/aes_context.h @@ -32,10 +32,10 @@ #define AES_CONTEXT_H #include "core/crypto/crypto_core.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class AESContext : public Reference { - GDCLASS(AESContext, Reference); +class AESContext : public RefCounted { + GDCLASS(AESContext, RefCounted); public: enum Mode { diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index 9438fcfea5..a46f42949d 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -35,7 +35,7 @@ #include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class CryptoKey : public Resource { GDCLASS(CryptoKey, Resource); @@ -67,8 +67,8 @@ public: virtual Error save(String p_path) = 0; }; -class HMACContext : public Reference { - GDCLASS(HMACContext, Reference); +class HMACContext : public RefCounted { + GDCLASS(HMACContext, RefCounted); protected: static void _bind_methods(); @@ -82,10 +82,11 @@ public: virtual PackedByteArray finish() = 0; HMACContext() {} + virtual ~HMACContext() {} }; -class Crypto : public Reference { - GDCLASS(Crypto, Reference); +class Crypto : public RefCounted { + GDCLASS(Crypto, RefCounted); protected: static void _bind_methods(); diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h index 27b380e838..7a2f4df589 100644 --- a/core/crypto/crypto_core.h +++ b/core/crypto/crypto_core.h @@ -31,7 +31,7 @@ #ifndef CRYPTO_CORE_H #define CRYPTO_CORE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class CryptoCore { public: diff --git a/core/crypto/hashing_context.h b/core/crypto/hashing_context.h index 892a48a4e8..31521a147c 100644 --- a/core/crypto/hashing_context.h +++ b/core/crypto/hashing_context.h @@ -31,10 +31,10 @@ #ifndef HASHING_CONTEXT_H #define HASHING_CONTEXT_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class HashingContext : public Reference { - GDCLASS(HashingContext, Reference); +class HashingContext : public RefCounted { + GDCLASS(HashingContext, RefCounted); public: enum HashType { diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index 39113eda14..ea5e32203c 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -84,7 +84,7 @@ RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) { thread.start(_thread_func, this); #endif } else { - tcp_client.instance(); + tcp_client.instantiate(); } } diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h index 652e2d9d20..8cba53a81c 100644 --- a/core/debugger/remote_debugger_peer.h +++ b/core/debugger/remote_debugger_peer.h @@ -32,12 +32,12 @@ #define REMOTE_DEBUGGER_PEER_H #include "core/io/stream_peer_tcp.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/os/thread.h" #include "core/string/ustring.h" -class RemoteDebuggerPeer : public Reference { +class RemoteDebuggerPeer : public RefCounted { protected: int max_queued_messages = 4096; diff --git a/core/extension/SCsub b/core/extension/SCsub new file mode 100644 index 0000000000..a3a54250c1 --- /dev/null +++ b/core/extension/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import("env") + +env_extension = env.Clone() + +env_extension.add_source_files(env.core_sources, "*.cpp") diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp new file mode 100644 index 0000000000..3c132a619d --- /dev/null +++ b/core/extension/extension_api_dump.cpp @@ -0,0 +1,805 @@ +/*************************************************************************/ +/* extension_api_dump.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "extension_api_dump.h" +#include "core/config/engine.h" +#include "core/core_constants.h" +#include "core/io/file_access.h" +#include "core/io/json.h" +#include "core/templates/pair.h" +#include "core/version.h" + +#ifdef TOOLS_ENABLED + +Dictionary NativeExtensionAPIDump::generate_extension_api() { + Dictionary api_dump; + + { + //header + Dictionary header; + header["version_major"] = VERSION_MAJOR; + header["version_minor"] = VERSION_MINOR; +#if VERSION_PATCH + header["version_patch"] = VERSION_PATCH; +#else + header["version_patch"] = 0; +#endif + header["version_status"] = VERSION_STATUS; + header["version_build"] = VERSION_BUILD; + header["version_full_name"] = VERSION_FULL_NAME; + + api_dump["header"] = header; + } + + const uint32_t vec3_elems = 3; + const uint32_t ptrsize_32 = 4; + const uint32_t ptrsize_64 = 4; + static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" }; + + { + //type sizes + struct { + Variant::Type type; + uint32_t size_32_bits_real_float; + uint32_t size_64_bits_real_float; + uint32_t size_32_bits_real_double; + uint32_t size_64_bits_real_double; + } type_size_array[Variant::VARIANT_MAX + 1] = { + { Variant::NIL, 0, 0, 0, 0 }, + { Variant::BOOL, sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) }, + { Variant::INT, sizeof(int64_t), sizeof(int64_t), sizeof(int64_t), sizeof(int64_t) }, + { Variant::FLOAT, sizeof(double), sizeof(double), sizeof(double), sizeof(double) }, + { Variant::STRING, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::VECTOR2, 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, + { Variant::VECTOR2I, 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, + { Variant::RECT2, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) }, + { Variant::RECT2I, 4 * sizeof(int32_t), 4 * sizeof(int32_t), 4 * sizeof(int32_t), 4 * sizeof(int32_t) }, + { Variant::VECTOR3, vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, + { Variant::VECTOR3I, 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t) }, + { Variant::TRANSFORM2D, 6 * sizeof(float), 6 * sizeof(float), 6 * sizeof(double), 6 * sizeof(double) }, + { Variant::PLANE, (vec3_elems + 1) * sizeof(float), (vec3_elems + 1) * sizeof(float), (vec3_elems + 1) * sizeof(double), (vec3_elems + 1) * sizeof(double) }, + { Variant::QUATERNION, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) }, + { Variant::AABB, (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(double), (vec3_elems * 2) * sizeof(double) }, + { Variant::BASIS, (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) }, + { Variant::TRANSFORM3D, (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(double), (vec3_elems * 4) * sizeof(double) }, + { Variant::COLOR, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float) }, + { Variant::STRING_NAME, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::NODE_PATH, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::RID, sizeof(uint64_t), sizeof(uint64_t), sizeof(uint64_t), sizeof(uint64_t) }, + { Variant::OBJECT, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::CALLABLE, sizeof(Callable), sizeof(Callable), sizeof(Callable), sizeof(Callable) }, //harcoded align + { Variant::SIGNAL, sizeof(Signal), sizeof(Signal), sizeof(Signal), sizeof(Signal) }, //harcoded align + { Variant::DICTIONARY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_BYTE_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_INT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_INT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_FLOAT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_FLOAT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_STRING_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_VECTOR2_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_VECTOR3_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_COLOR_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::VARIANT_MAX, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(double) * 4, sizeof(uint64_t) + sizeof(double) * 4 }, + }; + + Array core_type_sizes; + + for (int i = 0; i < 4; i++) { + Dictionary d; + d["build_configuration"] = build_config_name[i]; + Array sizes; + for (int j = 0; j < Variant::VARIANT_MAX; j++) { + Variant::Type t = type_size_array[j].type; + String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t); + Dictionary d2; + d2["name"] = name; + uint32_t size; + switch (i) { + case 0: + size = type_size_array[j].size_32_bits_real_float; + break; + case 1: + size = type_size_array[j].size_64_bits_real_float; + break; + case 2: + size = type_size_array[j].size_32_bits_real_double; + break; + case 3: + size = type_size_array[j].size_64_bits_real_double; + break; + } + d2["size"] = size; + sizes.push_back(d2); + } + d["sizes"] = sizes; + core_type_sizes.push_back(d); + } + api_dump["builtin_class_sizes"] = core_type_sizes; + } + + { + //member offsets sizes + 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; + } 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::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) }, + //rememer 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::COLOR, "x", 0, 0, 0, 0 }, + { Variant::COLOR, "y", sizeof(float), sizeof(float), sizeof(float), sizeof(float) }, + { Variant::COLOR, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) }, + { Variant::COLOR, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float) }, + { Variant::NIL, nullptr, 0, 0, 0, 0 }, + }; + + Array core_type_member_offsets; + + for (int i = 0; i < 4; i++) { + Dictionary d; + d["build_configuration"] = build_config_name[i]; + Array type_offsets; + uint32_t idx = 0; + + Variant::Type last_type = Variant::NIL; + + Dictionary d2; + Array members; + + while (true) { + Variant::Type t = member_offset_array[idx].type; + if (t != last_type) { + if (last_type != Variant::NIL) { + d2["members"] = members; + type_offsets.push_back(d2); + } + if (t == Variant::NIL) { + break; + } + + String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t); + d2 = Dictionary(); + members = Array(); + d2["name"] = name; + last_type = t; + } + Dictionary d3; + uint32_t offset; + switch (i) { + case 0: + offset = member_offset_array[idx].offset_32_bits_real_float; + break; + case 1: + offset = member_offset_array[idx].offset_64_bits_real_float; + break; + case 2: + offset = member_offset_array[idx].offset_32_bits_real_double; + break; + case 3: + offset = member_offset_array[idx].offset_64_bits_real_double; + break; + } + d3["member"] = member_offset_array[idx].member; + d3["offset"] = offset; + members.push_back(d3); + idx++; + } + d["classes"] = type_offsets; + core_type_member_offsets.push_back(d); + } + api_dump["builtin_class_member_offsets"] = core_type_member_offsets; + } + + { + // global enums and constants + Array constants; + Map<String, List<Pair<String, int>>> enum_list; + + for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { + int value = CoreConstants::get_global_constant_value(i); + String enum_name = CoreConstants::get_global_constant_enum(i); + String name = CoreConstants::get_global_constant_name(i); + if (enum_name != String()) { + enum_list[enum_name].push_back(Pair<String, int>(name, value)); + } else { + Dictionary d; + d["name"] = name; + d["value"] = value; + constants.push_back(d); + } + } + + api_dump["global_constants"] = constants; + + Array enums; + for (Map<String, List<Pair<String, int>>>::Element *E = enum_list.front(); E; E = E->next()) { + Dictionary d1; + d1["name"] = E->key(); + Array values; + for (List<Pair<String, int>>::Element *F = E->get().front(); F; F = F->next()) { + Dictionary d2; + d2["name"] = F->get().first; + d2["value"] = F->get().second; + values.push_back(d2); + } + d1["values"] = values; + enums.push_back(d1); + } + + api_dump["global_enums"] = enums; + } + { + Array utility_funcs; + + List<StringName> utility_func_names; + Variant::get_utility_function_list(&utility_func_names); + + for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) { + StringName name = E->get(); + Dictionary func; + func["name"] = String(name); + if (Variant::has_utility_function_return_value(name)) { + Variant::Type rt = Variant::get_utility_function_return_type(name); + func["return_type"] = rt == Variant::NIL ? String("Variant") : Variant::get_type_name(rt); + } + switch (Variant::get_utility_function_type(name)) { + case Variant::UTILITY_FUNC_TYPE_MATH: + func["category"] = "math"; + break; + case Variant::UTILITY_FUNC_TYPE_RANDOM: + func["category"] = "random"; + break; + case Variant::UTILITY_FUNC_TYPE_GENERAL: + func["category"] = "general"; + break; + } + bool vararg = Variant::is_utility_function_vararg(name); + func["is_vararg"] = Variant::is_utility_function_vararg(name); + func["hash"] = Variant::get_utility_function_hash(name); + Array arguments; + int argcount = Variant::get_utility_function_argument_count(name); + for (int i = 0; i < argcount; i++) { + 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); + //no default value support in utility functions + arguments.push_back(arg); + } + + if (arguments.size()) { + func["arguments"] = arguments; + } + + utility_funcs.push_back(func); + } + + api_dump["utility_functions"] = utility_funcs; + } + + { + // builtin types + + Array builtins; + + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (i == Variant::OBJECT) { + continue; + } + + Variant::Type type = Variant::Type(i); + + 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); + } + + { + //members + Array members; + + List<StringName> member_names; + Variant::get_member_list(type, &member_names); + for (List<StringName>::Element *E = member_names.front(); E; E = E->next()) { + StringName member_name = E->get(); + Dictionary d2; + d2["name"] = String(member_name); + d2["type"] = Variant::get_type_name(Variant::get_member_type(type, member_name)); + members.push_back(d2); + } + if (members.size()) { + d["members"] = members; + } + } + { + //constants + Array constants; + + List<StringName> constant_names; + Variant::get_constants_for_type(type, &constant_names); + for (List<StringName>::Element *E = constant_names.front(); E; E = E->next()) { + StringName constant_name = E->get(); + 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["value"] = constant.get_construct_string(); + constants.push_back(d2); + } + if (constants.size()) { + d["constants"] = constants; + } + } + { + //operators + Array operators; + + for (int j = 0; j < Variant::VARIANT_MAX; j++) { + for (int k = 0; k < Variant::OP_MAX; k++) { + Variant::Type rt = Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)); + if (rt != Variant::NIL) { + 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)); + } + operators.push_back(d2); + } + } + } + if (operators.size()) { + d["operators"] = operators; + } + } + { + //methods + Array methods; + + List<StringName> method_names; + Variant::get_builtin_method_list(type, &method_names); + for (List<StringName>::Element *E = method_names.front(); E; E = E->next()) { + StringName method_name = E->get(); + Dictionary d2; + d2["name"] = String(method_name); + if (Variant::has_builtin_method_return_value(type, method_name)) { + Variant::Type ret_type = Variant::get_builtin_method_return_type(type, method_name); + d2["return_type"] = ret_type == Variant::NIL ? String("Variant") : Variant::get_type_name(ret_type); + } + d2["is_vararg"] = Variant::is_builtin_method_vararg(type, method_name); + d2["is_const"] = Variant::is_builtin_method_const(type, method_name); + d2["is_static"] = Variant::is_builtin_method_static(type, method_name); + d2["hash"] = Variant::get_builtin_method_hash(type, method_name); + + Vector<Variant> default_args = Variant::get_builtin_method_default_arguments(type, method_name); + + Array arguments; + int argcount = Variant::get_builtin_method_argument_count(type, method_name); + 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); + + if (j >= (argcount - default_args.size())) { + int dargidx = j - (argcount - default_args.size()); + d3["default_value"] = default_args[dargidx].get_construct_string(); + } + arguments.push_back(d3); + } + + if (arguments.size()) { + d2["arguments"] = arguments; + } + + methods.push_back(d2); + } + if (methods.size()) { + d["methods"] = methods; + } + } + { + //constructors + Array constructors; + + for (int j = 0; j < Variant::get_constructor_count(type); j++) { + Dictionary d2; + d2["index"] = j; + + Array arguments; + int argcount = Variant::get_constructor_argument_count(type, j); + 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)); + arguments.push_back(d3); + } + if (arguments.size()) { + d2["arguments"] = arguments; + } + constructors.push_back(d2); + } + + if (constructors.size()) { + d["constructors"] = constructors; + } + } + + builtins.push_back(d); + } + + api_dump["builtin_classes"] = builtins; + } + + { + // classes + Array classes; + + List<StringName> class_list; + + ClassDB::get_class_list(&class_list); + + class_list.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) { + Dictionary d; + StringName class_name = E->get(); + d["name"] = String(class_name); + d["is_refcounted"] = ClassDB::is_parent_class(class_name, "RefCounted"); + d["is_instantiable"] = ClassDB::can_instantiate(class_name); + StringName parent_class = ClassDB::get_parent_class(class_name); + if (parent_class != StringName()) { + d["inherits"] = String(parent_class); + } + + { + ClassDB::APIType api = ClassDB::get_api_type(class_name); + static const char *api_type[5] = { "core", "editor", "extension", "editor_extension" }; + d["api_type"] = api_type[api]; + } + + { + //constants + Array constants; + List<String> constant_list; + ClassDB::get_integer_constant_list(class_name, &constant_list, true); + for (List<String>::Element *F = constant_list.front(); F; F = F->next()) { + StringName enum_name = ClassDB::get_integer_constant_enum(class_name, F->get()); + if (enum_name != StringName()) { + continue; //enums will be handled on their own + } + + Dictionary d2; + d2["name"] = String(F->get()); + d2["value"] = ClassDB::get_integer_constant(class_name, F->get()); + + constants.push_back(d2); + } + + if (constants.size()) { + d["constants"] = constants; + } + } + { + //enum + Array enums; + List<StringName> enum_list; + ClassDB::get_enum_list(class_name, &enum_list, true); + for (List<StringName>::Element *F = enum_list.front(); F; F = F->next()) { + Dictionary d2; + d2["name"] = String(F->get()); + + Array values; + List<StringName> enum_constant_list; + ClassDB::get_enum_constants(class_name, F->get(), &enum_constant_list, true); + for (List<StringName>::Element *G = enum_constant_list.front(); G; G = G->next()) { + Dictionary d3; + d3["name"] = String(G->get()); + d3["value"] = ClassDB::get_integer_constant(class_name, G->get()); + values.push_back(d3); + } + + d2["values"] = values; + + enums.push_back(d2); + } + + if (enums.size()) { + d["enums"] = enums; + } + } + { + //methods + Array methods; + List<MethodInfo> method_list; + ClassDB::get_method_list(class_name, &method_list, true); + for (List<MethodInfo>::Element *F = method_list.front(); F; F = F->next()) { + StringName method_name = F->get().name; + if (F->get().flags & METHOD_FLAG_VIRTUAL) { + //virtual method + const MethodInfo &mi = F->get(); + Dictionary d2; + d2["name"] = String(method_name); + d2["is_const"] = (F->get().flags & METHOD_FLAG_CONST) ? true : false; + d2["is_vararg"] = false; + d2["is_virtual"] = true; + // virtual functions have no hash since no MethodBind is involved + bool has_return = mi.return_val.type != Variant::NIL || (mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT); + Array arguments; + for (int i = (has_return ? -1 : 0); i < mi.arguments.size(); i++) { + PropertyInfo pinfo = i == -1 ? mi.return_val : mi.arguments[i]; + Dictionary d3; + + if (i >= 0) { + d3["name"] = pinfo.name; + } + if (pinfo.class_name != StringName()) { + d3["type"] = String(pinfo.class_name); + } else { + Variant::Type type = pinfo.type; + if (type == Variant::NIL) { + d3["type"] = "Variant"; + } else { + d3["type"] = Variant::get_type_name(type); + } + } + + if (i == -1) { + d2["return_value"] = d3; + } else { + arguments.push_back(d3); + } + } + + if (arguments.size()) { + d2["arguments"] = arguments; + } + + methods.push_back(d2); + + } else if (F->get().name.begins_with("_")) { + //hidden method, ignore + + } else { + Dictionary d2; + d2["name"] = String(method_name); + + MethodBind *method = ClassDB::get_method(class_name, method_name); + if (!method) { + continue; + } + + d2["is_const"] = method->is_const(); + d2["is_vararg"] = method->is_vararg(); + d2["is_virtual"] = false; + d2["hash"] = method->get_hash(); + + Vector<Variant> default_args = method->get_default_arguments(); + + Array arguments; + for (int i = (method->has_return() ? -1 : 0); i < method->get_argument_count(); i++) { + PropertyInfo pinfo = i == -1 ? method->get_return_info() : method->get_argument_info(i); + Dictionary d3; + + if (i >= 0) { + d3["name"] = pinfo.name; + } + if (pinfo.class_name != StringName()) { + d3["type"] = String(pinfo.class_name); + } else { + Variant::Type type = pinfo.type; + if (type == Variant::NIL) { + d3["type"] = "Variant"; + } else { + d3["type"] = Variant::get_type_name(type); + } + } + + if (method->get_argument_meta(i) > 0) { + static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" }; + d3["meta"] = argmeta[method->get_argument_meta(i)]; + } + + if (i >= 0 && i >= (method->get_argument_count() - default_args.size())) { + int dargidx = i - (method->get_argument_count() - default_args.size()); + d3["default_value"] = default_args[dargidx].get_construct_string(); + } + + if (i == -1) { + d2["return_value"] = d3; + } else { + arguments.push_back(d3); + } + } + + if (arguments.size()) { + d2["arguments"] = arguments; + } + + methods.push_back(d2); + } + } + + if (methods.size()) { + d["methods"] = methods; + } + } + + { + //signals + Array signals; + List<MethodInfo> signal_list; + ClassDB::get_signal_list(class_name, &signal_list, true); + for (List<MethodInfo>::Element *F = signal_list.front(); F; F = F->next()) { + StringName signal_name = F->get().name; + Dictionary d2; + d2["name"] = String(signal_name); + + Array arguments; + + for (int i = 0; i < F->get().arguments.size(); i++) { + Dictionary d3; + d3["name"] = F->get().arguments[i].name; + Variant::Type type = F->get().arguments[i].type; + if (F->get().arguments[i].class_name != StringName()) { + d3["type"] = String(F->get().arguments[i].class_name); + } else if (type == Variant::NIL) { + d3["type"] = "Variant"; + } else { + d3["type"] = Variant::get_type_name(type); + } + arguments.push_back(d3); + } + if (arguments.size()) { + d2["arguments"] = arguments; + } + + signals.push_back(d2); + } + + if (signals.size()) { + d["signals"] = signals; + } + } + { + //properties + Array properties; + List<PropertyInfo> property_list; + ClassDB::get_property_list(class_name, &property_list, true); + for (List<PropertyInfo>::Element *F = property_list.front(); F; F = F->next()) { + if (F->get().usage & PROPERTY_USAGE_CATEGORY || F->get().usage & PROPERTY_USAGE_GROUP || F->get().usage & PROPERTY_USAGE_SUBGROUP) { + continue; //not real properties + } + if (F->get().name.begins_with("_")) { + continue; //hidden property + } + StringName property_name = F->get().name; + Dictionary d2; + d2["name"] = String(property_name); + + if (F->get().class_name != StringName()) { + d2["type"] = String(F->get().class_name); + } else if (F->get().type == Variant::NIL && F->get().usage & PROPERTY_USAGE_NIL_IS_VARIANT) { + d2["type"] = "Variant"; + } else { + d2["type"] = Variant::get_type_name(F->get().type); + } + + d2["setter"] = ClassDB::get_property_setter(class_name, F->get().name); + d2["getter"] = ClassDB::get_property_getter(class_name, F->get().name); + d2["index"] = ClassDB::get_property_index(class_name, F->get().name); + properties.push_back(d2); + } + + if (properties.size()) { + d["properties"] = properties; + } + } + + classes.push_back(d); + } + + api_dump["classes"] = classes; + } + + { + // singletons + + Array singletons; + List<Engine::Singleton> singleton_list; + Engine::get_singleton()->get_singletons(&singleton_list); + + for (List<Engine::Singleton>::Element *E = singleton_list.front(); E; E = E->next()) { + const Engine::Singleton &s = E->get(); + Dictionary d; + d["name"] = s.name; + if (s.class_name != StringName()) { + d["type"] = String(s.class_name); + } else { + d["type"] = String(s.ptr->get_class()); + } + singletons.push_back(d); + } + + if (singletons.size()) { + api_dump["singletons"] = singletons; + } + } + + return api_dump; +} + +void NativeExtensionAPIDump::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); + FileAccessRef fa = FileAccess::open(p_path, FileAccess::WRITE); + CharString cs = text.ascii(); + fa->store_buffer((const uint8_t *)cs.ptr(), cs.length()); + fa->close(); +} +#endif diff --git a/core/extension/extension_api_dump.h b/core/extension/extension_api_dump.h new file mode 100644 index 0000000000..a7825c10a9 --- /dev/null +++ b/core/extension/extension_api_dump.h @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* extension_api_dump.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 API_DUMP_H +#define API_DUMP_H + +#include "core/extension/native_extension.h" + +#ifdef TOOLS_ENABLED + +class NativeExtensionAPIDump { +public: + static Dictionary generate_extension_api(); + static void generate_extension_json_file(const String &p_path); +}; +#endif + +#endif // API_DUMP_H diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp new file mode 100644 index 0000000000..8f68b8d848 --- /dev/null +++ b/core/extension/gdnative_interface.cpp @@ -0,0 +1,694 @@ +/*************************************************************************/ +/* gdnative_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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/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, 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, 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, ERR_HANDLER_SCRIPT); +} + +// 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 + +#define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr) + +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->call(*method, args, p_argcount, ret, error); + memnew_placement_custom(r_return, Variant, 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_custom(r_return, Variant, 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_custom(r_ret, Variant, 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_custom(r_ret, Variant, 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_custom(r_ret, Variant, 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_custom(r_ret, Variant, 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_custom(r_ret, Variant, Variant(self->iter_next(*iter, valid))); + *r_valid = valid; +} + +/// Variant functions. +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_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) { + const Variant *a = (const Variant *)p_a; + const Variant *b = (const Variant *)p_b; + memnew_placement(r_dst, Variant); + Variant::blend(*a, *b, p_c, *(Variant *)r_dst); +} + +static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) { + const Variant *a = (const Variant *)p_a; + const Variant *b = (const Variant *)p_b; + memnew_placement(r_dst, Variant); + Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst); +} + +static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) { + const Variant *self = (const Variant *)p_self; + memnew_placement_custom(r_ret, Variant, 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_custom(r_ret, String, 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; + return self->has_key(*key, valid); + *r_valid = valid; +} + +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_custom(r_ret, String, 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); +} + +// 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 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_custom(r_ret, Variant, 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 (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 (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 (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]; +} + +/* OBJECT API */ + +static void gdnative_object_method_bind_ptrcall(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_instance, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks) { + Object *o = (Object *)p_instance; + return o->get_instance_binding(p_token, p_callbacks); +} + +static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) { + return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id)); +} + +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 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_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'."); + return nullptr; + } + // MethodBind *mb = ClassDB::get_method("Node", "get_name"); + return (GDNativeMethodBindPtr)mb; +} + +static GDNativeClassConstructor gdnative_classdb_get_constructor(const char *p_classname) { + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname)); + if (class_info) { + return (GDNativeClassConstructor)class_info->creation_func; + } + return nullptr; +} + +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; + + /* 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_compare = gdnative_variant_hash_compare; + gdni.variant_booleanize = gdnative_variant_booleanize; + gdni.variant_blend = gdnative_variant_blend; + gdni.variant_interpolate = gdnative_variant_interpolate; + 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; + + //ptrcalls +#if 0 + GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type); + GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type); +#endif + + 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_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; + + /* OBJECT */ + + gdni.object_method_bind_ptrcall = gdnative_object_method_bind_ptrcall; + gdni.object_destroy = gdnative_object_destroy; + gdni.global_get_singleton = gdnative_global_get_singleton; + gdni.object_get_instance_binding = gdnative_object_get_instance_binding; + + gdni.object_cast_to = gdnative_object_cast_to; + gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id; + gdni.object_get_instance_id = gdnative_object_get_instance_id; + + /* CLASSDB */ + + gdni.classdb_get_constructor = gdnative_classdb_get_constructor; + 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_signal = nullptr; + gdni.classdb_unregister_extension_class = nullptr; +} diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h new file mode 100644 index 0000000000..c1ebb3e76a --- /dev/null +++ b/core/extension/gdnative_interface.h @@ -0,0 +1,438 @@ +/*************************************************************************/ +/* gdnative_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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> + +#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_PLANE, + GDNATIVE_VARIANT_TYPE_QUATERNION, + GDNATIVE_VARIANT_TYPE_AABB, + GDNATIVE_VARIANT_TYPE_BASIS, + GDNATIVE_VARIANT_TYPE_TRANSFORM3D, + + /* 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, + /* 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 *GDNativeMethodBindPtr; +typedef int64_t GDNativeInt; +typedef uint32_t GDNativeBool; +typedef uint64_t GDObjectInstanceID; + +/* VARIANT DATA I/O */ + +typedef enum { + NATIVE_CALL_OK, + NATIVE_CALL_ERROR_INVALID_METHOD, + NATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */ + NATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */ + NATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */ + NATIVE_CALL_ERROR_INSTANCE_IS_NULL, + +} 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 (*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_instance, GDNativeBool p_reference); + +struct GDNativeInstanceBindingCallbacks { + GDNativeInstanceBindingCreateCallback create_callback; + GDNativeInstanceBindingFreeCallback free_callback; + GDNativeInstanceBindingReferenceCallback reference_callback; +}; + +/* 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 struct { + uint32_t type; + const char *name; + const char *class_name; + uint32_t hint; + const char *hint_string; + uint32_t usage; +} GDNativePropertyInfo; + +typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); +typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list); +typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what); +typedef const char *(*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance); +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 GDExtensionClassInstancePtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata); +typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_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; + 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_firtual_func; + void *class_userdata; +} GDNativeExtensionClassCreationInfo; + +typedef void *GDNativeExtensionClassLibraryPtr; + +typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); + +/* Method */ + +typedef enum { + GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL = 1, + GDNATIVE_EXTENSION_METHOD_FLAG_EDITOR = 2, + GDNATIVE_EXTENSION_METHOD_FLAG_NOSCRIPT = 4, + GDNATIVE_EXTENSION_METHOD_FLAG_CONST = 8, + GDNATIVE_EXTENSION_METHOD_FLAG_REVERSE = 16, /* used for events */ + GDNATIVE_EXTENSION_METHOD_FLAG_VIRTUAL = 32, + GDNATIVE_EXTENSION_METHOD_FLAG_FROM_SCRIPT = 64, + GDNATIVE_EXTENSION_METHOD_FLAG_VARARG = 128, + GDNATIVE_EXTENSION_METHOD_FLAG_STATIC = 256, + 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)(GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error); +typedef void (*GDNativeExtensionClassMethodPtrCall)(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; + +/* 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); + + /* 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); + GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other); + GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self); + void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst); + void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst); + 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); + 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); + + /* OBJECT */ + + void (*object_method_bind_ptrcall)(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret); + void (*object_destroy)(GDNativeObjectPtr p_o); + GDNativeObjectPtr (*global_get_singleton)(const char *p_name); + void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks); + + GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag); + GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id); + GDObjectInstanceID (*object_get_instance_id)(const GDNativeObjectPtr p_object); + + /* CLASSDB */ + + GDNativeClassConstructor (*classdb_get_constructor)(const char *p_classname); + 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_enum_name, const char *p_class_name, const char *p_constant_name, uint32_t p_constant_value); + 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_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. */ +} GDNativeInterface; + +/* INITIALIZATION */ + +typedef enum { + GDNATIVE_INITIALIZATION_CORE, + GDNATIVE_INITIALIZATION_SERVERS, + GDNATIVE_INITIALIZATION_SCENE, + GDNATIVE_INITIALIZATION_EDITOR, +} 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 diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp new file mode 100644 index 0000000000..65718a7507 --- /dev/null +++ b/core/extension/native_extension.cpp @@ -0,0 +1,411 @@ +/*************************************************************************/ +/* native_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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/io/config_file.h" +#include "core/object/class_db.h" +#include "core/object/method_bind.h" +#include "core/os/os.h" + +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 { + return Variant::Type(get_argument_type_func(method_userdata, p_arg)); + } + virtual PropertyInfo _gen_argument_type_info(int p_arg) const { + GDNativePropertyInfo pinfo; + get_argument_info_func(method_userdata, p_arg, &pinfo); + PropertyInfo ret; + ret.type = Variant::Type(pinfo.type); + ret.name = pinfo.name; + ret.class_name = pinfo.class_name; + ret.hint = PropertyHint(pinfo.hint); + ret.usage = pinfo.usage; + ret.class_name = pinfo.class_name; + return ret; + } + +public: + virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const { + return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg)); + } + + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + Variant ret; + GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance(); + GDNativeCallError ce; + call_func(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) { + 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(extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret); + } + + virtual bool is_vararg() const { + return false; + } + 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; + + 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); +#ifdef DEBUG_METHODS_ENABLED + _generate_argument_types(p_method_info->argument_count); +#endif + set_argument_count(p_method_info->argument_count); + } +}; + +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 = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + ERR_FAIL_COND_MSG(String(class_name).is_valid_identifier(), "Attempt to register extension clas '" + 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.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; + + 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 = (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)); + + 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, uint32_t p_constant_value) { + NativeExtension *self = (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); +} +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 = (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 '" + String(p_info->name) + "' for unexisting class '" + class_name + "'."); + + //Extension *extension = &self->extension_classes[class_name]; + PropertyInfo pinfo; + pinfo.type = Variant::Type(p_info->type); + pinfo.name = p_info->name; + pinfo.class_name = p_info->class_name; + pinfo.hint = PropertyHint(p_info->hint); + pinfo.hint_string = p_info->hint_string; + pinfo.usage = p_info->usage; + + ClassDB::add_property(class_name, pinfo, p_setter, p_getter); +} + +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 = (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; + arg.type = Variant::Type(p_argument_info[i].type); + arg.name = p_argument_info[i].name; + arg.class_name = p_argument_info[i].class_name; + arg.hint = PropertyHint(p_argument_info[i].hint); + arg.hint_string = p_argument_info[i].hint_string; + arg.usage = p_argument_info[i].usage; + 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 = (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); +} + +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); + if (err != OK) { + 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) { + OS::get_singleton()->close_dynamic_library(library); + return err; + } + + GDNativeInitializationFunction initialization_function = (GDNativeInitializationFunction)entry_funcptr; + + initialization_function(&gdnative_interface, this, &initialization); + level_initialized = -1; + return OK; +} + +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(p_level <= int32_t(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_signal = _register_extension_class_signal; + gdnative_interface.classdb_unregister_extension_class = _unregister_extension_class; +} + +RES 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) { + return RES(); + } + + if (!config->has_section_key("configuration", "entry_symbol")) { + if (r_error) { + *r_error = ERR_INVALID_DATA; + } + return RES(); + } + + String entry_symbol = config->get_value("configuration", "entry_symbol"); + + List<String> libraries; + + config->get_section_keys("libraries", &libraries); + + String library_path; + + for (List<String>::Element *E = libraries.front(); E; E = E->next()) { + Vector<String> tags = E->get().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->get()); + break; + } + } + + if (library_path != String()) { + if (r_error) { + *r_error = ERR_FILE_NOT_FOUND; + } + return RES(); + } + + if (!library_path.is_resource_file()) { + library_path = p_path.get_base_dir().plus_file(library_path); + } + + Ref<NativeExtension> lib; + lib.instantiate(); + err = lib->open_library(library_path, entry_symbol); + + if (r_error) { + *r_error = err; + } + + if (err != OK) { + return RES(); + } + + 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/extension/native_extension.h b/core/extension/native_extension.h new file mode 100644 index 0000000000..0a23848eb2 --- /dev/null +++ b/core/extension/native_extension.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* native_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 NATIVE_EXTENSION_H +#define NATIVE_EXTENSION_H + +#include "core/extension/gdnative_interface.h" +#include "core/io/resource_loader.h" +#include "core/object/ref_counted.h" + +class NativeExtension : public RefCounted { + GDCLASS(NativeExtension, RefCounted) + + void *library = nullptr; // pointer if valid, + + struct Extension { + ObjectNativeExtension native_extension; + }; + + Map<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, uint32_t p_constant_value); + 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_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); + + GDNativeInitialization initialization; + int32_t level_initialized = -1; + +protected: + static void _bind_methods(); + +public: + Error open_library(const String &p_path, const String &p_entry_symbol); + void close_library(); + + enum InitializationLevel { + INITIALIZATION_LEVEL_CORE, + INITIALIZATION_LEVEL_SERVERS, + INITIALIZATION_LEVEL_SCENE, + INITIALIZATION_LEVEL_EDITOR, + }; + + bool is_library_open() const; + + InitializationLevel get_minimum_library_initialization_level() const; + void initialize_library(InitializationLevel p_level); + void deinitialize_library(InitializationLevel p_level); + + static void initialize_native_extensions(); + NativeExtension(); + ~NativeExtension(); +}; + +VARIANT_ENUM_CAST(NativeExtension::InitializationLevel) + +class NativeExtensionResourceLoader : public ResourceFormatLoader { +public: + virtual RES 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; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +#endif // NATIVEEXTENSION_H diff --git a/core/extension/native_extension_manager.cpp b/core/extension/native_extension_manager.cpp new file mode 100644 index 0000000000..7be2593845 --- /dev/null +++ b/core/extension/native_extension_manager.cpp @@ -0,0 +1,130 @@ +/*************************************************************************/ +/* native_extension_manager.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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_manager.h" + +NativeExtensionManager::LoadStatus NativeExtensionManager::load_extension(const String &p_path) { + if (native_extension_map.has(p_path)) { + return LOAD_STATUS_ALREADY_LOADED; + } + Ref<NativeExtension> 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)) { + return LOAD_STATUS_NEEDS_RESTART; + } + //initialize up to current level + for (int32_t i = minimum_level; i < level; i++) { + extension->initialize_library(NativeExtension::InitializationLevel(level)); + } + } + native_extension_map[p_path] = extension; + return LOAD_STATUS_OK; +} + +NativeExtensionManager::LoadStatus NativeExtensionManager::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)) { + return LOAD_STATUS_NOT_LOADED; + } + + Ref<NativeExtension> extension = native_extension_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)) { + return LOAD_STATUS_NEEDS_RESTART; + } + //initialize up to current level + for (int32_t i = level; i >= minimum_level; i--) { + extension->deinitialize_library(NativeExtension::InitializationLevel(level)); + } + } + native_extension_map.erase(p_path); + return LOAD_STATUS_OK; +} +Vector<String> NativeExtensionManager::get_loaded_extensions() const { + Vector<String> ret; + for (const Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) { + ret.push_back(E->key()); + } + return ret; +} +Ref<NativeExtension> NativeExtensionManager::get_extension(const String &p_path) { + Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.find(p_path); + ERR_FAIL_COND_V(!E, Ref<NativeExtension>()); + return E->get(); +} + +void NativeExtensionManager::initialize_extensions(NativeExtension::InitializationLevel p_level) { + ERR_FAIL_COND(int32_t(p_level) - 1 != level); + for (Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) { + E->get()->initialize_library(p_level); + } + level = p_level; +} + +void NativeExtensionManager::deinitialize_extensions(NativeExtension::InitializationLevel p_level) { + ERR_FAIL_COND(int32_t(p_level) != level); + for (Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) { + E->get()->deinitialize_library(p_level); + } + level = int32_t(p_level) - 1; +} + +NativeExtensionManager *NativeExtensionManager::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("get_loaded_extensions"), &NativeExtensionManager::get_loaded_extensions); + ClassDB::bind_method(D_METHOD("get_extension", "path"), &NativeExtensionManager::get_extension); + + BIND_ENUM_CONSTANT(LOAD_STATUS_OK); + BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED); + BIND_ENUM_CONSTANT(LOAD_STATUS_ALREADY_LOADED); + BIND_ENUM_CONSTANT(LOAD_STATUS_NOT_LOADED); + BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART); +} + +NativeExtensionManager *NativeExtensionManager::singleton = nullptr; + +NativeExtensionManager::NativeExtensionManager() { + ERR_FAIL_COND(singleton != nullptr); + singleton = this; +} diff --git a/core/extension/native_extension_manager.h b/core/extension/native_extension_manager.h new file mode 100644 index 0000000000..78465bd5cf --- /dev/null +++ b/core/extension/native_extension_manager.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* native_extension_manager.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 NATIVE_EXTENSION_MANAGER_H +#define NATIVE_EXTENSION_MANAGER_H + +#include "core/extension/native_extension.h" + +class NativeExtensionManager : public Object { + GDCLASS(NativeExtensionManager, Object); + + int32_t level = -1; + Map<String, Ref<NativeExtension>> native_extension_map; + + static void _bind_methods(); + + static NativeExtensionManager *singleton; + +public: + enum LoadStatus { + LOAD_STATUS_OK, + LOAD_STATUS_FAILED, + LOAD_STATUS_ALREADY_LOADED, + LOAD_STATUS_NOT_LOADED, + LOAD_STATUS_NEEDS_RESTART, + }; + + LoadStatus load_extension(const String &p_path); + LoadStatus reload_extension(const String &p_path); + LoadStatus unload_extension(const String &p_path); + Vector<String> get_loaded_extensions() const; + Ref<NativeExtension> get_extension(const String &p_path); + + void initialize_extensions(NativeExtension::InitializationLevel p_level); + void deinitialize_extensions(NativeExtension::InitializationLevel p_level); + + static NativeExtensionManager *get_singleton(); + + NativeExtensionManager(); +}; + +VARIANT_ENUM_CAST(NativeExtensionManager::LoadStatus) + +#endif // NATIVEEXTENSIONMANAGER_H diff --git a/core/input/input.cpp b/core/input/input.cpp index 6e98b596d7..a712394b35 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -227,7 +227,7 @@ bool Input::is_key_pressed(int p_keycode) const { return keys_pressed.has(p_keycode); } -bool Input::is_mouse_button_pressed(int p_button) const { +bool Input::is_mouse_button_pressed(MouseButton p_button) const { _THREAD_SAFE_METHOD_ return (mouse_button_mask & (1 << (p_button - 1))) != 0; } @@ -236,7 +236,7 @@ static int _combine_device(int p_value, int p_device) { return p_value | (p_device << 20); } -bool Input::is_joy_button_pressed(int p_device, int p_button) const { +bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const { _THREAD_SAFE_METHOD_ return joy_buttons_pressed.has(_combine_device(p_button, p_device)); } @@ -352,7 +352,7 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po return vector; } -float Input::get_joy_axis(int p_device, int p_axis) const { +float Input::get_joy_axis(int p_device, JoyAxis p_axis) const { _THREAD_SAFE_METHOD_ int c = _combine_device(p_axis, p_device); if (_joy_axis.has(c)) { @@ -433,7 +433,7 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S joy_buttons_pressed.erase(c); } for (int i = 0; i < JOY_AXIS_MAX; i++) { - set_joy_axis(p_idx, i, 0.0f); + set_joy_axis(p_idx, (JoyAxis)i, 0.0f); } } joy_names[p_idx] = js; @@ -488,9 +488,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (mb.is_valid()) { if (mb->is_pressed()) { - mouse_button_mask |= (1 << (mb->get_button_index() - 1)); + mouse_button_mask |= (MouseButton)(1 << (mb->get_button_index() - 1)); } else { - mouse_button_mask &= ~(1 << (mb->get_button_index() - 1)); + mouse_button_mask &= (MouseButton) ~(1 << (mb->get_button_index() - 1)); } Point2 pos = mb->get_global_position(); @@ -500,7 +500,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) { Ref<InputEventScreenTouch> touch_event; - touch_event.instance(); + touch_event.instantiate(); touch_event->set_pressed(mb->is_pressed()); touch_event->set_position(mb->get_position()); event_dispatch_function(touch_event); @@ -517,7 +517,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) { Ref<InputEventScreenDrag> drag_event; - drag_event.instance(); + drag_event.instantiate(); drag_event->set_position(mm->get_position()); drag_event->set_relative(mm->get_relative()); @@ -555,7 +555,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (translate) { Ref<InputEventMouseButton> button_event; - button_event.instance(); + button_event.instantiate(); button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); button_event->set_position(st->get_position()); @@ -563,9 +563,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em button_event->set_pressed(st->is_pressed()); button_event->set_button_index(MOUSE_BUTTON_LEFT); if (st->is_pressed()) { - button_event->set_button_mask(mouse_button_mask | (1 << (MOUSE_BUTTON_LEFT - 1))); + button_event->set_button_mask(MouseButton(mouse_button_mask | MOUSE_BUTTON_MASK_LEFT)); } else { - button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1))); + button_event->set_button_mask(MouseButton(mouse_button_mask & ~MOUSE_BUTTON_MASK_LEFT)); } _parse_input_event_impl(button_event, true); @@ -582,7 +582,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) { Ref<InputEventMouseMotion> motion_event; - motion_event.instance(); + motion_event.instantiate(); motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); motion_event->set_position(sd->get_position()); @@ -644,7 +644,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em } } -void Input::set_joy_axis(int p_device, int p_axis, float p_value) { +void Input::set_joy_axis(int p_device, JoyAxis p_axis, float p_value) { _THREAD_SAFE_METHOD_ int c = _combine_device(p_axis, p_device); _joy_axis[c] = p_value; @@ -787,14 +787,14 @@ void Input::ensure_touch_mouse_raised() { mouse_from_touch_index = -1; Ref<InputEventMouseButton> button_event; - button_event.instance(); + button_event.instantiate(); button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); button_event->set_position(mouse_pos); button_event->set_global_position(mouse_pos); button_event->set_pressed(false); button_event->set_button_index(MOUSE_BUTTON_LEFT); - button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1))); + button_event->set_button_mask(MouseButton(mouse_button_mask & ~MOUSE_BUTTON_MASK_LEFT)); _parse_input_event_impl(button_event, true); } @@ -821,7 +821,7 @@ void Input::set_default_cursor_shape(CursorShape p_shape) { // The default shape is set in Viewport::_gui_input_event. To instantly // see the shape in the viewport we need to trigger a mouse motion event. Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_position(mouse_pos); mm->set_global_position(mouse_pos); parse_input_event(mm); @@ -882,7 +882,7 @@ void Input::set_event_dispatch_function(EventDispatchFunc p_function) { event_dispatch_function = p_function; } -void Input::joy_button(int p_device, int p_button, bool p_pressed) { +void Input::joy_button(int p_device, JoyButton p_button, bool p_pressed) { _THREAD_SAFE_METHOD_; Joypad &joy = joy_names[p_device]; //printf("got button %i, mapping is %i\n", p_button, joy.mapping); @@ -898,17 +898,17 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) { JoyEvent map = _get_mapped_button_event(map_db[joy.mapping], p_button); if (map.type == TYPE_BUTTON) { - _button_event(p_device, map.index, p_pressed); + _button_event(p_device, (JoyButton)map.index, p_pressed); return; } if (map.type == TYPE_AXIS) { - _axis_event(p_device, map.index, p_pressed ? map.value : 0.0); + _axis_event(p_device, (JoyAxis)map.index, p_pressed ? map.value : 0.0); } // no event? } -void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) { +void Input::joy_axis(int p_device, JoyAxis p_axis, const JoyAxisValue &p_value) { _THREAD_SAFE_METHOD_; ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX); @@ -949,7 +949,7 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) { // Button already pressed or released; so ignore. return; } - _button_event(p_device, map.index, pressed); + _button_event(p_device, (JoyButton)map.index, pressed); // Ensure opposite D-Pad button is also released. switch (map.index) { @@ -981,7 +981,7 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) { } if (map.type == TYPE_AXIS) { - _axis_event(p_device, map.index, map.value); + _axis_event(p_device, (JoyAxis)map.index, map.value); return; } //printf("invalid mapping\n"); @@ -993,24 +993,24 @@ void Input::joy_hat(int p_device, int p_val) { JoyEvent map[HAT_MAX]; - map[HAT_UP].type = TYPE_BUTTON; - map[HAT_UP].index = JOY_BUTTON_DPAD_UP; - map[HAT_UP].value = 0; + map[HatDir::HAT_UP].type = TYPE_BUTTON; + map[HatDir::HAT_UP].index = JOY_BUTTON_DPAD_UP; + map[HatDir::HAT_UP].value = 0; - map[HAT_RIGHT].type = TYPE_BUTTON; - map[HAT_RIGHT].index = JOY_BUTTON_DPAD_RIGHT; - map[HAT_RIGHT].value = 0; + map[HatDir::HAT_RIGHT].type = TYPE_BUTTON; + map[HatDir::HAT_RIGHT].index = JOY_BUTTON_DPAD_RIGHT; + map[HatDir::HAT_RIGHT].value = 0; - map[HAT_DOWN].type = TYPE_BUTTON; - map[HAT_DOWN].index = JOY_BUTTON_DPAD_DOWN; - map[HAT_DOWN].value = 0; + map[HatDir::HAT_DOWN].type = TYPE_BUTTON; + map[HatDir::HAT_DOWN].index = JOY_BUTTON_DPAD_DOWN; + map[HatDir::HAT_DOWN].value = 0; - map[HAT_LEFT].type = TYPE_BUTTON; - map[HAT_LEFT].index = JOY_BUTTON_DPAD_LEFT; - map[HAT_LEFT].value = 0; + map[HatDir::HAT_LEFT].type = TYPE_BUTTON; + map[HatDir::HAT_LEFT].index = JOY_BUTTON_DPAD_LEFT; + map[HatDir::HAT_LEFT].value = 0; if (joy.mapping != -1) { - _get_mapped_hat_events(map_db[joy.mapping], 0, map); + _get_mapped_hat_events(map_db[joy.mapping], (HatDir)0, map); } int cur_val = joy_names[p_device].hat_current; @@ -1018,10 +1018,10 @@ void Input::joy_hat(int p_device, int p_val) { for (int hat_direction = 0, hat_mask = 1; hat_direction < HAT_MAX; hat_direction++, hat_mask <<= 1) { if ((p_val & hat_mask) != (cur_val & hat_mask)) { if (map[hat_direction].type == TYPE_BUTTON) { - _button_event(p_device, map[hat_direction].index, p_val & hat_mask); + _button_event(p_device, (JoyButton)map[hat_direction].index, p_val & hat_mask); } if (map[hat_direction].type == TYPE_AXIS) { - _axis_event(p_device, map[hat_direction].index, (p_val & hat_mask) ? map[hat_direction].value : 0.0); + _axis_event(p_device, (JoyAxis)map[hat_direction].index, (p_val & hat_mask) ? map[hat_direction].value : 0.0); } } } @@ -1029,9 +1029,9 @@ void Input::joy_hat(int p_device, int p_val) { joy_names[p_device].hat_current = p_val; } -void Input::_button_event(int p_device, int p_index, bool p_pressed) { +void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) { Ref<InputEventJoypadButton> ievent; - ievent.instance(); + ievent.instantiate(); ievent->set_device(p_device); ievent->set_button_index(p_index); ievent->set_pressed(p_pressed); @@ -1039,9 +1039,9 @@ void Input::_button_event(int p_device, int p_index, bool p_pressed) { parse_input_event(ievent); } -void Input::_axis_event(int p_device, int p_axis, float p_value) { +void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) { Ref<InputEventJoypadMotion> ievent; - ievent.instance(); + ievent.instantiate(); ievent->set_device(p_device); ievent->set_axis(p_axis); ievent->set_axis_value(p_value); @@ -1049,7 +1049,7 @@ void Input::_axis_event(int p_device, int p_axis, float p_value) { parse_input_event(ievent); } -Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button) { +Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) { JoyEvent event; event.type = TYPE_MAX; @@ -1085,7 +1085,7 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, return event; } -Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value) { +Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value) { JoyEvent event; event.type = TYPE_MAX; @@ -1156,23 +1156,23 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, i return event; } -void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[]) { +void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[]) { for (int i = 0; i < mapping.bindings.size(); i++) { const JoyBinding binding = mapping.bindings[i]; if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) { int hat_direction; switch (binding.input.hat.hat_mask) { - case HAT_MASK_UP: - hat_direction = HAT_UP; + case HatMask::HAT_MASK_UP: + hat_direction = HatDir::HAT_UP; break; - case HAT_MASK_RIGHT: - hat_direction = HAT_RIGHT; + case HatMask::HAT_MASK_RIGHT: + hat_direction = HatDir::HAT_RIGHT; break; - case HAT_MASK_DOWN: - hat_direction = HAT_DOWN; + case HatMask::HAT_MASK_DOWN: + hat_direction = HatDir::HAT_DOWN; break; - case HAT_MASK_LEFT: - hat_direction = HAT_LEFT; + case HatMask::HAT_MASK_LEFT: + hat_direction = HatDir::HAT_LEFT; break; default: ERR_PRINT_ONCE("Joypad button mapping error."); @@ -1300,11 +1300,11 @@ void Input::parse_mapping(String p_mapping) { switch (input[0]) { case 'b': binding.inputType = TYPE_BUTTON; - binding.input.button = input.substr(1).to_int(); + binding.input.button = (JoyButton)input.substr(1).to_int(); break; case 'a': binding.inputType = TYPE_AXIS; - binding.input.axis.axis = input.substr(1).to_int(); + binding.input.axis.axis = (JoyAxis)input.substr(1).to_int(); binding.input.axis.range = input_range; binding.input.axis.invert = invert_axis; break; @@ -1312,7 +1312,7 @@ void Input::parse_mapping(String p_mapping) { ERR_CONTINUE_MSG(input.length() != 4 || input[2] != '.', String(entry[idx] + "\nInvalid hat input: " + input)); binding.inputType = TYPE_HAT; - binding.input.hat.hat = input.substr(1, 1).to_int(); + binding.input.hat.hat = (HatDir)input.substr(1, 1).to_int(); binding.input.hat.hat_mask = static_cast<HatMask>(input.substr(3).to_int()); break; default: diff --git a/core/input/input.h b/core/input/input.h index ecb4981b13..fbcd5836ea 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -72,22 +72,6 @@ public: CURSOR_MAX }; - enum HatMask { - HAT_MASK_CENTER = 0, - HAT_MASK_UP = 1, - HAT_MASK_RIGHT = 2, - HAT_MASK_DOWN = 4, - HAT_MASK_LEFT = 8, - }; - - enum HatDir { - HAT_UP, - HAT_RIGHT, - HAT_DOWN, - HAT_LEFT, - HAT_MAX, - }; - enum { JOYPADS_MAX = 16, }; @@ -149,7 +133,7 @@ private: bool connected = false; bool last_buttons[JOY_BUTTON_MAX] = { false }; float last_axis[JOY_AXIS_MAX] = { 0.0f }; - int last_hat = HAT_MASK_CENTER; + int last_hat = HatMask::HAT_MASK_CENTER; int mapping = -1; int hat_current = 0; }; @@ -183,16 +167,16 @@ private: struct JoyBinding { JoyType inputType; union { - int button; + JoyButton button; struct { - int axis; + JoyAxis axis; JoyAxisRange range; bool invert; } axis; struct { - int hat; + HatDir hat; HatMask hat_mask; } hat; @@ -218,13 +202,13 @@ private: Vector<JoyDeviceMapping> map_db; - JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button); - JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value); - void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]); + JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button); + JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value); + void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[HAT_MAX]); JoyButton _get_output_button(String output); JoyAxis _get_output_axis(String output); - void _button_event(int p_device, int p_index, bool p_pressed); - void _axis_event(int p_device, int p_axis, float p_value); + void _button_event(int p_device, JoyButton p_index, bool p_pressed); + void _axis_event(int p_device, JoyAxis p_axis, float p_value); void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated); @@ -261,8 +245,8 @@ public: static Input *get_singleton(); bool is_key_pressed(int p_keycode) const; - bool is_mouse_button_pressed(int p_button) const; - bool is_joy_button_pressed(int p_device, int p_button) const; + bool is_mouse_button_pressed(MouseButton p_button) const; + bool is_joy_button_pressed(int p_device, JoyButton p_button) const; bool is_action_pressed(const StringName &p_action, bool p_exact = false) const; bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const; bool is_action_just_released(const StringName &p_action, bool p_exact = false) const; @@ -272,7 +256,7 @@ public: float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const; Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const; - float get_joy_axis(int p_device, int p_axis) const; + float get_joy_axis(int p_device, JoyAxis p_axis) const; String get_joy_name(int p_idx); Array get_connected_joypads(); Vector2 get_joy_vibration_strength(int p_device); @@ -299,7 +283,7 @@ public: void set_accelerometer(const Vector3 &p_accel); void set_magnetometer(const Vector3 &p_magnetometer); void set_gyroscope(const Vector3 &p_gyroscope); - void set_joy_axis(int p_device, int p_axis, float p_value); + void set_joy_axis(int p_device, JoyAxis p_axis, float p_value); void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0); void stop_joy_vibration(int p_device); @@ -325,8 +309,8 @@ public: void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()); void parse_mapping(String p_mapping); - void joy_button(int p_device, int p_button, bool p_pressed); - void joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value); + void joy_button(int p_device, JoyButton p_button, bool p_pressed); + void joy_axis(int p_device, JoyAxis p_axis, const JoyAxisValue &p_value); void joy_hat(int p_device, int p_val); void add_joy_mapping(String p_mapping, bool p_update_existing = false); diff --git a/core/input/input_enums.h b/core/input/input_enums.h new file mode 100644 index 0000000000..4479a85bfe --- /dev/null +++ b/core/input/input_enums.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* input_enums.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 INPUT_ENUMS_H +#define INPUT_ENUMS_H + +enum HatDir { + HAT_UP = 0, + HAT_RIGHT = 1, + HAT_DOWN = 2, + HAT_LEFT = 3, + HAT_MAX = 4, +}; + +enum HatMask { + HAT_MASK_CENTER = 0, + HAT_MASK_UP = 1, + HAT_MASK_RIGHT = 2, + HAT_MASK_DOWN = 4, + HAT_MASK_LEFT = 8, +}; + +enum JoyAxis { + JOY_AXIS_INVALID = -1, + JOY_AXIS_LEFT_X = 0, + JOY_AXIS_LEFT_Y = 1, + JOY_AXIS_RIGHT_X = 2, + JOY_AXIS_RIGHT_Y = 3, + JOY_AXIS_TRIGGER_LEFT = 4, + JOY_AXIS_TRIGGER_RIGHT = 5, + JOY_AXIS_SDL_MAX = 6, + JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes. +}; + +enum JoyButton { + JOY_BUTTON_INVALID = -1, + JOY_BUTTON_A = 0, + JOY_BUTTON_B = 1, + JOY_BUTTON_X = 2, + JOY_BUTTON_Y = 3, + JOY_BUTTON_BACK = 4, + JOY_BUTTON_GUIDE = 5, + JOY_BUTTON_START = 6, + JOY_BUTTON_LEFT_STICK = 7, + JOY_BUTTON_RIGHT_STICK = 8, + JOY_BUTTON_LEFT_SHOULDER = 9, + JOY_BUTTON_RIGHT_SHOULDER = 10, + JOY_BUTTON_DPAD_UP = 11, + JOY_BUTTON_DPAD_DOWN = 12, + JOY_BUTTON_DPAD_LEFT = 13, + JOY_BUTTON_DPAD_RIGHT = 14, + JOY_BUTTON_MISC1 = 15, + JOY_BUTTON_PADDLE1 = 16, + JOY_BUTTON_PADDLE2 = 17, + JOY_BUTTON_PADDLE3 = 18, + JOY_BUTTON_PADDLE4 = 19, + JOY_BUTTON_TOUCHPAD = 20, + JOY_BUTTON_SDL_MAX = 21, + JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons. +}; + +enum MIDIMessage { + MIDI_MESSAGE_NONE = 0, + MIDI_MESSAGE_NOTE_OFF = 0x8, + MIDI_MESSAGE_NOTE_ON = 0x9, + MIDI_MESSAGE_AFTERTOUCH = 0xA, + MIDI_MESSAGE_CONTROL_CHANGE = 0xB, + MIDI_MESSAGE_PROGRAM_CHANGE = 0xC, + MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD, + MIDI_MESSAGE_PITCH_BEND = 0xE, +}; + +enum MouseButton { + MOUSE_BUTTON_NONE = 0, + MOUSE_BUTTON_LEFT = 1, + MOUSE_BUTTON_RIGHT = 2, + MOUSE_BUTTON_MIDDLE = 3, + MOUSE_BUTTON_WHEEL_UP = 4, + MOUSE_BUTTON_WHEEL_DOWN = 5, + MOUSE_BUTTON_WHEEL_LEFT = 6, + MOUSE_BUTTON_WHEEL_RIGHT = 7, + MOUSE_BUTTON_XBUTTON1 = 8, + MOUSE_BUTTON_XBUTTON2 = 9, + MOUSE_BUTTON_MASK_LEFT = (1 << (MOUSE_BUTTON_LEFT - 1)), + MOUSE_BUTTON_MASK_RIGHT = (1 << (MOUSE_BUTTON_RIGHT - 1)), + MOUSE_BUTTON_MASK_MIDDLE = (1 << (MOUSE_BUTTON_MIDDLE - 1)), + MOUSE_BUTTON_MASK_XBUTTON1 = (1 << (MOUSE_BUTTON_XBUTTON1 - 1)), + MOUSE_BUTTON_MASK_XBUTTON2 = (1 << (MOUSE_BUTTON_XBUTTON2 - 1)), +}; + +inline MouseButton &operator|=(MouseButton &a, MouseButton b) { + return (MouseButton &)((int &)a |= (int)b); +} + +inline MouseButton &operator&=(MouseButton &a, MouseButton b) { + return (MouseButton &)((int &)a &= (int)b); +} + +#endif // INPUT_ENUMS_H diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 6f063c217f..4a2abffae8 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -38,6 +38,7 @@ const int InputEvent::DEVICE_ID_INTERNAL = -2; void InputEvent::set_device(int p_device) { device = p_device; + emit_changed(); } int InputEvent::get_device() const { @@ -88,7 +89,7 @@ bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, f return false; } -bool InputEvent::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEvent::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { return false; } @@ -110,7 +111,7 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text); - ClassDB::bind_method(D_METHOD("shortcut_match", "event"), &InputEvent::shortcut_match); + ClassDB::bind_method(D_METHOD("is_match", "event", "exact_match"), &InputEvent::is_match, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type); @@ -131,6 +132,7 @@ void InputEventFromWindow::_bind_methods() { void InputEventFromWindow::set_window_id(int64_t p_id) { window_id = p_id; + emit_changed(); } int64_t InputEventFromWindow::get_window_id() const { @@ -141,6 +143,7 @@ int64_t InputEventFromWindow::get_window_id() const { void InputEventWithModifiers::set_store_command(bool p_enabled) { store_command = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_storing_command() const { @@ -149,6 +152,7 @@ bool InputEventWithModifiers::is_storing_command() const { void InputEventWithModifiers::set_shift_pressed(bool p_enabled) { shift_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_shift_pressed() const { @@ -157,6 +161,7 @@ bool InputEventWithModifiers::is_shift_pressed() const { void InputEventWithModifiers::set_alt_pressed(bool p_enabled) { alt_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_alt_pressed() const { @@ -165,6 +170,7 @@ bool InputEventWithModifiers::is_alt_pressed() const { void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) { ctrl_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_ctrl_pressed() const { @@ -173,6 +179,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const { void InputEventWithModifiers::set_meta_pressed(bool p_enabled) { meta_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_meta_pressed() const { @@ -181,6 +188,7 @@ bool InputEventWithModifiers::is_meta_pressed() const { void InputEventWithModifiers::set_command_pressed(bool p_enabled) { command_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_command_pressed() const { @@ -194,6 +202,23 @@ void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModif set_meta_pressed(event->is_meta_pressed()); } +uint32_t InputEventWithModifiers::get_modifiers_mask() const { + uint32_t mask = 0; + if (is_ctrl_pressed()) { + mask |= KEY_MASK_CTRL; + } + if (is_shift_pressed()) { + mask |= KEY_MASK_SHIFT; + } + if (is_alt_pressed()) { + mask |= KEY_MASK_ALT; + } + if (is_meta_pressed()) { + mask |= KEY_MASK_META; + } + return mask; +} + String InputEventWithModifiers::as_text() const { Vector<String> mod_names; @@ -274,6 +299,7 @@ void InputEventWithModifiers::_validate_property(PropertyInfo &property) const { void InputEventKey::set_pressed(bool p_pressed) { pressed = p_pressed; + emit_changed(); } bool InputEventKey::is_pressed() const { @@ -282,6 +308,7 @@ bool InputEventKey::is_pressed() const { void InputEventKey::set_keycode(uint32_t p_keycode) { keycode = p_keycode; + emit_changed(); } uint32_t InputEventKey::get_keycode() const { @@ -290,6 +317,7 @@ uint32_t InputEventKey::get_keycode() const { void InputEventKey::set_physical_keycode(uint32_t p_keycode) { physical_keycode = p_keycode; + emit_changed(); } uint32_t InputEventKey::get_physical_keycode() const { @@ -298,6 +326,7 @@ uint32_t InputEventKey::get_physical_keycode() const { void InputEventKey::set_unicode(uint32_t p_unicode) { unicode = p_unicode; + emit_changed(); } uint32_t InputEventKey::get_unicode() const { @@ -306,6 +335,7 @@ uint32_t InputEventKey::get_unicode() const { void InputEventKey::set_echo(bool p_enable) { echo = p_enable; + emit_changed(); } bool InputEventKey::is_echo() const { @@ -313,39 +343,11 @@ bool InputEventKey::is_echo() const { } uint32_t InputEventKey::get_keycode_with_modifiers() const { - uint32_t sc = keycode; - if (is_ctrl_pressed()) { - sc |= KEY_MASK_CTRL; - } - if (is_alt_pressed()) { - sc |= KEY_MASK_ALT; - } - if (is_shift_pressed()) { - sc |= KEY_MASK_SHIFT; - } - if (is_meta_pressed()) { - sc |= KEY_MASK_META; - } - - return sc; + return keycode | get_modifiers_mask(); } uint32_t InputEventKey::get_physical_keycode_with_modifiers() const { - uint32_t sc = physical_keycode; - if (is_ctrl_pressed()) { - sc |= KEY_MASK_CTRL; - } - if (is_alt_pressed()) { - sc |= KEY_MASK_ALT; - } - if (is_shift_pressed()) { - sc |= KEY_MASK_SHIFT; - } - if (is_meta_pressed()) { - sc |= KEY_MASK_META; - } - - return sc; + return physical_keycode | get_modifiers_mask(); } String InputEventKey::as_text() const { @@ -386,7 +388,7 @@ String InputEventKey::to_string() { Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) { Ref<InputEventKey> ie; - ie.instance(); + ie.instantiate(); ie->set_keycode(p_keycode & KEY_CODE_MASK); ie->set_unicode(p_keycode & KEY_CODE_MASK); @@ -442,16 +444,14 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed return match; } -bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEventKey::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { Ref<InputEventKey> key = p_event; if (key.is_null()) { return false; } - uint32_t code = get_keycode_with_modifiers(); - uint32_t event_code = key->get_keycode_with_modifiers(); - - return code == event_code; + return keycode == key->keycode && + (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); } void InputEventKey::_bind_methods() { @@ -482,6 +482,7 @@ void InputEventKey::_bind_methods() { void InputEventMouse::set_button_mask(int p_mask) { button_mask = p_mask; + emit_changed(); } int InputEventMouse::get_button_mask() const { @@ -529,11 +530,12 @@ float InputEventMouseButton::get_factor() const { return factor; } -void InputEventMouseButton::set_button_index(int p_index) { +void InputEventMouseButton::set_button_index(MouseButton p_index) { button_index = p_index; + emit_changed(); } -int InputEventMouseButton::get_button_index() const { +MouseButton InputEventMouseButton::get_button_index() const { return button_index; } @@ -558,7 +560,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co Vector2 l = p_xform.xform(get_position() + p_local_ofs); Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_device(get_device()); mb->set_window_id(get_window_id()); @@ -599,6 +601,16 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p return match; } +bool InputEventMouseButton::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_null()) { + return false; + } + + return button_index == mb->button_index && + (!p_exact_match || get_modifiers_mask() == mb->get_modifiers_mask()); +} + static const char *_mouse_button_descriptions[9] = { TTRC("Left Mouse Button"), TTRC("Right Mouse Button"), @@ -734,7 +746,7 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co Vector2 s = p_xform.basis_xform(get_speed()); Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_device(get_device()); mm->set_window_id(get_window_id()); @@ -848,16 +860,18 @@ void InputEventMouseMotion::_bind_methods() { /////////////////////////////////// -void InputEventJoypadMotion::set_axis(int p_axis) { +void InputEventJoypadMotion::set_axis(JoyAxis p_axis) { axis = p_axis; + emit_changed(); } -int InputEventJoypadMotion::get_axis() const { +JoyAxis InputEventJoypadMotion::get_axis() const { return axis; } void InputEventJoypadMotion::set_axis_value(float p_value) { axis_value = p_value; + emit_changed(); } float InputEventJoypadMotion::get_axis_value() const { @@ -904,6 +918,16 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool * return match; } +bool InputEventJoypadMotion::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { + Ref<InputEventJoypadMotion> jm = p_event; + if (jm.is_null()) { + return false; + } + + return axis == jm->axis && + (!p_exact_match || ((axis_value < 0) == (jm->axis_value < 0))); +} + static const char *_joy_axis_descriptions[JOY_AXIS_MAX] = { TTRC("Left Stick X-Axis, Joystick 0 X-Axis"), TTRC("Left Stick Y-Axis, Joystick 0 Y-Axis"), @@ -940,11 +964,12 @@ void InputEventJoypadMotion::_bind_methods() { /////////////////////////////////// -void InputEventJoypadButton::set_button_index(int p_index) { +void InputEventJoypadButton::set_button_index(JoyButton p_index) { button_index = p_index; + emit_changed(); } -int InputEventJoypadButton::get_button_index() const { +JoyButton InputEventJoypadButton::get_button_index() const { return button_index; } @@ -987,7 +1012,7 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool * return match; } -bool InputEventJoypadButton::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEventJoypadButton::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { Ref<InputEventJoypadButton> button = p_event; if (button.is_null()) { return false; @@ -1023,7 +1048,7 @@ static const char *_joy_button_descriptions[JOY_BUTTON_SDL_MAX] = { String InputEventJoypadButton::as_text() const { String text = "Joypad Button " + itos(button_index); - if (button_index < JOY_BUTTON_SDL_MAX) { + if (button_index >= 0 && button_index < JOY_BUTTON_SDL_MAX) { text += vformat(" (%s)", _joy_button_descriptions[button_index]); } @@ -1039,9 +1064,9 @@ String InputEventJoypadButton::to_string() { return vformat("InputEventJoypadButton: button_index=%d, pressed=%s, pressure=%.2f", button_index, p, pressure); } -Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(int p_btn_index) { +Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(JoyButton p_btn_index) { Ref<InputEventJoypadButton> ie; - ie.instance(); + ie.instantiate(); ie->set_button_index(p_btn_index); return ie; @@ -1090,7 +1115,7 @@ bool InputEventScreenTouch::is_pressed() const { Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventScreenTouch> st; - st.instance(); + st.instantiate(); st->set_device(get_device()); st->set_window_id(get_window_id()); st->set_index(index); @@ -1163,7 +1188,7 @@ Vector2 InputEventScreenDrag::get_speed() const { Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventScreenDrag> sd; - sd.instance(); + sd.instantiate(); sd->set_device(get_device()); sd->set_window_id(get_window_id()); @@ -1229,7 +1254,7 @@ float InputEventAction::get_strength() const { return strength; } -bool InputEventAction::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { if (p_event.is_null()) { return false; } @@ -1318,7 +1343,7 @@ real_t InputEventMagnifyGesture::get_factor() const { Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventMagnifyGesture> ev; - ev.instance(); + ev.instantiate(); ev->set_device(get_device()); ev->set_window_id(get_window_id()); @@ -1358,7 +1383,7 @@ Vector2 InputEventPanGesture::get_delta() const { Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventPanGesture> ev; - ev.instance(); + ev.instantiate(); ev->set_device(get_device()); ev->set_window_id(get_window_id()); @@ -1396,11 +1421,11 @@ int InputEventMIDI::get_channel() const { return channel; } -void InputEventMIDI::set_message(const int p_message) { +void InputEventMIDI::set_message(const MIDIMessage p_message) { message = p_message; } -int InputEventMIDI::get_message() const { +MIDIMessage InputEventMIDI::get_message() const { return message; } diff --git a/core/input/input_event.h b/core/input/input_event.h index eed0d79326..76a45c04a4 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -31,6 +31,7 @@ #ifndef INPUT_EVENT_H #define INPUT_EVENT_H +#include "core/input/input_enums.h" #include "core/io/resource.h" #include "core/math/transform_2d.h" #include "core/string/ustring.h" @@ -41,72 +42,6 @@ * The events are pretty obvious. */ -enum MouseButton { - MOUSE_BUTTON_LEFT = 1, - MOUSE_BUTTON_RIGHT = 2, - MOUSE_BUTTON_MIDDLE = 3, - MOUSE_BUTTON_WHEEL_UP = 4, - MOUSE_BUTTON_WHEEL_DOWN = 5, - MOUSE_BUTTON_WHEEL_LEFT = 6, - MOUSE_BUTTON_WHEEL_RIGHT = 7, - MOUSE_BUTTON_XBUTTON1 = 8, - MOUSE_BUTTON_XBUTTON2 = 9, - MOUSE_BUTTON_MASK_LEFT = (1 << (MOUSE_BUTTON_LEFT - 1)), - MOUSE_BUTTON_MASK_RIGHT = (1 << (MOUSE_BUTTON_RIGHT - 1)), - MOUSE_BUTTON_MASK_MIDDLE = (1 << (MOUSE_BUTTON_MIDDLE - 1)), - MOUSE_BUTTON_MASK_XBUTTON1 = (1 << (MOUSE_BUTTON_XBUTTON1 - 1)), - MOUSE_BUTTON_MASK_XBUTTON2 = (1 << (MOUSE_BUTTON_XBUTTON2 - 1)) -}; - -enum JoyButton { - JOY_BUTTON_INVALID = -1, - JOY_BUTTON_A = 0, - JOY_BUTTON_B = 1, - JOY_BUTTON_X = 2, - JOY_BUTTON_Y = 3, - JOY_BUTTON_BACK = 4, - JOY_BUTTON_GUIDE = 5, - JOY_BUTTON_START = 6, - JOY_BUTTON_LEFT_STICK = 7, - JOY_BUTTON_RIGHT_STICK = 8, - JOY_BUTTON_LEFT_SHOULDER = 9, - JOY_BUTTON_RIGHT_SHOULDER = 10, - JOY_BUTTON_DPAD_UP = 11, - JOY_BUTTON_DPAD_DOWN = 12, - JOY_BUTTON_DPAD_LEFT = 13, - JOY_BUTTON_DPAD_RIGHT = 14, - JOY_BUTTON_MISC1 = 15, - JOY_BUTTON_PADDLE1 = 16, - JOY_BUTTON_PADDLE2 = 17, - JOY_BUTTON_PADDLE3 = 18, - JOY_BUTTON_PADDLE4 = 19, - JOY_BUTTON_TOUCHPAD = 20, - JOY_BUTTON_SDL_MAX = 21, - JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons. -}; - -enum JoyAxis { - JOY_AXIS_INVALID = -1, - JOY_AXIS_LEFT_X = 0, - JOY_AXIS_LEFT_Y = 1, - JOY_AXIS_RIGHT_X = 2, - JOY_AXIS_RIGHT_Y = 3, - JOY_AXIS_TRIGGER_LEFT = 4, - JOY_AXIS_TRIGGER_RIGHT = 5, - JOY_AXIS_SDL_MAX = 6, - JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes. -}; - -enum MIDIMessage { - MIDI_MESSAGE_NOTE_OFF = 0x8, - MIDI_MESSAGE_NOTE_ON = 0x9, - MIDI_MESSAGE_AFTERTOUCH = 0xA, - MIDI_MESSAGE_CONTROL_CHANGE = 0xB, - MIDI_MESSAGE_PROGRAM_CHANGE = 0xC, - MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD, - MIDI_MESSAGE_PITCH_BEND = 0xE, -}; - /** * Input Modifier Status * for keyboard/mouse events. @@ -142,7 +77,8 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const; + virtual bool is_action_type() const; virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; } @@ -212,6 +148,8 @@ public: void set_modifiers_from_event(const InputEventWithModifiers *event); + uint32_t get_modifiers_mask() const; + virtual String as_text() const override; virtual String to_string() override; @@ -252,7 +190,7 @@ public: uint32_t get_physical_keycode_with_modifiers() const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } @@ -292,7 +230,7 @@ class InputEventMouseButton : public InputEventMouse { GDCLASS(InputEventMouseButton, InputEventMouse); float factor = 1; - int button_index = 0; + MouseButton button_index = MOUSE_BUTTON_NONE; bool pressed = false; //otherwise released bool double_click = false; //last even less than double click time @@ -303,8 +241,8 @@ public: void set_factor(float p_factor); float get_factor() const; - void set_button_index(int p_index); - int get_button_index() const; + void set_button_index(MouseButton p_index); + MouseButton get_button_index() const; void set_pressed(bool p_pressed); virtual bool is_pressed() const override; @@ -313,7 +251,9 @@ public: bool is_double_click() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; @@ -357,15 +297,15 @@ public: class InputEventJoypadMotion : public InputEvent { GDCLASS(InputEventJoypadMotion, InputEvent); - int axis = 0; ///< Joypad axis + JoyAxis axis = (JoyAxis)0; ///< Joypad axis float axis_value = 0; ///< -1 to 1 protected: static void _bind_methods(); public: - void set_axis(int p_axis); - int get_axis() const; + void set_axis(JoyAxis p_axis); + JoyAxis get_axis() const; void set_axis_value(float p_value); float get_axis_value() const; @@ -373,6 +313,7 @@ public: virtual bool is_pressed() const override; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; @@ -384,15 +325,15 @@ public: class InputEventJoypadButton : public InputEvent { GDCLASS(InputEventJoypadButton, InputEvent); - int button_index = 0; + JoyButton button_index = (JoyButton)0; bool pressed = false; float pressure = 0; //0 to 1 protected: static void _bind_methods(); public: - void set_button_index(int p_index); - int get_button_index() const; + void set_button_index(JoyButton p_index); + JoyButton get_button_index() const; void set_pressed(bool p_pressed); virtual bool is_pressed() const override; @@ -401,13 +342,14 @@ public: float get_pressure() const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; virtual String to_string() override; - static Ref<InputEventJoypadButton> create_reference(int p_btn_index); + static Ref<InputEventJoypadButton> create_reference(JoyButton p_btn_index); InputEventJoypadButton() {} }; @@ -491,9 +433,10 @@ public: virtual bool is_action(const StringName &p_action) const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; virtual String to_string() override; @@ -553,7 +496,7 @@ class InputEventMIDI : public InputEvent { GDCLASS(InputEventMIDI, InputEvent); int channel = 0; - int message = 0; + MIDIMessage message = MIDI_MESSAGE_NONE; int pitch = 0; int velocity = 0; int instrument = 0; @@ -568,8 +511,8 @@ public: void set_channel(const int p_channel); int get_channel() const; - void set_message(const int p_message); - int get_message() const; + void set_message(const MIDIMessage p_message); + MIDIMessage get_message() const; void set_pitch(const int p_pitch); int get_pitch() const; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 878ce820fb..b5f067d499 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -45,6 +45,7 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone); + ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone); ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event); ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); @@ -130,12 +131,9 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) { const Ref<InputEvent> e = E->get(); - //if (e.type != Ref<InputEvent>::KEY && e.device != p_event.device) -- unsure about the KEY comparison, why is this here? - // continue; - int device = e->get_device(); if (device == ALL_DEVICES || device == p_event->get_device()) { - if (p_exact_match && e->shortcut_match(p_event)) { + if (p_exact_match && e->is_match(p_event, true)) { return E; } else if (!p_exact_match && e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) { return E; @@ -353,8 +351,9 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_text_scroll_down", TTRC("Scroll Down") }, { "ui_text_scroll_down.OSX", TTRC("Scroll Down") }, { "ui_text_select_all", TTRC("Select All") }, - { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") }, + { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") }, { "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") }, + { "ui_text_submit", TTRC("Text Submitted") }, { "ui_graph_duplicate", TTRC("Duplicate Nodes") }, { "ui_graph_delete", TTRC("Delete Nodes") }, { "ui_filedialog_up_one_level", TTRC("Go Up One Level") }, @@ -511,6 +510,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { // Text Backspace and Delete inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE)); + inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_SHIFT)); default_builtin_cache.insert("ui_text_backspace", inputs); inputs = List<Ref<InputEvent>>(); @@ -667,6 +667,11 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(KEY_MENU)); default_builtin_cache.insert("ui_menu", inputs); + inputs = List<Ref<InputEvent>>(); + inputs.push_back(InputEventKey::create_reference(KEY_ENTER)); + inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER)); + default_builtin_cache.insert("ui_text_submit", inputs); + // ///// UI Graph Shortcuts ///// inputs = List<Ref<InputEvent>>(); diff --git a/core/io/compression.cpp b/core/io/compression.cpp index 6de626db99..ca56509253 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -238,7 +238,10 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s case Z_DATA_ERROR: case Z_MEM_ERROR: case Z_STREAM_ERROR: - WARN_PRINT(strm.msg); + case Z_BUF_ERROR: + if (strm.msg) { + WARN_PRINT(strm.msg); + } (void)inflateEnd(&strm); p_dst_vect->resize(0); return ret; diff --git a/core/io/config_file.h b/core/io/config_file.h index 1b28257c60..dbba43ace5 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -31,13 +31,13 @@ #ifndef CONFIG_FILE_H #define CONFIG_FILE_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "core/templates/ordered_hash_map.h" #include "core/variant/variant_parser.h" -class ConfigFile : public Reference { - GDCLASS(ConfigFile, Reference); +class ConfigFile : public RefCounted { + GDCLASS(ConfigFile, RefCounted); OrderedHashMap<String, OrderedHashMap<String, Variant>> values; diff --git a/core/os/dir_access.cpp b/core/io/dir_access.cpp index 39ae475c12..dfba00067f 100644 --- a/core/os/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -31,7 +31,7 @@ #include "dir_access.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/memory.h" #include "core/os/os.h" diff --git a/core/os/dir_access.h b/core/io/dir_access.h index 16154a4850..16154a4850 100644 --- a/core/os/dir_access.h +++ b/core/io/dir_access.h diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp index 288b2efe0e..655fb18535 100644 --- a/core/io/dtls_server.cpp +++ b/core/io/dtls_server.cpp @@ -31,7 +31,7 @@ #include "dtls_server.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" DTLSServer *(*DTLSServer::_create)() = nullptr; bool DTLSServer::available = false; diff --git a/core/io/dtls_server.h b/core/io/dtls_server.h index 92b6caf508..02a32533e1 100644 --- a/core/io/dtls_server.h +++ b/core/io/dtls_server.h @@ -34,8 +34,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer_dtls.h" -class DTLSServer : public Reference { - GDCLASS(DTLSServer, Reference); +class DTLSServer : public RefCounted { + GDCLASS(DTLSServer, RefCounted); protected: static DTLSServer *(*_create)(); diff --git a/core/os/file_access.cpp b/core/io/file_access.cpp index 3d04e4e619..d21c0bd9a2 100644 --- a/core/os/file_access.cpp +++ b/core/io/file_access.cpp @@ -551,6 +551,7 @@ void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_ } void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); for (uint64_t i = 0; i < p_length; i++) { store_8(p_src[i]); } diff --git a/core/os/file_access.h b/core/io/file_access.h index 5804aa2c47..5804aa2c47 100644 --- a/core/os/file_access.h +++ b/core/io/file_access.h diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index 19e4f241dd..3389e020e3 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -32,7 +32,7 @@ #define FILE_ACCESS_COMPRESSED_H #include "core/io/compression.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" class FileAccessCompressed : public FileAccess { Compression::Mode cmode = Compression::MODE_ZSTD; diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index b9514c8c8b..9e316291e8 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -257,6 +257,7 @@ Error FileAccessEncrypted::get_error() const { void FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); + ERR_FAIL_COND(!p_src && p_length > 0); if (pos < get_length()) { for (uint64_t i = 0; i < p_length; i++) { diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 00f14099f9..decffae696 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_ENCRYPTED_H #define FILE_ACCESS_ENCRYPTED_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #define ENCRYPTED_HEADER_MAGIC 0x43454447 diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 0114ab1765..627fd2bf9c 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -31,7 +31,7 @@ #include "file_access_memory.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/templates/map.h" static Map<String, Vector<uint8_t>> *files = nullptr; @@ -168,6 +168,7 @@ void FileAccessMemory::store_8(uint8_t p_byte) { } void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); uint64_t left = length - pos; uint64_t write = MIN(p_length, left); if (write < p_length) { diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 4157531d01..14135bd68c 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_MEMORY_H #define FILE_ACCESS_MEMORY_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" class FileAccessMemory : public FileAccess { uint8_t *data = nullptr; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 63a8f9c5b6..9ee3876c2f 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -210,7 +210,7 @@ FileAccessNetworkClient *FileAccessNetworkClient::singleton = nullptr; FileAccessNetworkClient::FileAccessNetworkClient() { singleton = this; - client.instance(); + client.instantiate(); } FileAccessNetworkClient::~FileAccessNetworkClient() { diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 94b66c2480..1d9d761fbb 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_NETWORK_H #define FILE_ACCESS_NETWORK_H +#include "core/io/file_access.h" #include "core/io/stream_peer_tcp.h" -#include "core/os/file_access.h" #include "core/os/semaphore.h" #include "core/os/thread.h" diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 7a83fc938f..2f0ee62723 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_PACK_H #define FILE_ACCESS_PACK_H -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/string/print_string.h" #include "core/templates/list.h" #include "core/templates/map.h" diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index b8383fd865..b5c882e9ce 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -32,7 +32,7 @@ #include "file_access_zip.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" ZipArchive *ZipArchive::instance = nullptr; diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 0cf870e7e7..8000dd4290 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -30,9 +30,6 @@ #include "http_client.h" -#include "core/io/stream_peer_ssl.h" -#include "core/version.h" - const char *HTTPClient::_methods[METHOD_MAX] = { "GET", "HEAD", @@ -45,698 +42,23 @@ const char *HTTPClient::_methods[METHOD_MAX] = { "PATCH" }; -#ifndef JAVASCRIPT_ENABLED -Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { - close(); - - conn_port = p_port; - conn_host = p_host; - - ssl = p_ssl; - ssl_verify_host = p_verify_host; - - String host_lower = conn_host.to_lower(); - if (host_lower.begins_with("http://")) { - conn_host = conn_host.substr(7, conn_host.length() - 7); - } else if (host_lower.begins_with("https://")) { - ssl = true; - conn_host = conn_host.substr(8, conn_host.length() - 8); - } - - ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER); - - if (conn_port < 0) { - if (ssl) { - conn_port = PORT_HTTPS; - } else { - conn_port = PORT_HTTP; - } - } - - connection = tcp_connection; - - if (conn_host.is_valid_ip_address()) { - // Host contains valid IP - Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port); - if (err) { - status = STATUS_CANT_CONNECT; - return err; - } - - status = STATUS_CONNECTING; - } else { - // Host contains hostname and needs to be resolved to IP - resolving = IP::get_singleton()->resolve_hostname_queue_item(conn_host); - status = STATUS_RESOLVING; +HTTPClient *HTTPClient::create() { + if (_create) { + return _create(); } - - return OK; + return nullptr; } -void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) { - ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object."); - - if (ssl) { - ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()), - "Connection is not a reference to a valid StreamPeerSSL object."); - } - - if (connection == p_connection) { - return; - } - - close(); - connection = p_connection; - status = STATUS_CONNECTED; +Error HTTPClient::_request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) { + int size = p_body.size(); + return request(p_method, p_url, p_headers, size > 0 ? p_body.ptr() : nullptr, size); } -Ref<StreamPeer> HTTPClient::get_connection() const { - return connection; +Error HTTPClient::_request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { + int size = p_body.length(); + return request(p_method, p_url, p_headers, size > 0 ? (const uint8_t *)p_body.utf8().get_data() : nullptr, size); } -static bool _check_request_url(HTTPClient::Method p_method, const String &p_url) { - switch (p_method) { - case HTTPClient::METHOD_CONNECT: { - // Authority in host:port format, as in RFC7231 - int pos = p_url.find_char(':'); - return 0 < pos && pos < p_url.length() - 1; - } - case HTTPClient::METHOD_OPTIONS: { - if (p_url == "*") { - return true; - } - [[fallthrough]]; - } - default: - // Absolute path or absolute URL - return p_url.begins_with("/") || p_url.begins_with("http://") || p_url.begins_with("https://"); - } -} - -Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) { - ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); - - String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - bool add_host = true; - bool add_clen = p_body.size() > 0; - bool add_uagent = true; - bool add_accept = true; - for (int i = 0; i < p_headers.size(); i++) { - request += p_headers[i] + "\r\n"; - if (add_host && p_headers[i].findn("Host:") == 0) { - add_host = false; - } - if (add_clen && p_headers[i].findn("Content-Length:") == 0) { - add_clen = false; - } - if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { - add_uagent = false; - } - if (add_accept && p_headers[i].findn("Accept:") == 0) { - add_accept = false; - } - } - if (add_host) { - if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { - // Don't append the standard ports - request += "Host: " + conn_host + "\r\n"; - } else { - request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; - } - } - if (add_clen) { - request += "Content-Length: " + itos(p_body.size()) + "\r\n"; - // Should it add utf8 encoding? - } - if (add_uagent) { - request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; - } - if (add_accept) { - request += "Accept: */*\r\n"; - } - request += "\r\n"; - CharString cs = request.utf8(); - - Vector<uint8_t> data; - data.resize(cs.length()); - { - uint8_t *data_write = data.ptrw(); - for (int i = 0; i < cs.length(); i++) { - data_write[i] = cs[i]; - } - } - - data.append_array(p_body); - - const uint8_t *r = data.ptr(); - Error err = connection->put_data(&r[0], data.size()); - - if (err) { - close(); - status = STATUS_CONNECTION_ERROR; - return err; - } - - status = STATUS_REQUESTING; - head_request = p_method == METHOD_HEAD; - - return OK; -} - -Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { - ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); - - String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - bool add_host = true; - bool add_uagent = true; - bool add_accept = true; - bool add_clen = p_body.length() > 0; - for (int i = 0; i < p_headers.size(); i++) { - request += p_headers[i] + "\r\n"; - if (add_host && p_headers[i].findn("Host:") == 0) { - add_host = false; - } - if (add_clen && p_headers[i].findn("Content-Length:") == 0) { - add_clen = false; - } - if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { - add_uagent = false; - } - if (add_accept && p_headers[i].findn("Accept:") == 0) { - add_accept = false; - } - } - if (add_host) { - if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { - // Don't append the standard ports - request += "Host: " + conn_host + "\r\n"; - } else { - request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; - } - } - if (add_clen) { - request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n"; - // Should it add utf8 encoding? - } - if (add_uagent) { - request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; - } - if (add_accept) { - request += "Accept: */*\r\n"; - } - request += "\r\n"; - request += p_body; - - CharString cs = request.utf8(); - Error err = connection->put_data((const uint8_t *)cs.ptr(), cs.length()); - if (err) { - close(); - status = STATUS_CONNECTION_ERROR; - return err; - } - - status = STATUS_REQUESTING; - head_request = p_method == METHOD_HEAD; - - return OK; -} - -bool HTTPClient::has_response() const { - return response_headers.size() != 0; -} - -bool HTTPClient::is_response_chunked() const { - return chunked; -} - -int HTTPClient::get_response_code() const { - return response_num; -} - -Error HTTPClient::get_response_headers(List<String> *r_response) { - if (!response_headers.size()) { - return ERR_INVALID_PARAMETER; - } - - for (int i = 0; i < response_headers.size(); i++) { - r_response->push_back(response_headers[i]); - } - - response_headers.clear(); - - return OK; -} - -void HTTPClient::close() { - if (tcp_connection->get_status() != StreamPeerTCP::STATUS_NONE) { - tcp_connection->disconnect_from_host(); - } - - connection.unref(); - status = STATUS_DISCONNECTED; - head_request = false; - if (resolving != IP::RESOLVER_INVALID_ID) { - IP::get_singleton()->erase_resolve_item(resolving); - resolving = IP::RESOLVER_INVALID_ID; - } - - response_headers.clear(); - response_str.clear(); - body_size = -1; - body_left = 0; - chunk_left = 0; - chunk_trailer_part = false; - read_until_eof = false; - response_num = 0; - handshaking = false; -} - -Error HTTPClient::poll() { - switch (status) { - case STATUS_RESOLVING: { - ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG); - - IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving); - switch (rstatus) { - case IP::RESOLVER_STATUS_WAITING: - return OK; // Still resolving - - case IP::RESOLVER_STATUS_DONE: { - IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving); - Error err = tcp_connection->connect_to_host(host, conn_port); - IP::get_singleton()->erase_resolve_item(resolving); - resolving = IP::RESOLVER_INVALID_ID; - if (err) { - status = STATUS_CANT_CONNECT; - return err; - } - - status = STATUS_CONNECTING; - } break; - case IP::RESOLVER_STATUS_NONE: - case IP::RESOLVER_STATUS_ERROR: { - IP::get_singleton()->erase_resolve_item(resolving); - resolving = IP::RESOLVER_INVALID_ID; - close(); - status = STATUS_CANT_RESOLVE; - return ERR_CANT_RESOLVE; - } break; - } - } break; - case STATUS_CONNECTING: { - StreamPeerTCP::Status s = tcp_connection->get_status(); - switch (s) { - case StreamPeerTCP::STATUS_CONNECTING: { - return OK; - } break; - case StreamPeerTCP::STATUS_CONNECTED: { - if (ssl) { - Ref<StreamPeerSSL> ssl; - if (!handshaking) { - // Connect the StreamPeerSSL and start handshaking - ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); - ssl->set_blocking_handshake_enabled(false); - Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); - if (err != OK) { - close(); - status = STATUS_SSL_HANDSHAKE_ERROR; - return ERR_CANT_CONNECT; - } - connection = ssl; - handshaking = true; - } else { - // We are already handshaking, which means we can use your already active SSL connection - ssl = static_cast<Ref<StreamPeerSSL>>(connection); - if (ssl.is_null()) { - close(); - status = STATUS_SSL_HANDSHAKE_ERROR; - return ERR_CANT_CONNECT; - } - - ssl->poll(); // Try to finish the handshake - } - - if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { - // Handshake has been successful - handshaking = false; - status = STATUS_CONNECTED; - return OK; - } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { - // Handshake has failed - close(); - status = STATUS_SSL_HANDSHAKE_ERROR; - return ERR_CANT_CONNECT; - } - // ... we will need to poll more for handshake to finish - } else { - status = STATUS_CONNECTED; - } - return OK; - } break; - case StreamPeerTCP::STATUS_ERROR: - case StreamPeerTCP::STATUS_NONE: { - close(); - status = STATUS_CANT_CONNECT; - return ERR_CANT_CONNECT; - } break; - } - } break; - case STATUS_BODY: - case STATUS_CONNECTED: { - // Check if we are still connected - if (ssl) { - Ref<StreamPeerSSL> tmp = connection; - tmp->poll(); - if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) { - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } - } else if (tcp_connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } - // Connection established, requests can now be made - return OK; - } break; - case STATUS_REQUESTING: { - while (true) { - uint8_t byte; - int rec = 0; - Error err = _get_http_data(&byte, 1, rec); - if (err != OK) { - close(); - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } - - if (rec == 0) { - return OK; // Still requesting, keep trying! - } - - response_str.push_back(byte); - int rs = response_str.size(); - if ( - (rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') || - (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { - // End of response, parse. - response_str.push_back(0); - String response; - response.parse_utf8((const char *)response_str.ptr()); - Vector<String> responses = response.split("\n"); - body_size = -1; - chunked = false; - body_left = 0; - chunk_left = 0; - chunk_trailer_part = false; - read_until_eof = false; - response_str.clear(); - response_headers.clear(); - response_num = RESPONSE_OK; - - // Per the HTTP 1.1 spec, keep-alive is the default. - // Not following that specification breaks standard implementations. - // Broken web servers should be fixed. - bool keep_alive = true; - - for (int i = 0; i < responses.size(); i++) { - String header = responses[i].strip_edges(); - String s = header.to_lower(); - if (s.length() == 0) { - continue; - } - if (s.begins_with("content-length:")) { - body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int(); - body_left = body_size; - - } else if (s.begins_with("transfer-encoding:")) { - String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges(); - if (encoding == "chunked") { - chunked = true; - } - } else if (s.begins_with("connection: close")) { - keep_alive = false; - } - - if (i == 0 && responses[i].begins_with("HTTP")) { - String num = responses[i].get_slicec(' ', 1); - response_num = num.to_int(); - } else { - response_headers.push_back(header); - } - } - - // This is a HEAD request, we won't receive anything. - if (head_request) { - body_size = 0; - body_left = 0; - } - - if (body_size != -1 || chunked) { - status = STATUS_BODY; - } else if (!keep_alive) { - read_until_eof = true; - status = STATUS_BODY; - } else { - status = STATUS_CONNECTED; - } - return OK; - } - } - } break; - case STATUS_DISCONNECTED: { - return ERR_UNCONFIGURED; - } break; - case STATUS_CONNECTION_ERROR: - case STATUS_SSL_HANDSHAKE_ERROR: { - return ERR_CONNECTION_ERROR; - } break; - case STATUS_CANT_CONNECT: { - return ERR_CANT_CONNECT; - } break; - case STATUS_CANT_RESOLVE: { - return ERR_CANT_RESOLVE; - } break; - } - - return OK; -} - -int HTTPClient::get_response_body_length() const { - return body_size; -} - -PackedByteArray HTTPClient::read_response_body_chunk() { - ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray()); - - PackedByteArray ret; - Error err = OK; - - if (chunked) { - while (true) { - if (chunk_trailer_part) { - // We need to consume the trailer part too or keep-alive will break - uint8_t b; - int rec = 0; - err = _get_http_data(&b, 1, rec); - - if (rec == 0) { - break; - } - - chunk.push_back(b); - int cs = chunk.size(); - if ((cs >= 2 && chunk[cs - 2] == '\r' && chunk[cs - 1] == '\n')) { - if (cs == 2) { - // Finally over - chunk_trailer_part = false; - status = STATUS_CONNECTED; - chunk.clear(); - break; - } else { - // We do not process nor return the trailer data - chunk.clear(); - } - } - } else if (chunk_left == 0) { - // Reading length - uint8_t b; - int rec = 0; - err = _get_http_data(&b, 1, rec); - - if (rec == 0) { - break; - } - - chunk.push_back(b); - - if (chunk.size() > 32) { - ERR_PRINT("HTTP Invalid chunk hex len"); - status = STATUS_CONNECTION_ERROR; - break; - } - - if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') { - int len = 0; - for (int i = 0; i < chunk.size() - 2; i++) { - char c = chunk[i]; - int v = 0; - if (c >= '0' && c <= '9') { - v = c - '0'; - } else if (c >= 'a' && c <= 'f') { - v = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - v = c - 'A' + 10; - } else { - ERR_PRINT("HTTP Chunk len not in hex!!"); - status = STATUS_CONNECTION_ERROR; - break; - } - len <<= 4; - len |= v; - if (len > (1 << 24)) { - ERR_PRINT("HTTP Chunk too big!! >16mb"); - status = STATUS_CONNECTION_ERROR; - break; - } - } - - if (len == 0) { - // End reached! - chunk_trailer_part = true; - chunk.clear(); - break; - } - - chunk_left = len + 2; - chunk.resize(chunk_left); - } - } else { - int rec = 0; - err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec); - if (rec == 0) { - break; - } - chunk_left -= rec; - - if (chunk_left == 0) { - if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') { - ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)"); - status = STATUS_CONNECTION_ERROR; - break; - } - - ret.resize(chunk.size() - 2); - uint8_t *w = ret.ptrw(); - memcpy(w, chunk.ptr(), chunk.size() - 2); - chunk.clear(); - } - - break; - } - } - - } else { - int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size; - ret.resize(to_read); - int _offset = 0; - while (to_read > 0) { - int rec = 0; - { - uint8_t *w = ret.ptrw(); - err = _get_http_data(w + _offset, to_read, rec); - } - if (rec <= 0) { // Ended up reading less - ret.resize(_offset); - break; - } else { - _offset += rec; - to_read -= rec; - if (!read_until_eof) { - body_left -= rec; - } - } - if (err != OK) { - break; - } - } - } - - if (err != OK) { - close(); - - if (err == ERR_FILE_EOF) { - status = STATUS_DISCONNECTED; // Server disconnected - } else { - status = STATUS_CONNECTION_ERROR; - } - } else if (body_left == 0 && !chunked && !read_until_eof) { - status = STATUS_CONNECTED; - } - - return ret; -} - -HTTPClient::Status HTTPClient::get_status() const { - return status; -} - -void HTTPClient::set_blocking_mode(bool p_enable) { - blocking = p_enable; -} - -bool HTTPClient::is_blocking_mode_enabled() const { - return blocking; -} - -Error HTTPClient::_get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - if (blocking) { - // We can't use StreamPeer.get_data, since when reaching EOF we will get an - // error without knowing how many bytes we received. - Error err = ERR_FILE_EOF; - int read = 0; - int left = p_bytes; - r_received = 0; - while (left > 0) { - err = connection->get_partial_data(p_buffer + r_received, left, read); - if (err == OK) { - r_received += read; - } else if (err == ERR_FILE_EOF) { - r_received += read; - return err; - } else { - return err; - } - left -= read; - } - return err; - } else { - return connection->get_partial_data(p_buffer, p_bytes, r_received); - } -} - -void HTTPClient::set_read_chunk_size(int p_size) { - ERR_FAIL_COND(p_size < 256 || p_size > (1 << 24)); - read_chunk_size = p_size; -} - -int HTTPClient::get_read_chunk_size() const { - return read_chunk_size; -} - -HTTPClient::HTTPClient() { - tcp_connection.instance(); -} - -HTTPClient::~HTTPClient() {} - -#endif // #ifndef JAVASCRIPT_ENABLED - String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { String query = ""; Array keys = p_dict.keys(); @@ -802,8 +124,8 @@ void HTTPClient::_bind_methods() { ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(-1), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_connection", "connection"), &HTTPClient::set_connection); ClassDB::bind_method(D_METHOD("get_connection"), &HTTPClient::get_connection); - ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::request_raw); - ClassDB::bind_method(D_METHOD("request", "method", "url", "headers", "body"), &HTTPClient::request, DEFVAL(String())); + ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::_request_raw); + ClassDB::bind_method(D_METHOD("request", "method", "url", "headers", "body"), &HTTPClient::_request, DEFVAL(String())); ClassDB::bind_method(D_METHOD("close"), &HTTPClient::close); ClassDB::bind_method(D_METHOD("has_response"), &HTTPClient::has_response); @@ -825,7 +147,7 @@ void HTTPClient::_bind_methods() { ClassDB::bind_method(D_METHOD("query_string_from_dict", "fields"), &HTTPClient::query_string_from_dict); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_mode_enabled"), "set_blocking_mode", "is_blocking_mode_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_connection", "get_connection"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", PROPERTY_USAGE_NONE), "set_connection", "get_connection"); ADD_PROPERTY(PropertyInfo(Variant::INT, "read_chunk_size", PROPERTY_HINT_RANGE, "256,16777216"), "set_read_chunk_size", "get_read_chunk_size"); BIND_ENUM_CONSTANT(METHOD_GET); diff --git a/core/io/http_client.h b/core/io/http_client.h index ec4b86b26f..718c3a905e 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -34,10 +34,10 @@ #include "core/io/ip.h" #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class HTTPClient : public Reference { - GDCLASS(HTTPClient, Reference); +class HTTPClient : public RefCounted { + GDCLASS(HTTPClient, RefCounted); public: enum ResponseCode { @@ -142,7 +142,7 @@ public: }; -private: +protected: static const char *_methods[METHOD_MAX]; static const int HOST_MIN_LEN = 4; @@ -152,79 +152,48 @@ private: }; -#ifndef JAVASCRIPT_ENABLED - Status status = STATUS_DISCONNECTED; - IP::ResolverID resolving = IP::RESOLVER_INVALID_ID; - int conn_port = -1; - String conn_host; - bool ssl = false; - bool ssl_verify_host = false; - bool blocking = false; - bool handshaking = false; - bool head_request = false; - - Vector<uint8_t> response_str; - - bool chunked = false; - Vector<uint8_t> chunk; - int chunk_left = 0; - bool chunk_trailer_part = false; - int body_size = -1; - int body_left = 0; - bool read_until_eof = false; - - Ref<StreamPeerTCP> tcp_connection; - Ref<StreamPeer> connection; - - int response_num = 0; - Vector<String> response_headers; - // 64 KiB by default (favors fast download speeds at the cost of memory usage). - int read_chunk_size = 65536; - - Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received); - -#else -#include "platform/javascript/http_client.h.inc" -#endif - PackedStringArray _get_response_headers(); Dictionary _get_response_headers_as_dictionary(); + Error _request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body); + Error _request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body = String()); + + static HTTPClient *(*_create)(); static void _bind_methods(); public: - Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true); + static HTTPClient *create(); - void set_connection(const Ref<StreamPeer> &p_connection); - Ref<StreamPeer> get_connection() const; + String query_string_from_dict(const Dictionary &p_dict); - Error request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body); - Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body = String()); + virtual Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) = 0; + virtual Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) = 0; - void close(); + virtual void set_connection(const Ref<StreamPeer> &p_connection) = 0; + virtual Ref<StreamPeer> get_connection() const = 0; - Status get_status() const; + virtual void close() = 0; - bool has_response() const; - bool is_response_chunked() const; - int get_response_code() const; - Error get_response_headers(List<String> *r_response); - int get_response_body_length() const; + virtual Status get_status() const = 0; - PackedByteArray read_response_body_chunk(); // Can't get body as partial text because of most encodings UTF8, gzip, etc. + virtual bool has_response() const = 0; + virtual bool is_response_chunked() const = 0; + virtual int get_response_code() const = 0; + virtual Error get_response_headers(List<String> *r_response) = 0; + virtual int get_response_body_length() const = 0; - void set_blocking_mode(bool p_enable); // Useful mostly if running in a thread - bool is_blocking_mode_enabled() const; + virtual PackedByteArray read_response_body_chunk() = 0; // Can't get body as partial text because of most encodings UTF8, gzip, etc. - void set_read_chunk_size(int p_size); - int get_read_chunk_size() const; + virtual void set_blocking_mode(bool p_enable) = 0; // Useful mostly if running in a thread + virtual bool is_blocking_mode_enabled() const = 0; - Error poll(); + virtual void set_read_chunk_size(int p_size) = 0; + virtual int get_read_chunk_size() const = 0; - String query_string_from_dict(const Dictionary &p_dict); + virtual Error poll() = 0; - HTTPClient(); - ~HTTPClient(); + HTTPClient() {} + virtual ~HTTPClient() {} }; VARIANT_ENUM_CAST(HTTPClient::ResponseCode) diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp new file mode 100644 index 0000000000..f291086808 --- /dev/null +++ b/core/io/http_client_tcp.cpp @@ -0,0 +1,667 @@ +/*************************************************************************/ +/* http_client_tcp.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 JAVASCRIPT_ENABLED + +#include "http_client_tcp.h" + +#include "core/io/stream_peer_ssl.h" +#include "core/version.h" + +HTTPClient *HTTPClientTCP::_create_func() { + return memnew(HTTPClientTCP); +} + +Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { + close(); + + conn_port = p_port; + conn_host = p_host; + + ssl = p_ssl; + ssl_verify_host = p_verify_host; + + String host_lower = conn_host.to_lower(); + if (host_lower.begins_with("http://")) { + conn_host = conn_host.substr(7, conn_host.length() - 7); + } else if (host_lower.begins_with("https://")) { + ssl = true; + conn_host = conn_host.substr(8, conn_host.length() - 8); + } + + ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER); + + if (conn_port < 0) { + if (ssl) { + conn_port = PORT_HTTPS; + } else { + conn_port = PORT_HTTP; + } + } + + connection = tcp_connection; + + if (conn_host.is_valid_ip_address()) { + // Host contains valid IP + Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port); + if (err) { + status = STATUS_CANT_CONNECT; + return err; + } + + status = STATUS_CONNECTING; + } else { + // Host contains hostname and needs to be resolved to IP + resolving = IP::get_singleton()->resolve_hostname_queue_item(conn_host); + status = STATUS_RESOLVING; + } + + return OK; +} + +void HTTPClientTCP::set_connection(const Ref<StreamPeer> &p_connection) { + ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object."); + + if (ssl) { + ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()), + "Connection is not a reference to a valid StreamPeerSSL object."); + } + + if (connection == p_connection) { + return; + } + + close(); + connection = p_connection; + status = STATUS_CONNECTED; +} + +Ref<StreamPeer> HTTPClientTCP::get_connection() const { + return connection; +} + +static bool _check_request_url(HTTPClientTCP::Method p_method, const String &p_url) { + switch (p_method) { + case HTTPClientTCP::METHOD_CONNECT: { + // Authority in host:port format, as in RFC7231 + int pos = p_url.find_char(':'); + return 0 < pos && pos < p_url.length() - 1; + } + case HTTPClientTCP::METHOD_OPTIONS: { + if (p_url == "*") { + return true; + } + [[fallthrough]]; + } + default: + // Absolute path or absolute URL + return p_url.begins_with("/") || p_url.begins_with("http://") || p_url.begins_with("https://"); + } +} + +Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) { + ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); + + String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; + bool add_host = true; + bool add_clen = p_body_size > 0; + bool add_uagent = true; + bool add_accept = true; + for (int i = 0; i < p_headers.size(); i++) { + request += p_headers[i] + "\r\n"; + if (add_host && p_headers[i].findn("Host:") == 0) { + add_host = false; + } + if (add_clen && p_headers[i].findn("Content-Length:") == 0) { + add_clen = false; + } + if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { + add_uagent = false; + } + if (add_accept && p_headers[i].findn("Accept:") == 0) { + add_accept = false; + } + } + if (add_host) { + if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { + // Don't append the standard ports + request += "Host: " + conn_host + "\r\n"; + } else { + request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; + } + } + if (add_clen) { + request += "Content-Length: " + itos(p_body_size) + "\r\n"; + // Should it add utf8 encoding? + } + if (add_uagent) { + request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; + } + if (add_accept) { + request += "Accept: */*\r\n"; + } + request += "\r\n"; + CharString cs = request.utf8(); + + Vector<uint8_t> data; + data.resize(cs.length() + p_body_size); + memcpy(data.ptrw(), cs.get_data(), cs.length()); + if (p_body_size > 0) { + memcpy(data.ptrw() + cs.length(), p_body, p_body_size); + } + + // TODO Implement non-blocking requests. + Error err = connection->put_data(data.ptr(), data.size()); + + if (err) { + close(); + status = STATUS_CONNECTION_ERROR; + return err; + } + + status = STATUS_REQUESTING; + head_request = p_method == METHOD_HEAD; + + return OK; +} + +bool HTTPClientTCP::has_response() const { + return response_headers.size() != 0; +} + +bool HTTPClientTCP::is_response_chunked() const { + return chunked; +} + +int HTTPClientTCP::get_response_code() const { + return response_num; +} + +Error HTTPClientTCP::get_response_headers(List<String> *r_response) { + if (!response_headers.size()) { + return ERR_INVALID_PARAMETER; + } + + for (int i = 0; i < response_headers.size(); i++) { + r_response->push_back(response_headers[i]); + } + + response_headers.clear(); + + return OK; +} + +void HTTPClientTCP::close() { + if (tcp_connection->get_status() != StreamPeerTCP::STATUS_NONE) { + tcp_connection->disconnect_from_host(); + } + + connection.unref(); + status = STATUS_DISCONNECTED; + head_request = false; + if (resolving != IP::RESOLVER_INVALID_ID) { + IP::get_singleton()->erase_resolve_item(resolving); + resolving = IP::RESOLVER_INVALID_ID; + } + + response_headers.clear(); + response_str.clear(); + body_size = -1; + body_left = 0; + chunk_left = 0; + chunk_trailer_part = false; + read_until_eof = false; + response_num = 0; + handshaking = false; +} + +Error HTTPClientTCP::poll() { + switch (status) { + case STATUS_RESOLVING: { + ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG); + + IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving); + switch (rstatus) { + case IP::RESOLVER_STATUS_WAITING: + return OK; // Still resolving + + case IP::RESOLVER_STATUS_DONE: { + IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving); + Error err = tcp_connection->connect_to_host(host, conn_port); + IP::get_singleton()->erase_resolve_item(resolving); + resolving = IP::RESOLVER_INVALID_ID; + if (err) { + status = STATUS_CANT_CONNECT; + return err; + } + + status = STATUS_CONNECTING; + } break; + case IP::RESOLVER_STATUS_NONE: + case IP::RESOLVER_STATUS_ERROR: { + IP::get_singleton()->erase_resolve_item(resolving); + resolving = IP::RESOLVER_INVALID_ID; + close(); + status = STATUS_CANT_RESOLVE; + return ERR_CANT_RESOLVE; + } break; + } + } break; + case STATUS_CONNECTING: { + StreamPeerTCP::Status s = tcp_connection->get_status(); + switch (s) { + case StreamPeerTCP::STATUS_CONNECTING: { + return OK; + } break; + case StreamPeerTCP::STATUS_CONNECTED: { + if (ssl) { + Ref<StreamPeerSSL> ssl; + if (!handshaking) { + // Connect the StreamPeerSSL and start handshaking + ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); + ssl->set_blocking_handshake_enabled(false); + Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); + if (err != OK) { + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + connection = ssl; + handshaking = true; + } else { + // We are already handshaking, which means we can use your already active SSL connection + ssl = static_cast<Ref<StreamPeerSSL>>(connection); + if (ssl.is_null()) { + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + + ssl->poll(); // Try to finish the handshake + } + + if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { + // Handshake has been successful + handshaking = false; + status = STATUS_CONNECTED; + return OK; + } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { + // Handshake has failed + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + // ... we will need to poll more for handshake to finish + } else { + status = STATUS_CONNECTED; + } + return OK; + } break; + case StreamPeerTCP::STATUS_ERROR: + case StreamPeerTCP::STATUS_NONE: { + close(); + status = STATUS_CANT_CONNECT; + return ERR_CANT_CONNECT; + } break; + } + } break; + case STATUS_BODY: + case STATUS_CONNECTED: { + // Check if we are still connected + if (ssl) { + Ref<StreamPeerSSL> tmp = connection; + tmp->poll(); + if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) { + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + } else if (tcp_connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) { + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + // Connection established, requests can now be made + return OK; + } break; + case STATUS_REQUESTING: { + while (true) { + uint8_t byte; + int rec = 0; + Error err = _get_http_data(&byte, 1, rec); + if (err != OK) { + close(); + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + + if (rec == 0) { + return OK; // Still requesting, keep trying! + } + + response_str.push_back(byte); + int rs = response_str.size(); + if ( + (rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') || + (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { + // End of response, parse. + response_str.push_back(0); + String response; + response.parse_utf8((const char *)response_str.ptr()); + Vector<String> responses = response.split("\n"); + body_size = -1; + chunked = false; + body_left = 0; + chunk_left = 0; + chunk_trailer_part = false; + read_until_eof = false; + response_str.clear(); + response_headers.clear(); + response_num = RESPONSE_OK; + + // Per the HTTP 1.1 spec, keep-alive is the default. + // Not following that specification breaks standard implementations. + // Broken web servers should be fixed. + bool keep_alive = true; + + for (int i = 0; i < responses.size(); i++) { + String header = responses[i].strip_edges(); + String s = header.to_lower(); + if (s.length() == 0) { + continue; + } + if (s.begins_with("content-length:")) { + body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int(); + body_left = body_size; + + } else if (s.begins_with("transfer-encoding:")) { + String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges(); + if (encoding == "chunked") { + chunked = true; + } + } else if (s.begins_with("connection: close")) { + keep_alive = false; + } + + if (i == 0 && responses[i].begins_with("HTTP")) { + String num = responses[i].get_slicec(' ', 1); + response_num = num.to_int(); + } else { + response_headers.push_back(header); + } + } + + // This is a HEAD request, we won't receive anything. + if (head_request) { + body_size = 0; + body_left = 0; + } + + if (body_size != -1 || chunked) { + status = STATUS_BODY; + } else if (!keep_alive) { + read_until_eof = true; + status = STATUS_BODY; + } else { + status = STATUS_CONNECTED; + } + return OK; + } + } + } break; + case STATUS_DISCONNECTED: { + return ERR_UNCONFIGURED; + } break; + case STATUS_CONNECTION_ERROR: + case STATUS_SSL_HANDSHAKE_ERROR: { + return ERR_CONNECTION_ERROR; + } break; + case STATUS_CANT_CONNECT: { + return ERR_CANT_CONNECT; + } break; + case STATUS_CANT_RESOLVE: { + return ERR_CANT_RESOLVE; + } break; + } + + return OK; +} + +int HTTPClientTCP::get_response_body_length() const { + return body_size; +} + +PackedByteArray HTTPClientTCP::read_response_body_chunk() { + ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray()); + + PackedByteArray ret; + Error err = OK; + + if (chunked) { + while (true) { + if (chunk_trailer_part) { + // We need to consume the trailer part too or keep-alive will break + uint8_t b; + int rec = 0; + err = _get_http_data(&b, 1, rec); + + if (rec == 0) { + break; + } + + chunk.push_back(b); + int cs = chunk.size(); + if ((cs >= 2 && chunk[cs - 2] == '\r' && chunk[cs - 1] == '\n')) { + if (cs == 2) { + // Finally over + chunk_trailer_part = false; + status = STATUS_CONNECTED; + chunk.clear(); + break; + } else { + // We do not process nor return the trailer data + chunk.clear(); + } + } + } else if (chunk_left == 0) { + // Reading length + uint8_t b; + int rec = 0; + err = _get_http_data(&b, 1, rec); + + if (rec == 0) { + break; + } + + chunk.push_back(b); + + if (chunk.size() > 32) { + ERR_PRINT("HTTP Invalid chunk hex len"); + status = STATUS_CONNECTION_ERROR; + break; + } + + if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') { + int len = 0; + for (int i = 0; i < chunk.size() - 2; i++) { + char c = chunk[i]; + int v = 0; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (c >= 'a' && c <= 'f') { + v = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + v = c - 'A' + 10; + } else { + ERR_PRINT("HTTP Chunk len not in hex!!"); + status = STATUS_CONNECTION_ERROR; + break; + } + len <<= 4; + len |= v; + if (len > (1 << 24)) { + ERR_PRINT("HTTP Chunk too big!! >16mb"); + status = STATUS_CONNECTION_ERROR; + break; + } + } + + if (len == 0) { + // End reached! + chunk_trailer_part = true; + chunk.clear(); + break; + } + + chunk_left = len + 2; + chunk.resize(chunk_left); + } + } else { + int rec = 0; + err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec); + if (rec == 0) { + break; + } + chunk_left -= rec; + + if (chunk_left == 0) { + if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') { + ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)"); + status = STATUS_CONNECTION_ERROR; + break; + } + + ret.resize(chunk.size() - 2); + uint8_t *w = ret.ptrw(); + memcpy(w, chunk.ptr(), chunk.size() - 2); + chunk.clear(); + } + + break; + } + } + + } else { + int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size; + ret.resize(to_read); + int _offset = 0; + while (to_read > 0) { + int rec = 0; + { + uint8_t *w = ret.ptrw(); + err = _get_http_data(w + _offset, to_read, rec); + } + if (rec <= 0) { // Ended up reading less + ret.resize(_offset); + break; + } else { + _offset += rec; + to_read -= rec; + if (!read_until_eof) { + body_left -= rec; + } + } + if (err != OK) { + ret.resize(_offset); + break; + } + } + } + + if (err != OK) { + close(); + + if (err == ERR_FILE_EOF) { + status = STATUS_DISCONNECTED; // Server disconnected + } else { + status = STATUS_CONNECTION_ERROR; + } + } else if (body_left == 0 && !chunked && !read_until_eof) { + status = STATUS_CONNECTED; + } + + return ret; +} + +HTTPClientTCP::Status HTTPClientTCP::get_status() const { + return status; +} + +void HTTPClientTCP::set_blocking_mode(bool p_enable) { + blocking = p_enable; +} + +bool HTTPClientTCP::is_blocking_mode_enabled() const { + return blocking; +} + +Error HTTPClientTCP::_get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received) { + if (blocking) { + // We can't use StreamPeer.get_data, since when reaching EOF we will get an + // error without knowing how many bytes we received. + Error err = ERR_FILE_EOF; + int read = 0; + int left = p_bytes; + r_received = 0; + while (left > 0) { + err = connection->get_partial_data(p_buffer + r_received, left, read); + if (err == OK) { + r_received += read; + } else if (err == ERR_FILE_EOF) { + r_received += read; + return err; + } else { + return err; + } + left -= read; + } + return err; + } else { + return connection->get_partial_data(p_buffer, p_bytes, r_received); + } +} + +void HTTPClientTCP::set_read_chunk_size(int p_size) { + ERR_FAIL_COND(p_size < 256 || p_size > (1 << 24)); + read_chunk_size = p_size; +} + +int HTTPClientTCP::get_read_chunk_size() const { + return read_chunk_size; +} + +HTTPClientTCP::HTTPClientTCP() { + tcp_connection.instantiate(); +} + +HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func; + +#endif // #ifndef JAVASCRIPT_ENABLED diff --git a/core/io/http_client_tcp.h b/core/io/http_client_tcp.h new file mode 100644 index 0000000000..e178399fbe --- /dev/null +++ b/core/io/http_client_tcp.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* http_client_tcp.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 HTTP_CLIENT_TCP_H +#define HTTP_CLIENT_TCP_H + +#include "http_client.h" + +class HTTPClientTCP : public HTTPClient { +private: + Status status = STATUS_DISCONNECTED; + IP::ResolverID resolving = IP::RESOLVER_INVALID_ID; + int conn_port = -1; + String conn_host; + bool ssl = false; + bool ssl_verify_host = false; + bool blocking = false; + bool handshaking = false; + bool head_request = false; + + Vector<uint8_t> response_str; + + bool chunked = false; + Vector<uint8_t> chunk; + int chunk_left = 0; + bool chunk_trailer_part = false; + int body_size = -1; + int body_left = 0; + bool read_until_eof = false; + + Ref<StreamPeerTCP> tcp_connection; + Ref<StreamPeer> connection; + + int response_num = 0; + Vector<String> response_headers; + // 64 KiB by default (favors fast download speeds at the cost of memory usage). + int read_chunk_size = 65536; + + Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received); + +public: + static HTTPClient *_create_func(); + + Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override; + + Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) override; + void set_connection(const Ref<StreamPeer> &p_connection) override; + Ref<StreamPeer> get_connection() const override; + void close() override; + Status get_status() const override; + bool has_response() const override; + bool is_response_chunked() const override; + int get_response_code() const override; + Error get_response_headers(List<String> *r_response) override; + int get_response_body_length() const override; + PackedByteArray read_response_body_chunk() override; + void set_blocking_mode(bool p_enable) override; + bool is_blocking_mode_enabled() const override; + void set_read_chunk_size(int p_size) override; + int get_read_chunk_size() const override; + Error poll() override; + HTTPClientTCP(); +}; + +#endif // HTTP_CLIENT_TCP_H diff --git a/core/io/image.cpp b/core/io/image.cpp index c36fa6e45f..3112dd217f 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1428,16 +1428,23 @@ void Image::flip_x() { } } +/// Get mipmap size and offset. int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) { + // Data offset in mipmaps (including the original texture). int size = 0; + int w = p_width; int h = p_height; + + // Current mipmap index in the loop below. p_mipmaps is the target mipmap index. + // In this function, mipmap 0 represents the first mipmap instead of the original texture. int mm = 0; int pixsize = get_format_pixel_size(p_format); int pixshift = get_format_pixel_rshift(p_format); int block = get_format_block_size(p_format); - //technically, you can still compress up to 1 px no matter the format, so commenting this + + // Technically, you can still compress up to 1 px no matter the format, so commenting this. //int minw, minh; //get_format_min_pixel_size(p_format, minw, minh); int minw = 1, minh = 1; @@ -1453,17 +1460,6 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & size += s; - if (r_mm_width) { - *r_mm_width = bw; - } - if (r_mm_height) { - *r_mm_height = bh; - } - - if (p_mipmaps >= 0 && mm == p_mipmaps) { - break; - } - if (p_mipmaps >= 0) { w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); @@ -1474,6 +1470,21 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); } + + // Set mipmap size. + // It might be necessary to put this after the minimum mipmap size check because of the possible occurrence of "1 >> 1". + if (r_mm_width) { + *r_mm_width = bw >> 1; + } + if (r_mm_height) { + *r_mm_height = bh >> 1; + } + + // Reach target mipmap. + if (p_mipmaps >= 0 && mm == p_mipmaps) { + break; + } + mm++; } @@ -1934,7 +1945,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con memcpy(wr.ptr(), ptr, size); wr = uint8_t*(); Ref<Image> im; - im.instance(); + im.instantiate(); im->create(w, h, false, format, imgdata); im->save_png("res://mipmap_" + itos(i) + ".png"); } @@ -1974,6 +1985,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); + ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "Image format out of range, please see Image's Format enum."); int mm = 0; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -1996,6 +2008,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); + ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "Image format out of range, please see Image's Format enum."); int mm; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -2367,6 +2380,8 @@ Error Image::decompress() { } Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) { + ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode."); + ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source."); return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality); } @@ -2392,6 +2407,9 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE); _image_compress_bptc_func(this, p_lossy_quality, p_channels); } break; + case COMPRESS_MAX: { + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } break; } return OK; @@ -2718,10 +2736,11 @@ void (*Image::_image_decompress_bptc)(Image *) = nullptr; void (*Image::_image_decompress_etc1)(Image *) = nullptr; void (*Image::_image_decompress_etc2)(Image *) = nullptr; -Vector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = nullptr; -Ref<Image> (*Image::lossy_unpacker)(const Vector<uint8_t> &) = nullptr; -Vector<uint8_t> (*Image::lossless_packer)(const Ref<Image> &) = nullptr; -Ref<Image> (*Image::lossless_unpacker)(const Vector<uint8_t> &) = nullptr; +Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr; +Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr; +Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr; +Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr; +Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr; Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr; Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr; @@ -2985,6 +3004,8 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { } void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats."); + uint8_t *w = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); uint32_t pixel_count = data.size() / pixel_size; @@ -3268,7 +3289,7 @@ Ref<Image> Image::rgbe_to_srgb() { ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>()); Ref<Image> new_image; - new_image.instance(); + new_image.instantiate(); new_image->create(width, height, false, Image::FORMAT_RGB8); for (int row = 0; row < height; row++) { @@ -3298,7 +3319,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const { } Ref<Image> image; - image.instance(); + image.instantiate(); image->width = w; image->height = h; image->format = format; @@ -3615,7 +3636,7 @@ Image::Image(const uint8_t *p_mem_png_jpg, int p_len) { Ref<Resource> Image::duplicate(bool p_subresources) const { Ref<Image> copy; - copy.instance(); + copy.instantiate(); copy->_copy_internals_from(*this); return copy; } diff --git a/core/io/image.h b/core/io/image.h index df8f9b35a1..8f1b251ac3 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -148,10 +148,11 @@ public: static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc2)(Image *); - static Vector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality); - static Ref<Image> (*lossy_unpacker)(const Vector<uint8_t> &p_buffer); - static Vector<uint8_t> (*lossless_packer)(const Ref<Image> &p_image); - static Ref<Image> (*lossless_unpacker)(const Vector<uint8_t> &p_buffer); + static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality); + static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image); + static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer); + static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image); + static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer); static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels); static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer); @@ -335,11 +336,13 @@ public: COMPRESS_ETC, COMPRESS_ETC2, COMPRESS_BPTC, + COMPRESS_MAX, }; enum CompressSource { COMPRESS_SOURCE_GENERIC, COMPRESS_SOURCE_SRGB, - COMPRESS_SOURCE_NORMAL + COMPRESS_SOURCE_NORMAL, + COMPRESS_SOURCE_MAX, }; Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7); diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 7de038e6fe..b45e9d26b1 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -163,7 +163,7 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin } Ref<Image> image; - image.instance(); + image.instantiate(); Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0); diff --git a/core/io/image_loader.h b/core/io/image_loader.h index a5d588e0b5..6d1b1e3646 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -31,9 +31,9 @@ #ifndef IMAGE_LOADER_H #define IMAGE_LOADER_H +#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/string/ustring.h" #include "core/templates/list.h" diff --git a/core/io/json.cpp b/core/io/json.cpp index 394cf216e8..b3a2498212 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -45,7 +45,7 @@ const char *JSON::tk_name[TK_MAX] = { "EOF", }; -static String _make_indent(const String &p_indent, int p_size) { +String JSON::_make_indent(const String &p_indent, int p_size) { String indent_text = ""; if (!p_indent.is_empty()) { for (int i = 0; i < p_size; i++) { @@ -55,7 +55,7 @@ static String _make_indent(const String &p_indent, int p_size) { return indent_text; } -String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys) { +String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) { String colon = ":"; String end_statement = ""; @@ -71,8 +71,17 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ return p_var.operator bool() ? "true" : "false"; case Variant::INT: return itos(p_var); - case Variant::FLOAT: - return rtos(p_var); + case Variant::FLOAT: { + double num = p_var; + if (p_full_precision) { + // Store unreliable digits (17) instead of just reliable + // digits (14) so that the value can be decoded exactly. + return String::num(num, 17 - (int)floor(log10(num))); + } else { + // Store only reliable digits (14) by default. + return String::num(num, 14 - (int)floor(log10(num))); + } + } case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: case Variant::PACKED_FLOAT32_ARRAY: @@ -82,20 +91,29 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ String s = "["; s += end_statement; Array a = p_var; + + ERR_FAIL_COND_V_MSG(p_markers.has(a.id()), "\"[...]\"", "Converting circular structure to JSON."); + p_markers.insert(a.id()); + for (int i = 0; i < a.size(); i++) { if (i > 0) { s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys); + s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "]"; + p_markers.erase(a.id()); return s; } case Variant::DICTIONARY: { String s = "{"; s += end_statement; Dictionary d = p_var; + + ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON."); + p_markers.insert(d.id()); + List<Variant> keys; d.get_key_list(&keys); @@ -108,12 +126,13 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys); + s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers); s += colon; - s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys); + s += _stringify(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "}"; + p_markers.erase(d.id()); return s; } default: @@ -121,10 +140,6 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ } } -String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys) { - return _print_var(p_var, p_indent, 0, p_sort_keys); -} - Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) { while (p_len > 0) { switch (p_str[index]) { @@ -479,7 +494,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, return ERR_PARSE_ERROR; } -Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { +Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { const char32_t *str = p_json.ptr(); int idx = 0; int len = p_json.length(); @@ -510,34 +525,24 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int & return err; } -Error JSONParser::parse_string(const String &p_json_string) { - return JSON::parse(p_json_string, data, err_text, err_line); -} -String JSONParser::get_error_text() const { - return err_text; -} -int JSONParser::get_error_line() const { - return err_line; -} -Variant JSONParser::get_data() const { - return data; +String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { + Set<const void *> markers; + return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); } -Error JSONParser::decode_data(const Variant &p_data, const String &p_indent, bool p_sort_keys) { - string = JSON::print(p_data, p_indent, p_sort_keys); - data = p_data; - return OK; +Error JSON::parse(const String &p_json_string) { + Error err = _parse_string(p_json_string, data, err_str, err_line); + if (err == Error::OK) { + err_line = 0; + } + return err; } -String JSONParser::get_string() const { - return string; -} +void JSON::_bind_methods() { + ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); -void JSONParser::_bind_methods() { - ClassDB::bind_method(D_METHOD("parse_string", "json_string"), &JSONParser::parse_string); - ClassDB::bind_method(D_METHOD("get_error_text"), &JSONParser::get_error_text); - ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParser::get_error_line); - ClassDB::bind_method(D_METHOD("get_data"), &JSONParser::get_data); - ClassDB::bind_method(D_METHOD("decode_data", "data", "indent", "sort_keys"), &JSONParser::decode_data, DEFVAL(""), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_string"), &JSONParser::get_string); + ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data); + ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line); + ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message); } diff --git a/core/io/json.h b/core/io/json.h index 537477666e..f20c97f540 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -31,9 +31,12 @@ #ifndef JSON_H #define JSON_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/variant/variant.h" -class JSON { + +class JSON : public RefCounted { + GDCLASS(JSON, RefCounted); + enum TokenType { TK_CURLY_BRACKET_OPEN, TK_CURLY_BRACKET_CLOSE, @@ -60,39 +63,30 @@ class JSON { Variant value; }; - static const char *tk_name[TK_MAX]; + Variant data; + String err_str; + int err_line = 0; - static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys); + static const char *tk_name[]; + static String _make_indent(const String &p_indent, int p_size); + static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false); static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); - -public: - static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true); - static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); -}; - -class JSONParser : public Reference { - GDCLASS(JSONParser, Reference); - - Variant data; - String string; - String err_text; - int err_line = 0; + static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); protected: static void _bind_methods(); public: - Error parse_string(const String &p_json_string); - String get_error_text() const; - int get_error_line() const; - Variant get_data() const; + String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); + Error parse(const String &p_json_string); - Error decode_data(const Variant &p_data, const String &p_indent = "", bool p_sort_keys = true); - String get_string() const; + inline Variant get_data() const { return data; } + inline int get_error_line() const { return err_line; } + inline String get_error_message() const { return err_str; } }; #endif // JSON_H diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 8a07459a1d..09539f716c 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -31,8 +31,9 @@ #include "logger.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/string/print_string.h" #if defined(MINGW_ENABLED) || defined(_MSC_VER) @@ -156,11 +157,7 @@ void RotatedFileLogger::rotate_file() { if (FileAccess::exists(base_path)) { if (max_files > 1) { - char timestamp[21]; - OS::Date date = OS::get_singleton()->get_date(); - OS::Time time = OS::get_singleton()->get_time(); - sprintf(timestamp, "_%04d-%02d-%02d_%02d.%02d.%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); - + String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", "."); String backup_name = base_path.get_basename() + timestamp; if (base_path.get_extension() != String()) { backup_name += "." + base_path.get_extension(); diff --git a/core/io/logger.h b/core/io/logger.h index a12945911c..ccf68562d6 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -31,7 +31,7 @@ #ifndef LOGGER_H #define LOGGER_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/ustring.h" #include "core/templates/vector.h" diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 0282609270..f342db2dad 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -30,7 +30,7 @@ #include "marshalls.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" @@ -111,6 +111,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = 4; } + // Note: We cannot use sizeof(real_t) for decoding, in case a different size is encoded. + // Decoding math types always checks for the encoded size, while encoding always uses compilation setting. + // This does lead to some code duplication for decoding, but compatibility is the priority. switch (type & ENCODE_MASK) { case Variant::NIL: { r_variant = Variant(); @@ -144,18 +147,18 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::FLOAT: { if (type & ENCODE_FLAG_64) { - ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); + ERR_FAIL_COND_V((size_t)len < sizeof(double), ERR_INVALID_DATA); double val = decode_double(buf); r_variant = val; if (r_len) { - (*r_len) += 8; + (*r_len) += sizeof(double); } } else { - ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); + ERR_FAIL_COND_V((size_t)len < sizeof(float), ERR_INVALID_DATA); float val = decode_float(buf); r_variant = val; if (r_len) { - (*r_len) += 4; + (*r_len) += sizeof(float); } } @@ -172,15 +175,25 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int // math types case Variant::VECTOR2: { - ERR_FAIL_COND_V(len < 4 * 2, ERR_INVALID_DATA); Vector2 val; - val.x = decode_float(&buf[0]); - val.y = decode_float(&buf[4]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 2, ERR_INVALID_DATA); + val.x = decode_double(&buf[0]); + val.y = decode_double(&buf[sizeof(double)]); - if (r_len) { - (*r_len) += 4 * 2; + if (r_len) { + (*r_len) += sizeof(double) * 2; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 2, ERR_INVALID_DATA); + val.x = decode_float(&buf[0]); + val.y = decode_float(&buf[sizeof(float)]); + + if (r_len) { + (*r_len) += sizeof(float) * 2; + } } + r_variant = val; } break; case Variant::VECTOR2I: { @@ -196,17 +209,29 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::RECT2: { - ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); Rect2 val; - val.position.x = decode_float(&buf[0]); - val.position.y = decode_float(&buf[4]); - val.size.x = decode_float(&buf[8]); - val.size.y = decode_float(&buf[12]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); + val.position.x = decode_double(&buf[0]); + val.position.y = decode_double(&buf[sizeof(double)]); + val.size.x = decode_double(&buf[sizeof(double) * 2]); + val.size.y = decode_double(&buf[sizeof(double) * 3]); - if (r_len) { - (*r_len) += 4 * 4; + if (r_len) { + (*r_len) += sizeof(double) * 4; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 4, ERR_INVALID_DATA); + val.position.x = decode_float(&buf[0]); + val.position.y = decode_float(&buf[sizeof(float)]); + val.size.x = decode_float(&buf[sizeof(float) * 2]); + val.size.y = decode_float(&buf[sizeof(float) * 3]); + + if (r_len) { + (*r_len) += sizeof(float) * 4; + } } + r_variant = val; } break; case Variant::RECT2I: { @@ -224,16 +249,27 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::VECTOR3: { - ERR_FAIL_COND_V(len < 4 * 3, ERR_INVALID_DATA); Vector3 val; - val.x = decode_float(&buf[0]); - val.y = decode_float(&buf[4]); - val.z = decode_float(&buf[8]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 3, ERR_INVALID_DATA); + val.x = decode_double(&buf[0]); + val.y = decode_double(&buf[sizeof(double)]); + val.z = decode_double(&buf[sizeof(double) * 2]); - if (r_len) { - (*r_len) += 4 * 3; + if (r_len) { + (*r_len) += sizeof(double) * 3; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 3, ERR_INVALID_DATA); + val.x = decode_float(&buf[0]); + val.y = decode_float(&buf[sizeof(float)]); + val.z = decode_float(&buf[sizeof(float) * 2]); + + if (r_len) { + (*r_len) += sizeof(float) * 3; + } } + r_variant = val; } break; case Variant::VECTOR3I: { @@ -250,101 +286,177 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::TRANSFORM2D: { - ERR_FAIL_COND_V(len < 4 * 6, ERR_INVALID_DATA); Transform2D val; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - val.elements[i][j] = decode_float(&buf[(i * 2 + j) * 4]); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + val.elements[i][j] = decode_double(&buf[(i * 2 + j) * sizeof(double)]); + } } - } - r_variant = val; + if (r_len) { + (*r_len) += sizeof(double) * 6; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 6, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + val.elements[i][j] = decode_float(&buf[(i * 2 + j) * sizeof(float)]); + } + } - if (r_len) { - (*r_len) += 4 * 6; + if (r_len) { + (*r_len) += sizeof(float) * 6; + } } + r_variant = val; } break; case Variant::PLANE: { - ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); Plane val; - val.normal.x = decode_float(&buf[0]); - val.normal.y = decode_float(&buf[4]); - val.normal.z = decode_float(&buf[8]); - val.d = decode_float(&buf[12]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); + val.normal.x = decode_double(&buf[0]); + val.normal.y = decode_double(&buf[sizeof(double)]); + val.normal.z = decode_double(&buf[sizeof(double) * 2]); + val.d = decode_double(&buf[sizeof(double) * 3]); - if (r_len) { - (*r_len) += 4 * 4; + if (r_len) { + (*r_len) += sizeof(double) * 4; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 4, ERR_INVALID_DATA); + val.normal.x = decode_float(&buf[0]); + val.normal.y = decode_float(&buf[sizeof(float)]); + val.normal.z = decode_float(&buf[sizeof(float) * 2]); + val.d = decode_float(&buf[sizeof(float) * 3]); + + if (r_len) { + (*r_len) += sizeof(float) * 4; + } } + r_variant = val; } break; - case Variant::QUAT: { - ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); - Quat val; - val.x = decode_float(&buf[0]); - val.y = decode_float(&buf[4]); - val.z = decode_float(&buf[8]); - val.w = decode_float(&buf[12]); - r_variant = val; + case Variant::QUATERNION: { + Quaternion val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); + val.x = decode_double(&buf[0]); + val.y = decode_double(&buf[sizeof(double)]); + val.z = decode_double(&buf[sizeof(double) * 2]); + val.w = decode_double(&buf[sizeof(double) * 3]); - if (r_len) { - (*r_len) += 4 * 4; + if (r_len) { + (*r_len) += sizeof(double) * 4; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 4, ERR_INVALID_DATA); + val.x = decode_float(&buf[0]); + val.y = decode_float(&buf[sizeof(float)]); + val.z = decode_float(&buf[sizeof(float) * 2]); + val.w = decode_float(&buf[sizeof(float) * 3]); + + if (r_len) { + (*r_len) += sizeof(float) * 4; + } } + r_variant = val; } break; case Variant::AABB: { - ERR_FAIL_COND_V(len < 4 * 6, ERR_INVALID_DATA); AABB val; - val.position.x = decode_float(&buf[0]); - val.position.y = decode_float(&buf[4]); - val.position.z = decode_float(&buf[8]); - val.size.x = decode_float(&buf[12]); - val.size.y = decode_float(&buf[16]); - val.size.z = decode_float(&buf[20]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); + val.position.x = decode_double(&buf[0]); + val.position.y = decode_double(&buf[sizeof(double)]); + val.position.z = decode_double(&buf[sizeof(double) * 2]); + val.size.x = decode_double(&buf[sizeof(double) * 3]); + val.size.y = decode_double(&buf[sizeof(double) * 4]); + val.size.z = decode_double(&buf[sizeof(double) * 5]); - if (r_len) { - (*r_len) += 4 * 6; + if (r_len) { + (*r_len) += sizeof(double) * 6; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 6, ERR_INVALID_DATA); + val.position.x = decode_float(&buf[0]); + val.position.y = decode_float(&buf[sizeof(float)]); + val.position.z = decode_float(&buf[sizeof(float) * 2]); + val.size.x = decode_float(&buf[sizeof(float) * 3]); + val.size.y = decode_float(&buf[sizeof(float) * 4]); + val.size.z = decode_float(&buf[sizeof(float) * 5]); + + if (r_len) { + (*r_len) += sizeof(float) * 6; + } } + r_variant = val; } break; case Variant::BASIS: { - ERR_FAIL_COND_V(len < 4 * 9, ERR_INVALID_DATA); Basis val; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - val.elements[i][j] = decode_float(&buf[(i * 3 + j) * 4]); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 9, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.elements[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]); + } } - } - r_variant = val; + if (r_len) { + (*r_len) += sizeof(double) * 9; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 9, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.elements[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]); + } + } - if (r_len) { - (*r_len) += 4 * 9; + if (r_len) { + (*r_len) += sizeof(float) * 9; + } } + r_variant = val; } break; - case Variant::TRANSFORM: { - ERR_FAIL_COND_V(len < 4 * 12, ERR_INVALID_DATA); - Transform val; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * 4]); + case Variant::TRANSFORM3D: { + Transform3D val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 12, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.basis.elements[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]); + } } - } - val.origin[0] = decode_float(&buf[36]); - val.origin[1] = decode_float(&buf[40]); - val.origin[2] = decode_float(&buf[44]); + val.origin[0] = decode_double(&buf[sizeof(double) * 9]); + val.origin[1] = decode_double(&buf[sizeof(double) * 10]); + val.origin[2] = decode_double(&buf[sizeof(double) * 11]); - r_variant = val; + if (r_len) { + (*r_len) += sizeof(double) * 12; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 12, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]); + } + } + val.origin[0] = decode_float(&buf[sizeof(float) * 9]); + val.origin[1] = decode_float(&buf[sizeof(float) * 10]); + val.origin[2] = decode_float(&buf[sizeof(float) * 11]); - if (r_len) { - (*r_len) += 4 * 12; + if (r_len) { + (*r_len) += sizeof(float) * 12; + } } + r_variant = val; } break; - // misc types case Variant::COLOR: { ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); @@ -356,9 +468,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = val; if (r_len) { - (*r_len) += 4 * 4; + (*r_len) += 4 * 4; // Colors should always be in single-precision. } - } break; case Variant::STRING_NAME: { String str; @@ -436,7 +547,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = (Object *)nullptr; } else { Ref<EncodedObjectAsID> obj_as_id; - obj_as_id.instance(); + obj_as_id.instantiate(); obj_as_id->set_object_id(val); r_variant = obj_as_id; @@ -454,7 +565,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int if (str == String()) { r_variant = (Object *)nullptr; } else { - Object *obj = ClassDB::instance(str); + Object *obj = ClassDB::instantiate(str); ERR_FAIL_COND_V(!obj, ERR_UNAVAILABLE); ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); @@ -463,7 +574,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int buf += 4; len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } for (int i = 0; i < count; i++) { @@ -489,8 +600,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int obj->set(str, value); } - if (Object::cast_to<Reference>(obj)) { - REF ref = REF(Object::cast_to<Reference>(obj)); + if (Object::cast_to<RefCounted>(obj)) { + REF ref = REF(Object::cast_to<RefCounted>(obj)); r_variant = ref; } else { r_variant = obj; @@ -516,7 +627,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } Dictionary d; @@ -559,7 +670,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } Array varr; @@ -716,9 +827,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } - //printf("string count: %i\n",count); for (int32_t i = 0; i < count; i++) { String str; @@ -739,30 +849,57 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int buf += 4; len -= 4; - ERR_FAIL_MUL_OF(count, 4 * 2, ERR_INVALID_DATA); - ERR_FAIL_COND_V(count < 0 || count * 4 * 2 > len, ERR_INVALID_DATA); Vector<Vector2> varray; - if (r_len) { - (*r_len) += 4; - } - - if (count) { - varray.resize(count); - Vector2 *w = varray.ptrw(); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_MUL_OF(count, sizeof(double) * 2, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 2 > (size_t)len, ERR_INVALID_DATA); - for (int32_t i = 0; i < count; i++) { - w[i].x = decode_float(buf + i * 4 * 2 + 4 * 0); - w[i].y = decode_float(buf + i * 4 * 2 + 4 * 1); + if (r_len) { + (*r_len) += 4; // Size of count number. } - int adv = 4 * 2 * count; + if (count) { + varray.resize(count); + Vector2 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_double(buf + i * sizeof(double) * 2 + sizeof(double) * 0); + w[i].y = decode_double(buf + i * sizeof(double) * 2 + sizeof(double) * 1); + } + + int adv = sizeof(double) * 2 * count; + + if (r_len) { + (*r_len) += adv; + } + len -= adv; + buf += adv; + } + } else { + ERR_FAIL_MUL_OF(count, sizeof(float) * 2, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(float) * 2 > (size_t)len, ERR_INVALID_DATA); if (r_len) { - (*r_len) += adv; + (*r_len) += 4; // Size of count number. } - } + if (count) { + varray.resize(count); + Vector2 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_float(buf + i * sizeof(float) * 2 + sizeof(float) * 0); + w[i].y = decode_float(buf + i * sizeof(float) * 2 + sizeof(float) * 1); + } + + int adv = sizeof(float) * 2 * count; + + if (r_len) { + (*r_len) += adv; + } + } + } r_variant = varray; } break; @@ -772,32 +909,61 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int buf += 4; len -= 4; - ERR_FAIL_MUL_OF(count, 4 * 3, ERR_INVALID_DATA); - ERR_FAIL_COND_V(count < 0 || count * 4 * 3 > len, ERR_INVALID_DATA); - Vector<Vector3> varray; - if (r_len) { - (*r_len) += 4; - } - - if (count) { - varray.resize(count); - Vector3 *w = varray.ptrw(); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_MUL_OF(count, sizeof(double) * 3, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 3 > (size_t)len, ERR_INVALID_DATA); - for (int32_t i = 0; i < count; i++) { - w[i].x = decode_float(buf + i * 4 * 3 + 4 * 0); - w[i].y = decode_float(buf + i * 4 * 3 + 4 * 1); - w[i].z = decode_float(buf + i * 4 * 3 + 4 * 2); + if (r_len) { + (*r_len) += 4; // Size of count number. } - int adv = 4 * 3 * count; + if (count) { + varray.resize(count); + Vector3 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_double(buf + i * sizeof(double) * 3 + sizeof(double) * 0); + w[i].y = decode_double(buf + i * sizeof(double) * 3 + sizeof(double) * 1); + w[i].z = decode_double(buf + i * sizeof(double) * 3 + sizeof(double) * 2); + } + + int adv = sizeof(double) * 3 * count; + + if (r_len) { + (*r_len) += adv; + } + len -= adv; + buf += adv; + } + } else { + ERR_FAIL_MUL_OF(count, sizeof(float) * 3, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(float) * 3 > (size_t)len, ERR_INVALID_DATA); if (r_len) { - (*r_len) += adv; + (*r_len) += 4; // Size of count number. } - } + if (count) { + varray.resize(count); + Vector3 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_float(buf + i * sizeof(float) * 3 + sizeof(float) * 0); + w[i].y = decode_float(buf + i * sizeof(float) * 3 + sizeof(float) * 1); + w[i].z = decode_float(buf + i * sizeof(float) * 3 + sizeof(float) * 2); + } + + int adv = sizeof(float) * 3 * count; + + if (r_len) { + (*r_len) += adv; + } + len -= adv; + buf += adv; + } + } r_variant = varray; } break; @@ -813,7 +979,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Vector<Color> carray; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } if (count) { @@ -821,6 +987,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Color *w = carray.ptrw(); for (int32_t i = 0; i < count; i++) { + // Colors should always be in single-precision. w[i].r = decode_float(buf + i * 4 * 4 + 4 * 0); w[i].g = decode_float(buf + i * 4 * 4 + 4 * 1); w[i].b = decode_float(buf + i * 4 * 4 + 4 * 2); @@ -882,14 +1049,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo double d = p_variant; float f = d; if (double(f) != d) { - flags |= ENCODE_FLAG_64; //always encode real as double + flags |= ENCODE_FLAG_64; } } break; case Variant::OBJECT: { // Test for potential wrong values sent by the debugger when it breaks. Object *obj = p_variant.get_validated_object(); if (!obj) { - // Object is invalid, send a nullptr instead. + // Object is invalid, send a nullptr instead. if (buf) { encode_uint32(Variant::NIL, buf); } @@ -1013,11 +1180,11 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::VECTOR2: { if (buf) { Vector2 v2 = p_variant; - encode_float(v2.x, &buf[0]); - encode_float(v2.y, &buf[4]); + encode_real(v2.x, &buf[0]); + encode_real(v2.y, &buf[sizeof(real_t)]); } - r_len += 2 * 4; + r_len += 2 * sizeof(real_t); } break; case Variant::VECTOR2I: { @@ -1033,12 +1200,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::RECT2: { if (buf) { Rect2 r2 = p_variant; - encode_float(r2.position.x, &buf[0]); - encode_float(r2.position.y, &buf[4]); - encode_float(r2.size.x, &buf[8]); - encode_float(r2.size.y, &buf[12]); + encode_real(r2.position.x, &buf[0]); + encode_real(r2.position.y, &buf[sizeof(real_t)]); + encode_real(r2.size.x, &buf[sizeof(real_t) * 2]); + encode_real(r2.size.y, &buf[sizeof(real_t) * 3]); } - r_len += 4 * 4; + r_len += 4 * sizeof(real_t); } break; case Variant::RECT2I: { @@ -1055,12 +1222,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::VECTOR3: { if (buf) { Vector3 v3 = p_variant; - encode_float(v3.x, &buf[0]); - encode_float(v3.y, &buf[4]); - encode_float(v3.z, &buf[8]); + encode_real(v3.x, &buf[0]); + encode_real(v3.y, &buf[sizeof(real_t)]); + encode_real(v3.z, &buf[sizeof(real_t) * 2]); } - r_len += 3 * 4; + r_len += 3 * sizeof(real_t); } break; case Variant::VECTOR3I: { @@ -1079,50 +1246,50 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo Transform2D val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { - memcpy(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float)); + memcpy(&buf[(i * 2 + j) * sizeof(real_t)], &val.elements[i][j], sizeof(real_t)); } } } - r_len += 6 * 4; + r_len += 6 * sizeof(real_t); } break; case Variant::PLANE: { if (buf) { Plane p = p_variant; - encode_float(p.normal.x, &buf[0]); - encode_float(p.normal.y, &buf[4]); - encode_float(p.normal.z, &buf[8]); - encode_float(p.d, &buf[12]); + encode_real(p.normal.x, &buf[0]); + encode_real(p.normal.y, &buf[sizeof(real_t)]); + encode_real(p.normal.z, &buf[sizeof(real_t) * 2]); + encode_real(p.d, &buf[sizeof(real_t) * 3]); } - r_len += 4 * 4; + r_len += 4 * sizeof(real_t); } break; - case Variant::QUAT: { + case Variant::QUATERNION: { if (buf) { - Quat q = p_variant; - encode_float(q.x, &buf[0]); - encode_float(q.y, &buf[4]); - encode_float(q.z, &buf[8]); - encode_float(q.w, &buf[12]); + Quaternion q = p_variant; + encode_real(q.x, &buf[0]); + encode_real(q.y, &buf[sizeof(real_t)]); + encode_real(q.z, &buf[sizeof(real_t) * 2]); + encode_real(q.w, &buf[sizeof(real_t) * 3]); } - r_len += 4 * 4; + r_len += 4 * sizeof(real_t); } break; case Variant::AABB: { if (buf) { AABB aabb = p_variant; - encode_float(aabb.position.x, &buf[0]); - encode_float(aabb.position.y, &buf[4]); - encode_float(aabb.position.z, &buf[8]); - encode_float(aabb.size.x, &buf[12]); - encode_float(aabb.size.y, &buf[16]); - encode_float(aabb.size.z, &buf[20]); + encode_real(aabb.position.x, &buf[0]); + encode_real(aabb.position.y, &buf[sizeof(real_t)]); + encode_real(aabb.position.z, &buf[sizeof(real_t) * 2]); + encode_real(aabb.size.x, &buf[sizeof(real_t) * 3]); + encode_real(aabb.size.y, &buf[sizeof(real_t) * 4]); + encode_real(aabb.size.z, &buf[sizeof(real_t) * 5]); } - r_len += 6 * 4; + r_len += 6 * sizeof(real_t); } break; case Variant::BASIS: { @@ -1130,29 +1297,29 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo Basis val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - memcpy(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float)); + memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.elements[i][j], sizeof(real_t)); } } } - r_len += 9 * 4; + r_len += 9 * sizeof(real_t); } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { if (buf) { - Transform val = p_variant; + Transform3D val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - memcpy(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float)); + memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.basis.elements[i][j], sizeof(real_t)); } } - encode_float(val.origin.x, &buf[36]); - encode_float(val.origin.y, &buf[40]); - encode_float(val.origin.z, &buf[44]); + encode_real(val.origin.x, &buf[sizeof(real_t) * 9]); + encode_real(val.origin.y, &buf[sizeof(real_t) * 10]); + encode_real(val.origin.z, &buf[sizeof(real_t) * 11]); } - r_len += 12 * 4; + r_len += 12 * sizeof(real_t); } break; @@ -1166,7 +1333,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo encode_float(c.a, &buf[12]); } - r_len += 4 * 4; + r_len += 4 * 4; // Colors should always be in single-precision. } break; case Variant::RID: { @@ -1441,13 +1608,13 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo for (int i = 0; i < len; i++) { Vector2 v = data.get(i); - encode_float(v.x, &buf[0]); - encode_float(v.y, &buf[4]); - buf += 4 * 2; + encode_real(v.x, &buf[0]); + encode_real(v.y, &buf[sizeof(real_t)]); + buf += sizeof(real_t) * 2; } } - r_len += 4 * 2 * len; + r_len += sizeof(real_t) * 2 * len; } break; case Variant::PACKED_VECTOR3_ARRAY: { @@ -1465,14 +1632,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo for (int i = 0; i < len; i++) { Vector3 v = data.get(i); - encode_float(v.x, &buf[0]); - encode_float(v.y, &buf[4]); - encode_float(v.z, &buf[8]); - buf += 4 * 3; + encode_real(v.x, &buf[0]); + encode_real(v.y, &buf[sizeof(real_t)]); + encode_real(v.z, &buf[sizeof(real_t) * 2]); + buf += sizeof(real_t) * 3; } } - r_len += 4 * 3 * len; + r_len += sizeof(real_t) * 3 * len; } break; case Variant::PACKED_COLOR_ARRAY: { @@ -1494,7 +1661,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo encode_float(c.g, &buf[4]); encode_float(c.b, &buf[8]); encode_float(c.a, &buf[12]); - buf += 4 * 4; + buf += 4 * 4; // Colors should always be in single-precision. } } diff --git a/core/io/marshalls.h b/core/io/marshalls.h index cc0e9ba301..3ebed914a3 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -31,10 +31,18 @@ #ifndef MARSHALLS_H #define MARSHALLS_H -#include "core/object/reference.h" +#include "core/math/math_defs.h" +#include "core/object/ref_counted.h" #include "core/typedefs.h" #include "core/variant/variant.h" +// uintr_t is only for pairing with real_t, and we only need it in here. +#ifdef REAL_T_IS_DOUBLE +typedef uint64_t uintr_t; +#else +typedef uint32_t uintr_t; +#endif + /** * Miscellaneous helpers for marshalling data types, and encoding * in an endian independent way @@ -50,6 +58,12 @@ union MarshallDouble { double d; ///< double }; +// Behaves like one of the above, depending on compilation setting. +union MarshallReal { + uintr_t i; + real_t r; +}; + static inline unsigned int encode_uint16(uint16_t p_uint, uint8_t *p_arr) { for (int i = 0; i < 2; i++) { *p_arr = p_uint & 0xFF; @@ -96,6 +110,24 @@ static inline unsigned int encode_double(double p_double, uint8_t *p_arr) { return sizeof(uint64_t); } +static inline unsigned int encode_uintr(uintr_t p_uint, uint8_t *p_arr) { + for (size_t i = 0; i < sizeof(uintr_t); i++) { + *p_arr = p_uint & 0xFF; + p_arr++; + p_uint >>= 8; + } + + return sizeof(uintr_t); +} + +static inline unsigned int encode_real(real_t p_real, uint8_t *p_arr) { + MarshallReal mr; + mr.r = p_real; + encode_uintr(mr.i, p_arr); + + return sizeof(uintr_t); +} + static inline int encode_cstring(const char *p_string, uint8_t *p_data) { int len = 0; @@ -165,8 +197,8 @@ static inline double decode_double(const uint8_t *p_arr) { return md.d; } -class EncodedObjectAsID : public Reference { - GDCLASS(EncodedObjectAsID, Reference); +class EncodedObjectAsID : public RefCounted { + GDCLASS(EncodedObjectAsID, RefCounted); ObjectID id; diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index fda4083804..564397c88c 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -44,6 +44,56 @@ #include "core/os/os.h" #endif +String _get_rpc_md5(const Node *p_node) { + String rpc_list; + const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + rpc_list += String(node_config[i].name); + } + if (p_node->get_script_instance()) { + const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + rpc_list += String(script_config[i].name); + } + } + return rpc_list.md5_text(); +} + +const MultiplayerAPI::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) { + const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + if (node_config[i].name == p_method) { + r_id = ((uint16_t)i) & (1 << 15); + return node_config[i]; + } + } + if (p_node->get_script_instance()) { + const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + if (script_config[i].name == p_method) { + r_id = (uint16_t)i; + return script_config[i]; + } + } + } + return MultiplayerAPI::RPCConfig(); +} + +const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) { + Vector<MultiplayerAPI::RPCConfig> config; + uint16_t id = p_id; + if (id & (1 << 15)) { + id = id & ~(1 << 15); + config = p_node->get_node_rpc_methods(); + } else if (p_node->get_script_instance()) { + config = p_node->get_script_instance()->get_rpc_methods(); + } + if (id < config.size()) { + return config[p_id]; + } + return MultiplayerAPI::RPCConfig(); +} + _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) { switch (mode) { case MultiplayerAPI::RPC_MODE_DISABLED: { @@ -99,7 +149,7 @@ _FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, i } void MultiplayerAPI::poll() { - if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { + if (!network_peer.is_valid() || network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED) { return; } @@ -146,13 +196,13 @@ Node *MultiplayerAPI::get_root_node() { return root_node; } -void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) { +void MultiplayerAPI::set_network_peer(const Ref<MultiplayerPeer> &p_peer) { if (p_peer == network_peer) { return; // Nothing to do } - ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, - "Supplied NetworkedMultiplayerPeer must be connecting or connected."); + ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, + "Supplied MultiplayerPeer must be connecting or connected."); if (network_peer.is_valid()) { network_peer->disconnect("peer_connected", callable_mp(this, &MultiplayerAPI::_add_peer)); @@ -174,7 +224,7 @@ void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_pee } } -Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const { +Ref<MultiplayerPeer> MultiplayerAPI::get_network_peer() const { return network_peer; } @@ -231,8 +281,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ _process_confirm_path(p_from, p_packet, p_packet_len); } break; - case NETWORK_COMMAND_REMOTE_CALL: - case NETWORK_COMMAND_REMOTE_SET: { + case NETWORK_COMMAND_REMOTE_CALL: { // Extract packet meta int packet_min_size = 1; int name_id_offset = 1; @@ -302,13 +351,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } const int packet_len = get_packet_len(node_target, p_packet_len); - if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { - _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); - - } else { - _process_rset(node, name_id, p_from, p_packet, packet_len, packet_min_size); - } - + _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); } break; case NETWORK_COMMAND_RAW: { @@ -362,16 +405,11 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small."); // Check that remote can call the RPC on this node. - StringName name = p_node->get_node_rpc_method(p_rpc_method_id); - RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id); - if (name == StringName() && p_node->get_script_instance()) { - name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id); - rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id); - } - ERR_FAIL_COND(name == StringName()); + const RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id); + ERR_FAIL_COND(config.name == StringName()); - bool can_call = _can_call_mode(p_node, rpc_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); + bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from); + ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); int argc = 0; bool byte_only = false; @@ -424,47 +462,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, Callable::CallError ce; - p_node->call(name, (const Variant **)argp.ptr(), argc, ce); + p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); if (ce.error != Callable::CallError::CALL_OK) { - String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce); + String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); error = "RPC - " + error; ERR_PRINT(error); } } -void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); - - // Check that remote can call the RSET on this node. - StringName name = p_node->get_node_rset_property(p_rpc_property_id); - RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id); - if (name == StringName() && p_node->get_script_instance()) { - name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id); - rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id); - } - ERR_FAIL_COND(name == StringName()); - - bool can_call = _can_call_mode(p_node, rset_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - -#ifdef DEBUG_ENABLED - _profile_node_data("in_rset", p_node->get_instance_id()); -#endif - - Variant value; - Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, nullptr); - - ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value."); - - bool valid; - - p_node->set(name, value, &valid); - if (!valid) { - String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + "."; - ERR_PRINT(error); - } -} - void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); int ofs = 1; @@ -487,7 +492,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, Node *node = root_node->get_node(path); ERR_FAIL_COND(node == nullptr); - const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5; + const bool valid_rpc_checksum = _get_rpc_md5(node) == methods_md5; if (valid_rpc_checksum == false) { ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); } @@ -508,7 +513,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, packet.write[1] = valid_rpc_checksum; encode_cstring(pname.get_data(), &packet.write[2]); - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); network_peer->set_target_peer(p_from); network_peer->put_packet(packet.ptr(), packet.size()); } @@ -569,7 +574,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC const int path_len = encode_cstring(path.get_data(), nullptr); // Extract MD5 from rpc methods list. - const String methods_md5 = p_node->get_rpc_md5(); + const String methods_md5 = _get_rpc_md5(p_node); const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. Vector<uint8_t> packet; @@ -587,7 +592,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) { network_peer->set_target_peer(E->get()); // To all of you. - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); network_peer->put_packet(packet.ptr(), packet.size()); psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed. @@ -752,12 +757,12 @@ Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const u return OK; } -void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { +void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255."); @@ -797,7 +802,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p // - `NetworkNameIdCompression` in the next 1 bit. // - `byte_only_or_no_args` in the next 1 bit. // - So we still have the last bit free! - uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + uint8_t command_type = NETWORK_COMMAND_REMOTE_CALL; uint8_t node_id_compression = UINT8_MAX; uint8_t name_id_compression = UINT8_MAX; bool byte_only_or_no_args = false; @@ -837,81 +842,42 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p ofs += 4; } - if (p_set) { - // Take the rpc property ID - uint16_t property_id = p_from->get_node_rset_property_id(p_name); - if (property_id == UINT16_MAX && p_from->get_script_instance()) { - property_id = p_from->get_script_instance()->get_rset_property_id(p_name); - } - ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". This can only happen if this property is not marked as `remote`."); - - if (property_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(property_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(property_id, &(packet_cache.write[ofs])); - ofs += 2; - } - - // Set argument. - int len(0); - Error err = _encode_and_compress_variant(*p_arg[0], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - _encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len); - ofs += len; - + // Encode method ID + if (p_rpc_id <= UINT8_MAX) { + // The ID fits in 1 byte + name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id); + ofs += 1; } else { - // Take the rpc method ID - uint16_t method_id = p_from->get_node_rpc_method_id(p_name); - if (method_id == UINT16_MAX && p_from->get_script_instance()) { - method_id = p_from->get_script_instance()->get_rpc_method_id(p_name); - } - ERR_FAIL_COND_MSG(method_id == UINT16_MAX, - vformat("Unable to take the `method_id` for the function \"%s\" at path: \"%s\". This happens when the method is not marked as `remote`.", p_name, p_from->get_path())); - - if (method_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(method_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(method_id, &(packet_cache.write[ofs])); - ofs += 2; - } + // The ID is larger, let's use 2 bytes + name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(p_rpc_id, &(packet_cache.write[ofs])); + ofs += 2; + } - if (p_argcount == 0) { - byte_only_or_no_args = true; - } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { - byte_only_or_no_args = true; - // Special optimization when only the byte vector is sent. - const Vector<uint8_t> data = *p_arg[0]; - MAKE_ROOM(ofs + data.size()); - memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); - ofs += data.size(); - } else { - // Arguments - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = p_argcount; - ofs += 1; - for (int i = 0; i < p_argcount; i++) { - int len(0); - Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); - ofs += len; - } + if (p_argcount == 0) { + byte_only_or_no_args = true; + } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { + byte_only_or_no_args = true; + // Special optimization when only the byte vector is sent. + const Vector<uint8_t> data = *p_arg[0]; + MAKE_ROOM(ofs + data.size()); + memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); + ofs += data.size(); + } else { + // Arguments + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = p_argcount; + ofs += 1; + for (int i = 0; i < p_argcount; i++) { + int len(0); + Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); + MAKE_ROOM(ofs + len); + _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); + ofs += len; } } @@ -927,7 +893,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p #endif // Take chance and set transfer mode, since all send methods will use it. - network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(p_config.transfer_mode); if (has_all_peers) { // They all have verified paths, so send fast. @@ -1008,26 +974,22 @@ void MultiplayerAPI::_server_disconnected() { void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active."); ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); int node_id = network_peer->get_unique_id(); bool skip_rpc = node_id == p_peer_id; bool call_local_native = false; bool call_local_script = false; bool is_master = p_node->is_network_master(); - + uint16_t rpc_id = UINT16_MAX; + const RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id); + ERR_FAIL_COND_MSG(config.name == StringName(), + vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path())); if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - // Check that send mode can use local call. - - RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method); - call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc); - - if (call_local_native) { - // Done below. - } else if (p_node->get_script_instance()) { - // Attempt with script. - rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); - call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc); + if (rpc_id & (1 << 15)) { + call_local_native = _should_call_local(config.rpc_mode, is_master, skip_rpc); + } else { + call_local_script = _should_call_local(config.rpc_mode, is_master, skip_rpc); } } @@ -1036,7 +998,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const _profile_node_data("out_rpc", p_node->get_instance_id()); #endif - _send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount); + _send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); } if (call_local_native) { @@ -1071,74 +1033,10 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode."); } -void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { - ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to RSET while no network peer is active."); - ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to RSET on a node which is not inside SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to send an RSET via a network peer which is not connected."); - - int node_id = network_peer->get_unique_id(); - bool is_master = p_node->is_network_master(); - bool skip_rset = node_id == p_peer_id; - bool set_local = false; - - if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - // Check that send mode can use local call. - RPCMode rpc_mode = p_node->get_node_rset_mode(p_property); - set_local = _should_call_local(rpc_mode, is_master, skip_rset); - - if (set_local) { - bool valid; - int temp_id = rpc_sender_id; - - rpc_sender_id = get_network_unique_id(); - p_node->set(p_property, p_value, &valid); - rpc_sender_id = temp_id; - - if (!valid) { - String error = "rset() aborted in local set, property not found: - " + String(p_property) + "."; - ERR_PRINT(error); - return; - } - } else if (p_node->get_script_instance()) { - // Attempt with script. - rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); - - set_local = _should_call_local(rpc_mode, is_master, skip_rset); - - if (set_local) { - int temp_id = rpc_sender_id; - - rpc_sender_id = get_network_unique_id(); - bool valid = p_node->get_script_instance()->set(p_property, p_value); - rpc_sender_id = temp_id; - - if (!valid) { - String error = "rset() aborted in local script set, property not found: - " + String(p_property) + "."; - ERR_PRINT(error); - return; - } - } - } - } - - if (skip_rset) { - ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode."); - return; - } - -#ifdef DEBUG_ENABLED - _profile_node_data("out_rset", p_node->get_instance_id()); -#endif - - const Variant *vptr = &p_value; - - _send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1); -} - -Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { +Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, MultiplayerPeer::TransferMode p_mode) { ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet."); ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active."); - ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected."); + ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected."); MAKE_ROOM(p_data.size() + 1); const uint8_t *r = p_data.ptr(); @@ -1207,7 +1105,7 @@ bool MultiplayerAPI::is_object_decoding_allowed() const { void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node); - ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); + ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE)); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id); @@ -1225,8 +1123,8 @@ void MultiplayerAPI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_root_node", "get_root_node"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerPeer", PROPERTY_USAGE_NONE), "set_network_peer", "get_network_peer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_root_node", "get_root_node"); ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 7f88b53a27..e9f96383c9 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -31,11 +31,40 @@ #ifndef MULTIPLAYER_API_H #define MULTIPLAYER_API_H -#include "core/io/networked_multiplayer_peer.h" -#include "core/object/reference.h" +#include "core/io/multiplayer_peer.h" +#include "core/object/ref_counted.h" -class MultiplayerAPI : public Reference { - GDCLASS(MultiplayerAPI, Reference); +class MultiplayerAPI : public RefCounted { + GDCLASS(MultiplayerAPI, RefCounted); + +public: + enum RPCMode { + RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) + RPC_MODE_REMOTE, // Using rpc() on it will call method in all remote peers + RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote + RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets + RPC_MODE_REMOTESYNC, // Using rpc() on it will call method in all remote peers and locally + RPC_MODE_MASTERSYNC, // Using rpc() on it will call method in the master peer and locally + RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method in all puppets peers and locally + }; + + struct RPCConfig { + StringName name; + RPCMode rpc_mode = RPC_MODE_DISABLED; + MultiplayerPeer::TransferMode transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + int channel = 0; + + bool operator==(RPCConfig const &p_other) const { + return name == p_other.name; + } + }; + + struct SortRPCConfig { + StringName::AlphCompare compare; + bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const { + return compare(p_a.name, p_b.name); + } + }; private: //path sent caches @@ -54,7 +83,7 @@ private: Map<int, NodeInfo> nodes; }; - Ref<NetworkedMultiplayerPeer> network_peer; + Ref<MultiplayerPeer> network_peer; int rpc_sender_id = 0; Set<int> connected_peers; HashMap<NodePath, PathSentCache> path_send_cache; @@ -72,10 +101,9 @@ protected: void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len); Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); - void _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len); - void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); + void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount); bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); Error _encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len); @@ -84,7 +112,6 @@ protected: public: enum NetworkCommands { NETWORK_COMMAND_REMOTE_CALL = 0, - NETWORK_COMMAND_REMOTE_SET, NETWORK_COMMAND_SIMPLIFY_PATH, NETWORK_COMMAND_CONFIRM_PATH, NETWORK_COMMAND_RAW, @@ -101,28 +128,16 @@ public: NETWORK_NAME_ID_COMPRESSION_16, }; - enum RPCMode { - RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) - RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers - RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote - RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets - RPC_MODE_REMOTESYNC, // Using rpc() on it will call method / set property in all remote peers and locally - RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally - RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method / set property in all puppets peers and locally - }; - void poll(); void clear(); void set_root_node(Node *p_node); Node *get_root_node(); - void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer); - Ref<NetworkedMultiplayerPeer> get_network_peer() const; - Error send_bytes(Vector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + void set_network_peer(const Ref<MultiplayerPeer> &p_peer); + Ref<MultiplayerPeer> get_network_peer() const; + Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE); // Called by Node.rpc void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); - // Called by Node.rset - void rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); void _add_peer(int p_id); void _del_peer(int p_id); diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/multiplayer_peer.cpp index b6af046e77..8126b4cea3 100644 --- a/core/io/networked_multiplayer_peer.cpp +++ b/core/io/multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_peer.cpp */ +/* multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,22 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "networked_multiplayer_peer.h" +#include "multiplayer_peer.h" -void NetworkedMultiplayerPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &NetworkedMultiplayerPeer::set_transfer_mode); - ClassDB::bind_method(D_METHOD("get_transfer_mode"), &NetworkedMultiplayerPeer::get_transfer_mode); - ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &NetworkedMultiplayerPeer::set_target_peer); +void MultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &MultiplayerPeer::set_transfer_mode); + ClassDB::bind_method(D_METHOD("get_transfer_mode"), &MultiplayerPeer::get_transfer_mode); + ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer); - ClassDB::bind_method(D_METHOD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer); + ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer); - ClassDB::bind_method(D_METHOD("poll"), &NetworkedMultiplayerPeer::poll); + ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll); - ClassDB::bind_method(D_METHOD("get_connection_status"), &NetworkedMultiplayerPeer::get_connection_status); - ClassDB::bind_method(D_METHOD("get_unique_id"), &NetworkedMultiplayerPeer::get_unique_id); + ClassDB::bind_method(D_METHOD("get_connection_status"), &MultiplayerPeer::get_connection_status); + ClassDB::bind_method(D_METHOD("get_unique_id"), &MultiplayerPeer::get_unique_id); - ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &NetworkedMultiplayerPeer::set_refuse_new_connections); - ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &NetworkedMultiplayerPeer::is_refusing_new_connections); + ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections); + ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode"); diff --git a/core/io/networked_multiplayer_peer.h b/core/io/multiplayer_peer.h index 7c90f97d88..432f47280f 100644 --- a/core/io/networked_multiplayer_peer.h +++ b/core/io/multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_peer.h */ +/* multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,8 +33,8 @@ #include "core/io/packet_peer.h" -class NetworkedMultiplayerPeer : public PacketPeer { - GDCLASS(NetworkedMultiplayerPeer, PacketPeer); +class MultiplayerPeer : public PacketPeer { + GDCLASS(MultiplayerPeer, PacketPeer); protected: static void _bind_methods(); @@ -73,10 +73,10 @@ public: virtual ConnectionStatus get_connection_status() const = 0; - NetworkedMultiplayerPeer() {} + MultiplayerPeer() {} }; -VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::TransferMode) -VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::ConnectionStatus) +VARIANT_ENUM_CAST(MultiplayerPeer::TransferMode) +VARIANT_ENUM_CAST(MultiplayerPeer::ConnectionStatus) #endif // NETWORKED_MULTIPLAYER_PEER_H diff --git a/core/io/net_socket.h b/core/io/net_socket.h index 98ff9562d9..fd7d50c704 100644 --- a/core/io/net_socket.h +++ b/core/io/net_socket.h @@ -32,9 +32,9 @@ #define NET_SOCKET_H #include "core/io/ip.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class NetSocket : public Reference { +class NetSocket : public RefCounted { protected: static NetSocket *(*_create)(); diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp index 52169987fd..cf6a0b6027 100644 --- a/core/io/packed_data_container.cpp +++ b/core/io/packed_data_container.cpp @@ -227,10 +227,10 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd case Variant::VECTOR3: case Variant::TRANSFORM2D: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::BASIS: - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: diff --git a/core/io/packed_data_container.h b/core/io/packed_data_container.h index 7791e21bb3..40772bb2bf 100644 --- a/core/io/packed_data_container.h +++ b/core/io/packed_data_container.h @@ -80,8 +80,8 @@ public: PackedDataContainer() {} }; -class PackedDataContainerRef : public Reference { - GDCLASS(PackedDataContainerRef, Reference); +class PackedDataContainerRef : public RefCounted { + GDCLASS(PackedDataContainerRef, RefCounted); friend class PackedDataContainer; uint32_t offset = 0; diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 318fd10243..8da44fd290 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -161,7 +161,7 @@ void PacketPeerStream::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "input_buffer_max_size"), "set_input_buffer_max_size", "get_input_buffer_max_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "output_buffer_max_size"), "set_output_buffer_max_size", "get_output_buffer_max_size"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream_peer", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_stream_peer", "get_stream_peer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream_peer", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", PROPERTY_USAGE_NONE), "set_stream_peer", "get_stream_peer"); } Error PacketPeerStream::_poll_buffer() const { diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 9e03c44750..9a345af3d0 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -35,8 +35,8 @@ #include "core/object/class_db.h" #include "core/templates/ring_buffer.h" -class PacketPeer : public Reference { - GDCLASS(PacketPeer, Reference); +class PacketPeer : public RefCounted { + GDCLASS(PacketPeer, RefCounted); Variant _bnd_get_var(bool p_allow_objects = false); diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp index bac98e20e7..a6d220622b 100644 --- a/core/io/packet_peer_dtls.cpp +++ b/core/io/packet_peer_dtls.cpp @@ -30,7 +30,7 @@ #include "packet_peer_dtls.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr; bool PacketPeerDTLS::available = false; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index cadb02b5dd..806a95398f 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -31,9 +31,9 @@ #include "pck_packer.h" #include "core/crypto/crypto_core.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION -#include "core/os/file_access.h" #include "core/version.h" static int _get_pad(int p_alignment, int p_n) { diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index dec8f8748d..3d2ce8f240 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -31,12 +31,12 @@ #ifndef PCK_PACKER_H #define PCK_PACKER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class FileAccess; -class PCKPacker : public Reference { - GDCLASS(PCKPacker, Reference); +class PCKPacker : public RefCounted { + GDCLASS(PCKPacker, RefCounted); FileAccess *file = nullptr; int alignment = 0; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index d46e9edafa..efa622d976 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -31,9 +31,9 @@ #include "resource.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "scene/main/node.h" //only so casting works @@ -164,7 +164,7 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res List<PropertyInfo> plist; get_property_list(&plist); - Ref<Resource> r = Object::cast_to<Resource>(ClassDB::instance(get_class())); + Ref<Resource> r = Object::cast_to<Resource>(ClassDB::instantiate(get_class())); ERR_FAIL_COND_V(r.is_null(), Ref<Resource>()); r->local_scene = p_for_scene; @@ -224,7 +224,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const { List<PropertyInfo> plist; get_property_list(&plist); - Ref<Resource> r = (Resource *)ClassDB::instance(get_class()); + Ref<Resource> r = (Resource *)ClassDB::instantiate(get_class()); ERR_FAIL_COND_V(r.is_null(), Ref<Resource>()); for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { diff --git a/core/io/resource.h b/core/io/resource.h index 75a9f928f8..028fed1c6e 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -32,7 +32,7 @@ #define RESOURCE_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/safe_refcount.h" #include "core/templates/self_list.h" @@ -43,8 +43,8 @@ public: \ private: -class Resource : public Reference { - GDCLASS(Resource, Reference); +class Resource : public RefCounted { + GDCLASS(Resource, RefCounted); OBJ_CATEGORY("Resources"); public: diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index d6601513bc..0e9815245f 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -31,10 +31,10 @@ #include "resource_format_binary.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/file_access_compressed.h" #include "core/io/image.h" #include "core/io/marshalls.h" -#include "core/os/dir_access.h" #include "core/version.h" //#define print_bl(m_what) print_line(m_what) @@ -51,7 +51,7 @@ enum { VARIANT_RECT2 = 11, VARIANT_VECTOR3 = 12, VARIANT_PLANE = 13, - VARIANT_QUAT = 14, + VARIANT_QUATERNION = 14, VARIANT_AABB = 15, VARIANT_MATRIX3 = 16, VARIANT_TRANSFORM = 17, @@ -199,8 +199,8 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { v.d = f->get_real(); r_v = v; } break; - case VARIANT_QUAT: { - Quat v; + case VARIANT_QUATERNION: { + Quaternion v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); @@ -245,7 +245,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { } break; case VARIANT_TRANSFORM: { - Transform v; + Transform3D v; v.basis.elements[0].x = f->get_real(); v.basis.elements[0].y = f->get_real(); v.basis.elements[0].z = f->get_real(); @@ -704,7 +704,7 @@ Error ResourceLoaderBinary::load() { if (res.is_null()) { //did not replace - Object *obj = ClassDB::instance(t); + Object *obj = ClassDB::instantiate(t); if (!obj) { error = ERR_FILE_CORRUPT; ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + "."); @@ -1371,9 +1371,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.d); } break; - case Variant::QUAT: { - f->store_32(VARIANT_QUAT); - Quat val = p_property; + case Variant::QUATERNION: { + f->store_32(VARIANT_QUATERNION); + Quaternion val = p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); @@ -1416,9 +1416,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.elements[2].z); } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { f->store_32(VARIANT_TRANSFORM); - Transform val = p_property; + Transform3D val = p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 3592bbdbc4..abc7403935 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -31,9 +31,9 @@ #ifndef RESOURCE_FORMAT_BINARY_H #define RESOURCE_FORMAT_BINARY_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" class ResourceLoaderBinary { bool translation_remapped = false; diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index a14d6ba52c..2ceeb176e5 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -93,8 +93,8 @@ public: ResourceFormatImporter(); }; -class ResourceImporter : public Reference { - GDCLASS(ResourceImporter, Reference); +class ResourceImporter : public RefCounted { + GDCLASS(ResourceImporter, RefCounted); public: virtual String get_importer_name() const = 0; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index b942c30086..c5dfe1f2b0 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -31,8 +31,8 @@ #include "resource_loader.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_importer.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/string/print_string.h" #include "core/string/translation.h" @@ -68,17 +68,17 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ } bool ResourceFormatLoader::handles_type(const String &p_type) const { - if (get_script_instance() && get_script_instance()->has_method("handles_type")) { + if (get_script_instance() && get_script_instance()->has_method("_handles_type")) { // I guess custom loaders for custom resources should use "Resource" - return get_script_instance()->call("handles_type", p_type); + return get_script_instance()->call("_handles_type", p_type); } return false; } String ResourceFormatLoader::get_resource_type(const String &p_path) const { - if (get_script_instance() && get_script_instance()->has_method("get_resource_type")) { - return get_script_instance()->call("get_resource_type", p_path); + if (get_script_instance() && get_script_instance()->has_method("_get_resource_type")) { + return get_script_instance()->call("_get_resource_type", p_path); } return ""; @@ -101,8 +101,8 @@ bool ResourceFormatLoader::exists(const String &p_path) const { } void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const { - if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { - PackedStringArray exts = get_script_instance()->call("get_recognized_extensions"); + if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) { + PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions"); { const String *r = exts.ptr(); @@ -115,8 +115,8 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) RES ResourceFormatLoader::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) { // Check user-defined loader if there's any. Hard fail if it returns an error. - if (get_script_instance() && get_script_instance()->has_method("load")) { - Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode); + if (get_script_instance() && get_script_instance()->has_method("_load")) { + Variant res = get_script_instance()->call("_load", p_path, p_original_path, p_use_sub_threads, p_cache_mode); if (res.get_type() == Variant::INT) { // Error code, abort. if (r_error) { @@ -135,8 +135,8 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa } void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - if (get_script_instance() && get_script_instance()->has_method("get_dependencies")) { - PackedStringArray deps = get_script_instance()->call("get_dependencies", p_path, p_add_types); + if (get_script_instance() && get_script_instance()->has_method("_get_dependencies")) { + PackedStringArray deps = get_script_instance()->call("_get_dependencies", p_path, p_add_types); { const String *r = deps.ptr(); @@ -148,13 +148,13 @@ void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> * } Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { - if (get_script_instance() && get_script_instance()->has_method("rename_dependencies")) { + if (get_script_instance() && get_script_instance()->has_method("_rename_dependencies")) { Dictionary deps_dict; for (Map<String, String>::Element *E = p_map.front(); E; E = E->next()) { deps_dict[E->key()] = E->value(); } - int64_t res = get_script_instance()->call("rename_dependencies", deps_dict); + int64_t res = get_script_instance()->call("_rename_dependencies", deps_dict); return (Error)res; } @@ -163,16 +163,16 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map< void ResourceFormatLoader::_bind_methods() { { - MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode")); + MethodInfo info = MethodInfo(Variant::NIL, "_load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode")); info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - ClassDB::add_virtual_method(get_class_static(), info); + BIND_VMETHOD(info); } - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_resource_type", PropertyInfo(Variant::STRING, "path"))); + BIND_VMETHOD(MethodInfo("_get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); + BIND_VMETHOD(MethodInfo(Variant::INT, "_rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE); BIND_ENUM_CONSTANT(CACHE_MODE_REUSE); @@ -354,7 +354,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String & ThreadLoadTask &load_task = thread_load_tasks[local_path]; - if (load_task.resource.is_null()) { //needs to be loaded in thread + if (load_task.resource.is_null()) { //needs to be loaded in thread load_task.semaphore = memnew(Semaphore); if (thread_loading_count < thread_load_max) { @@ -1045,7 +1045,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader"); ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceLoader: " + script_path + "."); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + "."); diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 914d988caa..c656b9a69c 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -35,8 +35,8 @@ #include "core/os/semaphore.h" #include "core/os/thread.h" -class ResourceFormatLoader : public Reference { - GDCLASS(ResourceFormatLoader, Reference); +class ResourceFormatLoader : public RefCounted { + GDCLASS(ResourceFormatLoader, RefCounted); public: enum CacheMode { diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 7ebc7f34b3..80cb85fba3 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -30,9 +30,9 @@ #include "resource_saver.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS]; @@ -41,24 +41,24 @@ bool ResourceSaver::timestamp_on_save = false; ResourceSavedCallback ResourceSaver::save_callback = nullptr; Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - if (get_script_instance() && get_script_instance()->has_method("save")) { - return (Error)get_script_instance()->call("save", p_path, p_resource, p_flags).operator int64_t(); + if (get_script_instance() && get_script_instance()->has_method("_save")) { + return (Error)get_script_instance()->call("_save", p_path, p_resource, p_flags).operator int64_t(); } return ERR_METHOD_NOT_FOUND; } bool ResourceFormatSaver::recognize(const RES &p_resource) const { - if (get_script_instance() && get_script_instance()->has_method("recognize")) { - return get_script_instance()->call("recognize", p_resource); + if (get_script_instance() && get_script_instance()->has_method("_recognize")) { + return get_script_instance()->call("_recognize", p_resource); } return false; } void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { - PackedStringArray exts = get_script_instance()->call("get_recognized_extensions", p_resource); + if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) { + PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions", p_resource); { const String *r = exts.ptr(); @@ -74,11 +74,11 @@ void ResourceFormatSaver::_bind_methods() { PropertyInfo arg0 = PropertyInfo(Variant::STRING, "path"); PropertyInfo arg1 = PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"); PropertyInfo arg2 = PropertyInfo(Variant::INT, "flags"); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "save", arg0, arg1, arg2)); + BIND_VMETHOD(MethodInfo(Variant::INT, "_save", arg0, arg1, arg2)); } - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); } Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { @@ -210,7 +210,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver"); ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + "."); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + "."); diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 2c9e8f1aa3..07154aac4d 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -33,8 +33,8 @@ #include "core/io/resource.h" -class ResourceFormatSaver : public Reference { - GDCLASS(ResourceFormatSaver, Reference); +class ResourceFormatSaver : public RefCounted { + GDCLASS(ResourceFormatSaver, RefCounted); protected: static void _bind_methods(); diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index ee5e9eca0c..27f8d4e88f 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -512,7 +512,7 @@ void StreamPeerBuffer::clear() { Ref<StreamPeerBuffer> StreamPeerBuffer::duplicate() const { Ref<StreamPeerBuffer> spb; - spb.instance(); + spb.instantiate(); spb->data = data; return spb; } diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index 1e1a3e890c..effc3850af 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -31,10 +31,10 @@ #ifndef STREAM_PEER_H #define STREAM_PEER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class StreamPeer : public Reference { - GDCLASS(StreamPeer, Reference); +class StreamPeer : public RefCounted { + GDCLASS(StreamPeer, RefCounted); OBJ_CATEGORY("Networking"); protected: diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index b760a9ef80..5e0c0390f9 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -43,7 +43,6 @@ Error TCPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) { ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); Error err; IP::Type ip_type = IP::TYPE_ANY; diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index abefa53c6f..10985a04d5 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -36,8 +36,8 @@ #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" -class TCPServer : public Reference { - GDCLASS(TCPServer, Reference); +class TCPServer : public RefCounted { + GDCLASS(TCPServer, RefCounted); protected: enum { diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 9adf912224..83d575cee8 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -30,7 +30,7 @@ #include "translation_loader_po.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/translation.h" #include "core/string/translation_po.h" diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 36d33fcac3..c52820e60d 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -31,8 +31,8 @@ #ifndef TRANSLATION_LOADER_PO_H #define TRANSLATION_LOADER_PO_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/string/translation.h" class TranslationLoaderPO : public ResourceFormatLoader { diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp index 6a1af0c2a9..27a1cab721 100644 --- a/core/io/udp_server.cpp +++ b/core/io/udp_server.cpp @@ -91,7 +91,6 @@ Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) { ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); Error err; IP::Type ip_type = IP::TYPE_ANY; diff --git a/core/io/udp_server.h b/core/io/udp_server.h index 60d03f37f0..e49a559c51 100644 --- a/core/io/udp_server.h +++ b/core/io/udp_server.h @@ -34,8 +34,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer_udp.h" -class UDPServer : public Reference { - GDCLASS(UDPServer, Reference); +class UDPServer : public RefCounted { + GDCLASS(UDPServer, RefCounted); protected: enum { diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index 847edf958d..1113cce715 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -31,8 +31,8 @@ #ifndef XML_PARSER_H #define XML_PARSER_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/templates/vector.h" @@ -40,8 +40,8 @@ Based on irrXML (see their zlib license). Added mainly for compatibility with their Collada loader. */ -class XMLParser : public Reference { - GDCLASS(XMLParser, Reference); +class XMLParser : public RefCounted { + GDCLASS(XMLParser, RefCounted); public: //! Enumeration of all supported source text file formats @@ -80,7 +80,6 @@ private: Vector<Attribute> attributes; - String _replace_special_characters(const String &origstr); bool _set_text(char *start, char *end); void _parse_closing_xml_element(); void _ignore_definition(); diff --git a/core/io/zip_io.h b/core/io/zip_io.h index 52691c65e9..776473bfa1 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -31,7 +31,7 @@ #ifndef ZIP_IO_H #define ZIP_IO_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" // Not directly used in this header, but assumed available in downstream users // like platform/*/export/export.cpp. Could be fixed, but probably better to have diff --git a/core/math/a_star.h b/core/math/a_star.h index 4c61abd91c..44758cb046 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -31,7 +31,7 @@ #ifndef A_STAR_H #define A_STAR_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/oa_hash_map.h" /** @@ -40,8 +40,8 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class AStar : public Reference { - GDCLASS(AStar, Reference); +class AStar : public RefCounted { + GDCLASS(AStar, RefCounted); friend class AStar2D; struct Point { @@ -157,8 +157,8 @@ public: ~AStar(); }; -class AStar2D : public Reference { - GDCLASS(AStar2D, Reference); +class AStar2D : public RefCounted { + GDCLASS(AStar2D, RefCounted); AStar astar; bool _solve(AStar::Point *begin_point, AStar::Point *end_point); diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index 2c721997d8..33aa65f15d 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -392,5 +392,5 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c } AABB::operator String() const { - return String() + position + " - " + size; + return "[P: " + position.operator String() + ", S: " + size + "]"; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 037378b9d7..aa3831d4cf 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -345,12 +345,12 @@ void Basis::rotate(const Vector3 &p_euler) { *this = rotated(p_euler); } -Basis Basis::rotated(const Quat &p_quat) const { - return Basis(p_quat) * (*this); +Basis Basis::rotated(const Quaternion &p_quaternion) const { + return Basis(p_quaternion) * (*this); } -void Basis::rotate(const Quat &p_quat) { - *this = rotated(p_quat); +void Basis::rotate(const Quaternion &p_quaternion) { + *this = rotated(p_quaternion); } Vector3 Basis::get_rotation_euler() const { @@ -367,7 +367,7 @@ Vector3 Basis::get_rotation_euler() const { return m.get_euler(); } -Quat Basis::get_rotation_quat() const { +Quaternion Basis::get_rotation_quaternion() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // See the comment in get_scale() for further information. @@ -378,7 +378,7 @@ Quat Basis::get_rotation_quat() const { m.scale(Vector3(-1, -1, -1)); } - return m.get_quat(); + return m.get_quaternion(); } void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { @@ -756,23 +756,14 @@ bool Basis::operator!=(const Basis &p_matrix) const { } Basis::operator String() const { - String mtx; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (i != 0 || j != 0) { - mtx += ", "; - } - - mtx += rtos(elements[j][i]); //matrix is stored transposed for performance, so print it transposed - } - } - - return mtx; + return "[X: " + get_axis(0).operator String() + + ", Y: " + get_axis(1).operator String() + + ", Z: " + get_axis(2).operator String() + "]"; } -Quat Basis::get_quat() const { +Quaternion Basis::get_quaternion() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_rotation(), Quat(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead."); + ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() instead."); #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; @@ -803,7 +794,7 @@ Quat Basis::get_quat() const { temp[k] = (m.elements[k][i] + m.elements[i][k]) * s; } - return Quat(temp[0], temp[1], temp[2], temp[3]); + return Quaternion(temp[0], temp[1], temp[2], temp[3]); } static const Basis _ortho_bases[24] = { @@ -945,13 +936,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = angle; } -void Basis::set_quat(const Quat &p_quat) { - real_t d = p_quat.length_squared(); +void Basis::set_quaternion(const Quaternion &p_quaternion) { + real_t d = p_quaternion.length_squared(); real_t s = 2.0 / d; - real_t xs = p_quat.x * s, ys = p_quat.y * s, zs = p_quat.z * s; - real_t wx = p_quat.w * xs, wy = p_quat.w * ys, wz = p_quat.w * zs; - real_t xx = p_quat.x * xs, xy = p_quat.x * ys, xz = p_quat.x * zs; - real_t yy = p_quat.y * ys, yz = p_quat.y * zs, zz = p_quat.z * zs; + real_t xs = p_quaternion.x * s, ys = p_quaternion.y * s, zs = p_quaternion.z * s; + real_t wx = p_quaternion.w * xs, wy = p_quaternion.w * ys, wz = p_quaternion.w * zs; + real_t xx = p_quaternion.x * xs, xy = p_quaternion.x * ys, xz = p_quaternion.x * zs; + real_t yy = p_quaternion.y * ys, yz = p_quaternion.y * zs, zz = p_quaternion.z * zs; set(1.0 - (yy + zz), xy - wz, xz + wy, xy + wz, 1.0 - (xx + zz), yz - wx, xz - wy, yz + wx, 1.0 - (xx + yy)); @@ -997,9 +988,9 @@ void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { rotate(p_euler); } -void Basis::set_quat_scale(const Quat &p_quat, const Vector3 &p_scale) { +void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_diagonal(p_scale); - rotate(p_quat); + rotate(p_quaternion); } void Basis::set_diagonal(const Vector3 &p_diag) { @@ -1018,8 +1009,8 @@ void Basis::set_diagonal(const Vector3 &p_diag) { Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { //consider scale - Quat from(*this); - Quat to(p_to); + Quaternion from(*this); + Quaternion to(p_to); Basis b(from.slerp(to, p_weight)); b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight); diff --git a/core/math/basis.h b/core/math/basis.h index 56f6227313..2889a4aa5e 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -31,7 +31,7 @@ #ifndef BASIS_H #define BASIS_H -#include "core/math/quat.h" +#include "core/math/quaternion.h" #include "core/math/vector3.h" class Basis { @@ -79,13 +79,13 @@ public: void rotate(const Vector3 &p_euler); Basis rotated(const Vector3 &p_euler) const; - void rotate(const Quat &p_quat); - Basis rotated(const Quat &p_quat) const; + void rotate(const Quaternion &p_quaternion); + Basis rotated(const Quaternion &p_quaternion) const; Vector3 get_rotation_euler() 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; - Quat get_rotation_quat() const; + Quaternion get_rotation_quaternion() const; Vector3 get_rotation() const { return get_rotation_euler(); }; Vector3 rotref_posscale_decomposition(Basis &rotref) const; @@ -108,8 +108,8 @@ public: Vector3 get_euler_zyx() const; void set_euler_zyx(const Vector3 &p_euler); - Quat get_quat() const; - void set_quat(const Quat &p_quat); + Quaternion get_quaternion() const; + void set_quaternion(const Quaternion &p_quaternion); Vector3 get_euler() const { return get_euler_yxz(); } void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); } @@ -132,7 +132,7 @@ public: void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale); void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale); - void set_quat_scale(const Quat &p_quat, const Vector3 &p_scale); + void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale); // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { @@ -158,8 +158,8 @@ public: _FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const; _FORCE_INLINE_ void operator-=(const Basis &p_matrix); _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator*=(real_t p_val); - _FORCE_INLINE_ Basis operator*(real_t p_val) const; + _FORCE_INLINE_ void operator*=(const real_t p_val); + _FORCE_INLINE_ Basis operator*(const real_t p_val) const; int get_orthogonal_index() const; void set_orthogonal_index(int p_index); @@ -240,10 +240,10 @@ public: #endif Basis diagonalize(); - operator Quat() const { return get_quat(); } + operator Quaternion() const { return get_quaternion(); } - Basis(const Quat &p_quat) { set_quat(p_quat); }; - Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } + Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }; + Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); } Basis(const Vector3 &p_euler) { set_euler(p_euler); } Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); } @@ -298,13 +298,13 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { return ret; } -_FORCE_INLINE_ void Basis::operator*=(real_t p_val) { +_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) { elements[0] *= p_val; elements[1] *= p_val; elements[2] *= p_val; } -_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const { +_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const { Basis ret(*this); ret *= p_val; return ret; diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 1066cf5e30..66c18f7b3c 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -315,8 +315,8 @@ Vector2 CameraMatrix::get_far_plane_half_extents() const { return Vector2(res.x, res.y); } -bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const { - Vector<Plane> planes = get_projection_planes(Transform()); +bool CameraMatrix::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { + Vector<Plane> planes = get_projection_planes(Transform3D()); const Planes intersections[8][3] = { { PLANE_FAR, PLANE_LEFT, PLANE_TOP }, { PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM }, @@ -338,7 +338,7 @@ bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8point return true; } -Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const { +Vector<Plane> CameraMatrix::get_projection_planes(const Transform3D &p_transform) const { /** Fast Plane Extraction from combined modelview/projection matrices. * References: * https://web.archive.org/web/20011221205252/http://www.markmorley.com/opengl/frustumculling.html @@ -707,8 +707,8 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { matrix[3][3] = 1; } -CameraMatrix::operator Transform() const { - Transform tr; +CameraMatrix::operator Transform3D() const { + Transform3D tr; const real_t *m = &matrix[0][0]; tr.basis.elements[0][0] = m[0]; @@ -730,8 +730,8 @@ CameraMatrix::operator Transform() const { return tr; } -CameraMatrix::CameraMatrix(const Transform &p_transform) { - const Transform &tr = p_transform; +CameraMatrix::CameraMatrix(const Transform3D &p_transform) { + const Transform3D &tr = p_transform; real_t *m = &matrix[0][0]; m[0] = tr.basis.elements[0][0]; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 3f327d3bc4..786d46055a 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -32,7 +32,7 @@ #define CAMERA_MATRIX_H #include "core/math/rect2.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" struct CameraMatrix { enum Planes { @@ -71,9 +71,9 @@ struct CameraMatrix { real_t get_fov() const; bool is_orthogonal() const; - Vector<Plane> get_projection_planes(const Transform &p_transform) const; + Vector<Plane> get_projection_planes(const Transform3D &p_transform) const; - bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const; + bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const; Vector2 get_viewport_half_extents() const; Vector2 get_far_plane_half_extents() const; @@ -90,7 +90,7 @@ struct CameraMatrix { void scale_translate_to_fit(const AABB &p_aabb); void make_scale(const Vector3 &p_scale); int get_pixels_per_meter(int p_for_pixel_width) const; - operator Transform() const; + operator Transform3D() const; void flip_y(); @@ -112,7 +112,7 @@ struct CameraMatrix { float get_lod_multiplier() const; CameraMatrix(); - CameraMatrix(const Transform &p_transform); + CameraMatrix(const Transform3D &p_transform); ~CameraMatrix(); }; diff --git a/core/math/color.cpp b/core/math/color.cpp index 52f029ef4b..dc86cacf8f 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -368,7 +368,7 @@ Color Color::named(const String &p_name) { ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + "."); return Color(); } - return get_named_color(idx); + return named_colors[idx].color; } Color Color::named(const String &p_name, const Color &p_default) { @@ -376,7 +376,7 @@ Color Color::named(const String &p_name, const Color &p_default) { if (idx == -1) { return p_default; } - return get_named_color(idx); + return named_colors[idx].color; } int Color::find_named_color(const String &p_name) { @@ -409,10 +409,12 @@ int Color::get_named_color_count() { } String Color::get_named_color_name(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), ""); return named_colors[p_idx].name; } Color Color::get_named_color(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), Color()); return named_colors[p_idx].color; } @@ -466,7 +468,7 @@ Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { } Color::operator String() const { - return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a); + return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } Color Color::operator+(const Color &p_color) const { diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 25cc1125db..6f7209556e 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -31,10 +31,10 @@ #ifndef DELAUNAY_3D_H #define DELAUNAY_3D_H +#include "core/io/file_access.h" #include "core/math/aabb.h" #include "core/math/camera_matrix.h" #include "core/math/vector3.h" -#include "core/os/file_access.h" #include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/oa_hash_map.h" diff --git a/core/math/expression.cpp b/core/math/expression.cpp index f7ac44d321..0146c345f0 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -33,7 +33,7 @@ #include "core/io/marshalls.h" #include "core/math/math_funcs.h" #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" diff --git a/core/math/expression.h b/core/math/expression.h index a6b288ed6e..aecf662d0a 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -31,10 +31,10 @@ #ifndef EXPRESSION_H #define EXPRESSION_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class Expression : public Reference { - GDCLASS(Expression, Reference); +class Expression : public RefCounted { + GDCLASS(Expression, RefCounted); private: struct Input { diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 20c316c322..9af3f868d2 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -230,7 +230,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const { real_t minA, maxA, minB, maxB; p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); - project_range(axis, Transform(), minB, maxB); + project_range(axis, Transform3D(), minB, maxB); if (maxA < minB || maxB < minA) { return false; @@ -244,7 +244,7 @@ Face3::operator String() const { return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2]; } -void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void Face3::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { for (int i = 0; i < 3; i++) { Vector3 v = p_transform.xform(vertex[i]); real_t d = p_normal.dot(v); @@ -259,7 +259,7 @@ void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, } } -void Face3::get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { +void Face3::get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { #define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.98 #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.05 diff --git a/core/math/face3.h b/core/math/face3.h index 2e86b0a904..5091b338ef 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -33,7 +33,7 @@ #include "core/math/aabb.h" #include "core/math/plane.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" class Face3 { @@ -74,8 +74,8 @@ public: ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity - void get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; - void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; + void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; AABB get_aabb() const { AABB aabb(vertex[0], Vector3()); diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index 4958b5ac6a..a2894bc1d3 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -362,6 +362,19 @@ public: return (intersections & 1); } + static bool is_segment_intersecting_polygon(const Vector2 &p_from, const Vector2 &p_to, const Vector<Vector2> &p_polygon) { + int c = p_polygon.size(); + const Vector2 *p = p_polygon.ptr(); + for (int i = 0; i < c; i++) { + const Vector2 &v1 = p[i]; + const Vector2 &v2 = p[(i + 1) % c]; + if (segment_intersects_segment(p_from, p_to, v1, v2, nullptr)) { + return true; + } + } + return false; + } + static real_t vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B) { return (real_t)(A.x - O.x) * (B.y - O.y) - (real_t)(A.y - O.y) * (B.x - O.x); } diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp index 0985a727f2..570c57e254 100644 --- a/core/math/math_fieldwise.cpp +++ b/core/math/math_fieldwise.cpp @@ -88,8 +88,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } - case Variant::QUAT: { - SETUP_TYPE(Quat) + case Variant::QUATERNION: { + SETUP_TYPE(Quaternion) /**/ TRY_TRANSFER_FIELD("x", x) else TRY_TRANSFER_FIELD("y", y) @@ -141,8 +141,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } - case Variant::TRANSFORM: { - SETUP_TYPE(Transform) + case Variant::TRANSFORM3D: { + SETUP_TYPE(Transform3D) /**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0]) else TRY_TRANSFER_FIELD("xy", basis.elements[0][1]) diff --git a/core/math/plane.cpp b/core/math/plane.cpp index f1d3bbbd54..3c78b55b90 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -175,5 +175,5 @@ bool Plane::is_equal_approx(const Plane &p_plane) const { } Plane::operator String() const { - return normal.operator String() + ", " + rtos(d); + return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]"; } diff --git a/core/math/quat.cpp b/core/math/quaternion.cpp index 3982a0b993..3f1d2c58e5 100644 --- a/core/math/quat.cpp +++ b/core/math/quaternion.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.cpp */ +/* quaternion.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "quat.h" +#include "quaternion.h" #include "core/math/basis.h" #include "core/string/print_string.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 Quat::get_euler_xyz() const { +Vector3 Quaternion::get_euler_xyz() const { Basis m(*this); return m.get_euler_xyz(); } @@ -46,7 +51,7 @@ Vector3 Quat::get_euler_xyz() const { // (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 Quat::get_euler_yxz() const { +Vector3 Quaternion::get_euler_yxz() const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized."); #endif @@ -54,7 +59,7 @@ Vector3 Quat::get_euler_yxz() const { return m.get_euler_yxz(); } -void Quat::operator*=(const Quat &p_q) { +void Quaternion::operator*=(const Quaternion &p_q) { real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; @@ -64,45 +69,45 @@ void Quat::operator*=(const Quat &p_q) { z = zz; } -Quat Quat::operator*(const Quat &p_q) const { - Quat r = *this; +Quaternion Quaternion::operator*(const Quaternion &p_q) const { + Quaternion r = *this; r *= p_q; return r; } -bool Quat::is_equal_approx(const Quat &p_quat) const { - return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w); +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); } -real_t Quat::length() const { +real_t Quaternion::length() const { return Math::sqrt(length_squared()); } -void Quat::normalize() { +void Quaternion::normalize() { *this /= length(); } -Quat Quat::normalized() const { +Quaternion Quaternion::normalized() const { return *this / length(); } -bool Quat::is_normalized() const { +bool Quaternion::is_normalized() const { return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon } -Quat Quat::inverse() const { +Quaternion Quaternion::inverse() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized."); #endif - return Quat(-x, -y, -z, w); + return Quaternion(-x, -y, -z, w); } -Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { +Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - Quat to1; + Quaternion to1; real_t omega, cosom, sinom, scale0, scale1; // calc cosine @@ -137,19 +142,19 @@ Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { scale1 = p_weight; } // calculate final values - return Quat( + return Quaternion( scale0 * x + scale1 * to1.x, scale0 * y + scale1 * to1.y, scale0 * z + scale1 * to1.z, scale0 * w + scale1 * to1.w); } -Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { +Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - const Quat &from = *this; + const Quaternion &from = *this; real_t dot = from.dot(p_to); @@ -162,29 +167,29 @@ Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { newFactor = Math::sin(p_weight * theta) * sinT, invFactor = Math::sin((1.0 - p_weight) * theta) * sinT; - return Quat(invFactor * from.x + newFactor * p_to.x, + return Quaternion(invFactor * from.x + newFactor * p_to.x, invFactor * from.y + newFactor * p_to.y, invFactor * from.z + newFactor * p_to.z, invFactor * from.w + newFactor * p_to.w); } -Quat Quat::cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const { +Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif //the only way to do slerp :| real_t t2 = (1.0 - p_weight) * p_weight * 2; - Quat sp = this->slerp(p_b, p_weight); - Quat sq = p_pre_a.slerpni(p_post_b, p_weight); + Quaternion sp = this->slerp(p_b, p_weight); + Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight); return sp.slerpni(sq, t2); } -Quat::operator String() const { - return String::num(x) + ", " + String::num(y) + ", " + String::num(z) + ", " + String::num(w); +Quaternion::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } -Quat::Quat(const Vector3 &p_axis, real_t p_angle) { +Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); #endif @@ -209,7 +214,7 @@ Quat::Quat(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). -Quat::Quat(const Vector3 &p_euler) { +Quaternion::Quaternion(const Vector3 &p_euler) { real_t half_a1 = p_euler.y * 0.5; real_t half_a2 = p_euler.x * 0.5; real_t half_a3 = p_euler.z * 0.5; diff --git a/core/math/quat.h b/core/math/quaternion.h index d9b130c050..35324323b3 100644 --- a/core/math/quat.h +++ b/core/math/quaternion.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.h */ +/* quaternion.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef QUAT_H -#define QUAT_H +#ifndef QUATERNION_H +#define QUATERNION_H #include "core/math/math_defs.h" #include "core/math/math_funcs.h" #include "core/math/vector3.h" #include "core/string/ustring.h" -class Quat { +class Quaternion { public: union { struct { @@ -55,21 +55,22 @@ public: return components[idx]; } _FORCE_INLINE_ real_t length_squared() const; - bool is_equal_approx(const Quat &p_quat) const; + bool is_equal_approx(const Quaternion &p_quaternion) const; real_t length() const; void normalize(); - Quat normalized() const; + Quaternion normalized() const; bool is_normalized() const; - Quat inverse() const; - _FORCE_INLINE_ real_t dot(const Quat &p_q) const; + Quaternion inverse() const; + _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(); }; - Quat slerp(const Quat &p_to, const real_t &p_weight) const; - Quat slerpni(const Quat &p_to, const real_t &p_weight) const; - Quat cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const; + Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = 2 * Math::acos(w); @@ -79,11 +80,11 @@ public: r_axis.z = z * r; } - void operator*=(const Quat &p_q); - Quat operator*(const Quat &p_q) const; + void operator*=(const Quaternion &p_q); + Quaternion operator*(const Quaternion &p_q) const; - Quat operator*(const Vector3 &v) const { - return Quat(w * v.x + y * v.z - z * v.y, + Quaternion operator*(const Vector3 &v) const { + return Quaternion(w * v.x + y * v.z - z * v.y, w * v.y + z * v.x - x * v.z, w * v.z + x * v.y - y * v.x, -x * v.x - y * v.y - z * v.z); @@ -102,42 +103,42 @@ public: return inverse().xform(v); } - _FORCE_INLINE_ void operator+=(const Quat &p_q); - _FORCE_INLINE_ void operator-=(const Quat &p_q); + _FORCE_INLINE_ void operator+=(const Quaternion &p_q); + _FORCE_INLINE_ void operator-=(const Quaternion &p_q); _FORCE_INLINE_ void operator*=(const real_t &s); _FORCE_INLINE_ void operator/=(const real_t &s); - _FORCE_INLINE_ Quat operator+(const Quat &q2) const; - _FORCE_INLINE_ Quat operator-(const Quat &q2) const; - _FORCE_INLINE_ Quat operator-() const; - _FORCE_INLINE_ Quat operator*(const real_t &s) const; - _FORCE_INLINE_ Quat operator/(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-() const; + _FORCE_INLINE_ Quaternion operator*(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator/(const real_t &s) const; - _FORCE_INLINE_ bool operator==(const Quat &p_quat) const; - _FORCE_INLINE_ bool operator!=(const Quat &p_quat) const; + _FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const; + _FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const; operator String() const; - _FORCE_INLINE_ Quat() {} + _FORCE_INLINE_ Quaternion() {} - _FORCE_INLINE_ Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + _FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : x(p_x), y(p_y), z(p_z), w(p_w) { } - Quat(const Vector3 &p_axis, real_t p_angle); + Quaternion(const Vector3 &p_axis, real_t p_angle); - Quat(const Vector3 &p_euler); + Quaternion(const Vector3 &p_euler); - Quat(const Quat &p_q) : + Quaternion(const Quaternion &p_q) : x(p_q.x), y(p_q.y), z(p_q.z), w(p_q.w) { } - Quat &operator=(const Quat &p_q) { + Quaternion &operator=(const Quaternion &p_q) { x = p_q.x; y = p_q.y; z = p_q.z; @@ -145,7 +146,7 @@ public: return *this; } - Quat(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); @@ -167,72 +168,72 @@ public: } }; -real_t Quat::dot(const Quat &p_q) const { +real_t Quaternion::dot(const Quaternion &p_q) const { return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w; } -real_t Quat::length_squared() const { +real_t Quaternion::length_squared() const { return dot(*this); } -void Quat::operator+=(const Quat &p_q) { +void Quaternion::operator+=(const Quaternion &p_q) { x += p_q.x; y += p_q.y; z += p_q.z; w += p_q.w; } -void Quat::operator-=(const Quat &p_q) { +void Quaternion::operator-=(const Quaternion &p_q) { x -= p_q.x; y -= p_q.y; z -= p_q.z; w -= p_q.w; } -void Quat::operator*=(const real_t &s) { +void Quaternion::operator*=(const real_t &s) { x *= s; y *= s; z *= s; w *= s; } -void Quat::operator/=(const real_t &s) { +void Quaternion::operator/=(const real_t &s) { *this *= 1.0 / s; } -Quat Quat::operator+(const Quat &q2) const { - const Quat &q1 = *this; - return Quat(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); +Quaternion Quaternion::operator+(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); } -Quat Quat::operator-(const Quat &q2) const { - const Quat &q1 = *this; - return Quat(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); +Quaternion Quaternion::operator-(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); } -Quat Quat::operator-() const { - const Quat &q2 = *this; - return Quat(-q2.x, -q2.y, -q2.z, -q2.w); +Quaternion Quaternion::operator-() const { + const Quaternion &q2 = *this; + return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w); } -Quat Quat::operator*(const real_t &s) const { - return Quat(x * s, y * s, z * s, w * s); +Quaternion Quaternion::operator*(const real_t &s) const { + return Quaternion(x * s, y * s, z * s, w * s); } -Quat Quat::operator/(const real_t &s) const { +Quaternion Quaternion::operator/(const real_t &s) const { return *this * (1.0 / s); } -bool Quat::operator==(const Quat &p_quat) const { - return x == p_quat.x && y == p_quat.y && z == p_quat.z && w == p_quat.w; +bool Quaternion::operator==(const Quaternion &p_quaternion) const { + return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w; } -bool Quat::operator!=(const Quat &p_quat) const { - return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w; +bool Quaternion::operator!=(const Quaternion &p_quaternion) const { + return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w; } -_FORCE_INLINE_ Quat operator*(const real_t &p_real, const Quat &p_quat) { - return p_quat * p_real; +_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) { + return p_quaternion * p_real; } -#endif // QUAT_H +#endif // QUATERNION_H diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index fe18cc3d41..0d77bfe933 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -112,7 +112,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ } } - //fourth vertex is the one most further away from the plane + //fourth vertex is the one most further away from the plane { real_t maxd = 0; diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h index a396c2b7d7..06cd3999f3 100644 --- a/core/math/random_number_generator.h +++ b/core/math/random_number_generator.h @@ -32,10 +32,10 @@ #define RANDOM_NUMBER_GENERATOR_H #include "core/math/random_pcg.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class RandomNumberGenerator : public Reference { - GDCLASS(RandomNumberGenerator, Reference); +class RandomNumberGenerator : public RefCounted { + GDCLASS(RandomNumberGenerator, RefCounted); protected: RandomPCG randbase; diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index 60c44999f7..f64bf560c8 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -263,3 +263,11 @@ next4: return true; } + +Rect2::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} + +Rect2i::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} diff --git a/core/math/rect2.h b/core/math/rect2.h index 1dc027cf72..ab0b489b4a 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -320,7 +320,7 @@ struct Rect2 { return position + size; } - operator String() const { return String(position) + ", " + String(size); } + operator String() const; Rect2() {} Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : @@ -498,7 +498,7 @@ struct Rect2i { return position + size; } - operator String() const { return String(position) + ", " + String(size); } + operator String() const; operator Rect2() const { return Rect2(position, size); } diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 4a521b96ae..16934d67df 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -158,6 +158,13 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]); } +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); + return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle()); + return return_trans; +} + bool Transform2D::operator==(const Transform2D &p_transform) const { for (int i = 0; i < 3; i++) { if (elements[i] != p_transform.elements[i]) { @@ -269,6 +276,20 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t return res; } +void Transform2D::operator*=(const real_t p_val) { + elements[0] *= p_val; + elements[1] *= p_val; + elements[2] *= p_val; +} + +Transform2D Transform2D::operator*(const real_t p_val) const { + Transform2D ret(*this); + ret *= p_val; + return ret; +} + Transform2D::operator String() const { - return String(String() + elements[0] + ", " + elements[1] + ", " + elements[2]); + return "[X: " + elements[0].operator String() + + ", Y: " + elements[1].operator String() + + ", O: " + elements[2].operator String() + "]"; } diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 327d0f244f..34cfd0c1a9 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -100,11 +100,15 @@ struct Transform2D { Transform2D orthonormalized() const; bool is_equal_approx(const Transform2D &p_transform) const; + Transform2D looking_at(const Vector2 &p_target) const; + bool operator==(const Transform2D &p_transform) const; bool operator!=(const Transform2D &p_transform) const; void operator*=(const Transform2D &p_transform); Transform2D operator*(const Transform2D &p_transform) const; + void operator*=(const real_t p_val); + Transform2D operator*(const real_t p_val) const; Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; diff --git a/core/math/transform.cpp b/core/math/transform_3d.cpp index d4d7ff6d28..51766b39f4 100644 --- a/core/math/transform.cpp +++ b/core/math/transform_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.cpp */ +/* transform_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,54 +28,54 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "transform.h" +#include "transform_3d.h" #include "core/math/math_funcs.h" #include "core/string/print_string.h" -void Transform::affine_invert() { +void Transform3D::affine_invert() { basis.invert(); origin = basis.xform(-origin); } -Transform Transform::affine_inverse() const { - Transform ret = *this; +Transform3D Transform3D::affine_inverse() const { + Transform3D ret = *this; ret.affine_invert(); return ret; } -void Transform::invert() { +void Transform3D::invert() { basis.transpose(); origin = basis.xform(-origin); } -Transform Transform::inverse() const { +Transform3D Transform3D::inverse() const { // FIXME: this function assumes the basis is a rotation matrix, with no scaling. - // Transform::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. - Transform ret = *this; + // Transform3D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. + Transform3D ret = *this; ret.invert(); return ret; } -void Transform::rotate(const Vector3 &p_axis, real_t p_phi) { +void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) { *this = rotated(p_axis, p_phi); } -Transform Transform::rotated(const Vector3 &p_axis, real_t p_phi) const { - return Transform(Basis(p_axis, p_phi), Vector3()) * (*this); +Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const { + return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this); } -void Transform::rotate_basis(const Vector3 &p_axis, real_t p_phi) { +void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) { basis.rotate(p_axis, p_phi); } -Transform Transform::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { - Transform t = *this; +Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { + Transform3D t = *this; t.set_look_at(origin, p_target, p_up); return t; } -void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { #ifdef MATH_CHECKS ERR_FAIL_COND(p_eye == p_target); ERR_FAIL_COND(p_up.length() == 0); @@ -108,105 +108,119 @@ void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const origin = p_eye; } -Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) const { +Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const { /* not sure if very "efficient" but good enough? */ Vector3 src_scale = basis.get_scale(); - Quat src_rot = basis.get_rotation_quat(); + Quaternion src_rot = basis.get_rotation_quaternion(); Vector3 src_loc = origin; Vector3 dst_scale = p_transform.basis.get_scale(); - Quat dst_rot = p_transform.basis.get_rotation_quat(); + Quaternion dst_rot = p_transform.basis.get_rotation_quaternion(); Vector3 dst_loc = p_transform.origin; - Transform interp; - interp.basis.set_quat_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); + Transform3D interp; + interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); interp.origin = src_loc.lerp(dst_loc, p_c); return interp; } -void Transform::scale(const Vector3 &p_scale) { +void Transform3D::scale(const Vector3 &p_scale) { basis.scale(p_scale); origin *= p_scale; } -Transform Transform::scaled(const Vector3 &p_scale) const { - Transform t = *this; +Transform3D Transform3D::scaled(const Vector3 &p_scale) const { + Transform3D t = *this; t.scale(p_scale); return t; } -void Transform::scale_basis(const Vector3 &p_scale) { +void Transform3D::scale_basis(const Vector3 &p_scale) { basis.scale(p_scale); } -void Transform::translate(real_t p_tx, real_t p_ty, real_t p_tz) { +void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) { translate(Vector3(p_tx, p_ty, p_tz)); } -void Transform::translate(const Vector3 &p_translation) { +void Transform3D::translate(const Vector3 &p_translation) { for (int i = 0; i < 3; i++) { origin[i] += basis[i].dot(p_translation); } } -Transform Transform::translated(const Vector3 &p_translation) const { - Transform t = *this; +Transform3D Transform3D::translated(const Vector3 &p_translation) const { + Transform3D t = *this; t.translate(p_translation); return t; } -void Transform::orthonormalize() { +void Transform3D::orthonormalize() { basis.orthonormalize(); } -Transform Transform::orthonormalized() const { - Transform _copy = *this; +Transform3D Transform3D::orthonormalized() const { + Transform3D _copy = *this; _copy.orthonormalize(); return _copy; } -bool Transform::is_equal_approx(const Transform &p_transform) const { +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 Transform::operator==(const Transform &p_transform) const { +bool Transform3D::operator==(const Transform3D &p_transform) const { return (basis == p_transform.basis && origin == p_transform.origin); } -bool Transform::operator!=(const Transform &p_transform) const { +bool Transform3D::operator!=(const Transform3D &p_transform) const { return (basis != p_transform.basis || origin != p_transform.origin); } -void Transform::operator*=(const Transform &p_transform) { +void Transform3D::operator*=(const Transform3D &p_transform) { origin = xform(p_transform.origin); basis *= p_transform.basis; } -Transform Transform::operator*(const Transform &p_transform) const { - Transform t = *this; +Transform3D Transform3D::operator*(const Transform3D &p_transform) const { + Transform3D t = *this; t *= p_transform; return t; } -Transform::operator String() const { - return basis.operator String() + " - " + origin.operator String(); +void Transform3D::operator*=(const real_t p_val) { + origin *= p_val; + basis *= p_val; } -Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) : +Transform3D Transform3D::operator*(const real_t p_val) const { + Transform3D ret(*this); + ret *= p_val; + return ret; +} + +Transform3D::operator String() const { + return "[X: " + basis.get_axis(0).operator String() + + ", Y: " + basis.get_axis(1).operator String() + + ", Z: " + basis.get_axis(2).operator String() + + ", O: " + origin.operator String() + "]"; +} + +Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : basis(p_basis), origin(p_origin) { } -Transform::Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : +Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : origin(p_origin) { basis.set_axis(0, p_x); basis.set_axis(1, p_y); basis.set_axis(2, p_z); } -Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { +Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz); origin = Vector3(ox, oy, oz); } diff --git a/core/math/transform.h b/core/math/transform_3d.h index 1c05dbe554..3d8e70cec7 100644 --- a/core/math/transform.h +++ b/core/math/transform_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.h */ +/* transform_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -35,31 +35,31 @@ #include "core/math/basis.h" #include "core/math/plane.h" -class Transform { +class Transform3D { public: Basis basis; Vector3 origin; void invert(); - Transform inverse() const; + Transform3D inverse() const; void affine_invert(); - Transform affine_inverse() const; + Transform3D affine_inverse() const; - Transform rotated(const Vector3 &p_axis, real_t p_phi) const; + Transform3D rotated(const Vector3 &p_axis, real_t p_phi) const; void rotate(const Vector3 &p_axis, real_t p_phi); void rotate_basis(const Vector3 &p_axis, real_t p_phi); void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); - Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; + Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; void scale(const Vector3 &p_scale); - Transform scaled(const Vector3 &p_scale) const; + Transform3D scaled(const Vector3 &p_scale) const; void scale_basis(const Vector3 &p_scale); void translate(real_t p_tx, real_t p_ty, real_t p_tz); void translate(const Vector3 &p_translation); - Transform translated(const Vector3 &p_translation) const; + Transform3D translated(const Vector3 &p_translation) const; const Basis &get_basis() const { return basis; } void set_basis(const Basis &p_basis) { basis = p_basis; } @@ -68,11 +68,11 @@ public: void set_origin(const Vector3 &p_origin) { origin = p_origin; } void orthonormalize(); - Transform orthonormalized() const; - bool is_equal_approx(const Transform &p_transform) const; + Transform3D orthonormalized() const; + bool is_equal_approx(const Transform3D &p_transform) const; - bool operator==(const Transform &p_transform) const; - bool operator!=(const Transform &p_transform) const; + bool operator==(const Transform3D &p_transform) const; + bool operator!=(const Transform3D &p_transform) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; @@ -86,14 +86,16 @@ public: _FORCE_INLINE_ Vector<Vector3> xform(const Vector<Vector3> &p_array) const; _FORCE_INLINE_ Vector<Vector3> xform_inv(const Vector<Vector3> &p_array) const; - void operator*=(const Transform &p_transform); - Transform operator*(const Transform &p_transform) const; + void operator*=(const Transform3D &p_transform); + Transform3D operator*(const Transform3D &p_transform) const; + void operator*=(const real_t p_val); + Transform3D operator*(const real_t p_val) const; - Transform interpolate_with(const Transform &p_transform, real_t p_c) const; + Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; - _FORCE_INLINE_ Transform inverse_xform(const Transform &t) const { + _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const { Vector3 v = t.origin - origin; - return Transform(basis.transpose_xform(t.basis), + return Transform3D(basis.transpose_xform(t.basis), basis.xform(v)); } @@ -106,20 +108,20 @@ public: operator String() const; - Transform() {} - Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3()); - Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); - Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); + Transform3D() {} + Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()); + Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); + Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); }; -_FORCE_INLINE_ Vector3 Transform::xform(const Vector3 &p_vector) const { +_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const { return Vector3( basis[0].dot(p_vector) + origin.x, basis[1].dot(p_vector) + origin.y, basis[2].dot(p_vector) + origin.z); } -_FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { +_FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const { Vector3 v = p_vector - origin; return Vector3( @@ -128,7 +130,7 @@ _FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { (basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z)); } -_FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { +_FORCE_INLINE_ Plane Transform3D::xform(const Plane &p_plane) const { Vector3 point = p_plane.normal * p_plane.d; Vector3 point_dir = point + p_plane.normal; point = xform(point); @@ -141,7 +143,7 @@ _FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { return Plane(normal, d); } -_FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { +_FORCE_INLINE_ Plane Transform3D::xform_inv(const Plane &p_plane) const { Vector3 point = p_plane.normal * p_plane.d; Vector3 point_dir = point + p_plane.normal; point = xform_inv(point); @@ -154,7 +156,7 @@ _FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { return Plane(normal, d); } -_FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { +_FORCE_INLINE_ AABB Transform3D::xform(const AABB &p_aabb) const { /* http://dev.theomader.com/transform-bounding-boxes/ */ Vector3 min = p_aabb.position; Vector3 max = p_aabb.position + p_aabb.size; @@ -179,7 +181,7 @@ _FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { return r_aabb; } -_FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { +_FORCE_INLINE_ AABB Transform3D::xform_inv(const AABB &p_aabb) const { /* define vertices */ Vector3 vertices[8] = { Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z), @@ -203,7 +205,7 @@ _FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { return ret; } -Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const { +Vector<Vector3> Transform3D::xform(const Vector<Vector3> &p_array) const { Vector<Vector3> array; array.resize(p_array.size()); @@ -216,7 +218,7 @@ Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const { return array; } -Vector<Vector3> Transform::xform_inv(const Vector<Vector3> &p_array) const { +Vector<Vector3> Transform3D::xform_inv(const Vector<Vector3> &p_array) const { Vector<Vector3> array; array.resize(p_array.size()); diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 23c0c686a2..903d5951a8 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -600,7 +600,7 @@ bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *vertexptr = vertices.ptr(); const BVH *bvhptr = bvh.ptr(); - Transform scale(Basis().scaled(p_scale)); + Transform3D scale(Basis().scaled(p_scale)); int pos = bvh.size() - 1; diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 1d1dbc114b..463b0dd5c8 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -32,10 +32,10 @@ #define TRIANGLE_MESH_H #include "core/math/face3.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class TriangleMesh : public Reference { - GDCLASS(TriangleMesh, Reference); +class TriangleMesh : public RefCounted { + GDCLASS(TriangleMesh, RefCounted); struct Triangle { Vector3 normal; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index ea430b15c4..eb3301f5d0 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -193,6 +193,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); } +Vector2::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")"; +} + /* Vector2i */ Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const { @@ -269,3 +273,7 @@ bool Vector2i::operator==(const Vector2i &p_vec2) const { bool Vector2i::operator!=(const Vector2i &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } + +Vector2i::operator String() const { + return "(" + itos(x) + ", " + itos(y) + ")"; +} diff --git a/core/math/vector2.h b/core/math/vector2.h index b0d2049f55..78deb473b4 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -165,7 +165,7 @@ struct Vector2 { Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const; real_t aspect() const { return width / height; } - operator String() const { return String::num(x) + ", " + String::num(y); } + operator String() const; _FORCE_INLINE_ Vector2() {} _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { @@ -340,7 +340,7 @@ struct Vector2i { Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; - operator String() const { return String::num(x) + ", " + String::num(y); } + operator String() const; operator Vector2() const { return Vector2(x, y); } diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index d5ca985244..3d59064af6 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -126,5 +126,5 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const { } Vector3::operator String() const { - return (rtos(x) + ", " + rtos(y) + ", " + rtos(z)); + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")"; } diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp index a82db7f7fc..2de1e4e331 100644 --- a/core/math/vector3i.cpp +++ b/core/math/vector3i.cpp @@ -56,5 +56,5 @@ Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { } Vector3i::operator String() const { - return (itos(x) + ", " + itos(y) + ", " + itos(z)); + return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; } diff --git a/core/object/SCsub b/core/object/SCsub index 5d429960e5..dc116aeb19 100644 --- a/core/object/SCsub +++ b/core/object/SCsub @@ -2,6 +2,11 @@ Import("env") +import make_virtuals +from platform_methods import run_in_subprocess + +env.CommandNoCache(["gdvirtual.gen.inc"], "make_virtuals.py", run_in_subprocess(make_virtuals.run)) + env_object = env.Clone() env_object.add_source_files(env.core_sources, "*.cpp") diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index fb7eb42738..a10405dfae 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -501,12 +501,27 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam compat_classes[p_class] = p_fallback; } -Object *ClassDB::instance(const StringName &p_class) { +thread_local bool initializing_with_extension = false; +thread_local ObjectNativeExtension *initializing_extension = nullptr; +thread_local GDExtensionClassInstancePtr initializing_extension_instance = nullptr; + +void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance) { + if (initializing_with_extension) { + *r_extension = initializing_extension; + *r_extension_instance = initializing_extension_instance; + initializing_with_extension = false; + } else { + *r_extension = nullptr; + *r_extension_instance = nullptr; + } +} + +Object *ClassDB::instantiate(const StringName &p_class) { ClassInfo *ti; { OBJTYPE_RLOCK; ti = classes.getptr(p_class); - if (!ti || ti->disabled || !ti->creation_func) { + if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) { if (compat_classes.has(p_class)) { ti = classes.getptr(compat_classes[p_class]); } @@ -521,10 +536,15 @@ Object *ClassDB::instance(const StringName &p_class) { return nullptr; } #endif + if (ti->native_extension) { + initializing_with_extension = true; + initializing_extension = ti->native_extension; + initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->class_userdata); + } return ti->creation_func(); } -bool ClassDB::can_instance(const StringName &p_class) { +bool ClassDB::can_instantiate(const StringName &p_class) { OBJTYPE_RLOCK; ClassInfo *ti = classes.getptr(p_class); @@ -534,7 +554,7 @@ bool ClassDB::can_instance(const StringName &p_class) { return false; } #endif - return (!ti->disabled && ti->creation_func != nullptr); + return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance)); } void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { @@ -1310,6 +1330,24 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe return false; } +void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) { + ClassInfo *type = classes.getptr(p_class); + if (!type) { + ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'."); + } + + if (type->method_map.has(p_method->get_name())) { + // overloading not supported + ERR_FAIL_MSG("Method already bound '" + p_class + "::" + p_method->get_name() + "'."); + } + +#ifdef DEBUG_METHODS_ENABLED + type->method_order.push_back(p_method->get_name()); +#endif + + type->method_map[p_method->get_name()] = p_method; +} + #ifdef DEBUG_METHODS_ENABLED MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname = method_name.name; @@ -1484,8 +1522,8 @@ 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_instance(p_class)) { - c = ClassDB::instance(p_class); + } else if (ClassDB::can_instantiate(p_class)) { + c = ClassDB::instantiate(p_class); cleanup_c = true; } @@ -1545,6 +1583,31 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con return var; } +void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) { + GLOBAL_LOCK_FUNCTION; + + ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name)); + ERR_FAIL_COND_MSG(classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name)); + + ClassInfo *parent = classes.getptr(p_extension->parent_class_name); + + ClassInfo c; + c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION; + c.native_extension = p_extension; + c.name = p_extension->class_name; + c.creation_func = parent->creation_func; + c.inherits = parent->name; + c.class_ptr = parent->class_ptr; + c.inherits_ptr = parent; + + classes[p_extension->class_name] = c; +} + +void ClassDB::unregister_extension_class(const StringName &p_class) { + ERR_FAIL_COND(!classes.has(p_class)); + classes.erase(p_class); +} + RWLock ClassDB::lock; void ClassDB::cleanup_defaults() { diff --git a/core/object/class_db.h b/core/object/class_db.h index 6fd5748dbb..af528bfde7 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -97,6 +97,8 @@ public: enum APIType { API_CORE, API_EDITOR, + API_EXTENSION, + API_EDITOR_EXTENSION, API_NONE }; @@ -115,6 +117,8 @@ public: ClassInfo *inherits_ptr = nullptr; void *class_ptr = nullptr; + ObjectNativeExtension *native_extension = nullptr; + HashMap<StringName, MethodBind *> method_map; HashMap<StringName, int> constant_map; HashMap<StringName, List<StringName>> enum_map; @@ -199,6 +203,9 @@ public: //nothing } + static void register_extension_class(ObjectNativeExtension *p_extension); + static void unregister_extension_class(const StringName &p_class); + template <class T> static Object *_create_ptr_func() { return T::create(); @@ -224,8 +231,10 @@ public: static StringName get_compatibility_remapped_class(const StringName &p_class); static bool class_exists(const StringName &p_class); static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); - static bool can_instance(const StringName &p_class); - static Object *instance(const StringName &p_class); + static bool can_instantiate(const StringName &p_class); + static Object *instantiate(const StringName &p_class); + static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance); + static APIType get_api_type(const StringName &p_class); static uint64_t get_api_hash(APIType p_api); @@ -334,6 +343,8 @@ public: return bind; } + static void bind_method_custom(const StringName &p_class, MethodBind *p_method); + static void add_signal(StringName p_class, const MethodInfo &p_signal); static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false); static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal); diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py new file mode 100644 index 0000000000..2c6b8cddc9 --- /dev/null +++ b/core/object/make_virtuals.py @@ -0,0 +1,152 @@ +proto = """ +#define GDVIRTUAL$VER($RET m_name $ARG) \\ +GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\ +StringName _gdvirtual_##m_name##_sn = #m_name;\\ +bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ + ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\ + if (script_instance) {\\ + Callable::CallError ce; \\ + $CALLSIARGS\\ + $CALLSIBEGINscript_instance->call(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\ + if (ce.error == Callable::CallError::CALL_OK) {\\ + $CALLSIRET\\ + return true;\\ + } \\ + }\\ + if (_gdvirtual_##m_name) {\\ + $CALLPTRARGS\\ + $CALLPTRRETDEF\\ + _gdvirtual_##m_name(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\ + $CALLPTRRET\\ + return true;\\ + }\\ +\\ + return false;\\ +}\\ +\\ +_FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() { \\ + MethodInfo method_info;\\ + method_info.name = #m_name;\\ + method_info.flags = METHOD_FLAG_VIRTUAL;\\ + $FILL_METHOD_INFO\\ + return method_info;\\ +} + + +""" + + +def generate_version(argcount, const=False, returns=False): + s = proto + sproto = str(argcount) + method_info = "" + if returns: + sproto += "R" + s = s.replace("$RET", "m_ret, ") + s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;") + method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n" + else: + s = s.replace("$RET", "") + s = s.replace("$CALLPTRRETDEF", "") + + if const: + sproto += "C" + s = s.replace("$CONST", "const") + method_info += "\tmethod_info.flags|=METHOD_FLAG_CONST;\\\n" + else: + s = s.replace("$CONST", "") + + s = s.replace("$VER", sproto) + argtext = "" + callargtext = "" + callsiargs = "" + callsiargptrs = "" + callptrargsptr = "" + if argcount > 0: + argtext += ", " + callsiargs = "Variant vargs[" + str(argcount) + "]={" + callsiargptrs = "\t\tconst Variant *vargptrs[" + str(argcount) + "]={" + callptrargsptr = "\t\tconst GDNativeTypePtr argptrs[" + str(argcount) + "]={" + callptrargs = "" + for i in range(argcount): + if i > 0: + argtext += ", " + callargtext += ", " + callsiargs += ", " + callsiargptrs += ", " + callptrargs += "\t\t" + callptrargsptr += ", " + argtext += "m_type" + str(i + 1) + callargtext += "const m_type" + str(i + 1) + "& arg" + str(i + 1) + callsiargs += "Variant(arg" + str(i + 1) + ")" + callsiargptrs += "&vargs[" + str(i) + "]" + callptrargs += ( + "PtrToArg<m_type" + str(i + 1) + ">::EncodeT argval" + str(i + 1) + " = arg" + str(i + 1) + ";\\\n" + ) + callptrargsptr += "&argval" + str(i + 1) + method_info += "\tmethod_info.arguments.push_back(GetTypeInfo<m_type" + str(i + 1) + ">::get_class_info());\\\n" + + if argcount: + callsiargs += "};\\\n" + callsiargptrs += "};\\\n" + s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs) + s = s.replace("$CALLSIARGPASS", "(const Variant **)vargptrs," + str(argcount)) + callptrargsptr += "};\\\n" + s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr) + s = s.replace("$CALLPTRARGPASS", "(const GDNativeTypePtr*)argptrs") + else: + s = s.replace("$CALLSIARGS", "") + s = s.replace("$CALLSIARGPASS", "nullptr, 0") + s = s.replace("$CALLPTRARGS", "") + s = s.replace("$CALLPTRARGPASS", "nullptr") + + if returns: + if argcount > 0: + callargtext += "," + callargtext += " m_ret& r_ret" + s = s.replace("$CALLSIBEGIN", "Variant ret = ") + s = s.replace("$CALLSIRET", "r_ret = ret;") + s = s.replace("$CALLPTRRETPASS", "&ret") + s = s.replace("$CALLPTRRET", "r_ret = ret;") + else: + s = s.replace("$CALLSIBEGIN", "") + s = s.replace("$CALLSIRET", "") + s = s.replace("$CALLPTRRETPASS", "nullptr") + s = s.replace("$CALLPTRRET", "") + + s = s.replace("$ARG", argtext) + s = s.replace("$CALLARGS", callargtext) + s = s.replace("$FILL_METHOD_INFO", method_info) + + return s + + +def run(target, source, env): + + max_versions = 12 + + txt = """ +#ifndef GDVIRTUAL_GEN_H +#define GDVIRTUAL_GEN_H + + +""" + + for i in range(max_versions + 1): + + txt += "/* " + str(i) + " Arguments */\n\n" + txt += generate_version(i, False, False) + txt += generate_version(i, False, True) + txt += generate_version(i, True, False) + txt += generate_version(i, True, True) + + txt += "#endif" + + with open(target[0], "w") as f: + f.write(txt) + + +if __name__ == "__main__": + from platform_methods import subprocess_main + + subprocess_main(globals()) diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp index 9c5ed60708..c53104fe3f 100644 --- a/core/object/method_bind.cpp +++ b/core/object/method_bind.cpp @@ -34,6 +34,35 @@ #include "method_bind.h" +uint32_t MethodBind::get_hash() const { + uint32_t hash = hash_djb2_one_32(has_return() ? 1 : 0); + hash = hash_djb2_one_32(get_argument_count(), hash); + +#ifndef _MSC_VER +#warning This needs proper class name and argument type for hashing +#endif +#if 0 + + for (int i = (has_return() ? -1 : 0); i < get_argument_count(); i++) { + PropertyInfo pi = i == -1 ? get_return_info() : get_argument_info(i); + hash = hash_djb2_one_32(get_argument_type(i), hash); + if (pi.class_name != StringName()) { + hash = hash_djb2_one_32(pi.class_name.operator String().hash(), hash); + } + } +#endif + hash = hash_djb2_one_32(get_default_argument_count(), hash); + for (int i = 0; i < get_default_argument_count(); i++) { + Variant v = get_default_argument(i); + hash = hash_djb2_one_32(v.hash(), hash); + } + + hash = hash_djb2_one_32(is_const(), hash); + hash = hash_djb2_one_32(is_vararg(), hash); + + return hash; +} + #ifdef DEBUG_METHODS_ENABLED PropertyInfo MethodBind::get_argument_info(int p_argument) const { ERR_FAIL_INDEX_V(p_argument, get_argument_count(), PropertyInfo()); diff --git a/core/object/method_bind.h b/core/object/method_bind.h index 7030ae201b..92b964772a 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -135,6 +135,8 @@ public: void set_default_arguments(const Vector<Variant> &p_defargs); + uint32_t get_hash() const; + MethodBind(); virtual ~MethodBind(); }; diff --git a/core/object/object.cpp b/core/object/object.cpp index a8b2c4a939..296d876701 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -385,6 +385,23 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid } } + if (_extension && _extension->set) { +// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + if (_extension->set(_extension_instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value)) { + if (r_valid) { + *r_valid = true; + } + return; + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + } + //try built-in setgetter { if (ClassDB::set_property(this, p_name, p_value, r_valid)) { @@ -450,6 +467,23 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { return ret; } } + if (_extension && _extension->get) { +// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + + if (_extension->get(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) { + if (r_valid) { + *r_valid = true; + } + return ret; + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + } //try built-in setgetter { @@ -596,6 +630,17 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons _get_property_listv(p_list, p_reversed); + if (_extension && _extension->get_property_list) { + uint32_t pcount; + const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount); + for (uint32_t i = 0; i < pcount; i++) { + p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name)); + } + if (_extension->free_property_list) { + _extension->free_property_list(_extension_instance, pinfo); + } + } + if (!is_class("Script")) { // can still be set, but this is for user-friendliness p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT)); } @@ -740,7 +785,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; return Variant(); } - if (Object::cast_to<Reference>(this)) { + if (Object::cast_to<RefCounted>(this)) { r_error.argument = 0; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); @@ -761,6 +806,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a Variant ret; OBJ_DEBUG_LOCK + if (script_instance) { ret = script_instance->call(p_method, p_args, p_argcount, r_error); //force jumptable @@ -778,6 +824,8 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a } } + //extension does not need this, because all methods are registered in MethodBind + MethodBind *method = ClassDB::get_method(get_class_name(), p_method); if (method) { @@ -795,6 +843,10 @@ void Object::notification(int p_notification, bool p_reversed) { if (script_instance) { script_instance->notification(p_notification); } + + if (_extension && _extension->notification) { + _extension->notification(_extension_instance, p_notification); + } } String Object::to_string() { @@ -805,6 +857,9 @@ String Object::to_string() { return ret; } } + if (_extension && _extension->to_string) { + return _extension->to_string(_extension_instance); + } return "[" + get_class() + ":" + itos(get_instance_id()) + "]"; } @@ -832,7 +887,7 @@ void Object::set_script(const Variant &p_script) { Ref<Script> s = script; if (!s.is_null()) { - if (s->can_instance()) { + if (s->can_instantiate()) { OBJ_DEBUG_LOCK script_instance = s->instance_create(this); } else if (Engine::get_singleton()->is_editor_hint()) { @@ -881,7 +936,7 @@ void Object::set_meta(const String &p_name, const Variant &p_value) { } Variant Object::get_meta(const String &p_name) const { - ERR_FAIL_COND_V(!metadata.has(p_name), Variant()); + ERR_FAIL_COND_V_MSG(!metadata.has(p_name), Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'."); return metadata[p_name]; } @@ -1248,10 +1303,10 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons } Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) { - ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null."); Object *target_object = p_callable.get_object(); - ERR_FAIL_COND_V(!target_object, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(!target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null."); SignalData *s = signal_map.getptr(p_signal); if (!s) { @@ -1309,7 +1364,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co } bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const { - ERR_FAIL_COND_V(p_callable.is_null(), false); + ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null."); const SignalData *s = signal_map.getptr(p_signal); if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); @@ -1336,10 +1391,10 @@ void Object::disconnect(const StringName &p_signal, const Callable &p_callable) } void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) { - ERR_FAIL_COND(p_callable.is_null()); + ERR_FAIL_COND_MSG(p_callable.is_null(), "Cannot disconnect from '" + p_signal + "': the provided callable is null."); Object *target_object = p_callable.get_object(); - ERR_FAIL_COND(!target_object); + ERR_FAIL_COND_MSG(!target_object, "Cannot disconnect '" + p_signal + "' from callable '" + p_callable + "': the callable object is null."); SignalData *s = signal_map.getptr(p_signal); if (!s) { @@ -1714,42 +1769,43 @@ uint32_t Object::get_edited_version() const { } #endif -void *Object::get_script_instance_binding(int p_script_language_index) { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr); -#endif - - //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync - //just return the same pointer. - //if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it - //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards - - if (!_script_instance_bindings[p_script_language_index]) { - void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this); - if (script_data) { - instance_binding_count.increment(); - _script_instance_bindings[p_script_language_index] = script_data; +void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) { + void *binding = nullptr; + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].token == p_token) { + binding = _instance_bindings[i].binding; + break; } } + if (unlikely(!binding)) { + uint32_t current_size = next_power_of_2(_instance_binding_count); + uint32_t new_size = next_power_of_2(_instance_binding_count + 1); - return _script_instance_bindings[p_script_language_index]; -} + if (current_size == 0 || new_size > current_size) { + _instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding)); + } -bool Object::has_script_instance_binding(int p_script_language_index) { - return _script_instance_bindings[p_script_language_index] != nullptr; -} + _instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback; + _instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback; + _instance_bindings[_instance_binding_count].token = p_token; -void Object::set_script_instance_binding(int p_script_language_index, void *p_data) { -#ifdef DEBUG_ENABLED - CRASH_COND(_script_instance_bindings[p_script_language_index] != nullptr); -#endif - _script_instance_bindings[p_script_language_index] = p_data; + binding = p_callbacks->create_callback(p_token, this); + _instance_bindings[_instance_binding_count].binding = binding; + + _instance_binding_count++; + } + + _instance_binding_mutex.unlock(); + + return binding; } void Object::_construct_object(bool p_reference) { type_is_reference = p_reference; _instance_id = ObjectDB::add_instance(this); - memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); + + ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance); #ifdef DEBUG_ENABLED _lock_index.init(1); @@ -1770,6 +1826,12 @@ Object::~Object() { } script_instance = nullptr; + if (_extension && _extension->free_instance) { + _extension->free_instance(_extension->class_userdata, _extension_instance); + _extension = nullptr; + _extension_instance = nullptr; + } + const StringName *S = nullptr; if (_emitting) { @@ -1801,12 +1863,13 @@ Object::~Object() { _instance_id = ObjectID(); _predelete_ok = 2; - if (!ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]); + if (_instance_bindings != nullptr) { + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].free_callback) { + _instance_bindings[i].free_callback(_instance_bindings[i].token, _instance_bindings[i].binding, this); } } + memfree(_instance_bindings); } } @@ -1824,7 +1887,6 @@ void ObjectDB::debug_objects(DebugFunc p_func) { for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) { if (object_slots[i].validator) { p_func(object_slots[i].object); - count--; } } @@ -1853,7 +1915,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max); for (uint32_t i = slot_max; i < new_slot_max; i++) { object_slots[i].object = nullptr; - object_slots[i].is_reference = false; + object_slots[i].is_ref_counted = false; object_slots[i].next_free = i; object_slots[i].validator = 0; } @@ -1866,7 +1928,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID()); } object_slots[slot].object = p_object; - object_slots[slot].is_reference = p_object->is_reference(); + object_slots[slot].is_ref_counted = p_object->is_ref_counted(); validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK; if (unlikely(validator_counter == 0)) { validator_counter = 1; @@ -1877,7 +1939,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { id <<= OBJECTDB_SLOT_MAX_COUNT_BITS; id |= uint64_t(slot); - if (p_object->is_reference()) { + if (p_object->is_ref_counted()) { id |= OBJECTDB_REFERENCE_BIT; } @@ -1915,7 +1977,7 @@ void ObjectDB::remove_instance(Object *p_object) { object_slots[slot_count].next_free = slot; //invalidate, so checks against it fail object_slots[slot].validator = 0; - object_slots[slot].is_reference = false; + object_slots[slot].is_ref_counted = false; object_slots[slot].object = nullptr; spin_lock.unlock(); @@ -1950,7 +2012,7 @@ void ObjectDB::cleanup() { extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); } - uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_reference ? OBJECTDB_REFERENCE_BIT : 0); + uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0); print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); count--; diff --git a/core/object/object.h b/core/object/object.h index 448a33d3bc..8389d80afc 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -31,6 +31,7 @@ #ifndef OBJECT_H #define OBJECT_H +#include "core/extension/gdnative_interface.h" #include "core/object/object_id.h" #include "core/os/rw_lock.h" #include "core/os/spin_lock.h" @@ -57,8 +58,7 @@ enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. - PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional" - PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit + PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range. PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) @@ -101,6 +101,7 @@ enum PropertyHint { }; enum PropertyUsageFlags { + PROPERTY_USAGE_NONE = 0, PROPERTY_USAGE_STORAGE = 1, PROPERTY_USAGE_EDITOR = 2, PROPERTY_USAGE_NETWORK = 4, @@ -150,7 +151,7 @@ struct PropertyInfo { String hint_string; uint32_t usage = PROPERTY_USAGE_DEFAULT; - _FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const { + _FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const { PropertyInfo pi = *this; pi.usage |= p_fl; return pi; @@ -162,7 +163,7 @@ struct PropertyInfo { PropertyInfo() {} - PropertyInfo(Variant::Type p_type, const String p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) : + PropertyInfo(const Variant::Type p_type, const String p_name, const PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", const uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) : type(p_type), name(p_name), hint(p_hint), @@ -238,6 +239,44 @@ struct MethodInfo { ////else //return nullptr; +// API used to extend in GDNative and other C compatible compiled languages +class MethodBind; + +struct ObjectNativeExtension { + ObjectNativeExtension *parent = nullptr; + List<ObjectNativeExtension *> children; + StringName parent_class_name; + StringName class_name; + bool editor_class = false; + GDNativeExtensionClassSet set; + GDNativeExtensionClassGet get; + GDNativeExtensionClassGetPropertyList get_property_list; + GDNativeExtensionClassFreePropertyList free_property_list; + GDNativeExtensionClassNotification notification; + GDNativeExtensionClassToString to_string; + GDNativeExtensionClassReference reference; + GDNativeExtensionClassReference unreference; + + _FORCE_INLINE_ bool is_class(const String &p_class) const { + const ObjectNativeExtension *e = this; + while (e) { + if (p_class == e->class_name.operator String()) { + return true; + } + e = e->parent; + } + return false; + } + void *class_userdata = nullptr; + + GDNativeExtensionClassCreateInstance create_instance; + GDNativeExtensionClassFreeInstance free_instance; + GDNativeExtensionClassGetVirtual get_virtual; +}; + +#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__) +#define GDVIRTUAL_BIND(m_name) ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info()); + /* the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model. */ @@ -262,9 +301,15 @@ private: \ public: \ virtual String get_class() const override { \ + if (_get_extension()) { \ + return _get_extension()->class_name.operator String(); \ + } \ return String(#m_class); \ } \ virtual const StringName *_get_class_namev() const override { \ + if (_get_extension()) { \ + return &_get_extension()->class_name; \ + } \ if (!_class_name) { \ _class_name = get_class_static(); \ } \ @@ -297,7 +342,12 @@ public: static String inherits_static() { \ return String(#m_inherits); \ } \ - virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \ + virtual bool is_class(const String &p_class) const override { \ + if (_get_extension() && _get_extension()->is_class(p_class)) { \ + return true; \ + } \ + return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \ + } \ virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \ \ static void get_valid_parents_static(List<String> *p_parents) { \ @@ -430,16 +480,15 @@ public: }; private: - enum { - MAX_SCRIPT_INSTANCE_BINDINGS = 8 - }; - #ifdef DEBUG_ENABLED friend struct _ObjectDebugLock; #endif friend bool predelete_handler(Object *); friend void postinitialize_handler(Object *); + ObjectNativeExtension *_extension = nullptr; + GDExtensionClassInstancePtr _extension_instance = nullptr; + struct SignalData { struct Slot { int reference_count = 0; @@ -487,14 +536,40 @@ private: _FORCE_INLINE_ void _construct_object(bool p_reference); - friend class Reference; + friend class RefCounted; bool type_is_reference = false; - SafeNumeric<uint32_t> instance_binding_count; - void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; + + std::mutex _instance_binding_mutex; + struct InstanceBinding { + void *binding; + void *token; + GDNativeInstanceBindingFreeCallback free_callback = nullptr; + GDNativeInstanceBindingReferenceCallback reference_callback = nullptr; + }; + InstanceBinding *_instance_bindings = nullptr; + uint32_t _instance_binding_count = 0; Object(bool p_reference); protected: + _FORCE_INLINE_ bool _instance_binding_reference(bool p_reference) { + bool can_die = true; + if (_instance_bindings) { + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].reference_callback) { + if (!_instance_bindings[i].reference_callback(_instance_bindings[i].token, _instance_bindings[i].binding, p_reference)) { + can_die = false; + } + } + } + _instance_binding_mutex.unlock(); + } + return can_die; + } + friend class NativeExtensionMethodBind; + _ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; } + _ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; } virtual void _initialize_classv() { initialize_class(); } virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; }; virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; }; @@ -610,13 +685,25 @@ public: static String get_parent_class_static() { return String(); } static String get_category_static() { return String(); } - virtual String get_class() const { return "Object"; } + virtual String get_class() const { + if (_extension) + return _extension->class_name.operator String(); + return "Object"; + } virtual String get_save_class() const { return get_class(); } //class stored when saving - virtual bool is_class(const String &p_class) const { return (p_class == "Object"); } + virtual bool is_class(const String &p_class) const { + if (_extension && _extension->is_class(p_class)) { + return true; + } + return (p_class == "Object"); + } virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; } _FORCE_INLINE_ const StringName &get_class_name() const { + if (_extension) { + return _extension->class_name; + } if (!_class_ptr) { return *_get_class_namev(); } else { @@ -717,13 +804,11 @@ public: #endif //used by script languages to store binding data - void *get_script_instance_binding(int p_script_language_index); - bool has_script_instance_binding(int p_script_language_index); - void set_script_instance_binding(int p_script_language_index, void *p_data); + void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks); void clear_internal_resource_paths(); - _ALWAYS_INLINE_ bool is_reference() const { return type_is_reference; } + _ALWAYS_INLINE_ bool is_ref_counted() const { return type_is_reference; } Object(); virtual ~Object(); @@ -743,7 +828,7 @@ class ObjectDB { struct ObjectSlot { //128 bits per slot uint64_t validator : OBJECTDB_VALIDATOR_BITS; uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS; - uint64_t is_reference : 1; + uint64_t is_ref_counted : 1; Object *object; }; diff --git a/core/object/object_id.h b/core/object/object_id.h index 7f2496ad48..0666ec0855 100644 --- a/core/object/object_id.h +++ b/core/object/object_id.h @@ -42,7 +42,7 @@ class ObjectID { uint64_t id = 0; public: - _ALWAYS_INLINE_ bool is_reference() const { return (id & (uint64_t(1) << 63)) != 0; } + _ALWAYS_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; } _ALWAYS_INLINE_ bool is_valid() const { return id != 0; } _ALWAYS_INLINE_ bool is_null() const { return id == 0; } _ALWAYS_INLINE_ operator uint64_t() const { return id; } diff --git a/core/object/reference.cpp b/core/object/ref_counted.cpp index 22e4e8a336..2833f774dc 100644 --- a/core/object/reference.cpp +++ b/core/object/ref_counted.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* reference.cpp */ +/* ref_counted.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "reference.h" +#include "ref_counted.h" #include "core/object/script_language.h" -bool Reference::init_ref() { +bool RefCounted::init_ref() { if (reference()) { if (!is_referenced() && refcount_init.unref()) { unreference(); // first referencing is already 1, so compensate for the ref above @@ -44,17 +44,17 @@ bool Reference::init_ref() { } } -void Reference::_bind_methods() { - ClassDB::bind_method(D_METHOD("init_ref"), &Reference::init_ref); - ClassDB::bind_method(D_METHOD("reference"), &Reference::reference); - ClassDB::bind_method(D_METHOD("unreference"), &Reference::unreference); +void RefCounted::_bind_methods() { + ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref); + ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference); + ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference); } -int Reference::reference_get_count() const { +int RefCounted::reference_get_count() const { return refcount.get(); } -bool Reference::reference() { +bool RefCounted::reference() { uint32_t rc_val = refcount.refval(); bool success = rc_val != 0; @@ -62,19 +62,17 @@ bool Reference::reference() { if (get_script_instance()) { get_script_instance()->refcount_incremented(); } - if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->refcount_incremented_instance_binding(this); - } - } + if (_get_extension() && _get_extension()->reference) { + _get_extension()->reference(_get_extension_instance()); } + + _instance_binding_reference(true); } return success; } -bool Reference::unreference() { +bool RefCounted::unreference() { uint32_t rc_val = refcount.unrefval(); bool die = rc_val == 0; @@ -83,20 +81,17 @@ bool Reference::unreference() { bool script_ret = get_script_instance()->refcount_decremented(); die = die && script_ret; } - if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this); - die = die && script_ret; - } - } + if (_get_extension() && _get_extension()->unreference) { + _get_extension()->unreference(_get_extension_instance()); } + + die = die && _instance_binding_reference(false); } return die; } -Reference::Reference() : +RefCounted::RefCounted() : Object(true) { refcount.init(); refcount_init.init(); @@ -111,7 +106,7 @@ Variant WeakRef::get_ref() const { if (!obj) { return Variant(); } - Reference *r = cast_to<Reference>(obj); + RefCounted *r = cast_to<RefCounted>(obj); if (r) { return REF(r); } diff --git a/core/object/reference.h b/core/object/ref_counted.h index d02cb12069..e0af2c18bb 100644 --- a/core/object/reference.h +++ b/core/object/ref_counted.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* reference.h */ +/* ref_counted.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REFERENCE_H -#define REFERENCE_H +#ifndef REF_COUNTED_H +#define REF_COUNTED_H #include "core/object/class_db.h" #include "core/templates/safe_refcount.h" -class Reference : public Object { - GDCLASS(Reference, Object); +class RefCounted : public Object { + GDCLASS(RefCounted, Object); SafeRefCount refcount; SafeRefCount refcount_init; @@ -49,8 +49,8 @@ public: bool unreference(); int reference_get_count() const; - Reference(); - ~Reference() {} + RefCounted(); + ~RefCounted() {} }; template <class T> @@ -78,7 +78,7 @@ class Ref { } } - //virtual Reference * get_reference() const { return reference; } + //virtual RefCounted * get_reference() const { return reference; } public: _FORCE_INLINE_ bool operator==(const T *p_ptr) const { return reference == p_ptr; @@ -130,7 +130,7 @@ public: template <class T_Other> void operator=(const Ref<T_Other> &p_from) { - Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr())); + RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); if (!refb) { unref(); return; @@ -179,7 +179,7 @@ public: template <class T_Other> Ref(const Ref<T_Other> &p_from) { - Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr())); + RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); if (!refb) { unref(); return; @@ -213,7 +213,7 @@ public: inline bool is_null() const { return reference == nullptr; } void unref() { - //TODO this should be moved to mutexes, since this engine does not really + // TODO: this should be moved to mutexes, since this engine does not really // do a lot of referencing on references and stuff // mutexes will avoid more crashes? @@ -223,7 +223,7 @@ public: reference = nullptr; } - void instance() { + void instantiate() { ref(memnew(T)); } @@ -234,10 +234,10 @@ public: } }; -typedef Ref<Reference> REF; +typedef Ref<RefCounted> REF; -class WeakRef : public Reference { - GDCLASS(WeakRef, Reference); +class WeakRef : public RefCounted { + GDCLASS(WeakRef, RefCounted); ObjectID ref; @@ -258,13 +258,17 @@ struct PtrToArg<Ref<T>> { 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) { - *(Ref<Reference> *)p_ptr = p_val; + *(Ref<RefCounted> *)p_ptr = p_val; } }; template <class T> struct PtrToArg<const Ref<T> &> { + typedef Ref<T> EncodeT; + _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { return Ref<T>((T *)p_ptr); } @@ -294,4 +298,4 @@ struct GetTypeInfo<const Ref<T> &> { #endif // DEBUG_METHODS_ENABLED -#endif // REFERENCE_H +#endif // REF_COUNTED_H diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 42fb0a0caf..626a7413e7 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -100,7 +100,7 @@ Dictionary Script::_get_script_constant_map() { } void Script::_bind_methods() { - ClassDB::bind_method(D_METHOD("can_instance"), &Script::can_instance); + ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate); //ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create); ClassDB::bind_method(D_METHOD("instance_has", "base_object"), &Script::instance_has); ClassDB::bind_method(D_METHOD("has_source_code"), &Script::has_source_code); @@ -120,7 +120,7 @@ void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code"); } void ScriptServer::set_scripting_enabled(bool p_enabled) { @@ -353,10 +353,10 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const p_core_type_words->push_back("Vector3i"); p_core_type_words->push_back("Transform2D"); p_core_type_words->push_back("Plane"); - p_core_type_words->push_back("Quat"); + p_core_type_words->push_back("Quaternion"); p_core_type_words->push_back("AABB"); p_core_type_words->push_back("Basis"); - p_core_type_words->push_back("Transform"); + p_core_type_words->push_back("Transform3D"); p_core_type_words->push_back("Color"); p_core_type_words->push_back("StringName"); p_core_type_words->push_back("NodePath"); @@ -585,14 +585,6 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam return Variant(); } -uint16_t PlaceHolderScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return UINT16_MAX; -} - -uint16_t PlaceHolderScriptInstance::get_rset_property_id(const StringName &p_method) const { - return UINT16_MAX; -} - PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) : owner(p_owner), language(p_language), diff --git a/core/object/script_language.h b/core/object/script_language.h index 9ed3c7e80f..2cbaa0f52e 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -41,21 +41,6 @@ class ScriptLanguage; typedef void (*ScriptEditRequestFunction)(const String &p_path); -struct ScriptNetData { - StringName name; - MultiplayerAPI::RPCMode mode; - bool operator==(ScriptNetData const &p_other) const { - return name == p_other.name; - } -}; - -struct SortNetData { - StringName::AlphCompare compare; - bool operator()(const ScriptNetData &p_a, const ScriptNetData &p_b) const { - return compare(p_a.name, p_b.name); - } -}; - class ScriptServer { enum { MAX_LANGUAGES = 16 @@ -130,7 +115,7 @@ protected: Dictionary _get_script_constant_map(); public: - virtual bool can_instance() const = 0; + virtual bool can_instantiate() const = 0; virtual Ref<Script> get_base_script() const = 0; //for script inheritance @@ -174,17 +159,7 @@ public: virtual bool is_placeholder_fallback_enabled() const { return false; } - virtual Vector<ScriptNetData> get_rpc_methods() const = 0; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; - - virtual Vector<ScriptNetData> get_rset_properties() const = 0; - virtual uint16_t get_rset_property_id(const StringName &p_property) const = 0; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; Script() {} }; @@ -225,17 +200,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); - virtual Vector<ScriptNetData> get_rpc_methods() const = 0; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0; - virtual StringName get_rpc_method(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; - - virtual Vector<ScriptNetData> get_rset_properties() const = 0; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const = 0; - virtual StringName get_rset_property(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); @@ -303,6 +268,12 @@ public: String message; }; + struct ScriptError { + int line = -1; + int column = -1; + String message; + }; + void get_core_type_words(List<String> *p_core_type_words) const; virtual void get_reserved_words(List<String> *p_words) const = 0; virtual bool is_control_flow_keyword(String p_string) const = 0; @@ -311,7 +282,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0; virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {} virtual bool is_using_templates() { return false; } - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0; virtual String validate_path(const String &p_path) const { return ""; } virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; @@ -447,17 +418,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr); - virtual Vector<ScriptNetData> get_rpc_methods() const { return Vector<ScriptNetData>(); } - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const { return StringName(); } - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - - virtual Vector<ScriptNetData> get_rset_properties() const { return Vector<ScriptNetData>(); } - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const { return StringName(); } - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; } + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); } PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner); ~PlaceHolderScriptInstance(); diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index e8735e335c..96c96c1efb 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -122,8 +122,8 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_METHOD; @@ -148,8 +148,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_METHOD; @@ -167,8 +167,8 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_PROPERTY; @@ -189,8 +189,8 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_PROPERTY; @@ -205,8 +205,8 @@ void UndoRedo::add_do_reference(Object *p_object) { ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_REFERENCE; @@ -225,8 +225,8 @@ void UndoRedo::add_undo_reference(Object *p_object) { Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_REFERENCE; diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index a08ca7792f..8f009830e3 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -32,7 +32,7 @@ #define UNDO_REDO_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class UndoRedo : public Object { GDCLASS(UndoRedo, Object); @@ -61,7 +61,7 @@ private: }; Type type; - Ref<Reference> ref; + Ref<RefCounted> ref; ObjectID object; StringName name; Variant args[VARIANT_ARG_MAX]; diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 25a09fe98f..34e944709b 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -32,7 +32,7 @@ #define MAIN_LOOP_H #include "core/input/input_event.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" class MainLoop : public Object { diff --git a/core/os/memory.h b/core/os/memory.h index 10e678103d..9d09626b8c 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -80,7 +80,7 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d #define memalloc(m_size) Memory::alloc_static(m_size) #define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size) -#define memfree(m_size) Memory::free_static(m_size) +#define memfree(m_mem) Memory::free_static(m_mem) _ALWAYS_INLINE_ void postinitialize_handler(void *) {} diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp index a8be84c56c..ee87346dfc 100644 --- a/core/os/midi_driver.cpp +++ b/core/os/midi_driver.cpp @@ -45,23 +45,23 @@ void MIDIDriver::set_singleton() { void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) { Ref<InputEventMIDI> event; - event.instance(); + event.instantiate(); uint32_t param_position = 1; if (length >= 1) { if (data[0] >= 0xF0) { // channel does not apply to system common messages event->set_channel(0); - event->set_message(data[0]); + event->set_message(MIDIMessage(data[0])); last_received_message = data[0]; } else if ((data[0] & 0x80) == 0x00) { // running status event->set_channel(last_received_message & 0xF); - event->set_message(last_received_message >> 4); + event->set_message(MIDIMessage(last_received_message >> 4)); param_position = 0; } else { event->set_channel(data[0] & 0xF); - event->set_message(data[0] >> 4); + event->set_message(MIDIMessage(data[0] >> 4)); param_position = 1; last_received_message = data[0]; } @@ -112,6 +112,8 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_ event->set_pressure(data[param_position]); } break; + default: + break; } Input *id = Input::get_singleton(); diff --git a/core/os/os.cpp b/core/os/os.cpp index ca1b798e11..535eee4797 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -32,8 +32,8 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/midi_driver.h" #include "core/version_generated.gen.h" #include "servers/audio_server.h" @@ -47,37 +47,8 @@ OS *OS::get_singleton() { return singleton; } -uint32_t OS::get_ticks_msec() const { - return get_ticks_usec() / 1000; -} - -String OS::get_iso_date_time(bool local) const { - OS::Date date = get_date(local); - OS::Time time = get_time(local); - - String timezone; - if (!local) { - TimeZoneInfo zone = get_time_zone_info(); - if (zone.bias >= 0) { - timezone = "+"; - } - timezone = timezone + itos(zone.bias / 60).pad_zeros(2) + itos(zone.bias % 60).pad_zeros(2); - } else { - timezone = "Z"; - } - - return itos(date.year).pad_zeros(2) + - "-" + - itos(date.month).pad_zeros(2) + - "-" + - itos(date.day).pad_zeros(2) + - "T" + - itos(time.hour).pad_zeros(2) + - ":" + - itos(time.min).pad_zeros(2) + - ":" + - itos(time.sec).pad_zeros(2) + - timezone; +uint64_t OS::get_ticks_msec() const { + return get_ticks_usec() / 1000ULL; } double OS::get_unix_time() const { @@ -310,6 +281,11 @@ String OS::get_user_data_dir() const { return "."; } +// Android OS path to app's external data storage +String OS::get_external_data_dir() const { + return get_user_data_dir(); +}; + // Absolute path to res:// String OS::get_resource_dir() const { return ProjectSettings::get_singleton()->get_resource_path(); diff --git a/core/os/os.h b/core/os/os.h index 7198607237..301718a8b3 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -58,8 +58,6 @@ class OS { int _orientation; bool _allow_hidpi = false; bool _allow_layered = false; - bool _use_vsync; - bool _vsync_via_compositor; bool _stdout_enabled = true; bool _stderr_enabled = true; @@ -158,17 +156,17 @@ public: virtual void yield(); - enum Weekday { - DAY_SUNDAY, - DAY_MONDAY, - DAY_TUESDAY, - DAY_WEDNESDAY, - DAY_THURSDAY, - DAY_FRIDAY, - DAY_SATURDAY + enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, }; - enum Month { + enum Month : uint8_t { /// Start at 1 to follow Windows SYSTEMTIME structure /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx MONTH_JANUARY = 1, @@ -182,21 +180,21 @@ public: MONTH_SEPTEMBER, MONTH_OCTOBER, MONTH_NOVEMBER, - MONTH_DECEMBER + MONTH_DECEMBER, }; struct Date { - int year; + int64_t year; Month month; - int day; + uint8_t day; Weekday weekday; bool dst; }; struct Time { - int hour; - int min; - int sec; + uint8_t hour; + uint8_t minute; + uint8_t second; }; struct TimeZoneInfo { @@ -207,14 +205,13 @@ public: virtual Date get_date(bool local = false) const = 0; virtual Time get_time(bool local = false) const = 0; virtual TimeZoneInfo get_time_zone_info() const = 0; - virtual String get_iso_date_time(bool local = false) const; virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; virtual void add_frame_delay(bool p_can_draw); virtual uint64_t get_ticks_usec() const = 0; - uint32_t get_ticks_msec() const; + uint64_t get_ticks_msec() const; virtual bool is_userfs_persistent() const { return true; } @@ -252,6 +249,7 @@ public: virtual String get_bundle_resource_dir() const; virtual String get_user_data_dir() const; + virtual String get_external_data_dir() const; virtual String get_resource_dir() const; enum SystemDir { diff --git a/core/os/time.cpp b/core/os/time.cpp new file mode 100644 index 0000000000..a185029969 --- /dev/null +++ b/core/os/time.cpp @@ -0,0 +1,433 @@ +/*************************************************************************/ +/* time.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "time.h" + +#include "core/os/os.h" + +#define UNIX_EPOCH_YEAR_AD 1970 // 1970 +#define SECONDS_PER_DAY (24 * 60 * 60) // 86400 +#define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) +#define YEAR_SIZE(year) (IS_LEAP_YEAR(year) ? 366 : 365) + +#define YEAR_KEY "year" +#define MONTH_KEY "month" +#define DAY_KEY "day" +#define WEEKDAY_KEY "weekday" +#define HOUR_KEY "hour" +#define MINUTE_KEY "minute" +#define SECOND_KEY "second" +#define DST_KEY "dst" + +// Table of number of days in each month (for regular year and leap year). +static const uint8_t MONTH_DAYS_TABLE[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +VARIANT_ENUM_CAST(Time::Month); +VARIANT_ENUM_CAST(Time::Weekday); + +#define UNIX_TIME_TO_HMS \ + uint8_t hour, minute, second; \ + { \ + /* The time of the day (in seconds since start of day). */ \ + uint32_t day_clock = Math::posmod(p_unix_time_val, SECONDS_PER_DAY); \ + /* On x86 these 4 lines can be optimized to only 2 divisions. */ \ + second = day_clock % 60; \ + day_clock /= 60; \ + minute = day_clock % 60; \ + hour = day_clock / 60; \ + } + +#define UNIX_TIME_TO_YMD \ + int64_t year; \ + Month month; \ + uint8_t day; \ + /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \ + int64_t day_number = Math::floor(p_unix_time_val / (double)SECONDS_PER_DAY); \ + { \ + int64_t day_number_copy = day_number; \ + year = UNIX_EPOCH_YEAR_AD; \ + uint8_t month_zero_index = 0; \ + while (day_number_copy >= YEAR_SIZE(year)) { \ + day_number_copy -= YEAR_SIZE(year); \ + year++; \ + } \ + while (day_number_copy < 0) { \ + year--; \ + day_number_copy += YEAR_SIZE(year); \ + } \ + /* After the above, day_number now represents the day of the year (0-index). */ \ + while (day_number_copy >= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]) { \ + day_number_copy -= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]; \ + month_zero_index++; \ + } \ + /* After the above, day_number now represents the day of the month (0-index). */ \ + month = (Month)(month_zero_index + 1); \ + day = day_number_copy + 1; \ + } + +#define VALIDATE_YMDHMS \ + ERR_FAIL_COND_V_MSG(month == 0, 0, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \ + ERR_FAIL_COND_V_MSG(month > 12, 0, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \ + ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); \ + ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); \ + ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \ + /* Do this check after month is tested as valid. */ \ + ERR_FAIL_COND_V_MSG(day == 0, 0, "Invalid day value of: " + itos(month) + ", days are 1-indexed and cannot be 0."); \ + uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \ + ERR_FAIL_COND_V_MSG(day > days_in_this_month, 0, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + "."); + +#define YMD_TO_DAY_NUMBER \ + /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \ + int64_t day_number = day - 1; \ + /* Add the days in the months to day_number. */ \ + for (int i = 0; i < month - 1; i++) { \ + day_number += MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][i]; \ + } \ + /* Add the days in the years to day_number. */ \ + if (year >= UNIX_EPOCH_YEAR_AD) { \ + for (int64_t iyear = UNIX_EPOCH_YEAR_AD; iyear < year; iyear++) { \ + day_number += YEAR_SIZE(iyear); \ + } \ + } else { \ + for (int64_t iyear = UNIX_EPOCH_YEAR_AD - 1; iyear >= year; iyear--) { \ + day_number -= YEAR_SIZE(iyear); \ + } \ + } + +#define PARSE_ISO8601_STRING \ + int64_t year = UNIX_EPOCH_YEAR_AD; \ + Month month = MONTH_JANUARY; \ + uint8_t day = 1; \ + uint8_t hour = 0; \ + uint8_t minute = 0; \ + uint8_t second = 0; \ + { \ + bool has_date = false, has_time = false; \ + String date, time; \ + if (p_datetime.find_char('T') > 0) { \ + has_date = has_time = true; \ + PackedStringArray array = p_datetime.split("T"); \ + date = array[0]; \ + time = array[1]; \ + } else if (p_datetime.find_char(' ') > 0) { \ + has_date = has_time = true; \ + PackedStringArray array = p_datetime.split(" "); \ + date = array[0]; \ + time = array[1]; \ + } else if (p_datetime.find_char('-', 1) > 0) { \ + has_date = true; \ + date = p_datetime; \ + } else if (p_datetime.find_char(':') > 0) { \ + has_time = true; \ + time = p_datetime; \ + } \ + /* Set the variables from the contents of the string. */ \ + if (has_date) { \ + PackedInt32Array array = date.split_ints("-", false); \ + year = array[0]; \ + month = (Month)array[1]; \ + day = array[2]; \ + /* Handle negative years. */ \ + if (p_datetime.find_char('-') == 0) { \ + year *= -1; \ + } \ + } \ + if (has_time) { \ + PackedInt32Array array = time.split_ints(":", false); \ + hour = array[0]; \ + minute = array[1]; \ + second = array[2]; \ + } \ + } + +#define EXTRACT_FROM_DICTIONARY \ + /* Get all time values from the dictionary. If it doesn't exist, set the */ \ + /* values to the default values for Unix epoch (1970-01-01 00:00:00). */ \ + int64_t year = p_datetime.has(YEAR_KEY) ? int64_t(p_datetime[YEAR_KEY]) : UNIX_EPOCH_YEAR_AD; \ + Month month = Month((p_datetime.has(MONTH_KEY)) ? uint8_t(p_datetime[MONTH_KEY]) : 1); \ + uint8_t day = p_datetime.has(DAY_KEY) ? uint8_t(p_datetime[DAY_KEY]) : 1; \ + uint8_t hour = p_datetime.has(HOUR_KEY) ? uint8_t(p_datetime[HOUR_KEY]) : 0; \ + uint8_t minute = p_datetime.has(MINUTE_KEY) ? uint8_t(p_datetime[MINUTE_KEY]) : 0; \ + uint8_t second = p_datetime.has(SECOND_KEY) ? uint8_t(p_datetime[SECOND_KEY]) : 0; + +Time *Time::singleton = nullptr; + +Time *Time::get_singleton() { + if (!singleton) { + memnew(Time); + } + return singleton; +} + +Dictionary Time::get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + UNIX_TIME_TO_YMD + Dictionary datetime; + datetime[YEAR_KEY] = year; + datetime[MONTH_KEY] = (uint8_t)month; + datetime[DAY_KEY] = day; + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + datetime[HOUR_KEY] = hour; + datetime[MINUTE_KEY] = minute; + datetime[SECOND_KEY] = second; + + return datetime; +} + +Dictionary Time::get_date_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_YMD + Dictionary datetime; + datetime[YEAR_KEY] = year; + datetime[MONTH_KEY] = (uint8_t)month; + datetime[DAY_KEY] = day; + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + + return datetime; +} + +Dictionary Time::get_time_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + Dictionary datetime; + datetime[HOUR_KEY] = hour; + datetime[MINUTE_KEY] = minute; + datetime[SECOND_KEY] = second; + + return datetime; +} + +String Time::get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space) const { + UNIX_TIME_TO_HMS + UNIX_TIME_TO_YMD + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second); + } + + return timestamp; +} + +String Time::get_date_string_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_YMD + // Android is picky about the types passed to make Variant, so we need a cast. + return vformat("%04d-%02d-%02d", year, (uint8_t)month, day); +} + +String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + return vformat("%02d:%02d:%02d", hour, minute, second); +} + +Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const { + PARSE_ISO8601_STRING + Dictionary dict; + dict[YEAR_KEY] = year; + dict[MONTH_KEY] = (uint8_t)month; + dict[DAY_KEY] = day; + if (p_weekday) { + YMD_TO_DAY_NUMBER + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + dict[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + } + dict[HOUR_KEY] = hour; + dict[MINUTE_KEY] = minute; + dict[SECOND_KEY] = second; + + return dict; +} + +String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const { + ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty."); + EXTRACT_FROM_DICTIONARY + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second); + } + return timestamp; +} + +int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const { + ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); + EXTRACT_FROM_DICTIONARY + VALIDATE_YMDHMS + YMD_TO_DAY_NUMBER + return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second; +} + +int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const { + PARSE_ISO8601_STRING + VALIDATE_YMDHMS + YMD_TO_DAY_NUMBER + return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second; +} + +Dictionary Time::get_datetime_dict_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + OS::Time time = OS::get_singleton()->get_time(p_utc); + Dictionary datetime; + datetime[YEAR_KEY] = date.year; + datetime[MONTH_KEY] = (uint8_t)date.month; + datetime[DAY_KEY] = date.day; + datetime[WEEKDAY_KEY] = (uint8_t)date.weekday; + datetime[DST_KEY] = date.dst; + datetime[HOUR_KEY] = time.hour; + datetime[MINUTE_KEY] = time.minute; + datetime[SECOND_KEY] = time.second; + return datetime; +} + +Dictionary Time::get_date_dict_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + Dictionary date_dictionary; + date_dictionary[YEAR_KEY] = date.year; + date_dictionary[MONTH_KEY] = (uint8_t)date.month; + date_dictionary[DAY_KEY] = date.day; + date_dictionary[WEEKDAY_KEY] = (uint8_t)date.weekday; + date_dictionary[DST_KEY] = date.dst; + return date_dictionary; +} + +Dictionary Time::get_time_dict_from_system(bool p_utc) const { + OS::Time time = OS::get_singleton()->get_time(p_utc); + Dictionary time_dictionary; + time_dictionary[HOUR_KEY] = time.hour; + time_dictionary[MINUTE_KEY] = time.minute; + time_dictionary[SECOND_KEY] = time.second; + return time_dictionary; +} + +String Time::get_datetime_string_from_system(bool p_utc, bool p_use_space) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + OS::Time time = OS::get_singleton()->get_time(p_utc); + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, time.hour, time.minute, time.second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, time.hour, time.minute, time.second); + } + + return timestamp; +} + +String Time::get_date_string_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + // Android is picky about the types passed to make Variant, so we need a cast. + return vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day); +} + +String Time::get_time_string_from_system(bool p_utc) const { + OS::Time time = OS::get_singleton()->get_time(p_utc); + return vformat("%02d:%02d:%02d", time.hour, time.minute, time.second); +} + +Dictionary Time::get_time_zone_from_system() const { + OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info(); + Dictionary timezone; + timezone["bias"] = info.bias; + timezone["name"] = info.name; + return timezone; +} + +double Time::get_unix_time_from_system() const { + return OS::get_singleton()->get_unix_time(); +} + +uint64_t Time::get_ticks_msec() const { + return OS::get_singleton()->get_ticks_msec(); +} + +uint64_t Time::get_ticks_usec() const { + return OS::get_singleton()->get_ticks_usec(); +} + +void Time::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_unix_time", "unix_time_val"), &Time::get_datetime_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_date_dict_from_unix_time", "unix_time_val"), &Time::get_date_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_time_dict_from_unix_time", "unix_time_val"), &Time::get_time_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time); + ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time); + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict); + ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict); + ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string); + + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_dict_from_system", "utc"), &Time::get_time_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_system", "utc", "use_space"), &Time::get_datetime_string_from_system, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_string_from_system", "utc"), &Time::get_date_string_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_string_from_system", "utc"), &Time::get_time_string_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_zone_from_system"), &Time::get_time_zone_from_system); + ClassDB::bind_method(D_METHOD("get_unix_time_from_system"), &Time::get_unix_time_from_system); + ClassDB::bind_method(D_METHOD("get_ticks_msec"), &Time::get_ticks_msec); + ClassDB::bind_method(D_METHOD("get_ticks_usec"), &Time::get_ticks_usec); + + BIND_ENUM_CONSTANT(MONTH_JANUARY); + BIND_ENUM_CONSTANT(MONTH_FEBRUARY); + BIND_ENUM_CONSTANT(MONTH_MARCH); + BIND_ENUM_CONSTANT(MONTH_APRIL); + BIND_ENUM_CONSTANT(MONTH_MAY); + BIND_ENUM_CONSTANT(MONTH_JUNE); + BIND_ENUM_CONSTANT(MONTH_JULY); + BIND_ENUM_CONSTANT(MONTH_AUGUST); + BIND_ENUM_CONSTANT(MONTH_SEPTEMBER); + BIND_ENUM_CONSTANT(MONTH_OCTOBER); + BIND_ENUM_CONSTANT(MONTH_NOVEMBER); + BIND_ENUM_CONSTANT(MONTH_DECEMBER); + + BIND_ENUM_CONSTANT(WEEKDAY_SUNDAY); + BIND_ENUM_CONSTANT(WEEKDAY_MONDAY); + BIND_ENUM_CONSTANT(WEEKDAY_TUESDAY); + BIND_ENUM_CONSTANT(WEEKDAY_WEDNESDAY); + BIND_ENUM_CONSTANT(WEEKDAY_THURSDAY); + BIND_ENUM_CONSTANT(WEEKDAY_FRIDAY); + BIND_ENUM_CONSTANT(WEEKDAY_SATURDAY); +} + +Time::Time() { + ERR_FAIL_COND_MSG(singleton, "Singleton for Time already exists."); + singleton = this; +} + +Time::~Time() { + singleton = nullptr; +} diff --git a/core/os/time.h b/core/os/time.h new file mode 100644 index 0000000000..4325f93d56 --- /dev/null +++ b/core/os/time.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* time.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 TIME_H +#define TIME_H + +#include "core/object/class_db.h" + +// This Time class conforms with as many of the ISO 8601 standards as possible. +// * As per ISO 8601:2004 4.3.2.1, all dates follow the Proleptic Gregorian +// calendar. As such, the day before 1582-10-15 is 1582-10-14, not 1582-10-04. +// See: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar +// * As per ISO 8601:2004 3.4.2 and 4.1.2.4, the year before 1 AD (aka 1 BC) +// is number "0", with the year before that (2 BC) being "-1", etc. +// Conversion methods assume "the same timezone", and do not handle DST. +// Leap seconds are not handled, they must be done manually if desired. +// Suffixes such as "Z" are not handled, you need to strip them away manually. + +class Time : public Object { + GDCLASS(Time, Object); + static void _bind_methods(); + static Time *singleton; + +public: + static Time *get_singleton(); + + enum Month : uint8_t { + /// Start at 1 to follow Windows SYSTEMTIME structure + /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx + MONTH_JANUARY = 1, + MONTH_FEBRUARY, + MONTH_MARCH, + MONTH_APRIL, + MONTH_MAY, + MONTH_JUNE, + MONTH_JULY, + MONTH_AUGUST, + MONTH_SEPTEMBER, + MONTH_OCTOBER, + MONTH_NOVEMBER, + MONTH_DECEMBER, + }; + + enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, + }; + + // Methods that convert times. + Dictionary get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_date_dict_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_time_dict_from_unix_time(int64_t p_unix_time_val) const; + String get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space = false) const; + String get_date_string_from_unix_time(int64_t p_unix_time_val) const; + String get_time_string_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const; + String get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space = false) const; + int64_t get_unix_time_from_datetime_dict(Dictionary p_datetime) const; + int64_t get_unix_time_from_datetime_string(String p_datetime) const; + + // Methods that get information from OS. + Dictionary get_datetime_dict_from_system(bool p_utc = false) const; + Dictionary get_date_dict_from_system(bool p_utc = false) const; + Dictionary get_time_dict_from_system(bool p_utc = false) const; + String get_datetime_string_from_system(bool p_utc = false, bool p_use_space = false) const; + String get_date_string_from_system(bool p_utc = false) const; + String get_time_string_from_system(bool p_utc = false) const; + Dictionary get_time_zone_from_system() const; + double get_unix_time_from_system() const; + uint64_t get_ticks_msec() const; + uint64_t get_ticks_usec() const; + + Time(); + virtual ~Time(); +}; + +#endif // TIME_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index f1b1b98bea..0739a0336d 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -37,6 +37,8 @@ #include "core/crypto/aes_context.h" #include "core/crypto/crypto.h" #include "core/crypto/hashing_context.h" +#include "core/extension/native_extension.h" +#include "core/extension/native_extension_manager.h" #include "core/input/input.h" #include "core/input/input_map.h" #include "core/io/config_file.h" @@ -46,7 +48,7 @@ #include "core/io/json.h" #include "core/io/marshalls.h" #include "core/io/multiplayer_api.h" -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "core/io/packed_data_container.h" #include "core/io/packet_peer.h" #include "core/io/packet_peer_dtls.h" @@ -68,6 +70,7 @@ #include "core/object/class_db.h" #include "core/object/undo_redo.h" #include "core/os/main_loop.h" +#include "core/os/time.h" #include "core/string/optimized_translation.h" #include "core/string/translation.h" @@ -85,7 +88,6 @@ static _OS *_os = nullptr; static _Engine *_engine = nullptr; static _ClassDB *_classdb = nullptr; static _Marshalls *_marshalls = nullptr; -static _JSON *_json = nullptr; static _EngineDebugger *_engine_debugger = nullptr; static IP *ip = nullptr; @@ -95,6 +97,8 @@ static _Geometry3D *_geometry_3d = nullptr; extern Mutex _global_mutex; +static NativeExtensionManager *native_extension_manager = nullptr; + extern void register_global_constants(); extern void unregister_global_constants(); @@ -113,25 +117,25 @@ void register_core_types() { CoreStringNames::create(); - resource_format_po.instance(); + resource_format_po.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_po); - resource_saver_binary.instance(); + resource_saver_binary.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_binary); - resource_loader_binary.instance(); + resource_loader_binary.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_binary); - resource_format_importer.instance(); + resource_format_importer.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_importer); - resource_format_image.instance(); + resource_format_image.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_image); ClassDB::register_class<Object>(); ClassDB::register_virtual_class<Script>(); - ClassDB::register_class<Reference>(); + ClassDB::register_class<RefCounted>(); ClassDB::register_class<WeakRef>(); ClassDB::register_class<Resource>(); ClassDB::register_class<Image>(); @@ -153,14 +157,20 @@ void register_core_types() { ClassDB::register_class<InputEventPanGesture>(); ClassDB::register_class<InputEventMIDI>(); + // Network + ClassDB::register_virtual_class<IP>(); + ClassDB::register_virtual_class<StreamPeer>(); ClassDB::register_class<StreamPeerBuffer>(); ClassDB::register_class<StreamPeerTCP>(); ClassDB::register_class<TCPServer>(); + + ClassDB::register_virtual_class<PacketPeer>(); + ClassDB::register_class<PacketPeerStream>(); ClassDB::register_class<PacketPeerUDP>(); ClassDB::register_class<UDPServer>(); - ClassDB::register_custom_instance_class<PacketPeerDTLS>(); - ClassDB::register_custom_instance_class<DTLSServer>(); + + ClassDB::register_custom_instance_class<HTTPClient>(); // Crypto ClassDB::register_class<HashingContext>(); @@ -170,22 +180,20 @@ void register_core_types() { ClassDB::register_custom_instance_class<HMACContext>(); ClassDB::register_custom_instance_class<Crypto>(); ClassDB::register_custom_instance_class<StreamPeerSSL>(); + ClassDB::register_custom_instance_class<PacketPeerDTLS>(); + ClassDB::register_custom_instance_class<DTLSServer>(); - resource_format_saver_crypto.instance(); + resource_format_saver_crypto.instantiate(); ResourceSaver::add_resource_format_saver(resource_format_saver_crypto); - resource_format_loader_crypto.instance(); + resource_format_loader_crypto.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_loader_crypto); - ClassDB::register_virtual_class<IP>(); - ClassDB::register_virtual_class<PacketPeer>(); - ClassDB::register_class<PacketPeerStream>(); - ClassDB::register_virtual_class<NetworkedMultiplayerPeer>(); + ClassDB::register_virtual_class<MultiplayerPeer>(); ClassDB::register_class<MultiplayerAPI>(); ClassDB::register_class<MainLoop>(); ClassDB::register_class<Translation>(); ClassDB::register_class<OptimizedTranslation>(); ClassDB::register_class<UndoRedo>(); - ClassDB::register_class<HTTPClient>(); ClassDB::register_class<TriangleMesh>(); ClassDB::register_class<ResourceFormatLoader>(); @@ -198,7 +206,7 @@ void register_core_types() { ClassDB::register_class<_Semaphore>(); ClassDB::register_class<XMLParser>(); - ClassDB::register_class<JSONParser>(); + ClassDB::register_class<JSON>(); ClassDB::register_class<ConfigFile>(); @@ -211,10 +219,14 @@ void register_core_types() { ClassDB::register_class<EncodedObjectAsID>(); ClassDB::register_class<RandomNumberGenerator>(); - ClassDB::register_class<JSONParseResult>(); - ClassDB::register_virtual_class<ResourceImporter>(); + ClassDB::register_class<NativeExtension>(); + + ClassDB::register_virtual_class<NativeExtensionManager>(); + + native_extension_manager = memnew(NativeExtensionManager); + ip = IP::create(); _geometry_2d = memnew(_Geometry2D); @@ -226,7 +238,6 @@ void register_core_types() { _engine = memnew(_Engine); _classdb = memnew(_ClassDB); _marshalls = memnew(_Marshalls); - _json = memnew(_JSON); _engine_debugger = memnew(_EngineDebugger); } @@ -255,12 +266,12 @@ void register_core_singletons() { ClassDB::register_class<TranslationServer>(); ClassDB::register_virtual_class<Input>(); ClassDB::register_class<InputMap>(); - ClassDB::register_class<_JSON>(); ClassDB::register_class<Expression>(); ClassDB::register_class<_EngineDebugger>(); + ClassDB::register_class<Time>(); Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton(), "IP")); Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry2D", _Geometry2D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry3D", _Geometry3D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceLoader", _ResourceLoader::get_singleton())); @@ -272,18 +283,33 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("TranslationServer", TranslationServer::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _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())); +} + +void register_core_extensions() { + //harcoded for now + if (ProjectSettings::get_singleton()->has_setting("native_extensions/paths")) { + Vector<String> paths = ProjectSettings::get_singleton()->get("native_extensions/paths"); + for (int i = 0; i < paths.size(); i++) { + NativeExtensionManager::LoadStatus status = native_extension_manager->load_extension(paths[i]); + ERR_CONTINUE_MSG(status != NativeExtensionManager::LOAD_STATUS_OK, "Error loading extension: " + paths[i]); + } + } + native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); } void unregister_core_types() { + native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); + + memdelete(native_extension_manager); memdelete(_resource_loader); memdelete(_resource_saver); memdelete(_os); memdelete(_engine); memdelete(_classdb); memdelete(_marshalls); - memdelete(_json); memdelete(_engine_debugger); memdelete(_geometry_2d); diff --git a/core/register_core_types.h b/core/register_core_types.h index baf7ddbe65..830f05607d 100644 --- a/core/register_core_types.h +++ b/core/register_core_types.h @@ -33,6 +33,7 @@ void register_core_types(); void register_core_settings(); +void register_core_extensions(); void register_core_singletons(); void unregister_core_types(); diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index ad768f7140..f9b4e661e4 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -30,7 +30,7 @@ #include "translation_po.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #ifdef DEBUG_TRANSLATION_PO void TranslationPO::print_translation_map() { @@ -188,7 +188,7 @@ void TranslationPO::set_plural_rule(const String &p_plural_rule) { plural_rule = plural_rule.replacen("(", ""); plural_rule = plural_rule.replacen(")", ""); _cache_plural_tests(plural_rule); - expr.instance(); + expr.instantiate(); input_name.push_back("n"); } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 7fec96944a..4cd2915ffa 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -54,7 +54,7 @@ #define snprintf _snprintf_s #endif -#define MAX_DIGITS 6 +#define MAX_DECIMALS 32 #define UPPERCASE(m_c) (((m_c) >= 'a' && (m_c) <= 'z') ? ((m_c) - ('a' - 'A')) : (m_c)) #define LOWERCASE(m_c) (((m_c) >= 'A' && (m_c) <= 'Z') ? ((m_c) + ('a' - 'A')) : (m_c)) #define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9') @@ -275,7 +275,7 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r base = base.substr(pos + 1, base.length() - pos - 1); } else { // Anything else - if (base.get_slice_count(":") > 1) { + if (base.get_slice_count(":") > 2) { return ERR_INVALID_PARAMETER; } pos = base.rfind(":"); @@ -294,7 +294,7 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r // Port if (base.begins_with(":")) { base = base.substr(1, base.length() - 1); - if (!base.is_valid_integer()) { + if (!base.is_valid_int()) { return ERR_INVALID_PARAMETER; } r_port = base.to_int(); @@ -1379,8 +1379,11 @@ String String::num(double p_num, int p_decimals) { } #ifndef NO_USE_STDLIB - if (p_decimals > 16) { - p_decimals = 16; + if (p_decimals < 0) { + p_decimals = 14 - (int)floor(log10(p_num)); + } + if (p_decimals > MAX_DECIMALS) { + p_decimals = MAX_DECIMALS; } char fmt[7]; @@ -1391,7 +1394,6 @@ String String::num(double p_num, int p_decimals) { fmt[1] = 'l'; fmt[2] = 'f'; fmt[3] = 0; - } else if (p_decimals < 10) { fmt[2] = '0' + p_decimals; fmt[3] = 'l'; @@ -1458,8 +1460,9 @@ String String::num(double p_num, int p_decimals) { double dec = p_num - (double)((int)p_num); int digit = 0; - if (p_decimals > MAX_DIGITS) - p_decimals = MAX_DIGITS; + if (p_decimals > MAX_DECIMALS) { + p_decimals = MAX_DECIMALS; + } int dec_int = 0; int dec_max = 0; @@ -1471,16 +1474,18 @@ String String::num(double p_num, int p_decimals) { digit++; if (p_decimals == -1) { - if (digit == MAX_DIGITS) //no point in going to infinite + if (digit == MAX_DECIMALS) { //no point in going to infinite break; + } if (dec - (double)((int)dec) < 1e-6) { break; } } - if (digit == p_decimals) + if (digit == p_decimals) { break; + } } dec *= 10; int last = (int)dec % 10; @@ -1589,7 +1594,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) { return s; } -String String::num_real(double p_num) { +String String::num_real(double p_num, bool p_trailing) { if (Math::is_nan(p_num)) { return "nan"; } @@ -1616,7 +1621,15 @@ String String::num_real(double p_num) { double dec = p_num - (double)((int)p_num); int digit = 0; - int decimals = MAX_DIGITS; + +#if REAL_T_IS_DOUBLE + int decimals = 14 - (int)floor(log10(p_num)); +#else + int decimals = 6 - (int)floor(log10(p_num)); +#endif + if (decimals > MAX_DECIMALS) { + decimals = MAX_DECIMALS; + } int dec_int = 0; int dec_max = 0; @@ -1656,8 +1669,10 @@ String String::num_real(double p_num) { dec_int /= 10; } sd = '.' + decimal; - } else { + } else if (p_trailing) { sd = ".0"; + } else { + sd = ""; } if (intn == 0) { @@ -3767,7 +3782,7 @@ String String::humanize_size(uint64_t p_size) { return String::num(p_size / divisor).pad_decimals(digits) + " " + prefixes[prefix_idx]; } -bool String::is_abs_path() const { +bool String::is_absolute_path() const { if (length() > 1) { return (operator[](0) == '/' || operator[](0) == '\\' || find(":/") != -1 || find(":\\") != -1); } else if ((length()) == 1) { @@ -4134,7 +4149,7 @@ String String::trim_suffix(const String &p_suffix) const { return s; } -bool String::is_valid_integer() const { +bool String::is_valid_int() const { int len = length(); if (len == 0) { @@ -4359,7 +4374,7 @@ bool String::is_valid_ip_address() const { } for (int i = 0; i < ip.size(); i++) { String n = ip[i]; - if (!n.is_valid_integer()) { + if (!n.is_valid_int()) { return false; } int val = n.to_int(); @@ -4377,7 +4392,7 @@ bool String::is_resource_file() const { } bool String::is_rel_path() const { - return !is_abs_path(); + return !is_absolute_path(); } String String::get_base_dir() const { diff --git a/core/string/ustring.h b/core/string/ustring.h index a56845deff..ffb354d6e1 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -309,7 +309,7 @@ public: String unquote() const; static String num(double p_num, int p_decimals = -1); static String num_scientific(double p_num); - static String num_real(double p_num); + static String num_real(double p_num, bool p_trailing = true); static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false); static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false); static String chr(char32_t p_char); @@ -397,7 +397,7 @@ public: _FORCE_INLINE_ bool is_empty() const { return length() == 0; } // path functions - bool is_abs_path() const; + bool is_absolute_path() const; bool is_rel_path() const; bool is_resource_file() const; String path_to(const String &p_path) const; @@ -425,7 +425,7 @@ public: String validate_node_name() const; bool is_valid_identifier() const; - bool is_valid_integer() const; + bool is_valid_int() const; bool is_valid_float() const; bool is_valid_hex_number(bool p_with_prefix) const; bool is_valid_html_color() const; diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h new file mode 100644 index 0000000000..be9d0b5475 --- /dev/null +++ b/core/templates/bin_sorted_array.h @@ -0,0 +1,181 @@ +/*************************************************************************/ +/* bin_sorted_array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 BIN_SORTED_ARRAY_H +#define BIN_SORTED_ARRAY_H + +#include "core/templates/local_vector.h" +#include "core/templates/paged_array.h" + +template <class T> +class BinSortedArray { + PagedArray<T> array; + LocalVector<uint64_t> bin_limits; + + // Implement if elements need to keep track of their own index in the array. + _FORCE_INLINE_ virtual void _update_idx(T &r_element, uint64_t p_idx) {} + + _FORCE_INLINE_ void _swap(uint64_t p_a, uint64_t p_b) { + SWAP(array[p_a], array[p_b]); + _update_idx(array[p_a], p_a); + _update_idx(array[p_b], p_b); + } + +public: + uint64_t insert(T &p_element, uint64_t p_bin) { + array.push_back(p_element); + uint64_t new_idx = array.size() - 1; + _update_idx(p_element, new_idx); + bin_limits[0] = new_idx; + if (p_bin != 0) { + new_idx = move(new_idx, p_bin); + } + return new_idx; + } + + uint64_t move(uint64_t p_idx, uint64_t p_bin) { + ERR_FAIL_COND_V(p_idx >= array.size(), -1); + + uint64_t current_bin = bin_limits.size() - 1; + while (p_idx > bin_limits[current_bin]) { + current_bin--; + } + + if (p_bin == current_bin) { + return p_idx; + } + + uint64_t current_idx = p_idx; + if (p_bin > current_bin) { + while (p_bin > current_bin) { + uint64_t swap_idx = 0; + + if (current_bin == bin_limits.size() - 1) { + bin_limits.push_back(0); + } else { + bin_limits[current_bin + 1]++; + swap_idx = bin_limits[current_bin + 1]; + } + + if (current_idx != swap_idx) { + _swap(current_idx, swap_idx); + current_idx = swap_idx; + } + + current_bin++; + } + } else { + while (p_bin < current_bin) { + uint64_t swap_idx = bin_limits[current_bin]; + + if (current_idx != swap_idx) { + _swap(current_idx, swap_idx); + } + + if (current_bin == bin_limits.size() - 1 && bin_limits[current_bin] == 0) { + bin_limits.resize(bin_limits.size() - 1); + } else { + bin_limits[current_bin]--; + } + current_idx = swap_idx; + current_bin--; + } + } + + return current_idx; + } + + void remove(uint64_t p_idx) { + ERR_FAIL_COND(p_idx >= array.size()); + uint64_t new_idx = move(p_idx, 0); + uint64_t swap_idx = array.size() - 1; + + if (new_idx != swap_idx) { + _swap(new_idx, swap_idx); + } + + if (bin_limits[0] > 0) { + bin_limits[0]--; + } + + array.pop_back(); + } + + void set_page_pool(PagedArrayPool<T> *p_page_pool) { + array.set_page_pool(p_page_pool); + } + + _FORCE_INLINE_ const T &operator[](uint64_t p_index) const { + return array[p_index]; + } + + _FORCE_INLINE_ T &operator[](uint64_t p_index) { + return array[p_index]; + } + + int get_bin_count() { + if (array.size() == 0) { + return 0; + } + return bin_limits.size(); + } + + int get_bin_start(int p_bin) { + ERR_FAIL_COND_V(p_bin >= get_bin_count(), ~0U); + if ((unsigned int)p_bin == bin_limits.size() - 1) { + return 0; + } + return bin_limits[p_bin + 1] + 1; + } + + int get_bin_size(int p_bin) { + ERR_FAIL_COND_V(p_bin >= get_bin_count(), 0); + if ((unsigned int)p_bin == bin_limits.size() - 1) { + return bin_limits[p_bin] + 1; + } + return bin_limits[p_bin] - bin_limits[p_bin + 1]; + } + + void reset() { + array.reset(); + bin_limits.clear(); + bin_limits.push_back(0); + } + + BinSortedArray() { + bin_limits.push_back(0); + } + + virtual ~BinSortedArray() { + reset(); + } +}; + +#endif //BIN_SORTED_ARRAY_H diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp index 238bf3975c..04a8095f0b 100644 --- a/core/templates/command_queue_mt.cpp +++ b/core/templates/command_queue_mt.cpp @@ -70,35 +70,7 @@ CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() { return &sync_sems[idx]; } -bool CommandQueueMT::dealloc_one() { -tryagain: - if (dealloc_ptr == (write_ptr_and_epoch >> 1)) { - // The queue is empty - return false; - } - - uint32_t size = *(uint32_t *)&command_mem[dealloc_ptr]; - - if (size == 0) { - // End of command buffer wrap down - dealloc_ptr = 0; - goto tryagain; - } - - if (size & 1) { - // Still used, nothing can be deallocated - return false; - } - - dealloc_ptr += (size >> 1) + 8; - return true; -} - CommandQueueMT::CommandQueueMT(bool p_sync) { - command_mem_size = GLOBAL_DEF_RST("memory/limits/command_queue/multithreading_queue_size_kb", DEFAULT_COMMAND_MEM_SIZE_KB); - ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/command_queue/multithreading_queue_size_kb", PropertyInfo(Variant::INT, "memory/limits/command_queue/multithreading_queue_size_kb", PROPERTY_HINT_RANGE, "1,4096,1,or_greater")); - command_mem_size *= 1024; - command_mem = (uint8_t *)memalloc(command_mem_size); if (p_sync) { sync = memnew(Semaphore); } @@ -108,5 +80,4 @@ CommandQueueMT::~CommandQueueMT() { if (sync) { memdelete(sync); } - memfree(command_mem); } diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 0012cea72d..acc46da0d5 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -34,6 +34,8 @@ #include "core/os/memory.h" #include "core/os/mutex.h" #include "core/os/semaphore.h" +#include "core/string/print_string.h" +#include "core/templates/local_vector.h" #include "core/templates/simple_type.h" #include "core/typedefs.h" @@ -334,11 +336,7 @@ class CommandQueueMT { SYNC_SEMAPHORES = 8 }; - uint8_t *command_mem = nullptr; - uint32_t read_ptr_and_epoch = 0; - uint32_t write_ptr_and_epoch = 0; - uint32_t dealloc_ptr = 0; - uint32_t command_mem_size = 0; + LocalVector<uint8_t> command_mem; SyncSemaphore sync_sems[SYNC_SEMAPHORES]; Mutex mutex; Semaphore *sync = nullptr; @@ -346,138 +344,47 @@ class CommandQueueMT { template <class T> T *allocate() { // alloc size is size+T+safeguard - uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)) + 8; - - // Assert that the buffer is big enough to hold at least two messages. - ERR_FAIL_COND_V(alloc_size * 2 + sizeof(uint32_t) > command_mem_size, nullptr); - - tryagain: - uint32_t write_ptr = write_ptr_and_epoch >> 1; - - if (write_ptr < dealloc_ptr) { - // behind dealloc_ptr, check that there is room - if ((dealloc_ptr - write_ptr) <= alloc_size) { - // There is no more room, try to deallocate something - if (dealloc_one()) { - goto tryagain; - } - return nullptr; - } - } else { - // ahead of dealloc_ptr, check that there is room - - if ((command_mem_size - write_ptr) < alloc_size + sizeof(uint32_t)) { - // no room at the end, wrap down; - - if (dealloc_ptr == 0) { // don't want write_ptr to become dealloc_ptr - - // There is no more room, try to deallocate something - if (dealloc_one()) { - goto tryagain; - } - return nullptr; - } - - // if this happens, it's a bug - ERR_FAIL_COND_V((command_mem_size - write_ptr) < 8, nullptr); - // zero means, wrap to beginning - - uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = 1; - write_ptr_and_epoch = 0 | (1 & ~write_ptr_and_epoch); // Invert epoch. - // See if we can get the thread to run and clear up some more space while we wait. - // This is required if alloc_size * 2 + 4 > COMMAND_MEM_SIZE - if (sync) { - sync->post(); - } - goto tryagain; - } - } - // Allocate the size and the 'in use' bit. - // First bit used to mark if command is still in use (1) - // or if it has been destroyed and can be deallocated (0). - uint32_t size = (sizeof(T) + 8 - 1) & ~(8 - 1); - uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = (size << 1) | 1; - write_ptr += 8; - // allocate the command - T *cmd = memnew_placement(&command_mem[write_ptr], T); - write_ptr += size; - write_ptr_and_epoch = (write_ptr << 1) | (write_ptr_and_epoch & 1); + uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)); + uint64_t size = command_mem.size(); + command_mem.resize(size + alloc_size + 8); + *(uint64_t *)&command_mem[size] = alloc_size; + T *cmd = memnew_placement(&command_mem[size + 8], T); return cmd; } template <class T> T *allocate_and_lock() { lock(); - T *ret; - - while ((ret = allocate<T>()) == nullptr) { - unlock(); - // sleep a little until fetch happened and some room is made - wait_for_flush(); - lock(); - } - + T *ret = allocate<T>(); return ret; } - bool flush_one(bool p_lock = true) { - if (p_lock) { - lock(); - } - tryagain: - - // tried to read an empty queue - if (read_ptr_and_epoch == write_ptr_and_epoch) { - if (p_lock) { - unlock(); - } - return false; - } - - uint32_t read_ptr = read_ptr_and_epoch >> 1; - uint32_t size_ptr = read_ptr; - uint32_t size = *(uint32_t *)&command_mem[read_ptr] >> 1; - - if (size == 0) { - *(uint32_t *)&command_mem[read_ptr] = 0; // clear in-use bit. - //end of ringbuffer, wrap - read_ptr_and_epoch = 0 | (1 & ~read_ptr_and_epoch); // Invert epoch. - goto tryagain; - } - - read_ptr += 8; + void _flush() { + lock(); - CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); + uint64_t read_ptr = 0; + uint64_t limit = command_mem.size(); - read_ptr += size; + while (read_ptr < limit) { + uint64_t size = *(uint64_t *)&command_mem[read_ptr]; + read_ptr += 8; + CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); - read_ptr_and_epoch = (read_ptr << 1) | (read_ptr_and_epoch & 1); + cmd->call(); //execute the function + cmd->post(); //release in case it needs sync/ret + cmd->~CommandBase(); //should be done, so erase the command - if (p_lock) { - unlock(); - } - cmd->call(); - if (p_lock) { - lock(); + read_ptr += size; } - cmd->post(); - cmd->~CommandBase(); - *(uint32_t *)&command_mem[size_ptr] &= ~1; - - if (p_lock) { - unlock(); - } - return true; + command_mem.clear(); + unlock(); } void lock(); void unlock(); void wait_for_flush(); SyncSemaphore *_alloc_sync_sem(); - bool dealloc_one(); public: /* NORMAL PUSH COMMANDS */ @@ -492,23 +399,19 @@ public: DECL_PUSH_AND_SYNC(0) SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 15) - void wait_and_flush_one() { - ERR_FAIL_COND(!sync); - sync->wait(); - flush_one(); - } - _FORCE_INLINE_ void flush_if_pending() { - if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) { - flush_all(); + if (unlikely(command_mem.size() > 0)) { + _flush(); } } void flush_all() { - //ERR_FAIL_COND(sync); - lock(); - while (flush_one(false)) { - } - unlock(); + _flush(); + } + + void wait_and_flush() { + ERR_FAIL_COND(!sync); + sync->wait(); + _flush(); } CommandQueueMT(bool p_sync); diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index dc378aed69..1257b54449 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -291,7 +291,7 @@ public: } /** - * Same as get, except it can return nullptr when item was not found. + * Same as get, except it can return nullptr when item was not found. * This is mainly used for speed purposes. */ @@ -324,7 +324,7 @@ public: } /** - * Same as get, except it can return nullptr when item was not found. + * Same as get, except it can return nullptr when item was not found. * This version is custom, will take a hash and a custom key (that should support operator==() */ @@ -443,7 +443,7 @@ public: /** * Get the next key to p_key, and the first key if p_key is null. - * Returns a pointer to the next key if found, nullptr otherwise. + * Returns a pointer to the next key if found, nullptr otherwise. * Adding/Removing elements while iterating will, of course, have unexpected results, don't do it. * * Example: diff --git a/core/templates/list.h b/core/templates/list.h index 010e35eed8..6047b89670 100644 --- a/core/templates/list.h +++ b/core/templates/list.h @@ -135,6 +135,83 @@ public: _FORCE_INLINE_ Element() {} }; + typedef T ValueType; + + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ T *operator->() const { return &E->get(); } + _FORCE_INLINE_ Iterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + Iterator(Element *p_E) { E = p_E; } + Iterator() {} + Iterator(const Iterator &p_it) { E = p_it.E; } + + private: + Element *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ const T *operator->() const { return &E->get(); } + _FORCE_INLINE_ ConstIterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + _FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; } + _FORCE_INLINE_ ConstIterator() {} + _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + + private: + const Element *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(front()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ Iterator find(const K &p_key) { + return Iterator(find(p_key)); + } +#endif + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(front()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } +#if 0 + //to use when replacing find() + _FORCE_INLINE_ ConstIterator find(const K &p_key) const { + return ConstIterator(find(p_key)); + } +#endif private: struct _Data { Element *first = nullptr; diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h index 5f22e08eb8..668ec513d6 100644 --- a/core/templates/local_vector.h +++ b/core/templates/local_vector.h @@ -178,7 +178,7 @@ public: } int64_t find(const T &p_val, U p_from = 0) const { - for (U i = 0; i < count; i++) { + for (U i = p_from; i < count; i++) { if (data[i] == p_val) { return int64_t(i); } diff --git a/core/templates/map.h b/core/templates/map.h index 7dfee13d2c..a47547d355 100644 --- a/core/templates/map.h +++ b/core/templates/map.h @@ -33,6 +33,7 @@ #include "core/error/error_macros.h" #include "core/os/memory.h" +#include "core/templates/pair.h" // based on the very nice implementation of rb-trees by: // https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html @@ -55,11 +56,12 @@ public: Element *parent = nullptr; Element *_next = nullptr; Element *_prev = nullptr; - K _key; - V _value; - //_Data *data; + KeyValue<K, V> _data; public: + KeyValue<K, V> &key_value() { return _data; } + const KeyValue<K, V> &key_value() const { return _data; } + const Element *next() const { return _next; } @@ -73,23 +75,106 @@ public: return _prev; } const K &key() const { - return _key; + return _data.key; } V &value() { - return _value; + return _data.value; } const V &value() const { - return _value; + return _data.value; } V &get() { - return _value; + return _data.value; } const V &get() const { - return _value; + return _data.value; } - Element() {} + Element(const KeyValue<K, V> &p_data) : + _data(p_data) {} }; + typedef KeyValue<K, V> ValueType; + + struct Iterator { + _FORCE_INLINE_ KeyValue<K, V> &operator*() const { + return E->key_value(); + } + _FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); } + _FORCE_INLINE_ Iterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + Iterator(Element *p_E) { E = p_E; } + Iterator() {} + Iterator(const Iterator &p_it) { E = p_it.E; } + + private: + Element *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const KeyValue<K, V> &operator*() const { + return E->key_value(); + } + _FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); } + _FORCE_INLINE_ ConstIterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; } + + ConstIterator(const Element *p_E) { E = p_E; } + ConstIterator() {} + ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + + private: + const Element *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(front()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ Iterator find(const K &p_key) { + return Iterator(find(p_key)); + } +#endif + _FORCE_INLINE_ void remove(const Iterator &p_iter) { + return erase(p_iter.E); + } + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(front()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ ConstIterator find(const K &p_key) const { + return ConstIterator(find(p_key)); + } +#endif private: struct _Data { Element *_root = nullptr; @@ -107,7 +192,7 @@ private: } void _create_root() { - _root = memnew_allocator(Element, A); + _root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A); _root->parent = _root->left = _root->right = _nil; _root->color = BLACK; } @@ -216,9 +301,9 @@ private: C less; while (node != _data._nil) { - if (less(p_key, node->_key)) { + if (less(p_key, node->_data.key)) { node = node->left; - } else if (less(node->_key, p_key)) { + } else if (less(node->_data.key, p_key)) { node = node->right; } else { return node; // found @@ -236,9 +321,9 @@ private: while (node != _data._nil) { prev = node; - if (less(p_key, node->_key)) { + if (less(p_key, node->_data.key)) { node = node->left; - } else if (less(node->_key, p_key)) { + } else if (less(node->_data.key, p_key)) { node = node->right; } else { return node; // found @@ -249,7 +334,7 @@ private: return nullptr; // tree empty } - if (less(p_key, prev->_key)) { + if (less(p_key, prev->_data.key)) { prev = prev->_prev; } @@ -312,25 +397,25 @@ private: while (node != _data._nil) { new_parent = node; - if (less(p_key, node->_key)) { + if (less(p_key, node->_data.key)) { node = node->left; - } else if (less(node->_key, p_key)) { + } else if (less(node->_data.key, p_key)) { node = node->right; } else { - node->_value = p_value; + node->_data.value = p_value; return node; // Return existing node with new value } } - Element *new_node = memnew_allocator(Element, A); + typedef KeyValue<K, V> KV; + Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A); new_node->parent = new_parent; new_node->right = _data._nil; new_node->left = _data._nil; - new_node->_key = p_key; - new_node->_value = p_value; + //new_node->data=_data; - if (new_parent == _data._root || less(p_key, new_parent->_key)) { + if (new_parent == _data._root || less(p_key, new_parent->_data.key)) { new_parent->left = new_node; } else { new_parent->right = new_node; @@ -575,7 +660,7 @@ public: CRASH_COND(!_data._root); const Element *e = find(p_key); CRASH_COND(!e); - return e->_value; + return e->_data.value; } V &operator[](const K &p_key) { @@ -588,7 +673,7 @@ public: e = insert(p_key, V()); } - return e->_value; + return e->_data.value; } Element *front() const { diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h index 2c7c64cd78..025cc30db4 100644 --- a/core/templates/oa_hash_map.h +++ b/core/templates/oa_hash_map.h @@ -231,7 +231,7 @@ public: /** * returns true if the value was found, false otherwise. * - * if r_data is not nullptr then the value will be written to the object + * if r_data is not nullptr then the value will be written to the object * it points to. */ bool lookup(const TKey &p_key, TValue &r_data) const { @@ -249,7 +249,7 @@ public: /** * returns true if the value was found, false otherwise. * - * if r_data is not nullptr then the value will be written to the object + * if r_data is not nullptr then the value will be written to the object * it points to. */ TValue *lookup_ptr(const TKey &p_key) const { diff --git a/core/templates/pair.h b/core/templates/pair.h index bc1a764694..31706b6ecb 100644 --- a/core/templates/pair.h +++ b/core/templates/pair.h @@ -31,6 +31,8 @@ #ifndef PAIR_H #define PAIR_H +#include "core/typedefs.h" + template <class F, class S> struct Pair { F first; @@ -64,4 +66,37 @@ struct PairSort { } }; +template <class K, class V> +struct KeyValue { + const K key; + V value; + + void operator=(const KeyValue &p_kv) = delete; + _FORCE_INLINE_ KeyValue(const KeyValue &p_kv) : + key(p_kv.key), + value(p_kv.value) { + } + _FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) : + key(p_key), + value(p_value) { + } +}; + +template <class K, class V> +bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) { + return (pair.key == other.key) && (pair.value == other.value); +} + +template <class K, class V> +bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) { + return (pair.key != other.key) || (pair.value != other.value); +} + +template <class K, class V> +struct KeyValueSort { + bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const { + return A.key < B.key; + } +}; + #endif // PAIR_H diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h index c4aa93c394..4f5c74ca46 100644 --- a/core/templates/rid_owner.h +++ b/core/templates/rid_owner.h @@ -79,7 +79,7 @@ class RID_Alloc : public RID_AllocBase { SpinLock spin_lock; - _FORCE_INLINE_ RID _allocate_rid(const T *p_initializer) { + _FORCE_INLINE_ RID _allocate_rid() { if (THREAD_SAFE) { spin_lock.lock(); } @@ -114,11 +114,6 @@ class RID_Alloc : public RID_AllocBase { uint32_t free_chunk = free_index / elements_in_chunk; uint32_t free_element = free_index % elements_in_chunk; - if (p_initializer) { - T *ptr = &chunks[free_chunk][free_element]; - memnew_placement(ptr, T(*p_initializer)); - } - uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF); uint64_t id = validator; id <<= 32; @@ -126,9 +121,7 @@ class RID_Alloc : public RID_AllocBase { validator_chunks[free_chunk][free_element] = validator; - if (!p_initializer) { - validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit - } + validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit alloc_count++; @@ -140,13 +133,20 @@ class RID_Alloc : public RID_AllocBase { } public: + RID make_rid() { + RID rid = _allocate_rid(); + initialize_rid(rid); + return rid; + } RID make_rid(const T &p_value) { - return _allocate_rid(&p_value); + RID rid = _allocate_rid(); + initialize_rid(rid, p_value); + return rid; } //allocate but don't initialize, use initialize_rid afterwards RID allocate_rid() { - return _allocate_rid(nullptr); + return _allocate_rid(); } _FORCE_INLINE_ T *getornull(const RID &p_rid, bool p_initialize = false) { @@ -193,7 +193,7 @@ public: if (THREAD_SAFE) { spin_lock.unlock(); } - if (validator_chunks[idx_chunk][idx_element] & 0x80000000) { + if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) { ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID"); } return nullptr; @@ -207,6 +207,11 @@ public: return ptr; } + void initialize_rid(RID p_rid) { + T *mem = getornull(p_rid, true); + ERR_FAIL_COND(!mem); + memnew_placement(mem, T); + } void initialize_rid(RID p_rid, const T &p_value) { T *mem = getornull(p_rid, true); ERR_FAIL_COND(!mem); @@ -333,7 +338,7 @@ public: description = p_descrption; } - RID_Alloc(uint32_t p_target_chunk_byte_size = 4096) { + RID_Alloc(uint32_t p_target_chunk_byte_size = 65536) { elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T)); } @@ -351,6 +356,9 @@ public: for (size_t i = 0; i < max_alloc; i++) { uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk]; + if (validator & 0x80000000) { + continue; //uninitialized + } if (validator != 0xFFFFFFFF) { chunks[i / elements_in_chunk][i % elements_in_chunk].~T(); } @@ -431,7 +439,7 @@ public: alloc.set_description(p_descrption); } - RID_PtrOwner(uint32_t p_target_chunk_byte_size = 4096) : + RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536) : alloc(p_target_chunk_byte_size) {} }; @@ -440,6 +448,9 @@ class RID_Owner { RID_Alloc<T, THREAD_SAFE> alloc; public: + _FORCE_INLINE_ RID make_rid() { + return alloc.make_rid(); + } _FORCE_INLINE_ RID make_rid(const T &p_ptr) { return alloc.make_rid(p_ptr); } @@ -448,6 +459,10 @@ public: return alloc.allocate_rid(); } + _FORCE_INLINE_ void initialize_rid(RID p_rid) { + alloc.initialize_rid(p_rid); + } + _FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) { alloc.initialize_rid(p_rid, p_ptr); } @@ -483,7 +498,7 @@ public: void set_description(const char *p_descrption) { alloc.set_description(p_descrption); } - RID_Owner(uint32_t p_target_chunk_byte_size = 4096) : + RID_Owner(uint32_t p_target_chunk_byte_size = 65536) : alloc(p_target_chunk_byte_size) {} }; diff --git a/core/templates/set.h b/core/templates/set.h index 3036ecf27d..245c174862 100644 --- a/core/templates/set.h +++ b/core/templates/set.h @@ -77,6 +77,85 @@ public: Element() {} }; + typedef T ValueType; + + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ T *operator->() const { return &E->get(); } + _FORCE_INLINE_ Iterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + Iterator(Element *p_E) { E = p_E; } + Iterator() {} + Iterator(const Iterator &p_it) { E = p_it.E; } + + private: + Element *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ const T *operator->() const { return &E->get(); } + _FORCE_INLINE_ ConstIterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + _FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; } + _FORCE_INLINE_ ConstIterator() {} + _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + + private: + const Element *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(front()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ Iterator find(const K &p_key) { + return Iterator(find(p_key)); + } +#endif + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(front()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ ConstIterator find(const K &p_key) const { + return ConstIterator(find(p_key)); + } +#endif private: struct _Data { Element *_root = nullptr; diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h index 9f7a692cc5..b242648bc8 100644 --- a/core/templates/thread_work_pool.h +++ b/core/templates/thread_work_pool.h @@ -105,7 +105,7 @@ public: } bool is_done_dispatching() const { - ERR_FAIL_COND_V(current_work == nullptr, false); + ERR_FAIL_COND_V(current_work == nullptr, true); return index.load(std::memory_order_acquire) >= current_work->max_elements; } diff --git a/core/templates/vector.h b/core/templates/vector.h index dae8874a87..08cbef6ba4 100644 --- a/core/templates/vector.h +++ b/core/templates/vector.h @@ -187,6 +187,70 @@ public: return false; } + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return *elem_ptr; + } + _FORCE_INLINE_ T *operator->() const { return elem_ptr; } + _FORCE_INLINE_ Iterator &operator++() { + elem_ptr++; + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + elem_ptr--; + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; } + + Iterator(T *p_ptr) { elem_ptr = p_ptr; } + Iterator() {} + Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + T *elem_ptr = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return *elem_ptr; + } + _FORCE_INLINE_ const T *operator->() const { return elem_ptr; } + _FORCE_INLINE_ ConstIterator &operator++() { + elem_ptr++; + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + elem_ptr--; + return *this; + } + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; } + + ConstIterator(T *p_ptr) { elem_ptr = p_ptr; } + ConstIterator() {} + ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + const T *elem_ptr = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(ptrw()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(ptrw() + size()); + } + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(ptr()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(ptr() + size()); + } + _FORCE_INLINE_ Vector() {} _FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); } diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 830e0a5cbd..ef5867c685 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -31,6 +31,7 @@ #ifndef BINDER_COMMON_H #define BINDER_COMMON_H +#include "core/input/input_enums.h" #include "core/object/object.h" #include "core/templates/list.h" #include "core/templates/simple_type.h" @@ -76,6 +77,7 @@ struct VariantCaster<const T &> { _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \ return m_enum(*reinterpret_cast<const int *>(p_ptr)); \ } \ + typedef int64_t EncodeT; \ _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \ *(int *)p_ptr = p_val; \ } \ @@ -90,6 +92,12 @@ VARIANT_ENUM_CAST(Error); VARIANT_ENUM_CAST(Side); VARIANT_ENUM_CAST(ClockDirection); VARIANT_ENUM_CAST(Corner); +VARIANT_ENUM_CAST(HatDir); +VARIANT_ENUM_CAST(HatMask); +VARIANT_ENUM_CAST(JoyAxis); +VARIANT_ENUM_CAST(JoyButton); +VARIANT_ENUM_CAST(MIDIMessage); +VARIANT_ENUM_CAST(MouseButton); VARIANT_ENUM_CAST(Orientation); VARIANT_ENUM_CAST(HAlign); VARIANT_ENUM_CAST(VAlign); @@ -110,6 +118,7 @@ struct PtrToArg<char32_t> { _FORCE_INLINE_ static char32_t convert(const void *p_ptr) { return char32_t(*reinterpret_cast<const int *>(p_ptr)); } + typedef int64_t EncodeT; _FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) { *(int *)p_ptr = p_val; } diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 5c87042f6b..ca6f3d615e 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -33,7 +33,7 @@ #include "callable_bind.h" #include "core/object/message_queue.h" #include "core/object/object.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const { @@ -89,6 +89,10 @@ Callable Callable::unbind(int p_argcount) const { return Callable(memnew(CallableCustomUnbind(*this, p_argcount))); } +bool Callable::is_valid() const { + return get_object() && (is_custom() || get_object()->has_method(get_method())); +} + Object *Callable::get_object() const { if (is_null()) { return nullptr; diff --git a/core/variant/callable.h b/core/variant/callable.h index 20d0804292..52094af3aa 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -81,6 +81,7 @@ public: _FORCE_INLINE_ bool is_standard() const { return method != StringName(); } + bool is_valid() const; Callable bind(const Variant **p_arguments, int p_argcount) const; Callable unbind(int p_argcount) const; diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index b2f7c6aa0a..07b3a9a675 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -33,6 +33,11 @@ #include "core/templates/ordered_hash_map.h" #include "core/templates/safe_refcount.h" #include "core/variant/variant.h" +// required in this order by VariantInternal, do not remove this comment. +#include "core/object/class_db.h" +#include "core/object/object.h" +#include "core/variant/type_info.h" +#include "core/variant/variant_internal.h" struct DictionaryPrivate { SafeRefCount refcount; @@ -74,15 +79,32 @@ Variant Dictionary::get_value_at_index(int p_index) const { } Variant &Dictionary::operator[](const Variant &p_key) { - return _p->variant_map[p_key]; + 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]; + } } const Variant &Dictionary::operator[](const Variant &p_key) const { - return _p->variant_map[p_key]; + 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]; + } } const Variant *Dictionary::getptr(const Variant &p_key) const { - OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E; + + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); + } else { + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + } if (!E) { return nullptr; @@ -91,8 +113,14 @@ const Variant *Dictionary::getptr(const Variant &p_key) const { } Variant *Dictionary::getptr(const Variant &p_key) { - OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E; + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + E = ((OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); + } else { + E = ((OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + } if (!E) { return nullptr; } @@ -100,7 +128,14 @@ Variant *Dictionary::getptr(const Variant &p_key) { } Variant Dictionary::get_valid(const Variant &p_key) const { - OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E; + + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); + } else { + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + } if (!E) { return Variant(); @@ -126,7 +161,12 @@ bool Dictionary::is_empty() const { } bool Dictionary::has(const Variant &p_key) const { - return _p->variant_map.has(p_key); + 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); + } } bool Dictionary::has_all(const Array &p_keys) const { @@ -139,7 +179,12 @@ bool Dictionary::has_all(const Array &p_keys) const { } bool Dictionary::erase(const Variant &p_key) { - return _p->variant_map.erase(p_key); + 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); + } } bool Dictionary::operator==(const Dictionary &p_dictionary) const { diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index e91029f330..7852187b77 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -45,6 +45,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ @@ -54,6 +55,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ @@ -65,6 +67,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \ } \ + typedef m_conv EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \ } \ @@ -74,6 +77,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \ } \ + typedef m_conv EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \ } \ @@ -85,6 +89,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ @@ -94,12 +99,13 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ } -MAKE_PTRARG(bool); +MAKE_PTRARGCONV(bool, uint32_t); // Integer types. MAKE_PTRARGCONV(uint8_t, int64_t); MAKE_PTRARGCONV(int8_t, int64_t); @@ -122,10 +128,10 @@ MAKE_PTRARG_BY_REFERENCE(Vector3); MAKE_PTRARG_BY_REFERENCE(Vector3i); MAKE_PTRARG(Transform2D); MAKE_PTRARG_BY_REFERENCE(Plane); -MAKE_PTRARG(Quat); +MAKE_PTRARG(Quaternion); MAKE_PTRARG_BY_REFERENCE(AABB); MAKE_PTRARG_BY_REFERENCE(Basis); -MAKE_PTRARG_BY_REFERENCE(Transform); +MAKE_PTRARG_BY_REFERENCE(Transform3D); MAKE_PTRARG_BY_REFERENCE(Color); MAKE_PTRARG(StringName); MAKE_PTRARG(NodePath); @@ -153,7 +159,7 @@ struct PtrToArg<T *> { _FORCE_INLINE_ static T *convert(const void *p_ptr) { return const_cast<T *>(reinterpret_cast<const T *>(p_ptr)); } - + typedef Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { *((T **)p_ptr) = p_var; } @@ -164,7 +170,7 @@ struct PtrToArg<const T *> { _FORCE_INLINE_ static const T *convert(const void *p_ptr) { return reinterpret_cast<const T *>(p_ptr); } - + typedef const Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { *((T **)p_ptr) = p_var; } @@ -177,7 +183,7 @@ struct PtrToArg<ObjectID> { _FORCE_INLINE_ static const ObjectID convert(const void *p_ptr) { return ObjectID(*reinterpret_cast<const uint64_t *>(p_ptr)); } - + typedef uint64_t EncodeT; _FORCE_INLINE_ static void encode(const ObjectID &p_val, void *p_ptr) { *((uint64_t *)p_ptr) = p_val; } diff --git a/core/variant/type_info.h b/core/variant/type_info.h index d5b6d85dfb..76cb065d10 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -146,10 +146,10 @@ MAKE_TYPE_INFO(Rect2i, Variant::RECT2I) MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPE_INFO(Plane, Variant::PLANE) -MAKE_TYPE_INFO(Quat, Variant::QUAT) +MAKE_TYPE_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPE_INFO(AABB, Variant::AABB) MAKE_TYPE_INFO(Basis, Variant::BASIS) -MAKE_TYPE_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPE_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPE_INFO(Color, Variant::COLOR) MAKE_TYPE_INFO(StringName, Variant::STRING_NAME) MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH) diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h index e0309aa3fe..900dcf7689 100644 --- a/core/variant/typed_array.h +++ b/core/variant/typed_array.h @@ -98,10 +98,10 @@ MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY(Plane, Variant::PLANE) -MAKE_TYPED_ARRAY(Quat, Variant::QUAT) +MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY(AABB, Variant::AABB) MAKE_TYPED_ARRAY(Basis, Variant::BASIS) -MAKE_TYPED_ARRAY(Transform, Variant::TRANSFORM) +MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY(Color, Variant::COLOR) MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH) @@ -196,10 +196,10 @@ MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE) -MAKE_TYPED_ARRAY_INFO(Quat, Variant::QUAT) +MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB) MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS) -MAKE_TYPED_ARRAY_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR) MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH) diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 333dd8e8d1..badb5ba103 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -32,6 +32,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" +#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/io/resource.h" #include "core/math/math_funcs.h" @@ -91,16 +92,16 @@ String Variant::get_type_name(Variant::Type p_type) { case AABB: { return "AABB"; } break; - case QUAT: { - return "Quat"; + case QUATERNION: { + return "Quaternion"; } break; case BASIS: { return "Basis"; } break; - case TRANSFORM: { - return "Transform"; + case TRANSFORM3D: { + return "Transform3D"; } break; @@ -275,7 +276,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case TRANSFORM2D: { static const Type valid[] = { - TRANSFORM, + TRANSFORM3D, NIL }; @@ -300,7 +301,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; - case QUAT: { + case QUATERNION: { static const Type valid[] = { BASIS, NIL @@ -311,7 +312,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case BASIS: { static const Type valid[] = { - QUAT, + QUATERNION, VECTOR3, NIL }; @@ -319,10 +320,10 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { valid_types = valid; } break; - case TRANSFORM: { + case TRANSFORM3D: { static const Type valid[] = { TRANSFORM2D, - QUAT, + QUATERNION, BASIS, NIL }; @@ -582,7 +583,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case TRANSFORM2D: { static const Type valid[] = { - TRANSFORM, + TRANSFORM3D, NIL }; @@ -607,7 +608,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; - case QUAT: { + case QUATERNION: { static const Type valid[] = { BASIS, NIL @@ -618,7 +619,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case BASIS: { static const Type valid[] = { - QUAT, + QUATERNION, VECTOR3, NIL }; @@ -626,10 +627,10 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; - case TRANSFORM: { + case TRANSFORM3D: { static const Type valid[] = { TRANSFORM2D, - QUAT, + QUATERNION, BASIS, NIL }; @@ -873,16 +874,16 @@ bool Variant::is_zero() const { case AABB: { return *_data._aabb == ::AABB(); } break; - case QUAT: { - return *reinterpret_cast<const Quat *>(_data._mem) == Quat(); + case QUATERNION: { + return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion(); } break; case BASIS: { return *_data._basis == Basis(); } break; - case TRANSFORM: { - return *_data._transform == Transform(); + case TRANSFORM3D: { + return *_data._transform3d == Transform3D(); } break; @@ -1092,16 +1093,16 @@ void Variant::reference(const Variant &p_variant) { case AABB: { _data._aabb = memnew(::AABB(*p_variant._data._aabb)); } break; - case QUAT: { - memnew_placement(_data._mem, Quat(*reinterpret_cast<const Quat *>(p_variant._data._mem))); + case QUATERNION: { + memnew_placement(_data._mem, Quaternion(*reinterpret_cast<const Quaternion *>(p_variant._data._mem))); } break; case BASIS: { _data._basis = memnew(Basis(*p_variant._data._basis)); } break; - case TRANSFORM: { - _data._transform = memnew(Transform(*p_variant._data._transform)); + case TRANSFORM3D: { + _data._transform3d = memnew(Transform3D(*p_variant._data._transform3d)); } break; // misc types @@ -1115,9 +1116,9 @@ void Variant::reference(const Variant &p_variant) { case OBJECT: { memnew_placement(_data._mem, ObjData); - if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); - if (!reference->reference()) { + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) { + RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj); + if (!ref_counted->reference()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); break; @@ -1254,8 +1255,8 @@ void Variant::zero() { case PLANE: *reinterpret_cast<Plane *>(this->_data._mem) = Plane(); break; - case QUAT: - *reinterpret_cast<Quat *>(this->_data._mem) = Quat(); + case QUATERNION: + *reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion(); break; case COLOR: *reinterpret_cast<Color *>(this->_data._mem) = Color(); @@ -1275,7 +1276,7 @@ void Variant::_clear_internal() { // no point, they don't allocate memory VECTOR3, PLANE, - QUAT, + QUATERNION, COLOR, VECTOR2, RECT2 @@ -1289,8 +1290,8 @@ void Variant::_clear_internal() { case BASIS: { memdelete(_data._basis); } break; - case TRANSFORM: { - memdelete(_data._transform); + case TRANSFORM3D: { + memdelete(_data._transform3d); } break; // misc types @@ -1301,11 +1302,11 @@ void Variant::_clear_internal() { reinterpret_cast<NodePath *>(_data._mem)->~NodePath(); } break; case OBJECT: { - if (_get_obj().id.is_reference()) { + if (_get_obj().id.is_ref_counted()) { //we are safe that there is a reference here - Reference *reference = static_cast<Reference *>(_get_obj().obj); - if (reference->unreference()) { - memdelete(reference); + RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj); + if (ref_counted->unreference()) { + memdelete(ref_counted); } } _get_obj().obj = nullptr; @@ -1636,60 +1637,35 @@ String Variant::stringify(List<const void *> &stack) const { case STRING: return *reinterpret_cast<const String *>(_data._mem); case VECTOR2: - return "(" + operator Vector2() + ")"; + return operator Vector2(); case VECTOR2I: - return "(" + operator Vector2i() + ")"; + return operator Vector2i(); case RECT2: - return "(" + operator Rect2() + ")"; + return operator Rect2(); case RECT2I: - return "(" + operator Rect2i() + ")"; - case TRANSFORM2D: { - Transform2D mat32 = operator Transform2D(); - return "(" + Variant(mat32.elements[0]).operator String() + ", " + Variant(mat32.elements[1]).operator String() + ", " + Variant(mat32.elements[2]).operator String() + ")"; - } break; + return operator Rect2i(); + case TRANSFORM2D: + return operator Transform2D(); case VECTOR3: - return "(" + operator Vector3() + ")"; + return operator Vector3(); case VECTOR3I: - return "(" + operator Vector3i() + ")"; + return operator Vector3i(); case PLANE: return operator Plane(); - //case QUAT: case AABB: return operator ::AABB(); - case QUAT: - return "(" + operator Quat() + ")"; - case BASIS: { - Basis mat3 = operator Basis(); - - String mtx("("); - for (int i = 0; i < 3; i++) { - if (i != 0) { - mtx += ", "; - } - - mtx += "("; - - for (int j = 0; j < 3; j++) { - if (j != 0) { - mtx += ", "; - } - - mtx += Variant(mat3.elements[i][j]).operator String(); - } - - mtx += ")"; - } - - return mtx + ")"; - } break; - case TRANSFORM: - return operator Transform(); + case QUATERNION: + return operator Quaternion(); + case BASIS: + return operator Basis(); + case TRANSFORM3D: + return operator Transform3D(); case STRING_NAME: return operator StringName(); case NODE_PATH: return operator NodePath(); case COLOR: - return String::num(operator Color().r) + "," + String::num(operator Color().g) + "," + String::num(operator Color().b) + "," + String::num(operator Color().a); + return operator Color(); case DICTIONARY: { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); if (stack.find(d.id())) { @@ -1723,6 +1699,7 @@ String Variant::stringify(List<const void *> &stack) const { } str += "}"; + stack.erase(d.id()); return str; } break; case PACKED_VECTOR2_ARRAY: { @@ -1826,12 +1803,13 @@ String Variant::stringify(List<const void *> &stack) const { } str += "]"; + stack.erase(arr.id()); return str; } break; case OBJECT: { if (_get_obj().obj) { - if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { return "[Freed Object]"; } @@ -1861,6 +1839,11 @@ String Variant::stringify(List<const void *> &stack) const { return ""; } +String Variant::to_json_string() const { + JSON json; + return json.stringify(*this); +} + Variant::operator Vector2() const { if (type == VECTOR2) { return *reinterpret_cast<const Vector2 *>(_data._mem); @@ -1956,39 +1939,39 @@ Variant::operator ::AABB() const { Variant::operator Basis() const { if (type == BASIS) { return *_data._basis; - } else if (type == QUAT) { - return *reinterpret_cast<const Quat *>(_data._mem); + } else if (type == QUATERNION) { + return *reinterpret_cast<const Quaternion *>(_data._mem); } else if (type == VECTOR3) { return Basis(*reinterpret_cast<const Vector3 *>(_data._mem)); - } else if (type == TRANSFORM) { // unexposed in Variant::can_convert? - return _data._transform->basis; + } else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert? + return _data._transform3d->basis; } else { return Basis(); } } -Variant::operator Quat() const { - if (type == QUAT) { - return *reinterpret_cast<const Quat *>(_data._mem); +Variant::operator Quaternion() const { + if (type == QUATERNION) { + return *reinterpret_cast<const Quaternion *>(_data._mem); } else if (type == BASIS) { return *_data._basis; - } else if (type == TRANSFORM) { - return _data._transform->basis; + } else if (type == TRANSFORM3D) { + return _data._transform3d->basis; } else { - return Quat(); + return Quaternion(); } } -Variant::operator Transform() const { - if (type == TRANSFORM) { - return *_data._transform; +Variant::operator Transform3D() const { + if (type == TRANSFORM3D) { + return *_data._transform3d; } else if (type == BASIS) { - return Transform(*_data._basis, Vector3()); - } else if (type == QUAT) { - return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3()); + return Transform3D(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform3D(Basis(*reinterpret_cast<const Quaternion *>(_data._mem)), Vector3()); } else if (type == TRANSFORM2D) { const Transform2D &t = *_data._transform2d; - Transform m; + Transform3D m; m.basis.elements[0][0] = t.elements[0][0]; m.basis.elements[1][0] = t.elements[0][1]; m.basis.elements[0][1] = t.elements[1][0]; @@ -1997,15 +1980,15 @@ Variant::operator Transform() const { m.origin[1] = t.elements[2][1]; return m; } else { - return Transform(); + return Transform3D(); } } Variant::operator Transform2D() const { if (type == TRANSFORM2D) { return *_data._transform2d; - } else if (type == TRANSFORM) { - const Transform &t = *_data._transform; + } else if (type == TRANSFORM3D) { + const Transform3D &t = *_data._transform3d; Transform2D m; m.elements[0][0] = t.basis.elements[0][0]; m.elements[0][1] = t.basis.elements[1][0]; @@ -2495,14 +2478,14 @@ Variant::Variant(const Basis &p_matrix) { _data._basis = memnew(Basis(p_matrix)); } -Variant::Variant(const Quat &p_quat) { - type = QUAT; - memnew_placement(_data._mem, Quat(p_quat)); +Variant::Variant(const Quaternion &p_quaternion) { + type = QUATERNION; + memnew_placement(_data._mem, Quaternion(p_quaternion)); } -Variant::Variant(const Transform &p_transform) { - type = TRANSFORM; - _data._transform = memnew(Transform(p_transform)); +Variant::Variant(const Transform3D &p_transform) { + type = TRANSFORM3D; + _data._transform3d = memnew(Transform3D(p_transform)); } Variant::Variant(const Transform2D &p_transform) { @@ -2531,9 +2514,9 @@ Variant::Variant(const Object *p_object) { memnew_placement(_data._mem, ObjData); if (p_object) { - if (p_object->is_reference()) { - Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(p_object)); - if (!reference->init_ref()) { + if (p_object->is_ref_counted()) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_object)); + if (!ref_counted->init_ref()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); return; @@ -2739,14 +2722,14 @@ void Variant::operator=(const Variant &p_variant) { case AABB: { *_data._aabb = *(p_variant._data._aabb); } break; - case QUAT: { - *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem); + case QUATERNION: { + *reinterpret_cast<Quaternion *>(_data._mem) = *reinterpret_cast<const Quaternion *>(p_variant._data._mem); } break; case BASIS: { *_data._basis = *(p_variant._data._basis); } break; - case TRANSFORM: { - *_data._transform = *(p_variant._data._transform); + case TRANSFORM3D: { + *_data._transform3d = *(p_variant._data._transform3d); } break; // misc types @@ -2757,17 +2740,17 @@ void Variant::operator=(const Variant &p_variant) { *reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast<const ::RID *>(p_variant._data._mem); } break; case OBJECT: { - if (_get_obj().id.is_reference()) { + if (_get_obj().id.is_ref_counted()) { //we are safe that there is a reference here - Reference *reference = static_cast<Reference *>(_get_obj().obj); - if (reference->unreference()) { - memdelete(reference); + RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj); + if (ref_counted->unreference()) { + memdelete(ref_counted); } } - if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); - if (!reference->reference()) { + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) { + RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj); + if (!ref_counted->reference()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); break; @@ -2916,11 +2899,11 @@ uint32_t Variant::hash() const { return hash; } break; - case QUAT: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->x); - hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->y, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->z, hash); - return hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->w, hash); + case QUATERNION: { + uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->x); + hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->y, hash); + hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->z, hash); + return hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->w, hash); } break; case BASIS: { @@ -2934,13 +2917,13 @@ uint32_t Variant::hash() const { return hash; } break; - case TRANSFORM: { + case TRANSFORM3D: { uint32_t hash = 5831; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - hash = hash_djb2_one_float(_data._transform->basis.elements[i][j], hash); + hash = hash_djb2_one_float(_data._transform3d->basis.elements[i][j], hash); } - hash = hash_djb2_one_float(_data._transform->origin[i], hash); + hash = hash_djb2_one_float(_data._transform3d->origin[i], hash); } return hash; @@ -3127,7 +3110,7 @@ uint32_t Variant::hash() const { (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) -#define hash_compare_quat(p_lhs, p_rhs) \ +#define hash_compare_quaternion(p_lhs, p_rhs) \ (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \ @@ -3235,11 +3218,11 @@ bool Variant::hash_compare(const Variant &p_variant) const { } break; - case QUAT: { - const Quat *l = reinterpret_cast<const Quat *>(_data._mem); - const Quat *r = reinterpret_cast<const Quat *>(p_variant._data._mem); + case QUATERNION: { + const Quaternion *l = reinterpret_cast<const Quaternion *>(_data._mem); + const Quaternion *r = reinterpret_cast<const Quaternion *>(p_variant._data._mem); - return hash_compare_quat(*l, *r); + return hash_compare_quaternion(*l, *r); } break; case BASIS: { @@ -3255,9 +3238,9 @@ bool Variant::hash_compare(const Variant &p_variant) const { return true; } break; - case TRANSFORM: { - const Transform *l = _data._transform; - const Transform *r = p_variant._data._transform; + case TRANSFORM3D: { + const Transform3D *l = _data._transform3d; + const Transform3D *r = p_variant._data._transform3d; for (int i = 0; i < 3; i++) { if (!(hash_compare_vector3(l->basis.elements[i], r->basis.elements[i]))) { @@ -3324,7 +3307,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { } bool Variant::is_ref() const { - return type == OBJECT && _get_obj().id.is_reference(); + return type == OBJECT && _get_obj().id.is_ref_counted(); } Vector<Variant> varray() { diff --git a/core/variant/variant.h b/core/variant/variant.h index 7f3c3477fc..373fe32921 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -37,9 +37,9 @@ #include "core/math/color.h" #include "core/math/face3.h" #include "core/math/plane.h" -#include "core/math/quat.h" -#include "core/math/transform.h" +#include "core/math/quaternion.h" #include "core/math/transform_2d.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/math/vector3i.h" #include "core/object/object_id.h" @@ -88,10 +88,10 @@ public: VECTOR3I, TRANSFORM2D, PLANE, - QUAT, + QUATERNION, AABB, BASIS, - TRANSFORM, + TRANSFORM3D, // misc types COLOR, @@ -200,7 +200,7 @@ private: Transform2D *_transform2d; ::AABB *_aabb; Basis *_basis; - Transform *_transform; + Transform3D *_transform3d; PackedArrayRefBase *packed_array; void *_ptr; //generic pointer uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]; @@ -225,7 +225,7 @@ private: false, //VECTOR3I, true, //TRANSFORM2D, false, //PLANE, - false, //QUAT, + false, //QUATERNION, true, //AABB, true, //BASIS, true, //TRANSFORM, @@ -320,10 +320,10 @@ public: operator Vector3i() const; operator Plane() const; operator ::AABB() const; - operator Quat() const; + operator Quaternion() const; operator Basis() const; - operator Transform() const; operator Transform2D() const; + operator Transform3D() const; operator Color() const; operator NodePath() const; @@ -392,10 +392,10 @@ public: Variant(const Vector3i &p_vector3i); Variant(const Plane &p_plane); Variant(const ::AABB &p_aabb); - Variant(const Quat &p_quat); + Variant(const Quaternion &p_quat); Variant(const Basis &p_matrix); Variant(const Transform2D &p_transform); - Variant(const Transform &p_transform); + Variant(const Transform3D &p_transform); Variant(const Color &p_color); Variant(const NodePath &p_node_path); Variant(const ::RID &p_rid); @@ -499,6 +499,7 @@ public: static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method); static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list); static int get_builtin_method_count(Variant::Type p_type); + static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method); void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error); Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant()); @@ -586,7 +587,7 @@ public: typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value); typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value); - typedef bool (*PTRKeyedChecker)(const void *base, const void *key); + typedef uint32_t (*PTRKeyedChecker)(const void *base, const void *key); static PTRKeyedSetter get_member_ptr_keyed_setter(Variant::Type p_type); static PTRKeyedGetter get_member_ptr_keyed_getter(Variant::Type p_type); @@ -631,6 +632,7 @@ public: static bool has_utility_function_return_value(const StringName &p_name); static Variant::Type get_utility_function_return_type(const StringName &p_name); static bool is_utility_function_vararg(const StringName &p_name); + static uint32_t get_utility_function_hash(const StringName &p_name); static void get_utility_function_list(List<StringName> *r_functions); static int get_utility_function_count(); @@ -645,6 +647,7 @@ public: bool hash_compare(const Variant &p_variant) const; bool booleanize() const; String stringify(List<const void *> &stack) const; + String to_json_string() const; void static_assign(const Variant &p_variant); static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index d9cc97154d..733361fe58 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -972,7 +972,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg return; } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return; } @@ -1126,6 +1126,25 @@ bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p return method->is_vararg; } +uint32_t Variant::get_builtin_method_hash(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, 0); + uint32_t hash = hash_djb2_one_32(method->is_const); + hash = hash_djb2_one_32(method->is_static, hash); + hash = hash_djb2_one_32(method->is_vararg, hash); + hash = hash_djb2_one_32(method->has_return_type, hash); + if (method->has_return_type) { + hash = hash_djb2_one_32(method->return_type, hash); + } + hash = hash_djb2_one_32(method->argument_count, hash); + for (int i = 0; i < method->argument_count; i++) { + hash = method->get_argument_type(i); + } + + return hash; +} + void Variant::get_method_list(List<MethodInfo> *p_list) const { if (type == OBJECT) { Object *obj = get_validated_object(); @@ -1365,7 +1384,7 @@ static void _register_variant_builtin_methods() { // FIXME: Static function, not sure how to bind //bind_method(String, humanize_size, sarray("size"), varray()); - bind_method(String, is_abs_path, sarray(), varray()); + bind_method(String, is_absolute_path, sarray(), varray()); bind_method(String, is_rel_path, sarray(), varray()); bind_method(String, get_base_dir, sarray(), varray()); bind_method(String, get_file, sarray(), varray()); @@ -1380,7 +1399,7 @@ static void _register_variant_builtin_methods() { bind_method(String, validate_node_name, sarray(), varray()); bind_method(String, is_valid_identifier, sarray(), varray()); - bind_method(String, is_valid_integer, 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()); @@ -1544,19 +1563,20 @@ static void _register_variant_builtin_methods() { bind_methodv(Plane, intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray()); bind_methodv(Plane, intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray()); - /* Quat */ - - bind_method(Quat, length, sarray(), varray()); - bind_method(Quat, length_squared, sarray(), varray()); - bind_method(Quat, normalized, sarray(), varray()); - bind_method(Quat, is_normalized, sarray(), varray()); - bind_method(Quat, is_equal_approx, sarray("to"), varray()); - bind_method(Quat, inverse, sarray(), varray()); - bind_method(Quat, dot, sarray("with"), varray()); - bind_method(Quat, slerp, sarray("to", "weight"), varray()); - bind_method(Quat, slerpni, sarray("to", "weight"), varray()); - bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); - bind_method(Quat, get_euler, sarray(), varray()); + /* Quaternion */ + + bind_method(Quaternion, length, sarray(), varray()); + bind_method(Quaternion, length_squared, sarray(), varray()); + 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, inverse, sarray(), varray()); + bind_method(Quaternion, angle_to, sarray("to"), varray()); + bind_method(Quaternion, dot, sarray("with"), varray()); + bind_method(Quaternion, slerp, sarray("to", "weight"), varray()); + bind_method(Quaternion, slerpni, sarray("to", "weight"), varray()); + bind_method(Quaternion, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Quaternion, get_euler, sarray(), varray()); /* Color */ @@ -1610,6 +1630,7 @@ static void _register_variant_builtin_methods() { bind_method(Callable, is_null, sarray(), varray()); bind_method(Callable, is_custom, sarray(), varray()); bind_method(Callable, is_standard, sarray(), varray()); + bind_method(Callable, is_valid, sarray(), varray()); bind_method(Callable, get_object, sarray(), varray()); bind_method(Callable, get_object_id, sarray(), varray()); bind_method(Callable, get_method, sarray(), varray()); @@ -1651,6 +1672,8 @@ 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, set_rotation, sarray("rotation"), varray()); + bind_method(Transform2D, looking_at, sarray("target"), varray(Transform2D())); /* Basis */ @@ -1668,7 +1691,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, get_orthogonal_index, sarray(), varray()); bind_method(Basis, slerp, sarray("to", "weight"), varray()); bind_method(Basis, is_equal_approx, sarray("b"), varray()); - bind_method(Basis, get_rotation_quat, sarray(), varray()); + bind_method(Basis, get_rotation_quaternion, sarray(), varray()); /* AABB */ @@ -1696,17 +1719,17 @@ static void _register_variant_builtin_methods() { bind_methodv(AABB, intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray()); bind_methodv(AABB, intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray()); - /* Transform */ + /* Transform3D */ - bind_method(Transform, inverse, sarray(), varray()); - bind_method(Transform, affine_inverse, sarray(), varray()); - bind_method(Transform, orthonormalized, sarray(), varray()); - bind_method(Transform, rotated, sarray("axis", "phi"), varray()); - bind_method(Transform, scaled, sarray("scale"), varray()); - bind_method(Transform, translated, sarray("offset"), varray()); - bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); - bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray()); - bind_method(Transform, is_equal_approx, sarray("xform"), varray()); + bind_method(Transform3D, inverse, sarray(), varray()); + bind_method(Transform3D, affine_inverse, sarray(), varray()); + bind_method(Transform3D, orthonormalized, sarray(), varray()); + bind_method(Transform3D, rotated, sarray("axis", "phi"), varray()); + bind_method(Transform3D, scaled, sarray("scale"), varray()); + bind_method(Transform3D, translated, sarray("offset"), varray()); + 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()); /* Dictionary */ @@ -2025,14 +2048,14 @@ static void _register_variant_builtin_methods() { _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)); - Transform identity_transform = Transform(); - Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); - Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0); - Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform); + Transform3D identity_transform = Transform3D(); + 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); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "IDENTITY", identity_transform); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_X", flip_x_transform); + _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 flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1); @@ -2047,7 +2070,7 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0)); _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0)); - _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1)); + _VariantCall::add_variant_constant(Variant::QUATERNION, "IDENTITY", Quaternion(0, 0, 0, 1)); } void Variant::_register_variant_methods() { diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index f0c9e52b46..a1a2bec369 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -28,543 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "variant.h" - -#include "core/core_string_names.h" -#include "core/crypto/crypto_core.h" -#include "core/debugger/engine_debugger.h" -#include "core/io/compression.h" -#include "core/object/class_db.h" -#include "core/os/os.h" -#include "core/templates/local_vector.h" -#include "core/templates/oa_hash_map.h" - -template <class T> -struct PtrConstruct {}; - -#define MAKE_PTRCONSTRUCT(m_type) \ - template <> \ - struct PtrConstruct<m_type> { \ - _FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \ - memnew_placement(p_ptr, m_type(p_value)); \ - } \ - }; - -MAKE_PTRCONSTRUCT(bool); -MAKE_PTRCONSTRUCT(int64_t); -MAKE_PTRCONSTRUCT(double); -MAKE_PTRCONSTRUCT(String); -MAKE_PTRCONSTRUCT(Vector2); -MAKE_PTRCONSTRUCT(Vector2i); -MAKE_PTRCONSTRUCT(Rect2); -MAKE_PTRCONSTRUCT(Rect2i); -MAKE_PTRCONSTRUCT(Vector3); -MAKE_PTRCONSTRUCT(Vector3i); -MAKE_PTRCONSTRUCT(Transform2D); -MAKE_PTRCONSTRUCT(Plane); -MAKE_PTRCONSTRUCT(Quat); -MAKE_PTRCONSTRUCT(AABB); -MAKE_PTRCONSTRUCT(Basis); -MAKE_PTRCONSTRUCT(Transform); -MAKE_PTRCONSTRUCT(Color); -MAKE_PTRCONSTRUCT(StringName); -MAKE_PTRCONSTRUCT(NodePath); -MAKE_PTRCONSTRUCT(RID); - -template <> -struct PtrConstruct<Object *> { - _FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) { - *((Object **)p_ptr) = p_value; - } -}; - -MAKE_PTRCONSTRUCT(Callable); -MAKE_PTRCONSTRUCT(Signal); -MAKE_PTRCONSTRUCT(Dictionary); -MAKE_PTRCONSTRUCT(Array); -MAKE_PTRCONSTRUCT(PackedByteArray); -MAKE_PTRCONSTRUCT(PackedInt32Array); -MAKE_PTRCONSTRUCT(PackedInt64Array); -MAKE_PTRCONSTRUCT(PackedFloat32Array); -MAKE_PTRCONSTRUCT(PackedFloat64Array); -MAKE_PTRCONSTRUCT(PackedStringArray); -MAKE_PTRCONSTRUCT(PackedVector2Array); -MAKE_PTRCONSTRUCT(PackedVector3Array); -MAKE_PTRCONSTRUCT(PackedColorArray); -MAKE_PTRCONSTRUCT(Variant); - -template <class T, class... P> -class VariantConstructor { - template <size_t... Is> - static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) { - r_error.error = Callable::CallError::CALL_OK; - -#ifdef DEBUG_METHODS_ENABLED - base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); -#else - base = T(VariantCaster<P>::cast(*p_args[Is])...); -#endif - } - - template <size_t... Is> - static _FORCE_INLINE_ void validated_construct_helper(T &base, const Variant **p_args, IndexSequence<Is...>) { - base = T((*VariantGetInternalPtr<P>::get_ptr(p_args[Is]))...); - } - - template <size_t... Is> - static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) { - PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base); - } - -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - r_error.error = Callable::CallError::CALL_OK; - VariantTypeChanger<T>::change(&r_ret); - construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<T>::change(r_ret); - validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{}); - } - static void ptr_construct(void *base, const void **p_args) { - ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{}); - } - - static int get_argument_count() { - return sizeof...(P); - } - - static Variant::Type get_argument_type(int p_arg) { - return call_get_argument_type<P...>(p_arg); - } - - static Variant::Type get_base_type() { - return GetTypeInfo<T>::VARIANT_TYPE; - } -}; - -class VariantConstructorObject { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - if (p_args[0]->get_type() == Variant::NIL) { - VariantInternal::object_assign_null(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } else if (p_args[0]->get_type() == Variant::OBJECT) { - VariantInternal::object_assign(&r_ret, p_args[0]); - r_error.error = Callable::CallError::CALL_OK; - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - } - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign(r_ret, p_args[0]); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::OBJECT; - } - - static Variant::Type get_base_type() { - return Variant::OBJECT; - } -}; - -class VariantConstructorNilObject { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != Variant::NIL) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::NIL; - } - - VariantInternal::clear(&r_ret); - VariantInternal::object_assign_null(&r_ret); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign_null(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Object *>::construct(nullptr, base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::OBJECT; - } -}; - -class VariantConstructorCallableArgs { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - ObjectID object_id; - StringName method; - - if (p_args[0]->get_type() == Variant::NIL) { - // leave as is - } else if (p_args[0]->get_type() == Variant::OBJECT) { - object_id = VariantInternal::get_object_id(p_args[0]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return; - } - - if (p_args[1]->get_type() == Variant::STRING_NAME) { - method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); - } else if (p_args[1]->get_type() == Variant::STRING) { - method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return; - } - - VariantTypeChanger<Callable>::change(&r_ret); - *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<Callable>::change(r_ret); - *VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); - } - - static int get_argument_count() { - return 2; - } - - static Variant::Type get_argument_type(int p_arg) { - if (p_arg == 0) { - return Variant::OBJECT; - } else { - return Variant::STRING_NAME; - } - } - - static Variant::Type get_base_type() { - return Variant::CALLABLE; - } -}; - -class VariantConstructorSignalArgs { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - ObjectID object_id; - StringName method; - - if (p_args[0]->get_type() == Variant::NIL) { - // leave as is - } else if (p_args[0]->get_type() == Variant::OBJECT) { - object_id = VariantInternal::get_object_id(p_args[0]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return; - } - - if (p_args[1]->get_type() == Variant::STRING_NAME) { - method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); - } else if (p_args[1]->get_type() == Variant::STRING) { - method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return; - } - - VariantTypeChanger<Signal>::change(&r_ret); - *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<Signal>::change(r_ret); - *VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); - } - - static int get_argument_count() { - return 2; - } - - static Variant::Type get_argument_type(int p_arg) { - if (p_arg == 0) { - return Variant::OBJECT; - } else { - return Variant::STRING_NAME; - } - } - - static Variant::Type get_base_type() { - return Variant::SIGNAL; - } -}; - -template <class T> -class VariantConstructorToArray { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != GetTypeInfo<T>::VARIANT_TYPE) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = GetTypeInfo<T>::VARIANT_TYPE; - return; - } - - VariantTypeChanger<Array>::change(&r_ret); - Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret); - const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr[i] = src_arr[i]; - } - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<Array>::change(r_ret); - Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret); - const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr[i] = src_arr[i]; - } - } - static void ptr_construct(void *base, const void **p_args) { - Array dst_arr; - T src_arr = PtrToArg<T>::convert(p_args[0]); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr[i] = src_arr[i]; - } - - PtrConstruct<Array>::construct(dst_arr, base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return GetTypeInfo<T>::VARIANT_TYPE; - } - - static Variant::Type get_base_type() { - return Variant::ARRAY; - } -}; - -template <class T> -class VariantConstructorFromArray { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != Variant::ARRAY) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::ARRAY; - return; - } - - VariantTypeChanger<T>::change(&r_ret); - const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); - T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr.write[i] = src_arr[i]; - } - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<T>::change(r_ret); - const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); - T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr.write[i] = src_arr[i]; - } - } - static void ptr_construct(void *base, const void **p_args) { - Array src_arr = PtrToArg<Array>::convert(p_args[0]); - T dst_arr; - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr.write[i] = src_arr[i]; - } - - PtrConstruct<T>::construct(dst_arr, base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::ARRAY; - } - - static Variant::Type get_base_type() { - return GetTypeInfo<T>::VARIANT_TYPE; - } -}; - -class VariantConstructorNil { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != Variant::NIL) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::NIL; - return; - } - - r_error.error = Callable::CallError::CALL_OK; - VariantInternal::clear(&r_ret); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Variant>::construct(Variant(), base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::NIL; - } -}; - -template <class T> -class VariantConstructNoArgs { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantTypeChanger<T>::change_and_reset(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<T>::change_and_reset(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<T>::construct(T(), base); - } - - static int get_argument_count() { - return 0; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return GetTypeInfo<T>::VARIANT_TYPE; - } -}; - -class VariantConstructNoArgsNil { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - ERR_FAIL_MSG("can't ptrcall nil constructor"); - } - - static int get_argument_count() { - return 0; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::NIL; - } -}; - -class VariantConstructNoArgsObject { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - VariantInternal::object_assign_null(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign_null(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Object *>::construct(nullptr, base); - } - - static int get_argument_count() { - return 0; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::OBJECT; - } -}; +#include "variant_construct.h" struct VariantConstructData { void (*construct)(Variant &r_base, const Variant **p_args, Callable::CallError &r_error); @@ -659,13 +123,13 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3")); add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d")); - add_constructor<VariantConstructNoArgs<Quat>>(sarray()); - add_constructor<VariantConstructor<Quat, Quat>>(sarray("from")); - add_constructor<VariantConstructor<Quat, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Quat, Vector3>>(sarray("euler")); - add_constructor<VariantConstructor<Quat, Vector3, double>>(sarray("axis", "angle")); - add_constructor<VariantConstructor<Quat, Vector3, Vector3>>(sarray("arc_from", "arc_to")); - add_constructor<VariantConstructor<Quat, double, double, double, double>>(sarray("x", "y", "z", "w")); + add_constructor<VariantConstructNoArgs<Quaternion>>(sarray()); + add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from")); + add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from")); + add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler")); + 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<VariantConstructNoArgs<::AABB>>(sarray()); add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from")); @@ -673,15 +137,15 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Basis>>(sarray()); add_constructor<VariantConstructor<Basis, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Basis, Quat>>(sarray("from")); + add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from")); add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi")); add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis")); - add_constructor<VariantConstructNoArgs<Transform>>(sarray()); - add_constructor<VariantConstructor<Transform, Transform>>(sarray("from")); - add_constructor<VariantConstructor<Transform, Basis, Vector3>>(sarray("basis", "origin")); - add_constructor<VariantConstructor<Transform, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin")); + add_constructor<VariantConstructNoArgs<Transform3D>>(sarray()); + add_constructor<VariantConstructor<Transform3D, Transform3D>>(sarray("from")); + add_constructor<VariantConstructor<Transform3D, Basis, Vector3>>(sarray("basis", "origin")); + add_constructor<VariantConstructor<Transform3D, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin")); add_constructor<VariantConstructNoArgs<Color>>(sarray()); add_constructor<VariantConstructor<Color, Color>>(sarray("from")); @@ -836,9 +300,9 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr void VariantInternal::object_assign(Variant *v, const Object *o) { if (o) { - if (o->is_reference()) { - Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(o)); - if (!reference->init_ref()) { + if (o->is_ref_counted()) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(o)); + if (!ref_counted->init_ref()) { v->_get_obj().obj = nullptr; v->_get_obj().id = ObjectID(); return; diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h new file mode 100644 index 0000000000..b03f4a8d3b --- /dev/null +++ b/core/variant/variant_construct.h @@ -0,0 +1,572 @@ +/*************************************************************************/ +/* variant_construct.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 VARIANT_CONSTRUCT_H +#define VARIANT_CONSTRUCT_H + +#include "variant.h" + +#include "core/core_string_names.h" +#include "core/crypto/crypto_core.h" +#include "core/debugger/engine_debugger.h" +#include "core/io/compression.h" +#include "core/object/class_db.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "core/templates/oa_hash_map.h" + +template <class T> +struct PtrConstruct {}; + +#define MAKE_PTRCONSTRUCT(m_type) \ + template <> \ + struct PtrConstruct<m_type> { \ + _FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \ + memnew_placement(p_ptr, m_type(p_value)); \ + } \ + }; + +MAKE_PTRCONSTRUCT(bool); +MAKE_PTRCONSTRUCT(int64_t); +MAKE_PTRCONSTRUCT(double); +MAKE_PTRCONSTRUCT(String); +MAKE_PTRCONSTRUCT(Vector2); +MAKE_PTRCONSTRUCT(Vector2i); +MAKE_PTRCONSTRUCT(Rect2); +MAKE_PTRCONSTRUCT(Rect2i); +MAKE_PTRCONSTRUCT(Vector3); +MAKE_PTRCONSTRUCT(Vector3i); +MAKE_PTRCONSTRUCT(Transform2D); +MAKE_PTRCONSTRUCT(Plane); +MAKE_PTRCONSTRUCT(Quaternion); +MAKE_PTRCONSTRUCT(AABB); +MAKE_PTRCONSTRUCT(Basis); +MAKE_PTRCONSTRUCT(Transform3D); +MAKE_PTRCONSTRUCT(Color); +MAKE_PTRCONSTRUCT(StringName); +MAKE_PTRCONSTRUCT(NodePath); +MAKE_PTRCONSTRUCT(RID); + +template <> +struct PtrConstruct<Object *> { + _FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) { + *((Object **)p_ptr) = p_value; + } +}; + +MAKE_PTRCONSTRUCT(Callable); +MAKE_PTRCONSTRUCT(Signal); +MAKE_PTRCONSTRUCT(Dictionary); +MAKE_PTRCONSTRUCT(Array); +MAKE_PTRCONSTRUCT(PackedByteArray); +MAKE_PTRCONSTRUCT(PackedInt32Array); +MAKE_PTRCONSTRUCT(PackedInt64Array); +MAKE_PTRCONSTRUCT(PackedFloat32Array); +MAKE_PTRCONSTRUCT(PackedFloat64Array); +MAKE_PTRCONSTRUCT(PackedStringArray); +MAKE_PTRCONSTRUCT(PackedVector2Array); +MAKE_PTRCONSTRUCT(PackedVector3Array); +MAKE_PTRCONSTRUCT(PackedColorArray); +MAKE_PTRCONSTRUCT(Variant); + +template <class T, class... P> +class VariantConstructor { + template <size_t... Is> + static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) { + r_error.error = Callable::CallError::CALL_OK; + +#ifdef DEBUG_METHODS_ENABLED + base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); +#else + base = T(VariantCaster<P>::cast(*p_args[Is])...); +#endif + } + + template <size_t... Is> + static _FORCE_INLINE_ void validated_construct_helper(T &base, const Variant **p_args, IndexSequence<Is...>) { + base = T((*VariantGetInternalPtr<P>::get_ptr(p_args[Is]))...); + } + + template <size_t... Is> + static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) { + PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base); + } + +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + r_error.error = Callable::CallError::CALL_OK; + VariantTypeChanger<T>::change(&r_ret); + construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change(r_ret); + validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{}); + } + static void ptr_construct(void *base, const void **p_args) { + ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{}); + } + + static int get_argument_count() { + return sizeof...(P); + } + + static Variant::Type get_argument_type(int p_arg) { + return call_get_argument_type<P...>(p_arg); + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + +class VariantConstructorObject { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); + if (p_args[0]->get_type() == Variant::NIL) { + VariantInternal::object_assign_null(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } else if (p_args[0]->get_type() == Variant::OBJECT) { + VariantInternal::object_assign(&r_ret, p_args[0]); + r_error.error = Callable::CallError::CALL_OK; + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + VariantInternal::object_assign(r_ret, p_args[0]); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::OBJECT; + } + + static Variant::Type get_base_type() { + return Variant::OBJECT; + } +}; + +class VariantConstructorNilObject { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::NIL) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::NIL; + } + + VariantInternal::clear(&r_ret); + VariantInternal::object_assign_null(&r_ret); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + VariantInternal::object_assign_null(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Object *>::construct(nullptr, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::OBJECT; + } +}; + +class VariantConstructorCallableArgs { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + ObjectID object_id; + StringName method; + + if (p_args[0]->get_type() == Variant::NIL) { + // leave as is + } else if (p_args[0]->get_type() == Variant::OBJECT) { + object_id = VariantInternal::get_object_id(p_args[0]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() == Variant::STRING_NAME) { + method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); + } else if (p_args[1]->get_type() == Variant::STRING) { + method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + VariantTypeChanger<Callable>::change(&r_ret); + *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<Callable>::change(r_ret); + *VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); + } + + static int get_argument_count() { + return 2; + } + + static Variant::Type get_argument_type(int p_arg) { + if (p_arg == 0) { + return Variant::OBJECT; + } else { + return Variant::STRING_NAME; + } + } + + static Variant::Type get_base_type() { + return Variant::CALLABLE; + } +}; + +class VariantConstructorSignalArgs { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + ObjectID object_id; + StringName method; + + if (p_args[0]->get_type() == Variant::NIL) { + // leave as is + } else if (p_args[0]->get_type() == Variant::OBJECT) { + object_id = VariantInternal::get_object_id(p_args[0]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() == Variant::STRING_NAME) { + method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); + } else if (p_args[1]->get_type() == Variant::STRING) { + method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + VariantTypeChanger<Signal>::change(&r_ret); + *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<Signal>::change(r_ret); + *VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); + } + + static int get_argument_count() { + return 2; + } + + static Variant::Type get_argument_type(int p_arg) { + if (p_arg == 0) { + return Variant::OBJECT; + } else { + return Variant::STRING_NAME; + } + } + + static Variant::Type get_base_type() { + return Variant::SIGNAL; + } +}; + +template <class T> +class VariantConstructorToArray { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != GetTypeInfo<T>::VARIANT_TYPE) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = GetTypeInfo<T>::VARIANT_TYPE; + return; + } + + VariantTypeChanger<Array>::change(&r_ret); + Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret); + const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr[i] = src_arr[i]; + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<Array>::change(r_ret); + Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret); + const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr[i] = src_arr[i]; + } + } + static void ptr_construct(void *base, const void **p_args) { + Array dst_arr; + T src_arr = PtrToArg<T>::convert(p_args[0]); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr[i] = src_arr[i]; + } + + PtrConstruct<Array>::construct(dst_arr, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return GetTypeInfo<T>::VARIANT_TYPE; + } + + static Variant::Type get_base_type() { + return Variant::ARRAY; + } +}; + +template <class T> +class VariantConstructorFromArray { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::ARRAY) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::ARRAY; + return; + } + + VariantTypeChanger<T>::change(&r_ret); + const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); + T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr.write[i] = src_arr[i]; + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change(r_ret); + const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); + T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr.write[i] = src_arr[i]; + } + } + static void ptr_construct(void *base, const void **p_args) { + Array src_arr = PtrToArg<Array>::convert(p_args[0]); + T dst_arr; + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr.write[i] = src_arr[i]; + } + + PtrConstruct<T>::construct(dst_arr, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::ARRAY; + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + +class VariantConstructorNil { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::NIL) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::NIL; + return; + } + + r_error.error = Callable::CallError::CALL_OK; + VariantInternal::clear(&r_ret); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Variant>::construct(Variant(), base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::NIL; + } +}; + +template <class T> +class VariantConstructNoArgs { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantTypeChanger<T>::change_and_reset(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change_and_reset(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<T>::construct(T(), base); + } + + static int get_argument_count() { + return 0; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + +class VariantConstructNoArgsNil { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + ERR_FAIL_MSG("can't ptrcall nil constructor"); + } + + static int get_argument_count() { + return 0; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::NIL; + } +}; + +class VariantConstructNoArgsObject { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); + VariantInternal::object_assign_null(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + VariantInternal::object_assign_null(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Object *>::construct(nullptr, base); + } + + static int get_argument_count() { + return 0; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::OBJECT; + } +}; + +#endif // VARIANT_CONSTRUCT_H diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index fb791f8c0c..78e1ad06ae 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -55,7 +55,7 @@ public: case Variant::BASIS: init_basis(v); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: init_transform(v); break; case Variant::STRING_NAME: @@ -138,14 +138,14 @@ public: _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; } _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); } _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); } - _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); } - _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); } + _FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return reinterpret_cast<Quaternion *>(v->_data._mem); } + _FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return reinterpret_cast<const Quaternion *>(v->_data._mem); } _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; } _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; } _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; } _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; } - _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; } - _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; } + _FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return v->_data._transform3d; } + _FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return v->_data._transform3d; } // Misc types. _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); } @@ -217,8 +217,8 @@ public: v->type = Variant::BASIS; } _FORCE_INLINE_ static void init_transform(Variant *v) { - v->_data._transform = memnew(Transform); - v->type = Variant::TRANSFORM; + v->_data._transform3d = memnew(Transform3D); + v->type = Variant::TRANSFORM3D; } _FORCE_INLINE_ static void init_string_name(Variant *v) { memnew_placement(v->_data._mem, StringName); @@ -285,7 +285,7 @@ public: v->clear(); } - static void object_assign(Variant *v, const Object *o); // Needs Reference, so it's implemented elsewhere. + static void object_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere. _FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) { object_assign(v, o->_get_obj().obj); @@ -320,12 +320,12 @@ public: return get_rect2(v); case Variant::RECT2I: return get_rect2i(v); - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: return get_transform(v); case Variant::TRANSFORM2D: return get_transform2d(v); - case Variant::QUAT: - return get_quat(v); + case Variant::QUATERNION: + return get_quaternion(v); case Variant::PLANE: return get_plane(v); case Variant::BASIS: @@ -398,12 +398,12 @@ public: return get_rect2(v); case Variant::RECT2I: return get_rect2i(v); - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: return get_transform(v); case Variant::TRANSFORM2D: return get_transform2d(v); - case Variant::QUAT: - return get_quat(v); + case Variant::QUATERNION: + return get_quaternion(v); case Variant::PLANE: return get_plane(v); case Variant::BASIS: @@ -590,9 +590,9 @@ struct VariantGetInternalPtr<Transform2D> { }; template <> -struct VariantGetInternalPtr<Transform> { - static Transform *get_ptr(Variant *v) { return VariantInternal::get_transform(v); } - static const Transform *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); } +struct VariantGetInternalPtr<Transform3D> { + static Transform3D *get_ptr(Variant *v) { return VariantInternal::get_transform(v); } + static const Transform3D *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); } }; template <> @@ -602,9 +602,9 @@ struct VariantGetInternalPtr<Plane> { }; template <> -struct VariantGetInternalPtr<Quat> { - static Quat *get_ptr(Variant *v) { return VariantInternal::get_quat(v); } - static const Quat *get_ptr(const Variant *v) { return VariantInternal::get_quat(v); } +struct VariantGetInternalPtr<Quaternion> { + static Quaternion *get_ptr(Variant *v) { return VariantInternal::get_quaternion(v); } + static const Quaternion *get_ptr(const Variant *v) { return VariantInternal::get_quaternion(v); } }; template <> @@ -819,9 +819,9 @@ struct VariantInternalAccessor<Transform2D> { }; template <> -struct VariantInternalAccessor<Transform> { - static _FORCE_INLINE_ const Transform &get(const Variant *v) { return *VariantInternal::get_transform(v); } - static _FORCE_INLINE_ void set(Variant *v, const Transform &p_value) { *VariantInternal::get_transform(v) = p_value; } +struct VariantInternalAccessor<Transform3D> { + static _FORCE_INLINE_ const Transform3D &get(const Variant *v) { return *VariantInternal::get_transform(v); } + static _FORCE_INLINE_ void set(Variant *v, const Transform3D &p_value) { *VariantInternal::get_transform(v) = p_value; } }; template <> @@ -831,9 +831,9 @@ struct VariantInternalAccessor<Plane> { }; template <> -struct VariantInternalAccessor<Quat> { - static _FORCE_INLINE_ const Quat &get(const Variant *v) { return *VariantInternal::get_quat(v); } - static _FORCE_INLINE_ void set(Variant *v, const Quat &p_value) { *VariantInternal::get_quat(v) = p_value; } +struct VariantInternalAccessor<Quaternion> { + static _FORCE_INLINE_ const Quaternion &get(const Variant *v) { return *VariantInternal::get_quaternion(v); } + static _FORCE_INLINE_ void set(Variant *v, const Quaternion &p_value) { *VariantInternal::get_quaternion(v) = p_value; } }; template <> @@ -1067,8 +1067,8 @@ struct VariantInitializer<Plane> { }; template <> -struct VariantInitializer<Quat> { - static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quat>(v); } +struct VariantInitializer<Quaternion> { + static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quaternion>(v); } }; template <> @@ -1082,7 +1082,7 @@ struct VariantInitializer<Basis> { }; template <> -struct VariantInitializer<Transform> { +struct VariantInitializer<Transform3D> { static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_transform(v); } }; @@ -1241,8 +1241,8 @@ struct VariantZeroAssigner<Plane> { }; template <> -struct VariantZeroAssigner<Quat> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quat(v) = Quat(); } +struct VariantZeroAssigner<Quaternion> { + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quaternion(v) = Quaternion(); } }; template <> @@ -1256,8 +1256,8 @@ struct VariantZeroAssigner<Basis> { }; template <> -struct VariantZeroAssigner<Transform> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform(); } +struct VariantZeroAssigner<Transform3D> { + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform3D(); } }; template <> diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 8cfa793c0e..16c7428781 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -28,1342 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "variant.h" - -#include "core/core_string_names.h" -#include "core/debugger/engine_debugger.h" -#include "core/object/class_db.h" - -template <class R, class A, class B> -class OperatorEvaluatorAdd { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a + b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) + *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) + PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorSub { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a - b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) - *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) - PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorMul { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a * b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) * *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) * PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorXForm { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a.xform(b); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<A>::get_ptr(left)->xform(*VariantGetInternalPtr<B>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left).xform(PtrToArg<B>::convert(right)), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorXFormInv { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = b.xform_inv(a); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<B>::get_ptr(right)->xform_inv(*VariantGetInternalPtr<A>::get_ptr(left)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<B>::convert(right).xform_inv(PtrToArg<A>::convert(left)), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorDiv { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a / b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorDivNZ { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - if (b == 0) { - r_valid = false; - *r_ret = "Division by zero error"; - return; - } - *r_ret = a / b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorMod { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a % b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorModNZ { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - if (b == 0) { - r_valid = false; - *r_ret = "Module by zero error"; - return; - } - *r_ret = a % b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A> -class OperatorEvaluatorNeg { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = -a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = -*VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(-PtrToArg<A>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A> -class OperatorEvaluatorPos { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorShiftLeft { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - -#if defined(DEBUG_ENABLED) - if (b < 0 || a < 0) { - *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; - r_valid = false; - return; - } -#endif - *r_ret = a << b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) << *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) << PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorShiftRight { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - -#if defined(DEBUG_ENABLED) - if (b < 0 || a < 0) { - *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; - r_valid = false; - return; - } -#endif - *r_ret = a >> b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >> *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) >> PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorBitOr { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a | b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) | *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) | PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorBitAnd { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a & b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) & PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorBitXor { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a ^ b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) ^ *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) ^ PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A> -class OperatorEvaluatorBitNeg { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = ~a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = ~*VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(~PtrToArg<A>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class A, class B> -class OperatorEvaluatorEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a == b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorEqualObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.get_validated_object(); - const Object *b = p_right.get_validated_object(); - *r_ret = a == b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->get_validated_object(); - const Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorEqualObjectNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.get_validated_object(); - *r_ret = a == nullptr; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorEqualNilObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *b = p_right.get_validated_object(); - *r_ret = nullptr == b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(nullptr == PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorNotEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a != b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) != *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) != PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotEqualObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.get_validated_object(); - Object *b = p_right.get_validated_object(); - *r_ret = a != b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->get_validated_object(); - Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotEqualObjectNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.get_validated_object(); - *r_ret = a != nullptr; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != nullptr, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotEqualNilObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); - *r_ret = nullptr != b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(nullptr != PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorLess { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a < b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) < *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) < PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorLessEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a <= b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) <= *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) <= PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorGreater { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a > b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) > *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) > PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorGreaterEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a >= b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >= *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) >= PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorAnd { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a && b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) && *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) && PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorOr { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a || b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) || *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) || PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b))) -template <class A, class B> -class OperatorEvaluatorXor { -public: - _FORCE_INLINE_ static bool xor_op(const A &a, const B &b) { - return ((a) || (b)) && !((a) && (b)); - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = xor_op(a, b); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = xor_op(*VariantGetInternalPtr<A>::get_ptr(left), *VariantGetInternalPtr<B>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(xor_op(PtrToArg<A>::convert(left), PtrToArg<B>::convert(right)), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A> -class OperatorEvaluatorNot { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = !a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<A>::convert(left)); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -//// CUSTOM //// - -class OperatorEvaluatorAddArray { -public: - _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) { - int asize = array_a.size(); - int bsize = array_b.size(); - sum.resize(asize + bsize); - for (int i = 0; i < asize; i++) { - sum[i] = array_a[i]; - } - for (int i = 0; i < bsize; i++) { - sum[i + asize] = array_b[i]; - } - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Array &array_a = *VariantGetInternalPtr<Array>::get_ptr(&p_left); - const Array &array_b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); - Array sum; - _add_arrays(sum, array_a, array_b); - *r_ret = sum; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<Array>::change(r_ret); - _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - Array ret; - _add_arrays(ret, PtrToArg<Array>::convert(left), PtrToArg<Array>::convert(right)); - PtrToArg<Array>::encode(ret, r_ret); - } - static Variant::Type get_return_type() { return Variant::ARRAY; } -}; - -template <class T> -class OperatorEvaluatorAppendArray { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Vector<T> &array_a = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_left); - const Vector<T> &array_b = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_right); - Vector<T> sum = array_a; - sum.append_array(array_b); - *r_ret = sum; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<Vector<T>>::change(r_ret); - *VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret) = *VariantGetInternalPtr<Vector<T>>::get_ptr(left); - VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret)->append_array(*VariantGetInternalPtr<Vector<T>>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - Vector<T> sum = PtrToArg<Vector<T>>::convert(left); - sum.append_array(PtrToArg<Vector<T>>::convert(right)); - PtrToArg<Vector<T>>::encode(sum, r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; } -}; - -class OperatorEvaluatorStringModNil { -public: - _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) { - Array values; - values.push_back(Variant()); - - String a = s.sprintf(values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - 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; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr); - } - 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); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -class OperatorEvaluatorStringModArray { -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); - if (r_valid) { - *r_valid = !*r_valid; - } - 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; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr); - } - 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); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -class OperatorEvaluatorStringModObject { -public: - _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) { - Array values; - values.push_back(p_object); - String a = s.sprintf(values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - - 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; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr); - } - 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); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -template <class T> -class OperatorEvaluatorStringModT { -public: - _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) { - Array values; - values.push_back(p_value); - String a = s.sprintf(values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - 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; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr); - } - 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); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> -class OperatorEvaluatorAlwaysTrue { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = true; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = true; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(true, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> -class OperatorEvaluatorAlwaysFalse { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = false; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(false, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -///// OR /////// - -_FORCE_INLINE_ static bool _operate_or(bool p_left, bool p_right) { - return p_left || p_right; -} - -_FORCE_INLINE_ static bool _operate_and(bool p_left, bool p_right) { - return p_left && p_right; -} - -_FORCE_INLINE_ static bool _operate_xor(bool p_left, bool p_right) { - return (p_left || p_right) && !(p_left && p_right); -} - -_FORCE_INLINE_ static bool _operate_get_nil(const Variant *p_ptr) { - return p_ptr->get_validated_object() != nullptr; -} - -_FORCE_INLINE_ static bool _operate_get_bool(const Variant *p_ptr) { - return *VariantGetInternalPtr<bool>::get_ptr(p_ptr); -} - -_FORCE_INLINE_ static bool _operate_get_int(const Variant *p_ptr) { - return *VariantGetInternalPtr<int64_t>::get_ptr(p_ptr) != 0; -} - -_FORCE_INLINE_ static bool _operate_get_float(const Variant *p_ptr) { - return *VariantGetInternalPtr<double>::get_ptr(p_ptr) != 0.0; -} - -_FORCE_INLINE_ static bool _operate_get_object(const Variant *p_ptr) { - return p_ptr->get_validated_object() != nullptr; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_nil(const void *p_ptr) { - return false; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_bool(const void *p_ptr) { - return PtrToArg<bool>::convert(p_ptr); -} - -_FORCE_INLINE_ static bool _operate_get_ptr_int(const void *p_ptr) { - return PtrToArg<int64_t>::convert(p_ptr) != 0; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_float(const void *p_ptr) { - return PtrToArg<double>::convert(p_ptr) != 0.0; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_object(const void *p_ptr) { - return PtrToArg<Object *>::convert(p_ptr) != nullptr; -} - -#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \ - class m_class_name { \ - public: \ - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \ - *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \ - r_valid = true; \ - } \ - \ - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \ - VariantTypeChanger<bool>::change(r_ret); \ - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \ - } \ - \ - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { \ - PtrToArg<bool>::encode(m_op(_operate_get_ptr_##m_left(left), _operate_get_ptr_##m_right(right)), r_ret); \ - } \ - \ - static Variant::Type get_return_type() { \ - return Variant::BOOL; \ - } \ - }; - -// OR - -// nil -OP_EVALUATOR(OperatorEvaluatorNilXBoolOr, nil, bool, _operate_or) -OP_EVALUATOR(OperatorEvaluatorBoolXNilOr, bool, nil, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorNilXIntOr, nil, int, _operate_or) -OP_EVALUATOR(OperatorEvaluatorIntXNilOr, int, nil, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorNilXFloatOr, nil, float, _operate_or) -OP_EVALUATOR(OperatorEvaluatorFloatXNilOr, float, nil, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorObjectXNilOr, object, nil, _operate_or) -OP_EVALUATOR(OperatorEvaluatorNilXObjectOr, nil, object, _operate_or) - -// bool -OP_EVALUATOR(OperatorEvaluatorBoolXBoolOr, bool, bool, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorBoolXIntOr, bool, int, _operate_or) -OP_EVALUATOR(OperatorEvaluatorIntXBoolOr, int, bool, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorBoolXFloatOr, bool, float, _operate_or) -OP_EVALUATOR(OperatorEvaluatorFloatXBoolOr, float, bool, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorBoolXObjectOr, bool, object, _operate_or) -OP_EVALUATOR(OperatorEvaluatorObjectXBoolOr, object, bool, _operate_or) - -// int -OP_EVALUATOR(OperatorEvaluatorIntXIntOr, int, int, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorIntXFloatOr, int, float, _operate_or) -OP_EVALUATOR(OperatorEvaluatorFloatXIntOr, float, int, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorIntXObjectOr, int, object, _operate_or) -OP_EVALUATOR(OperatorEvaluatorObjectXIntOr, object, int, _operate_or) - -// float -OP_EVALUATOR(OperatorEvaluatorFloatXFloatOr, float, float, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorFloatXObjectOr, float, object, _operate_or) -OP_EVALUATOR(OperatorEvaluatorObjectXFloatOr, object, float, _operate_or) - -// object -OP_EVALUATOR(OperatorEvaluatorObjectXObjectOr, object, object, _operate_or) - -// AND - -// nil -OP_EVALUATOR(OperatorEvaluatorNilXBoolAnd, nil, bool, _operate_and) -OP_EVALUATOR(OperatorEvaluatorBoolXNilAnd, bool, nil, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorNilXIntAnd, nil, int, _operate_and) -OP_EVALUATOR(OperatorEvaluatorIntXNilAnd, int, nil, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorNilXFloatAnd, nil, float, _operate_and) -OP_EVALUATOR(OperatorEvaluatorFloatXNilAnd, float, nil, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorObjectXNilAnd, object, nil, _operate_and) -OP_EVALUATOR(OperatorEvaluatorNilXObjectAnd, nil, object, _operate_and) - -// bool -OP_EVALUATOR(OperatorEvaluatorBoolXBoolAnd, bool, bool, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorBoolXIntAnd, bool, int, _operate_and) -OP_EVALUATOR(OperatorEvaluatorIntXBoolAnd, int, bool, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorBoolXFloatAnd, bool, float, _operate_and) -OP_EVALUATOR(OperatorEvaluatorFloatXBoolAnd, float, bool, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorBoolXObjectAnd, bool, object, _operate_and) -OP_EVALUATOR(OperatorEvaluatorObjectXBoolAnd, object, bool, _operate_and) - -// int -OP_EVALUATOR(OperatorEvaluatorIntXIntAnd, int, int, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorIntXFloatAnd, int, float, _operate_and) -OP_EVALUATOR(OperatorEvaluatorFloatXIntAnd, float, int, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorIntXObjectAnd, int, object, _operate_and) -OP_EVALUATOR(OperatorEvaluatorObjectXIntAnd, object, int, _operate_and) - -// float -OP_EVALUATOR(OperatorEvaluatorFloatXFloatAnd, float, float, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorFloatXObjectAnd, float, object, _operate_and) -OP_EVALUATOR(OperatorEvaluatorObjectXFloatAnd, object, float, _operate_and) - -// object -OP_EVALUATOR(OperatorEvaluatorObjectXObjectAnd, object, object, _operate_and) - -// XOR - -// nil -OP_EVALUATOR(OperatorEvaluatorNilXBoolXor, nil, bool, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorBoolXNilXor, bool, nil, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorNilXIntXor, nil, int, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorIntXNilXor, int, nil, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorNilXFloatXor, nil, float, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorFloatXNilXor, float, nil, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorObjectXNilXor, object, nil, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorNilXObjectXor, nil, object, _operate_xor) - -// bool -OP_EVALUATOR(OperatorEvaluatorBoolXBoolXor, bool, bool, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorBoolXIntXor, bool, int, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorIntXBoolXor, int, bool, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorBoolXFloatXor, bool, float, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorFloatXBoolXor, float, bool, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorBoolXObjectXor, bool, object, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorObjectXBoolXor, object, bool, _operate_xor) - -// int -OP_EVALUATOR(OperatorEvaluatorIntXIntXor, int, int, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorIntXFloatXor, int, float, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorFloatXIntXor, float, int, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorIntXObjectXor, int, object, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorObjectXIntXor, object, int, _operate_xor) - -// float -OP_EVALUATOR(OperatorEvaluatorFloatXFloatXor, float, float, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorFloatXObjectXor, float, object, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorObjectXFloatXor, object, float, _operate_xor) - -// object -OP_EVALUATOR(OperatorEvaluatorObjectXObjectXor, object, object, _operate_xor) - -class OperatorEvaluatorNotBool { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = !*VariantGetInternalPtr<bool>::get_ptr(&p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<bool>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<bool>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotInt { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = !*VariantGetInternalPtr<int64_t>::get_ptr(&p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<int64_t>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<int64_t>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotFloat { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = !*VariantGetInternalPtr<double>::get_ptr(&p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<double>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<double>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = p_left.get_validated_object() == nullptr; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = left->get_validated_object() == nullptr; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -//// - -class OperatorEvaluatorInStringFind { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right); - - *r_ret = str_b.find(str_a) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left); - const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorInArrayFind { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - - *r_ret = b.find(a) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(a) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<B>::convert(right).find(PtrToArg<A>::convert(left)) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInArrayFindNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); - *r_ret = b.find(Variant()) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(Variant()) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(Variant()) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInArrayFindObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); - *r_ret = b.find(p_left) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(*left) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(PtrToArg<Object *>::convert(left)) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A> -class OperatorEvaluatorInDictionaryHas { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - - *r_ret = b.has(a); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); - const A &a = *VariantGetInternalPtr<A>::get_ptr(left); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(a); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<A>::convert(left)), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInDictionaryHasNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); - - *r_ret = b.has(Variant()); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(Variant()); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(Variant()), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInDictionaryHasObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); - - *r_ret = b.has(p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(*left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<Object *>::convert(left)), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorObjectHasPropertyString { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); - if (!b) { - *r_ret = "Invalid base object for 'in'"; - r_valid = false; - return; - } - - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - - b->get(a, &r_valid); - *r_ret = r_valid; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *l = right->get_validated_object(); - ERR_FAIL_COND(l == nullptr); - const String &a = *VariantGetInternalPtr<String>::get_ptr(left); - - bool valid; - l->get(a, &valid); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - bool valid; - PtrToArg<Object *>::convert(right)->get(PtrToArg<String>::convert(left), &valid); - PtrToArg<bool>::encode(valid, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorObjectHasPropertyStringName { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); - if (!b) { - *r_ret = "Invalid base object for 'in'"; - r_valid = false; - return; - } - - const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left); - - b->get(a, &r_valid); - *r_ret = r_valid; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *l = right->get_validated_object(); - ERR_FAIL_COND(l == nullptr); - const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left); - - bool valid; - l->get(a, &valid); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - bool valid; - PtrToArg<Object *>::convert(right)->get(PtrToArg<StringName>::convert(left), &valid); - PtrToArg<bool>::encode(valid, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; +#include "variant_op.h" typedef void (*VariantEvaluatorFunction)(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid); @@ -1395,7 +60,7 @@ void Variant::_register_variant_operators() { 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); register_op<OperatorEvaluatorAdd<Vector3i, Vector3i, Vector3i>>(Variant::OP_ADD, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorAdd<Quat, Quat, Quat>>(Variant::OP_ADD, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorAdd<Quaternion, Quaternion, Quaternion>>(Variant::OP_ADD, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorAdd<Color, Color, Color>>(Variant::OP_ADD, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorAddArray>(Variant::OP_ADD, Variant::ARRAY, Variant::ARRAY); register_op<OperatorEvaluatorAppendArray<uint8_t>>(Variant::OP_ADD, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY); @@ -1416,7 +81,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorSub<Vector2i, Vector2i, Vector2i>>(Variant::OP_SUBTRACT, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorSub<Vector3, Vector3, Vector3>>(Variant::OP_SUBTRACT, Variant::VECTOR3, Variant::VECTOR3); register_op<OperatorEvaluatorSub<Vector3i, Vector3i, Vector3i>>(Variant::OP_SUBTRACT, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorSub<Quat, Quat, Quat>>(Variant::OP_SUBTRACT, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorSub<Quaternion, Quaternion, Quaternion>>(Variant::OP_SUBTRACT, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorSub<Color, Color, Color>>(Variant::OP_SUBTRACT, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<int64_t, int64_t, int64_t>>(Variant::OP_MULTIPLY, Variant::INT, Variant::INT); @@ -1449,15 +114,17 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorMul<Vector3i, Vector3i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT); register_op<OperatorEvaluatorMul<Vector3i, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); - register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT); - register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT); register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT); register_op<OperatorEvaluatorMul<Color, Color, double>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::FLOAT); register_op<OperatorEvaluatorMul<Transform2D, Transform2D, Transform2D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::TRANSFORM2D); + register_op<OperatorEvaluatorMul<Transform2D, Transform2D, int64_t>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::INT); + register_op<OperatorEvaluatorMul<Transform2D, Transform2D, double>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::FLOAT); register_op<OperatorEvaluatorXForm<Vector2, Transform2D, Vector2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::VECTOR2); register_op<OperatorEvaluatorXFormInv<Vector2, Vector2, Transform2D>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::TRANSFORM2D); register_op<OperatorEvaluatorXForm<Rect2, Transform2D, Rect2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::RECT2); @@ -1465,25 +132,29 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorXForm<Vector<Vector2>, Transform2D, Vector<Vector2>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::PACKED_VECTOR2_ARRAY); register_op<OperatorEvaluatorXFormInv<Vector<Vector2>, Vector<Vector2>, Transform2D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR2_ARRAY, Variant::TRANSFORM2D); - register_op<OperatorEvaluatorMul<Transform, Transform, Transform>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<Vector3, Transform, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::VECTOR3); - register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<::AABB, Transform, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::AABB); - register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::PACKED_VECTOR3_ARRAY); - register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, Transform3D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, int64_t>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::INT); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, double>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::FLOAT); + register_op<OperatorEvaluatorXForm<Vector3, Transform3D, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::VECTOR3); + register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB); + register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY); + register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D); register_op<OperatorEvaluatorMul<Basis, Basis, Basis>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::BASIS); + register_op<OperatorEvaluatorMul<Basis, Basis, int64_t>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::INT); + register_op<OperatorEvaluatorMul<Basis, Basis, double>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::FLOAT); register_op<OperatorEvaluatorXForm<Vector3, Basis, Vector3>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::VECTOR3); register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Basis>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::BASIS); - register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT); - register_op<OperatorEvaluatorMul<Quat, int64_t, Quat>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT); - register_op<OperatorEvaluatorMul<Quat, double, Quat>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUAT); - register_op<OperatorEvaluatorXForm<Vector3, Quat, Vector3>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::VECTOR3); - register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quat>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUAT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); + register_op<OperatorEvaluatorMul<Quaternion, int64_t, Quaternion>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Quaternion, double, Quaternion>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUATERNION); + register_op<OperatorEvaluatorXForm<Vector3, Quaternion, Vector3>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::VECTOR3); + register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quaternion>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUATERNION); register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT); @@ -1516,8 +187,8 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT); - register_op<OperatorEvaluatorDiv<Quat, Quat, double>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::FLOAT); - register_op<OperatorEvaluatorDiv<Quat, Quat, int64_t>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::INT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, double>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, int64_t>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::INT); register_op<OperatorEvaluatorDiv<Color, Color, Color>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorDiv<Color, Color, double>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::FLOAT); @@ -1544,10 +215,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I); 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<Quat>>(Variant::OP_MODULE, Variant::STRING, Variant::QUAT); + 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<Transform>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM); + register_op<OperatorEvaluatorStringModT<Transform3D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM3D); register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR); register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME); @@ -1574,7 +245,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNeg<Vector2i, Vector2i>>(Variant::OP_NEGATE, Variant::VECTOR2I, Variant::NIL); register_op<OperatorEvaluatorNeg<Vector3, Vector3>>(Variant::OP_NEGATE, Variant::VECTOR3, Variant::NIL); register_op<OperatorEvaluatorNeg<Vector3i, Vector3i>>(Variant::OP_NEGATE, Variant::VECTOR3I, Variant::NIL); - register_op<OperatorEvaluatorNeg<Quat, Quat>>(Variant::OP_NEGATE, Variant::QUAT, Variant::NIL); + register_op<OperatorEvaluatorNeg<Quaternion, Quaternion>>(Variant::OP_NEGATE, Variant::QUATERNION, Variant::NIL); register_op<OperatorEvaluatorNeg<Plane, Plane>>(Variant::OP_NEGATE, Variant::PLANE, Variant::NIL); register_op<OperatorEvaluatorNeg<Color, Color>>(Variant::OP_NEGATE, Variant::COLOR, Variant::NIL); @@ -1584,7 +255,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorPos<Vector2i, Vector2i>>(Variant::OP_POSITIVE, Variant::VECTOR2I, Variant::NIL); register_op<OperatorEvaluatorPos<Vector3, Vector3>>(Variant::OP_POSITIVE, Variant::VECTOR3, Variant::NIL); register_op<OperatorEvaluatorPos<Vector3i, Vector3i>>(Variant::OP_POSITIVE, Variant::VECTOR3I, Variant::NIL); - register_op<OperatorEvaluatorPos<Quat, Quat>>(Variant::OP_POSITIVE, Variant::QUAT, Variant::NIL); + register_op<OperatorEvaluatorPos<Quaternion, Quaternion>>(Variant::OP_POSITIVE, Variant::QUATERNION, Variant::NIL); register_op<OperatorEvaluatorPos<Plane, Plane>>(Variant::OP_POSITIVE, Variant::PLANE, Variant::NIL); register_op<OperatorEvaluatorPos<Color, Color>>(Variant::OP_POSITIVE, Variant::COLOR, Variant::NIL); @@ -1612,10 +283,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorEqual<Vector3i, Vector3i>>(Variant::OP_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorEqual<Transform2D, Transform2D>>(Variant::OP_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D); register_op<OperatorEvaluatorEqual<Plane, Plane>>(Variant::OP_EQUAL, Variant::PLANE, Variant::PLANE); - register_op<OperatorEvaluatorEqual<Quat, Quat>>(Variant::OP_EQUAL, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorEqual<Quaternion, Quaternion>>(Variant::OP_EQUAL, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorEqual<::AABB, ::AABB>>(Variant::OP_EQUAL, Variant::AABB, Variant::AABB); register_op<OperatorEvaluatorEqual<Basis, Basis>>(Variant::OP_EQUAL, Variant::BASIS, Variant::BASIS); - register_op<OperatorEvaluatorEqual<Transform, Transform>>(Variant::OP_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM); + register_op<OperatorEvaluatorEqual<Transform3D, Transform3D>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D); 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); @@ -1658,10 +329,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotEqual<Vector3i, Vector3i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorNotEqual<Transform2D, Transform2D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D); register_op<OperatorEvaluatorNotEqual<Plane, Plane>>(Variant::OP_NOT_EQUAL, Variant::PLANE, Variant::PLANE); - register_op<OperatorEvaluatorNotEqual<Quat, Quat>>(Variant::OP_NOT_EQUAL, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorNotEqual<Quaternion, Quaternion>>(Variant::OP_NOT_EQUAL, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorNotEqual<::AABB, ::AABB>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::AABB); register_op<OperatorEvaluatorNotEqual<Basis, Basis>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::BASIS); - register_op<OperatorEvaluatorNotEqual<Transform, Transform>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM); + register_op<OperatorEvaluatorNotEqual<Transform3D, Transform3D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D); 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); @@ -1849,10 +520,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInDictionaryHas<Vector3i>>(Variant::OP_IN, Variant::VECTOR3I, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Transform2D>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Plane>>(Variant::OP_IN, Variant::PLANE, Variant::DICTIONARY); - register_op<OperatorEvaluatorInDictionaryHas<Quat>>(Variant::OP_IN, Variant::QUAT, Variant::DICTIONARY); + register_op<OperatorEvaluatorInDictionaryHas<Quaternion>>(Variant::OP_IN, Variant::QUATERNION, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<::AABB>>(Variant::OP_IN, Variant::AABB, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Basis>>(Variant::OP_IN, Variant::BASIS, Variant::DICTIONARY); - register_op<OperatorEvaluatorInDictionaryHas<Transform>>(Variant::OP_IN, Variant::TRANSFORM, Variant::DICTIONARY); + register_op<OperatorEvaluatorInDictionaryHas<Transform3D>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Color>>(Variant::OP_IN, Variant::COLOR, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::DICTIONARY); @@ -1886,10 +557,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInArrayFind<Vector3i, Array>>(Variant::OP_IN, Variant::VECTOR3I, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Transform2D, Array>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Plane, Array>>(Variant::OP_IN, Variant::PLANE, Variant::ARRAY); - register_op<OperatorEvaluatorInArrayFind<Quat, Array>>(Variant::OP_IN, Variant::QUAT, Variant::ARRAY); + register_op<OperatorEvaluatorInArrayFind<Quaternion, Array>>(Variant::OP_IN, Variant::QUATERNION, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<::AABB, Array>>(Variant::OP_IN, Variant::AABB, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Basis, Array>>(Variant::OP_IN, Variant::BASIS, Variant::ARRAY); - register_op<OperatorEvaluatorInArrayFind<Transform, Array>>(Variant::OP_IN, Variant::TRANSFORM, Variant::ARRAY); + register_op<OperatorEvaluatorInArrayFind<Transform3D, Array>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Color, Array>>(Variant::OP_IN, Variant::COLOR, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<StringName, Array>>(Variant::OP_IN, Variant::STRING_NAME, Variant::ARRAY); @@ -1990,8 +661,8 @@ static const char *_op_names[Variant::OP_MAX] = { "-", "*", "/", - "-", - "+", + "unary-", + "unary+", "%", "<<", ">>", diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h new file mode 100644 index 0000000000..e744e76ea3 --- /dev/null +++ b/core/variant/variant_op.h @@ -0,0 +1,1316 @@ +/*************************************************************************/ +/* variant_op.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 VARIANT_OP_H +#define VARIANT_OP_H + +#include "variant.h" + +#include "core/core_string_names.h" +#include "core/debugger/engine_debugger.h" +#include "core/object/class_db.h" + +template <class R, class A, class B> +class OperatorEvaluatorAdd { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) + *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) + PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorSub { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) - *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) - PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorMul { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) * *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) * PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorXForm { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a.xform(b); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<A>::get_ptr(left)->xform(*VariantGetInternalPtr<B>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left).xform(PtrToArg<B>::convert(right)), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorXFormInv { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = b.xform_inv(a); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<B>::get_ptr(right)->xform_inv(*VariantGetInternalPtr<A>::get_ptr(left)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<B>::convert(right).xform_inv(PtrToArg<A>::convert(left)), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorDiv { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorDivNZ { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + if (b == 0) { + r_valid = false; + *r_ret = "Division by zero error"; + return; + } + *r_ret = a / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorMod { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorModNZ { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + if (b == 0) { + r_valid = false; + *r_ret = "Module by zero error"; + return; + } + *r_ret = a % b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A> +class OperatorEvaluatorNeg { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = -a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = -*VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(-PtrToArg<A>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A> +class OperatorEvaluatorPos { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorShiftLeft { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + +#if defined(DEBUG_ENABLED) + if (b < 0 || a < 0) { + *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; + r_valid = false; + return; + } +#endif + *r_ret = a << b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) << *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) << PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorShiftRight { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + +#if defined(DEBUG_ENABLED) + if (b < 0 || a < 0) { + *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; + r_valid = false; + return; + } +#endif + *r_ret = a >> b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >> *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) >> PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorBitOr { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) | *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) | PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorBitAnd { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) & PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorBitXor { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) ^ *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) ^ PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A> +class OperatorEvaluatorBitNeg { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = ~a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = ~*VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(~PtrToArg<A>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class A, class B> +class OperatorEvaluatorEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorEqualObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Object *a = p_left.get_validated_object(); + const Object *b = p_right.get_validated_object(); + *r_ret = a == b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Object *a = left->get_validated_object(); + const Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorEqualObjectNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Object *a = p_left.get_validated_object(); + *r_ret = a == nullptr; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Object *a = left->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorEqualNilObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Object *b = p_right.get_validated_object(); + *r_ret = nullptr == b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(nullptr == PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorNotEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) != *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) != PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotEqualObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *a = p_left.get_validated_object(); + Object *b = p_right.get_validated_object(); + *r_ret = a != b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *a = left->get_validated_object(); + Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotEqualObjectNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *a = p_left.get_validated_object(); + *r_ret = a != nullptr; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *a = left->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != nullptr, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotEqualNilObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *b = p_right.get_validated_object(); + *r_ret = nullptr != b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(nullptr != PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorLess { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) < *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) < PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorLessEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) <= *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) <= PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorGreater { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) > *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) > PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorGreaterEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >= *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) >= PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorAnd { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) && *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) && PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorOr { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::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) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) || *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) || PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b))) +template <class A, class B> +class OperatorEvaluatorXor { +public: + _FORCE_INLINE_ static bool xor_op(const A &a, const B &b) { + return ((a) || (b)) && !((a) && (b)); + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = xor_op(a, b); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = xor_op(*VariantGetInternalPtr<A>::get_ptr(left), *VariantGetInternalPtr<B>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(xor_op(PtrToArg<A>::convert(left), PtrToArg<B>::convert(right)), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A> +class OperatorEvaluatorNot { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = !a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<A>::convert(left)); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +//// CUSTOM //// + +class OperatorEvaluatorAddArray { +public: + _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) { + int asize = array_a.size(); + int bsize = array_b.size(); + sum.resize(asize + bsize); + for (int i = 0; i < asize; i++) { + sum[i] = array_a[i]; + } + for (int i = 0; i < bsize; i++) { + sum[i + asize] = array_b[i]; + } + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Array &array_a = *VariantGetInternalPtr<Array>::get_ptr(&p_left); + const Array &array_b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); + Array sum; + _add_arrays(sum, array_a, array_b); + *r_ret = sum; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + Array ret; + _add_arrays(ret, PtrToArg<Array>::convert(left), PtrToArg<Array>::convert(right)); + PtrToArg<Array>::encode(ret, r_ret); + } + static Variant::Type get_return_type() { return Variant::ARRAY; } +}; + +template <class T> +class OperatorEvaluatorAppendArray { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector<T> &array_a = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_left); + const Vector<T> &array_b = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_right); + Vector<T> sum = array_a; + sum.append_array(array_b); + *r_ret = sum; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret) = *VariantGetInternalPtr<Vector<T>>::get_ptr(left); + VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret)->append_array(*VariantGetInternalPtr<Vector<T>>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + Vector<T> sum = PtrToArg<Vector<T>>::convert(left); + sum.append_array(PtrToArg<Vector<T>>::convert(right)); + PtrToArg<Vector<T>>::encode(sum, r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; } +}; + +class OperatorEvaluatorStringModNil { +public: + _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) { + Array values; + values.push_back(Variant()); + + String a = s.sprintf(values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + 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; + } + 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); + } + 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); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +class OperatorEvaluatorStringModArray { +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); + if (r_valid) { + *r_valid = !*r_valid; + } + 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; + } + 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); + } + 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); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +class OperatorEvaluatorStringModObject { +public: + _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) { + Array values; + values.push_back(p_object); + String a = s.sprintf(values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + + 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; + } + 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); + } + 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); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +template <class T> +class OperatorEvaluatorStringModT { +public: + _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) { + Array values; + values.push_back(p_value); + String a = s.sprintf(values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + 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; + } + 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); + } + 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); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> +class OperatorEvaluatorAlwaysTrue { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = true; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = true; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(true, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> +class OperatorEvaluatorAlwaysFalse { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = false; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(false, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +///// OR /////// + +_FORCE_INLINE_ static bool _operate_or(bool p_left, bool p_right) { + return p_left || p_right; +} + +_FORCE_INLINE_ static bool _operate_and(bool p_left, bool p_right) { + return p_left && p_right; +} + +_FORCE_INLINE_ static bool _operate_xor(bool p_left, bool p_right) { + return (p_left || p_right) && !(p_left && p_right); +} + +_FORCE_INLINE_ static bool _operate_get_nil(const Variant *p_ptr) { + return p_ptr->get_validated_object() != nullptr; +} + +_FORCE_INLINE_ static bool _operate_get_bool(const Variant *p_ptr) { + return *VariantGetInternalPtr<bool>::get_ptr(p_ptr); +} + +_FORCE_INLINE_ static bool _operate_get_int(const Variant *p_ptr) { + return *VariantGetInternalPtr<int64_t>::get_ptr(p_ptr) != 0; +} + +_FORCE_INLINE_ static bool _operate_get_float(const Variant *p_ptr) { + return *VariantGetInternalPtr<double>::get_ptr(p_ptr) != 0.0; +} + +_FORCE_INLINE_ static bool _operate_get_object(const Variant *p_ptr) { + return p_ptr->get_validated_object() != nullptr; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_nil(const void *p_ptr) { + return false; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_bool(const void *p_ptr) { + return PtrToArg<bool>::convert(p_ptr); +} + +_FORCE_INLINE_ static bool _operate_get_ptr_int(const void *p_ptr) { + return PtrToArg<int64_t>::convert(p_ptr) != 0; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_float(const void *p_ptr) { + return PtrToArg<double>::convert(p_ptr) != 0.0; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_object(const void *p_ptr) { + return PtrToArg<Object *>::convert(p_ptr) != nullptr; +} + +#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \ + class m_class_name { \ + public: \ + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \ + *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \ + r_valid = true; \ + } \ + \ + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \ + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \ + } \ + \ + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { \ + PtrToArg<bool>::encode(m_op(_operate_get_ptr_##m_left(left), _operate_get_ptr_##m_right(right)), r_ret); \ + } \ + \ + static Variant::Type get_return_type() { \ + return Variant::BOOL; \ + } \ + }; + +// OR + +// nil +OP_EVALUATOR(OperatorEvaluatorNilXBoolOr, nil, bool, _operate_or) +OP_EVALUATOR(OperatorEvaluatorBoolXNilOr, bool, nil, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorNilXIntOr, nil, int, _operate_or) +OP_EVALUATOR(OperatorEvaluatorIntXNilOr, int, nil, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorNilXFloatOr, nil, float, _operate_or) +OP_EVALUATOR(OperatorEvaluatorFloatXNilOr, float, nil, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorObjectXNilOr, object, nil, _operate_or) +OP_EVALUATOR(OperatorEvaluatorNilXObjectOr, nil, object, _operate_or) + +// bool +OP_EVALUATOR(OperatorEvaluatorBoolXBoolOr, bool, bool, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorBoolXIntOr, bool, int, _operate_or) +OP_EVALUATOR(OperatorEvaluatorIntXBoolOr, int, bool, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorBoolXFloatOr, bool, float, _operate_or) +OP_EVALUATOR(OperatorEvaluatorFloatXBoolOr, float, bool, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorBoolXObjectOr, bool, object, _operate_or) +OP_EVALUATOR(OperatorEvaluatorObjectXBoolOr, object, bool, _operate_or) + +// int +OP_EVALUATOR(OperatorEvaluatorIntXIntOr, int, int, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorIntXFloatOr, int, float, _operate_or) +OP_EVALUATOR(OperatorEvaluatorFloatXIntOr, float, int, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorIntXObjectOr, int, object, _operate_or) +OP_EVALUATOR(OperatorEvaluatorObjectXIntOr, object, int, _operate_or) + +// float +OP_EVALUATOR(OperatorEvaluatorFloatXFloatOr, float, float, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorFloatXObjectOr, float, object, _operate_or) +OP_EVALUATOR(OperatorEvaluatorObjectXFloatOr, object, float, _operate_or) + +// object +OP_EVALUATOR(OperatorEvaluatorObjectXObjectOr, object, object, _operate_or) + +// AND + +// nil +OP_EVALUATOR(OperatorEvaluatorNilXBoolAnd, nil, bool, _operate_and) +OP_EVALUATOR(OperatorEvaluatorBoolXNilAnd, bool, nil, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorNilXIntAnd, nil, int, _operate_and) +OP_EVALUATOR(OperatorEvaluatorIntXNilAnd, int, nil, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorNilXFloatAnd, nil, float, _operate_and) +OP_EVALUATOR(OperatorEvaluatorFloatXNilAnd, float, nil, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorObjectXNilAnd, object, nil, _operate_and) +OP_EVALUATOR(OperatorEvaluatorNilXObjectAnd, nil, object, _operate_and) + +// bool +OP_EVALUATOR(OperatorEvaluatorBoolXBoolAnd, bool, bool, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorBoolXIntAnd, bool, int, _operate_and) +OP_EVALUATOR(OperatorEvaluatorIntXBoolAnd, int, bool, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorBoolXFloatAnd, bool, float, _operate_and) +OP_EVALUATOR(OperatorEvaluatorFloatXBoolAnd, float, bool, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorBoolXObjectAnd, bool, object, _operate_and) +OP_EVALUATOR(OperatorEvaluatorObjectXBoolAnd, object, bool, _operate_and) + +// int +OP_EVALUATOR(OperatorEvaluatorIntXIntAnd, int, int, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorIntXFloatAnd, int, float, _operate_and) +OP_EVALUATOR(OperatorEvaluatorFloatXIntAnd, float, int, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorIntXObjectAnd, int, object, _operate_and) +OP_EVALUATOR(OperatorEvaluatorObjectXIntAnd, object, int, _operate_and) + +// float +OP_EVALUATOR(OperatorEvaluatorFloatXFloatAnd, float, float, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorFloatXObjectAnd, float, object, _operate_and) +OP_EVALUATOR(OperatorEvaluatorObjectXFloatAnd, object, float, _operate_and) + +// object +OP_EVALUATOR(OperatorEvaluatorObjectXObjectAnd, object, object, _operate_and) + +// XOR + +// nil +OP_EVALUATOR(OperatorEvaluatorNilXBoolXor, nil, bool, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorBoolXNilXor, bool, nil, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorNilXIntXor, nil, int, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorIntXNilXor, int, nil, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorNilXFloatXor, nil, float, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorFloatXNilXor, float, nil, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorObjectXNilXor, object, nil, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorNilXObjectXor, nil, object, _operate_xor) + +// bool +OP_EVALUATOR(OperatorEvaluatorBoolXBoolXor, bool, bool, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorBoolXIntXor, bool, int, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorIntXBoolXor, int, bool, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorBoolXFloatXor, bool, float, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorFloatXBoolXor, float, bool, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorBoolXObjectXor, bool, object, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorObjectXBoolXor, object, bool, _operate_xor) + +// int +OP_EVALUATOR(OperatorEvaluatorIntXIntXor, int, int, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorIntXFloatXor, int, float, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorFloatXIntXor, float, int, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorIntXObjectXor, int, object, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorObjectXIntXor, object, int, _operate_xor) + +// float +OP_EVALUATOR(OperatorEvaluatorFloatXFloatXor, float, float, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorFloatXObjectXor, float, object, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorObjectXFloatXor, object, float, _operate_xor) + +// object +OP_EVALUATOR(OperatorEvaluatorObjectXObjectXor, object, object, _operate_xor) + +class OperatorEvaluatorNotBool { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = !*VariantGetInternalPtr<bool>::get_ptr(&p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<bool>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<bool>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotInt { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = !*VariantGetInternalPtr<int64_t>::get_ptr(&p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<int64_t>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<int64_t>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotFloat { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = !*VariantGetInternalPtr<double>::get_ptr(&p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<double>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<double>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = p_left.get_validated_object() == nullptr; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = left->get_validated_object() == nullptr; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +//// + +class OperatorEvaluatorInStringFind { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right); + + *r_ret = str_b.find(str_a) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left); + const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorInArrayFind { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + + *r_ret = b.find(a) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(a) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<B>::convert(right).find(PtrToArg<A>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInArrayFindNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); + *r_ret = b.find(Variant()) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(Variant()) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(Variant()) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInArrayFindObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); + *r_ret = b.find(p_left) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(*left) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(PtrToArg<Object *>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A> +class OperatorEvaluatorInDictionaryHas { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + + *r_ret = b.has(a); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); + const A &a = *VariantGetInternalPtr<A>::get_ptr(left); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(a); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<A>::convert(left)), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInDictionaryHasNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); + + *r_ret = b.has(Variant()); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(Variant()); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(Variant()), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInDictionaryHasObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); + + *r_ret = b.has(p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(*left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<Object *>::convert(left)), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorObjectHasPropertyString { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *b = p_right.get_validated_object(); + if (!b) { + *r_ret = "Invalid base object for 'in'"; + r_valid = false; + return; + } + + const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + + b->get(a, &r_valid); + *r_ret = r_valid; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *l = right->get_validated_object(); + ERR_FAIL_COND(l == nullptr); + const String &a = *VariantGetInternalPtr<String>::get_ptr(left); + + bool valid; + l->get(a, &valid); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + bool valid; + PtrToArg<Object *>::convert(right)->get(PtrToArg<String>::convert(left), &valid); + PtrToArg<bool>::encode(valid, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorObjectHasPropertyStringName { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *b = p_right.get_validated_object(); + if (!b) { + *r_ret = "Invalid base object for 'in'"; + r_valid = false; + return; + } + + const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left); + + b->get(a, &r_valid); + *r_ret = r_valid; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *l = right->get_validated_object(); + ERR_FAIL_COND(l == nullptr); + const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left); + + bool valid; + l->get(a, &valid); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + bool valid; + PtrToArg<Object *>::convert(right)->get(PtrToArg<StringName>::convert(left), &valid); + PtrToArg<bool>::encode(valid, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +#endif // VARIANT_OP_H diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index edaeddbf27..86d5ae7f38 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -190,10 +190,13 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.type = TK_COLOR; return OK; } - case '@': { +#ifndef DISABLE_DEPRECATED + case '@': // Compatibility with 3.x StringNames. +#endif + case '&': { // StringName. cchar = p_stream->get_char(); if (cchar != '"') { - r_err_str = "Expected '\"' after '@'"; + r_err_str = "Expected '\"' after '&'"; r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } @@ -614,7 +617,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = Plane(args[0], args[1], args[2], args[3]); - } else if (id == "Quat") { + } else if (id == "Quaternion" || id == "Quat") { // "Quat" kept for compatibility Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); if (err) { @@ -626,7 +629,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - value = Quat(args[0], args[1], args[2], args[3]); + value = Quaternion(args[0], args[1], args[2], args[3]); } else if (id == "AABB" || id == "Rect3") { Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); @@ -653,7 +656,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); - } else if (id == "Transform") { + } else if (id == "Transform3D" || id == "Transform") { // "Transform" kept for compatibility with Godot <4. Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); if (err) { @@ -665,7 +668,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - value = Transform(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); + value = Transform3D(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); } else if (id == "Color") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -735,14 +738,14 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, String type = token.value; - Object *obj = ClassDB::instance(type); + Object *obj = ClassDB::instantiate(type); if (!obj) { - r_err_str = "Can't instance Object() of type: " + type; + r_err_str = "Can't instantiate Object() of type: " + type; return ERR_PARSE_ERROR; } - REF ref = REF(Object::cast_to<Reference>(obj)); + REF ref = REF(Object::cast_to<RefCounted>(obj)); get_token(p_stream, token, line, r_err_str); if (token.type != TK_COMMA) { @@ -1201,16 +1204,32 @@ Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, Strin r_tag.name = ""; r_tag.fields.clear(); - while (true) { - char32_t c = p_stream->get_char(); - if (p_stream->is_eof()) { - r_err_str = "Unexpected EOF while parsing simple tag"; - return ERR_PARSE_ERROR; + if (p_stream->is_utf8()) { + CharString cs; + while (true) { + char c = p_stream->get_char(); + if (p_stream->is_eof()) { + r_err_str = "Unexpected EOF while parsing simple tag"; + return ERR_PARSE_ERROR; + } + if (c == ']') { + break; + } + cs += c; } - if (c == ']') { - break; + r_tag.name.parse_utf8(cs.get_data(), cs.length()); + } else { + while (true) { + char32_t c = p_stream->get_char(); + if (p_stream->is_eof()) { + r_err_str = "Unexpected EOF while parsing simple tag"; + return ERR_PARSE_ERROR; + } + if (c == ']') { + break; + } + r_tag.name += String::chr(c); } - r_tag.name += String::chr(c); } r_tag.name = r_tag.name.strip_edges(); @@ -1420,47 +1439,47 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::VECTOR2: { Vector2 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector2( " + rtosfix(v.x) + ", " + rtosfix(v.y) + " )"); + p_store_string_func(p_store_string_ud, "Vector2(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ")"); } break; case Variant::VECTOR2I: { Vector2i v = p_variant; - p_store_string_func(p_store_string_ud, "Vector2i( " + itos(v.x) + ", " + itos(v.y) + " )"); + p_store_string_func(p_store_string_ud, "Vector2i(" + itos(v.x) + ", " + itos(v.y) + ")"); } break; case Variant::RECT2: { Rect2 aabb = p_variant; - p_store_string_func(p_store_string_ud, "Rect2( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + " )"); + p_store_string_func(p_store_string_ud, "Rect2(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ")"); } break; case Variant::RECT2I: { Rect2i aabb = p_variant; - p_store_string_func(p_store_string_ud, "Rect2i( " + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + " )"); + p_store_string_func(p_store_string_ud, "Rect2i(" + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + ")"); } break; case Variant::VECTOR3: { Vector3 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector3( " + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + " )"); + p_store_string_func(p_store_string_ud, "Vector3(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + ")"); } break; case Variant::VECTOR3I: { Vector3i v = p_variant; - p_store_string_func(p_store_string_ud, "Vector3i( " + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + " )"); + p_store_string_func(p_store_string_ud, "Vector3i(" + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + ")"); } break; case Variant::PLANE: { Plane p = p_variant; - p_store_string_func(p_store_string_ud, "Plane( " + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + " )"); + p_store_string_func(p_store_string_ud, "Plane(" + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + ")"); } break; case Variant::AABB: { AABB aabb = p_variant; - p_store_string_func(p_store_string_ud, "AABB( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + " )"); + p_store_string_func(p_store_string_ud, "AABB(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + ")"); } break; - case Variant::QUAT: { - Quat quat = p_variant; - p_store_string_func(p_store_string_ud, "Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )"); + case Variant::QUATERNION: { + Quaternion quaternion = p_variant; + p_store_string_func(p_store_string_ud, "Quaternion(" + rtosfix(quaternion.x) + ", " + rtosfix(quaternion.y) + ", " + rtosfix(quaternion.z) + ", " + rtosfix(quaternion.w) + ")"); } break; case Variant::TRANSFORM2D: { - String s = "Transform2D( "; + String s = "Transform2D("; Transform2D m3 = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { @@ -1471,11 +1490,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } } - p_store_string_func(p_store_string_ud, s + " )"); + p_store_string_func(p_store_string_ud, s + ")"); } break; case Variant::BASIS: { - String s = "Basis( "; + String s = "Basis("; Basis m3 = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -1486,12 +1505,12 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } } - p_store_string_func(p_store_string_ud, s + " )"); + p_store_string_func(p_store_string_ud, s + ")"); } break; - case Variant::TRANSFORM: { - String s = "Transform( "; - Transform t = p_variant; + case Variant::TRANSFORM3D: { + String s = "Transform3D("; + Transform3D t = p_variant; Basis &m3 = t.basis; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -1504,19 +1523,19 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z); - p_store_string_func(p_store_string_ud, s + " )"); + p_store_string_func(p_store_string_ud, s + ")"); } break; // misc types case Variant::COLOR: { Color c = p_variant; - p_store_string_func(p_store_string_ud, "Color( " + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + " )"); + p_store_string_func(p_store_string_ud, "Color(" + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + ")"); } break; case Variant::STRING_NAME: { String str = p_variant; - str = "@\"" + str.c_escape() + "\""; + str = "&\"" + str.c_escape() + "\""; p_store_string_func(p_store_string_ud, str); } break; @@ -1550,7 +1569,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (res_text == String() && res->get_path().is_resource_file()) { //external resource String path = res->get_path(); - res_text = "Resource( \"" + path + "\")"; + res_text = "Resource(\"" + path + "\")"; } //could come up with some sort of text @@ -1613,7 +1632,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::ARRAY: { - p_store_string_func(p_store_string_ud, "[ "); + p_store_string_func(p_store_string_ud, "["); Array array = p_variant; int len = array.size(); for (int i = 0; i < len; i++) { @@ -1622,12 +1641,12 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); } - p_store_string_func(p_store_string_ud, " ]"); + p_store_string_func(p_store_string_ud, "]"); } break; case Variant::PACKED_BYTE_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedByteArray( "); + p_store_string_func(p_store_string_ud, "PackedByteArray("); String s; Vector<uint8_t> data = p_variant; int len = data.size(); @@ -1641,11 +1660,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_INT32_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedInt32Array( "); + p_store_string_func(p_store_string_ud, "PackedInt32Array("); Vector<int32_t> data = p_variant; int32_t len = data.size(); const int32_t *ptr = data.ptr(); @@ -1658,11 +1677,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_INT64_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedInt64Array( "); + p_store_string_func(p_store_string_ud, "PackedInt64Array("); Vector<int64_t> data = p_variant; int64_t len = data.size(); const int64_t *ptr = data.ptr(); @@ -1675,11 +1694,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_FLOAT32_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedFloat32Array( "); + p_store_string_func(p_store_string_ud, "PackedFloat32Array("); Vector<float> data = p_variant; int len = data.size(); const float *ptr = data.ptr(); @@ -1691,11 +1710,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_FLOAT64_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedFloat64Array( "); + p_store_string_func(p_store_string_ud, "PackedFloat64Array("); Vector<double> data = p_variant; int len = data.size(); const double *ptr = data.ptr(); @@ -1707,11 +1726,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_STRING_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedStringArray( "); + p_store_string_func(p_store_string_ud, "PackedStringArray("); Vector<String> data = p_variant; int len = data.size(); const String *ptr = data.ptr(); @@ -1727,11 +1746,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "\"" + str.c_escape() + "\""); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_VECTOR2_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedVector2Array( "); + p_store_string_func(p_store_string_ud, "PackedVector2Array("); Vector<Vector2> data = p_variant; int len = data.size(); const Vector2 *ptr = data.ptr(); @@ -1743,11 +1762,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y)); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_VECTOR3_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedVector3Array( "); + p_store_string_func(p_store_string_ud, "PackedVector3Array("); Vector<Vector3> data = p_variant; int len = data.size(); const Vector3 *ptr = data.ptr(); @@ -1759,12 +1778,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y) + ", " + rtosfix(ptr[i].z)); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_COLOR_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedColorArray( "); - + p_store_string_func(p_store_string_ud, "PackedColorArray("); Vector<Color> data = p_variant; int len = data.size(); const Color *ptr = data.ptr(); @@ -1776,7 +1794,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i].r) + ", " + rtosfix(ptr[i].g) + ", " + rtosfix(ptr[i].b) + ", " + rtosfix(ptr[i].a)); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; default: { diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 5703f0200c..05fc29b5e0 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -31,8 +31,8 @@ #ifndef VARIANT_PARSER_H #define VARIANT_PARSER_H +#include "core/io/file_access.h" #include "core/io/resource.h" -#include "core/os/file_access.h" #include "core/variant/variant.h" class VariantParser { diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 9ab8602782..de1deace63 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -28,282 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "variant.h" - -#include "core/core_string_names.h" -#include "core/debugger/engine_debugger.h" -#include "core/object/class_db.h" -#include "core/templates/local_vector.h" -#include "core/variant/variant_internal.h" - -/**** NAMED SETTERS AND GETTERS ****/ - -#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_member = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == Variant::FLOAT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \ - valid = true; \ - } else if (value->get_type() == Variant::INT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_member = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_custom = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == Variant::FLOAT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \ - valid = true; \ - } else if (value->get_type() == Variant::INT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_custom = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_setter(PtrToArg<m_member_type>::convert(member)); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == Variant::FLOAT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \ - valid = true; \ - } else if (value->get_type() == Variant::INT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_setter(PtrToArg<m_member_type>::convert(member)); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -SETGET_NUMBER_STRUCT(Vector2, double, x) -SETGET_NUMBER_STRUCT(Vector2, double, y) - -SETGET_NUMBER_STRUCT(Vector2i, int64_t, x) -SETGET_NUMBER_STRUCT(Vector2i, int64_t, y) - -SETGET_NUMBER_STRUCT(Vector3, double, x) -SETGET_NUMBER_STRUCT(Vector3, double, y) -SETGET_NUMBER_STRUCT(Vector3, double, z) - -SETGET_NUMBER_STRUCT(Vector3i, int64_t, x) -SETGET_NUMBER_STRUCT(Vector3i, int64_t, y) -SETGET_NUMBER_STRUCT(Vector3i, int64_t, z) - -SETGET_STRUCT(Rect2, Vector2, position) -SETGET_STRUCT(Rect2, Vector2, size) -SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end) - -SETGET_STRUCT(Rect2i, Vector2i, position) -SETGET_STRUCT(Rect2i, Vector2i, size) -SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end) - -SETGET_STRUCT(AABB, Vector3, position) -SETGET_STRUCT(AABB, Vector3, size) -SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end) - -SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0]) -SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1]) -SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2]) - -SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x) -SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y) -SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z) -SETGET_STRUCT(Plane, Vector3, normal) -SETGET_NUMBER_STRUCT(Plane, double, d) - -SETGET_NUMBER_STRUCT(Quat, double, x) -SETGET_NUMBER_STRUCT(Quat, double, y) -SETGET_NUMBER_STRUCT(Quat, double, z) -SETGET_NUMBER_STRUCT(Quat, double, w) - -SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0) -SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1) -SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2) - -SETGET_STRUCT(Transform, Basis, basis) -SETGET_STRUCT(Transform, Vector3, origin) - -SETGET_NUMBER_STRUCT(Color, double, r) -SETGET_NUMBER_STRUCT(Color, double, g) -SETGET_NUMBER_STRUCT(Color, double, b) -SETGET_NUMBER_STRUCT(Color, double, a) - -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8) -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8) -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8) -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8) - -SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h) -SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s) -SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v) +#include "variant_setget.h" struct VariantSetterGetterInfo { void (*setter)(Variant *base, const Variant *value, bool &valid); @@ -326,7 +51,7 @@ static void register_member(Variant::Type p_type, const StringName &p_member) { sgi.ptr_setter = T::ptr_set; sgi.getter = T::get; - sgi.validated_getter = T::get; + sgi.validated_getter = T::validated_get; sgi.ptr_getter = T::ptr_get; sgi.member_type = T::get_type(); @@ -374,17 +99,17 @@ void register_named_setters_getters() { REGISTER_MEMBER(Plane, d); REGISTER_MEMBER(Plane, normal); - REGISTER_MEMBER(Quat, x); - REGISTER_MEMBER(Quat, y); - REGISTER_MEMBER(Quat, z); - REGISTER_MEMBER(Quat, w); + REGISTER_MEMBER(Quaternion, x); + REGISTER_MEMBER(Quaternion, y); + REGISTER_MEMBER(Quaternion, z); + REGISTER_MEMBER(Quaternion, w); REGISTER_MEMBER(Basis, x); REGISTER_MEMBER(Basis, y); REGISTER_MEMBER(Basis, z); - REGISTER_MEMBER(Transform, basis); - REGISTER_MEMBER(Transform, origin); + REGISTER_MEMBER(Transform3D, basis); + REGISTER_MEMBER(Transform3D, origin); REGISTER_MEMBER(Color, r); REGISTER_MEMBER(Color, g); @@ -975,7 +700,7 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quat, double, real_t, 4) +INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quaternion, double, real_t, 4) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4) INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3) @@ -1037,7 +762,7 @@ void register_indexed_setters_getters() { REGISTER_INDEXED_MEMBER(Vector2i); REGISTER_INDEXED_MEMBER(Vector3); REGISTER_INDEXED_MEMBER(Vector3i); - REGISTER_INDEXED_MEMBER(Quat); + REGISTER_INDEXED_MEMBER(Quaternion); REGISTER_INDEXED_MEMBER(Color); REGISTER_INDEXED_MEMBER(Transform2D); REGISTER_INDEXED_MEMBER(Basis); @@ -1146,7 +871,7 @@ struct VariantKeyedSetGetDictionary { *r_valid = true; return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key); } - static bool ptr_has(const void *base, const void *key) { + static uint32_t ptr_has(const void *base, const void *key) { /* avoid ptrconvert for performance*/ const Dictionary &v = *reinterpret_cast<const Dictionary *>(base); return v.has(PtrToArg<Variant>::convert(key)); @@ -1196,7 +921,7 @@ struct VariantKeyedSetGetObject { obj->getvar(*key, &exists); return exists; } - static bool ptr_has(const void *base, const void *key) { + static uint32_t ptr_has(const void *base, const void *key) { const Object *obj = PtrToArg<Object *>::convert(base); ERR_FAIL_COND_V(!obj, false); bool valid; @@ -1453,7 +1178,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } @@ -1680,7 +1405,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } @@ -1865,7 +1590,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { return Variant(); } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_valid = false; return Variant(); } @@ -2135,10 +1860,10 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c); } return; - case QUAT: { - Quat empty_rot; - const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem); - const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem); + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem); + const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem); r_dst = *qa * empty_rot.slerp(*qb, c); } return; @@ -2295,8 +2020,8 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = a; } return; - case QUAT: { - r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c); + case QUATERNION: { + r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c); } return; case AABB: { @@ -2304,11 +2029,11 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case BASIS: { - r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis; + r_dst = Transform3D(*a._data._basis).interpolate_with(Transform3D(*b._data._basis), c).basis; } return; - case TRANSFORM: { - r_dst = a._data._transform->interpolate_with(*b._data._transform, c); + case TRANSFORM3D: { + r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c); } return; case COLOR: { diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h new file mode 100644 index 0000000000..dbf24ab3e3 --- /dev/null +++ b/core/variant/variant_setget.h @@ -0,0 +1,332 @@ +/*************************************************************************/ +/* variant_setget.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 VARIANT_SETGET_H +#define VARIANT_SETGET_H + +#include "variant.h" + +#include "core/core_string_names.h" +#include "core/debugger/engine_debugger.h" +#include "core/object/class_db.h" +#include "core/templates/local_vector.h" +#include "core/variant/variant_internal.h" + +/**** NAMED SETTERS AND GETTERS ****/ + +#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_member = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == Variant::FLOAT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \ + valid = true; \ + } else if (value->get_type() == Variant::INT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_member = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_custom = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == Variant::FLOAT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \ + valid = true; \ + } else if (value->get_type() == Variant::INT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_custom = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_setter(PtrToArg<m_member_type>::convert(member)); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == Variant::FLOAT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \ + valid = true; \ + } else if (value->get_type() == Variant::INT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_setter(PtrToArg<m_member_type>::convert(member)); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +SETGET_NUMBER_STRUCT(Vector2, double, x) +SETGET_NUMBER_STRUCT(Vector2, double, y) + +SETGET_NUMBER_STRUCT(Vector2i, int64_t, x) +SETGET_NUMBER_STRUCT(Vector2i, int64_t, y) + +SETGET_NUMBER_STRUCT(Vector3, double, x) +SETGET_NUMBER_STRUCT(Vector3, double, y) +SETGET_NUMBER_STRUCT(Vector3, double, z) + +SETGET_NUMBER_STRUCT(Vector3i, int64_t, x) +SETGET_NUMBER_STRUCT(Vector3i, int64_t, y) +SETGET_NUMBER_STRUCT(Vector3i, int64_t, z) + +SETGET_STRUCT(Rect2, Vector2, position) +SETGET_STRUCT(Rect2, Vector2, size) +SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end) + +SETGET_STRUCT(Rect2i, Vector2i, position) +SETGET_STRUCT(Rect2i, Vector2i, size) +SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end) + +SETGET_STRUCT(AABB, Vector3, position) +SETGET_STRUCT(AABB, Vector3, size) +SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end) + +SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0]) +SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1]) +SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2]) + +SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x) +SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y) +SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z) +SETGET_STRUCT(Plane, Vector3, normal) +SETGET_NUMBER_STRUCT(Plane, double, d) + +SETGET_NUMBER_STRUCT(Quaternion, double, x) +SETGET_NUMBER_STRUCT(Quaternion, double, y) +SETGET_NUMBER_STRUCT(Quaternion, double, z) +SETGET_NUMBER_STRUCT(Quaternion, double, w) + +SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0) +SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1) +SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2) + +SETGET_STRUCT(Transform3D, Basis, basis) +SETGET_STRUCT(Transform3D, Vector3, origin) + +SETGET_NUMBER_STRUCT(Color, double, r) +SETGET_NUMBER_STRUCT(Color, double, g) +SETGET_NUMBER_STRUCT(Color, double, b) +SETGET_NUMBER_STRUCT(Color, double, a) + +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8) +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8) +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8) +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8) + +SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h) +SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s) +SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v) + +#endif // VARIANT_SETGET_H diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 553f2b23a2..1f69e81d99 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/io/marshalls.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/templates/oa_hash_map.h" #include "core/variant/binder_common.h" @@ -1348,8 +1348,8 @@ String Variant::get_utility_function_argument_name(const StringName &p_name, int if (!bfi) { return String(); } - ERR_FAIL_COND_V(bfi->is_vararg, String()); ERR_FAIL_INDEX_V(p_arg, bfi->argnames.size(), String()); + ERR_FAIL_COND_V(bfi->is_vararg, String()); return bfi->argnames[p_arg]; } @@ -1379,6 +1379,23 @@ bool Variant::is_utility_function_vararg(const StringName &p_name) { return bfi->is_vararg; } +uint32_t Variant::get_utility_function_hash(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + ERR_FAIL_COND_V(!bfi, 0); + + uint32_t hash = hash_djb2_one_32(bfi->is_vararg); + hash = hash_djb2_one_32(bfi->returns_value, hash); + if (bfi->returns_value) { + hash = hash_djb2_one_32(bfi->return_type, hash); + } + hash = hash_djb2_one_32(bfi->argcount, hash); + for (int i = 0; i < bfi->argcount; i++) { + hash = hash_djb2_one_32(bfi->get_arg_type(i), hash); + } + + return hash; +} + void Variant::get_utility_function_list(List<StringName> *r_functions) { for (List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) { r_functions->push_back(E->get()); |