summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub1
-rw-r--r--core/config/engine.cpp19
-rw-r--r--core/config/engine.h6
-rw-r--r--core/config/project_settings.cpp18
-rw-r--r--core/core_bind.cpp355
-rw-r--r--core/core_bind.h91
-rw-r--r--core/core_constants.cpp9
-rw-r--r--core/crypto/aes_context.h6
-rw-r--r--core/crypto/crypto.h11
-rw-r--r--core/crypto/crypto_core.h2
-rw-r--r--core/crypto/hashing_context.h6
-rw-r--r--core/debugger/remote_debugger_peer.cpp2
-rw-r--r--core/debugger/remote_debugger_peer.h4
-rw-r--r--core/extension/SCsub7
-rw-r--r--core/extension/extension_api_dump.cpp805
-rw-r--r--core/extension/extension_api_dump.h45
-rw-r--r--core/extension/gdnative_interface.cpp694
-rw-r--r--core/extension/gdnative_interface.h438
-rw-r--r--core/extension/native_extension.cpp411
-rw-r--r--core/extension/native_extension.h94
-rw-r--r--core/extension/native_extension_manager.cpp130
-rw-r--r--core/extension/native_extension_manager.h71
-rw-r--r--core/input/input.cpp110
-rw-r--r--core/input/input.h46
-rw-r--r--core/input/input_enums.h126
-rw-r--r--core/input/input_event.cpp139
-rw-r--r--core/input/input_event.h109
-rw-r--r--core/input/input_map.cpp15
-rw-r--r--core/io/compression.cpp5
-rw-r--r--core/io/config_file.h8
-rw-r--r--core/io/dir_access.cpp (renamed from core/os/dir_access.cpp)2
-rw-r--r--core/io/dir_access.h (renamed from core/os/dir_access.h)0
-rw-r--r--core/io/dtls_server.cpp2
-rw-r--r--core/io/dtls_server.h4
-rw-r--r--core/io/file_access.cpp (renamed from core/os/file_access.cpp)1
-rw-r--r--core/io/file_access.h (renamed from core/os/file_access.h)0
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp1
-rw-r--r--core/io/file_access_encrypted.h2
-rw-r--r--core/io/file_access_memory.cpp3
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp2
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.h4
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/http_client.cpp704
-rw-r--r--core/io/http_client.h89
-rw-r--r--core/io/http_client_tcp.cpp667
-rw-r--r--core/io/http_client_tcp.h92
-rw-r--r--core/io/image.cpp61
-rw-r--r--core/io/image.h13
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/json.cpp79
-rw-r--r--core/io/json.h40
-rw-r--r--core/io/logger.cpp9
-rw-r--r--core/io/logger.h2
-rw-r--r--core/io/marshalls.cpp533
-rw-r--r--core/io/marshalls.h38
-rw-r--r--core/io/multiplayer_api.cpp344
-rw-r--r--core/io/multiplayer_api.h61
-rw-r--r--core/io/multiplayer_peer.cpp (renamed from core/io/networked_multiplayer_peer.cpp)24
-rw-r--r--core/io/multiplayer_peer.h (renamed from core/io/networked_multiplayer_peer.h)12
-rw-r--r--core/io/net_socket.h4
-rw-r--r--core/io/packed_data_container.cpp4
-rw-r--r--core/io/packed_data_container.h4
-rw-r--r--core/io/packet_peer.cpp2
-rw-r--r--core/io/packet_peer.h4
-rw-r--r--core/io/packet_peer_dtls.cpp2
-rw-r--r--core/io/pck_packer.cpp2
-rw-r--r--core/io/pck_packer.h6
-rw-r--r--core/io/resource.cpp6
-rw-r--r--core/io/resource.h6
-rw-r--r--core/io/resource_format_binary.cpp22
-rw-r--r--core/io/resource_format_binary.h2
-rw-r--r--core/io/resource_importer.h4
-rw-r--r--core/io/resource_loader.cpp44
-rw-r--r--core/io/resource_loader.h4
-rw-r--r--core/io/resource_saver.cpp22
-rw-r--r--core/io/resource_saver.h4
-rw-r--r--core/io/stream_peer.cpp2
-rw-r--r--core/io/stream_peer.h6
-rw-r--r--core/io/tcp_server.cpp1
-rw-r--r--core/io/tcp_server.h4
-rw-r--r--core/io/translation_loader_po.cpp2
-rw-r--r--core/io/translation_loader_po.h2
-rw-r--r--core/io/udp_server.cpp1
-rw-r--r--core/io/udp_server.h4
-rw-r--r--core/io/xml_parser.h9
-rw-r--r--core/io/zip_io.h2
-rw-r--r--core/math/a_star.h10
-rw-r--r--core/math/aabb.cpp2
-rw-r--r--core/math/basis.cpp53
-rw-r--r--core/math/basis.h28
-rw-r--r--core/math/camera_matrix.cpp14
-rw-r--r--core/math/camera_matrix.h10
-rw-r--r--core/math/color.cpp8
-rw-r--r--core/math/delaunay_3d.h2
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/expression.h6
-rw-r--r--core/math/face3.cpp6
-rw-r--r--core/math/face3.h6
-rw-r--r--core/math/geometry_2d.h13
-rw-r--r--core/math/math_fieldwise.cpp8
-rw-r--r--core/math/plane.cpp2
-rw-r--r--core/math/quaternion.cpp (renamed from core/math/quat.cpp)75
-rw-r--r--core/math/quaternion.h (renamed from core/math/quat.h)113
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/random_number_generator.h6
-rw-r--r--core/math/rect2.cpp8
-rw-r--r--core/math/rect2.h4
-rw-r--r--core/math/transform_2d.cpp23
-rw-r--r--core/math/transform_2d.h4
-rw-r--r--core/math/transform_3d.cpp (renamed from core/math/transform.cpp)100
-rw-r--r--core/math/transform_3d.h (renamed from core/math/transform.h)60
-rw-r--r--core/math/triangle_mesh.cpp2
-rw-r--r--core/math/triangle_mesh.h6
-rw-r--r--core/math/vector2.cpp8
-rw-r--r--core/math/vector2.h4
-rw-r--r--core/math/vector3.cpp2
-rw-r--r--core/math/vector3i.cpp2
-rw-r--r--core/object/SCsub5
-rw-r--r--core/object/class_db.cpp75
-rw-r--r--core/object/class_db.h15
-rw-r--r--core/object/make_virtuals.py152
-rw-r--r--core/object/method_bind.cpp29
-rw-r--r--core/object/method_bind.h2
-rw-r--r--core/object/object.cpp150
-rw-r--r--core/object/object.h123
-rw-r--r--core/object/object_id.h2
-rw-r--r--core/object/ref_counted.cpp (renamed from core/object/reference.cpp)45
-rw-r--r--core/object/ref_counted.h (renamed from core/object/reference.h)38
-rw-r--r--core/object/script_language.cpp16
-rw-r--r--core/object/script_language.h61
-rw-r--r--core/object/undo_redo.cpp24
-rw-r--r--core/object/undo_redo.h4
-rw-r--r--core/os/main_loop.h2
-rw-r--r--core/os/memory.h2
-rw-r--r--core/os/midi_driver.cpp10
-rw-r--r--core/os/os.cpp42
-rw-r--r--core/os/os.h36
-rw-r--r--core/os/time.cpp433
-rw-r--r--core/os/time.h109
-rw-r--r--core/register_core_types.cpp76
-rw-r--r--core/register_core_types.h1
-rw-r--r--core/string/translation_po.cpp4
-rw-r--r--core/string/ustring.cpp49
-rw-r--r--core/string/ustring.h6
-rw-r--r--core/templates/bin_sorted_array.h181
-rw-r--r--core/templates/command_queue_mt.cpp29
-rw-r--r--core/templates/command_queue_mt.h161
-rw-r--r--core/templates/hash_map.h6
-rw-r--r--core/templates/list.h77
-rw-r--r--core/templates/local_vector.h2
-rw-r--r--core/templates/map.h133
-rw-r--r--core/templates/oa_hash_map.h4
-rw-r--r--core/templates/pair.h35
-rw-r--r--core/templates/rid_owner.h45
-rw-r--r--core/templates/set.h79
-rw-r--r--core/templates/thread_work_pool.h2
-rw-r--r--core/templates/vector.h64
-rw-r--r--core/variant/binder_common.h9
-rw-r--r--core/variant/callable.cpp6
-rw-r--r--core/variant/callable.h1
-rw-r--r--core/variant/dictionary.cpp59
-rw-r--r--core/variant/method_ptrcall.h18
-rw-r--r--core/variant/type_info.h4
-rw-r--r--core/variant/typed_array.h8
-rw-r--r--core/variant/variant.cpp247
-rw-r--r--core/variant/variant.h25
-rw-r--r--core/variant/variant_call.cpp95
-rw-r--r--core/variant/variant_construct.cpp568
-rw-r--r--core/variant/variant_construct.h572
-rw-r--r--core/variant/variant_internal.h66
-rw-r--r--core/variant/variant_op.cpp1413
-rw-r--r--core/variant/variant_op.h1316
-rw-r--r--core/variant/variant_parser.cpp138
-rw-r--r--core/variant/variant_parser.h2
-rw-r--r--core/variant/variant_setget.cpp323
-rw-r--r--core/variant/variant_setget.h332
-rw-r--r--core/variant/variant_utility.cpp21
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());