diff options
Diffstat (limited to 'core/object')
-rw-r--r-- | core/object/class_db.cpp | 39 | ||||
-rw-r--r-- | core/object/class_db.h | 21 | ||||
-rw-r--r-- | core/object/make_virtuals.py | 7 | ||||
-rw-r--r-- | core/object/message_queue.cpp | 41 | ||||
-rw-r--r-- | core/object/message_queue.h | 43 | ||||
-rw-r--r-- | core/object/object.cpp | 73 | ||||
-rw-r--r-- | core/object/object.h | 100 | ||||
-rw-r--r-- | core/object/script_language.cpp | 24 | ||||
-rw-r--r-- | core/object/script_language.h | 20 | ||||
-rw-r--r-- | core/object/undo_redo.cpp | 99 | ||||
-rw-r--r-- | core/object/undo_redo.h | 34 |
11 files changed, 256 insertions, 245 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 3df4db9c5e..08e12dfcaa 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -557,6 +557,19 @@ bool ClassDB::can_instantiate(const StringName &p_class) { return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance)); } +bool ClassDB::is_virtual(const StringName &p_class) { + OBJTYPE_RLOCK; + + ClassInfo *ti = classes.getptr(p_class); + ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'."); +#ifdef TOOLS_ENABLED + if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { + return false; + } +#endif + return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance) && ti->is_virtual); +} + void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { OBJTYPE_WLOCK; @@ -1007,20 +1020,30 @@ bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal, return false; } -void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix) { +void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) { OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); ERR_FAIL_COND(!type); - type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP)); + String prefix = p_prefix; + if (p_indent_depth > 0) { + prefix = vformat("%s,%d", p_prefix, p_indent_depth); + } + + type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_GROUP)); } -void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix) { +void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) { OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); ERR_FAIL_COND(!type); - type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP)); + String prefix = p_prefix; + if (p_indent_depth > 0) { + prefix = vformat("%s,%d", p_prefix, p_indent_depth); + } + + type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_SUBGROUP)); } void ClassDB::add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage) { @@ -1187,7 +1210,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const if (psg->_setptr) { psg->_setptr->call(p_object, arg, 2, ce); } else { - p_object->call(psg->setter, arg, 2, ce); + p_object->callp(psg->setter, arg, 2, ce); } } else { @@ -1195,7 +1218,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const if (psg->_setptr) { psg->_setptr->call(p_object, arg, 1, ce); } else { - p_object->call(psg->setter, arg, 1, ce); + p_object->callp(psg->setter, arg, 1, ce); } } @@ -1228,14 +1251,14 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia Variant index = psg->index; const Variant *arg[1] = { &index }; Callable::CallError ce; - r_value = p_object->call(psg->getter, arg, 1, ce); + r_value = p_object->callp(psg->getter, arg, 1, ce); } else { Callable::CallError ce; if (psg->_getptr) { r_value = psg->_getptr->call(p_object, nullptr, 0, ce); } else { - r_value = p_object->call(psg->getter, nullptr, 0, ce); + r_value = p_object->callp(psg->getter, nullptr, 0, ce); } } return true; diff --git a/core/object/class_db.h b/core/object/class_db.h index 5adf1a59a4..580ae3582f 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -118,6 +118,7 @@ public: StringName name; bool disabled = false; bool exposed = false; + bool is_virtual = false; Object *(*creation_func)() = nullptr; ClassInfo() {} @@ -156,20 +157,21 @@ public: } template <class T> - static void register_class() { + static void register_class(bool p_virtual = false) { GLOBAL_LOCK_FUNCTION; T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_COND(!t); t->creation_func = &creator<T>; t->exposed = true; + t->is_virtual = p_virtual; t->class_ptr = T::get_class_ptr_static(); t->api = current_api; T::register_custom_data_to_otdb(); } template <class T> - static void register_virtual_class() { + static void register_abstract_class() { GLOBAL_LOCK_FUNCTION; T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); @@ -210,6 +212,7 @@ public: static bool class_exists(const StringName &p_class); static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); static bool can_instantiate(const StringName &p_class); + static bool is_virtual(const StringName &p_class); static Object *instantiate(const StringName &p_class); static void set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance); @@ -328,8 +331,8 @@ public: static bool get_signal(const StringName &p_class, const StringName &p_signal, MethodInfo *r_signal); static void get_signal_list(const StringName &p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false); - static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix = ""); - static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = ""); + static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix = "", int p_indent_depth = 0); + static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = "", int p_indent_depth = 0); static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_DEFAULT); static void add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix); static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1); @@ -436,9 +439,13 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) { if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \ ::ClassDB::register_class<m_class>(); \ } -#define GDREGISTER_VIRTUAL_CLASS(m_class) \ - if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \ - ::ClassDB::register_virtual_class<m_class>(); \ +#define GDREGISTER_VIRTUAL_CLASS(m_class) \ + if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \ + ::ClassDB::register_class<m_class>(true); \ + } +#define GDREGISTER_ABSTRACT_CLASS(m_class) \ + if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \ + ::ClassDB::register_abstract_class<m_class>(); \ } #include "core/disabled_classes.gen.h" diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index 5de1b49026..2e909b8042 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -3,12 +3,13 @@ proto = """ StringName _gdvirtual_##m_name##_sn = #m_name;\\ mutable bool _gdvirtual_##m_name##_initialized = false;\\ mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\ +template<bool required>\\ _FORCE_INLINE_ 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);\\ + $CALLSIBEGINscript_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\ if (ce.error == Callable::CallError::CALL_OK) {\\ $CALLSIRET\\ return true;\\ @@ -25,6 +26,10 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ $CALLPTRRET\\ return true;\\ }\\ + \\ + if (required) {\\ + WARN_PRINT_ONCE("Required virtual method: "+get_class()+"::" + #m_name + " must be overriden before calling.");\\ + }\\ \\ return false;\\ }\\ diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp index 3c828eabd9..79c36ac81f 100644 --- a/core/object/message_queue.cpp +++ b/core/object/message_queue.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" +#include "core/object/class_db.h" #include "core/object/script_language.h" MessageQueue *MessageQueue::singleton = nullptr; @@ -40,23 +41,8 @@ MessageQueue *MessageQueue::get_singleton() { return singleton; } -Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) { - return push_callable(Callable(p_id, p_method), p_args, p_argcount, p_show_error); -} - -Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - return push_call(p_id, p_method, argptr, argc, false); +Error MessageQueue::push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) { + return push_callablep(Callable(p_id, p_method), p_args, p_argcount, p_show_error); } Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value) { @@ -113,8 +99,8 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) { return OK; } -Error MessageQueue::push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { - return push_call(p_object->get_instance_id(), p_method, VARIANT_ARG_PASS); +Error MessageQueue::push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) { + return push_callp(p_object->get_instance_id(), p_method, p_args, p_argcount, p_show_error); } Error MessageQueue::push_notification(Object *p_object, int p_notification) { @@ -125,7 +111,7 @@ Error MessageQueue::push_set(Object *p_object, const StringName &p_prop, const V return push_set(p_object->get_instance_id(), p_prop, p_value); } -Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) { +Error MessageQueue::push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) { _THREAD_SAFE_METHOD_ int room_needed = sizeof(Message) + sizeof(Variant) * p_argcount; @@ -155,21 +141,6 @@ Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_ return OK; } -Error MessageQueue::push_callable(const Callable &p_callable, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - return push_callable(p_callable, argptr, argc); -} - void MessageQueue::statistics() { Map<StringName, int> set_count; Map<int, int> notify_count; diff --git a/core/object/message_queue.h b/core/object/message_queue.h index a4449cf473..eaab01d0aa 100644 --- a/core/object/message_queue.h +++ b/core/object/message_queue.h @@ -31,8 +31,11 @@ #ifndef MESSAGE_QUEUE_H #define MESSAGE_QUEUE_H -#include "core/object/class_db.h" +#include "core/object/object_id.h" #include "core/os/thread_safe.h" +#include "core/variant/variant.h" + +class Object; class MessageQueue { _THREAD_SAFE_CLASS_ @@ -73,14 +76,42 @@ class MessageQueue { public: static MessageQueue *get_singleton(); - Error push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false); - Error push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_LIST); + Error push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false); + template <typename... VarArgs> + Error push_call(ObjectID p_id, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + return push_callp(p_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + Error push_notification(ObjectID p_id, int p_notification); Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value); - Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false); - Error push_callable(const Callable &p_callable, VARIANT_ARG_LIST); + Error push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false); + + template <typename... VarArgs> + Error push_callable(const Callable &p_callable, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + return push_callablep(p_callable, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + Error push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false); + template <typename... VarArgs> + Error push_call(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + return push_callp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } - Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); Error push_notification(Object *p_object, int p_notification); Error push_set(Object *p_object, const StringName &p_prop, const Variant &p_value); diff --git a/core/object/object.cpp b/core/object/object.cpp index f966607e03..096edd4e60 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -402,13 +402,9 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid #endif } - //try built-in setgetter + // Try built-in setter. { if (ClassDB::set_property(this, p_name, p_value, r_valid)) { - /* - if (r_valid) - *r_valid=true; - */ return; } } @@ -421,7 +417,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid return; } else if (p_name == CoreStringNames::get_singleton()->_meta) { - //set_meta(p_name,p_value); metadata = p_value.duplicate(); if (r_valid) { *r_valid = true; @@ -429,7 +424,7 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid return; } - //something inside the object... :| + // Something inside the object... :| bool success = _setv(p_name, p_value); if (success) { if (r_valid) { @@ -485,7 +480,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { #endif } - //try built-in setgetter + // Try built-in getter. { if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) { if (r_valid) { @@ -510,7 +505,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { return ret; } else { - //something inside the object... :| + // Something inside the object... :| bool success = _getv(p_name, ret); if (success) { if (r_valid) { @@ -629,8 +624,12 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons } if (_extension) { - p_list->push_back(PropertyInfo(Variant::NIL, _extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); - ClassDB::get_property_list(_extension->class_name, p_list, true, this); + const ObjectNativeExtension *current_extension = _extension; + while (current_extension) { + p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); + ClassDB::get_property_list(current_extension->class_name, p_list, true, this); + current_extension = current_extension->parent; + } } if (_extension && _extension->get_property_list) { @@ -684,7 +683,7 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal StringName method = *p_args[0]; - return call(method, &p_args[1], p_argcount - 1, r_error); + return callp(method, &p_args[1], p_argcount - 1, r_error); } Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { @@ -705,7 +704,7 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call StringName method = *p_args[0]; - MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true); + MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true); return Variant(); } @@ -755,31 +754,14 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) { } Callable::CallError ce; - Variant ret = call(p_method, argptrs, p_args.size(), ce); + Variant ret = callp(p_method, argptrs, p_args.size(), ce); if (ce.error != Callable::CallError::CALL_OK) { ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + "."); } return ret; } -Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - Callable::CallError error; - - Variant ret = call(p_name, argptr, argc, error); - return ret; -} - -Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; if (p_method == CoreStringNames::get_singleton()->_free) { @@ -813,7 +795,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a OBJ_DEBUG_LOCK if (script_instance) { - ret = script_instance->call(p_method, p_args, p_argcount, r_error); + ret = script_instance->callp(p_method, p_args, p_argcount, r_error); //force jumptable switch (r_error.error) { case Callable::CallError::CALL_OK: @@ -1032,12 +1014,12 @@ Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::C args = &p_args[1]; } - emit_signal(signal, args, argc); + emit_signalp(signal, args, argc); return Variant(); } -Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount) { +Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) { if (_block_signals) { return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked } @@ -1096,7 +1078,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int } if (c.flags & CONNECT_DEFERRED) { - MessageQueue::get_singleton()->push_callable(c.callable, args, argc, true); + MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true); } else { Callable::CallError ce; _emitting = true; @@ -1144,21 +1126,6 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int return err; } -Error Object::emit_signal(const StringName &p_name, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - return emit_signal(p_name, argptr, argc); -} - void Object::_add_user_signal(const String &p_name, const Array &p_args) { // this version of add_user_signal is meant to be used from scripts or external apis // without access to ADD_SIGNAL in bind_methods @@ -1653,10 +1620,6 @@ void Object::_bind_methods() { BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED); } -void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) { - MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS); -} - void Object::set_deferred(const StringName &p_property, const Variant &p_value) { MessageQueue::get_singleton()->push_set(this, p_property, p_value); } diff --git a/core/object/object.h b/core/object/object.h index 1a0a81581d..6b4f1c81e6 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -32,6 +32,7 @@ #define OBJECT_H #include "core/extension/gdnative_interface.h" +#include "core/object/message_queue.h" #include "core/object/object_id.h" #include "core/os/rw_lock.h" #include "core/os/spin_lock.h" @@ -44,14 +45,6 @@ #include "core/variant/callable_bind.h" #include "core/variant/variant.h" -#define VARIANT_ARG_LIST 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(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant() -#define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5, p_arg6, p_arg7, p_arg8 -#define VARIANT_ARG_DECLARE const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8 -#define VARIANT_ARG_MAX 8 -#define VARIANT_ARGPTRS const Variant *argptr[8] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5, &p_arg6, &p_arg7, &p_arg8 }; -#define VARIANT_ARGPTRS_PASS *argptr[0], *argptr[1], *argptr[2], *argptr[3], *argptr[4], *argptr[5], *argptr[6]], *argptr[7] -#define VARIANT_ARGS_FROM_ARRAY(m_arr) m_arr[0], m_arr[1], m_arr[2], m_arr[3], m_arr[4], m_arr[5], m_arr[6], m_arr[7] - enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range. @@ -95,6 +88,7 @@ enum PropertyHint { PROPERTY_HINT_ARRAY_TYPE, PROPERTY_HINT_INT_IS_POINTER, PROPERTY_HINT_LOCALE_ID, + PROPERTY_HINT_LOCALIZABLE_STRING, PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; @@ -142,7 +136,9 @@ enum PropertyUsageFlags { #define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index) #define ADD_PROPERTY_DEFAULT(m_property, m_default) ::ClassDB::set_property_default_value(get_class_static(), m_property, m_default) #define ADD_GROUP(m_name, m_prefix) ::ClassDB::add_property_group(get_class_static(), m_name, m_prefix) +#define ADD_GROUP_INDENT(m_name, m_prefix, m_depth) ::ClassDB::add_property_group(get_class_static(), m_name, m_prefix, m_depth) #define ADD_SUBGROUP(m_name, m_prefix) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix) +#define ADD_SUBGROUP_INDENT(m_name, m_prefix, m_depth) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix, m_depth) #define ADD_LINKED_PROPERTY(m_property, m_linked_property) ::ClassDB::add_linked_property(get_class_static(), m_property, m_linked_property) #define ADD_ARRAY_COUNT(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix) @@ -243,13 +239,7 @@ struct MethodInfo { MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); }; -// old cast_to -//if ( is_type(T::get_class_static()) ) -//return static_cast<T*>(this); -////else -//return nullptr; - -// API used to extend in GDNative and other C compatible compiled languages +// API used to extend in GDNative and other C compatible compiled languages. class MethodBind; struct ObjectNativeExtension { @@ -266,6 +256,7 @@ struct ObjectNativeExtension { GDNativeExtensionClassToString to_string; GDNativeExtensionClassReference reference; GDNativeExtensionClassReference unreference; + GDNativeExtensionClassGetRID get_rid; _FORCE_INLINE_ bool is_class(const String &p_class) const { const ObjectNativeExtension *e = this; @@ -284,8 +275,12 @@ struct ObjectNativeExtension { GDNativeExtensionClassGetVirtual get_virtual; }; -#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__) -#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call(__VA_ARGS__) +#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__) +#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__) + +#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__) +#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__) + #ifdef DEBUG_METHODS_ENABLED #define GDVIRTUAL_BIND(m_name, ...) ::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), true, sarray(__VA_ARGS__)); #else @@ -295,8 +290,10 @@ struct ObjectNativeExtension { #define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden() /* - 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. -*/ + * The following is an incomprehensible blob of hacks and workarounds to + * compensate for many of the fallacies in C++. As a plus, this macro pretty + * much alone defines the object model. + */ #define REVERSE_GET_PROPERTY_LIST \ public: \ @@ -532,7 +529,7 @@ private: Set<String> editor_section_folding; #endif ScriptInstance *script_instance = nullptr; - Variant script; //reference does not yet exist, store it in a + Variant script; // Reference does not exist yet, store it in a Variant. Dictionary metadata; mutable StringName _class_name; mutable const StringName *_class_ptr = nullptr; @@ -581,6 +578,7 @@ protected: } 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; } @@ -615,9 +613,6 @@ protected: static void get_valid_parents_static(List<String> *p_parents); static void _get_valid_parents_static(List<String> *p_parents); - //Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); - //void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); - Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); @@ -639,7 +634,7 @@ protected: void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); -public: //should be protected, but bug in clang++ +public: // Should be protected, but bug in clang++. static void initialize_class(); _FORCE_INLINE_ static void register_custom_data_to_otdb() {} @@ -727,8 +722,6 @@ public: } /* IAPI */ - //void set(const String& p_name, const Variant& p_value); - //Variant get(const String& p_name) const; void set(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr); Variant get(const StringName &p_name, bool *r_valid = nullptr) const; @@ -740,13 +733,23 @@ public: bool has_method(const StringName &p_method) const; void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); + + template <typename... VarArgs> + Variant call(const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + Callable::CallError cerr; + return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr); + } void notification(int p_notification, bool p_reversed = false); virtual String to_string(); - //used mainly by script, get and set all INCLUDING string + // Used mainly by script, get and set all INCLUDING string. virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const; virtual void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = nullptr); @@ -755,8 +758,6 @@ public: void set_script(const Variant &p_script); Variant get_script() const; - /* SCRIPT */ - bool has_meta(const StringName &p_name) const; void set_meta(const StringName &p_name, const Variant &p_value); void remove_meta(const StringName &p_name); @@ -766,17 +767,29 @@ public: #ifdef TOOLS_ENABLED void set_edited(bool p_edited); bool is_edited() const; - uint32_t get_edited_version() const; //this function is used to check when something changed beyond a point, it's used mainly for generating previews + // This function is used to check when something changed beyond a point, it's used mainly for generating previews. + uint32_t get_edited_version() const; #endif void set_script_instance(ScriptInstance *p_instance); _FORCE_INLINE_ ScriptInstance *get_script_instance() const { return script_instance; } - void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process + // Some script languages can't control instance creation, so this function eases the process. + void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance); void add_user_signal(const MethodInfo &p_signal); - Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST); - Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount); + + template <typename... VarArgs> + Error emit_signal(const StringName &p_name, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount); bool has_signal(const StringName &p_name) const; void get_signal_list(List<MethodInfo> *p_signals) const; void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const; @@ -788,7 +801,11 @@ public: void disconnect(const StringName &p_signal, const Callable &p_callable); bool is_connected(const StringName &p_signal, const Callable &p_callable) const; - void call_deferred(const StringName &p_method, VARIANT_ARG_LIST); + template <typename... VarArgs> + void call_deferred(const StringName &p_name, VarArgs... p_args) { + MessageQueue::get_singleton()->push_call(this, p_name, p_args...); + } + void set_deferred(const StringName &p_property, const Variant &p_value); void set_block_signals(bool p_block); @@ -801,10 +818,11 @@ public: virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; - String tr(const StringName &p_message, const StringName &p_context = "") const; // translate message (internationalization) + // Translate message (internationalization). + String tr(const StringName &p_message, const StringName &p_context = "") const; String tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - bool _is_queued_for_deletion = false; // set to true by SceneTree::queue_delete() + bool _is_queued_for_deletion = false; // Set to true by SceneTree::queue_delete(). bool is_queued_for_deletion() const; _FORCE_INLINE_ void set_message_translation(bool p_enable) { _can_translate = p_enable; } @@ -836,14 +854,14 @@ bool predelete_handler(Object *p_object); void postinitialize_handler(Object *p_object); class ObjectDB { -//this needs to add up to 63, 1 bit is for reference +// This needs to add up to 63, 1 bit is for reference. #define OBJECTDB_VALIDATOR_BITS 39 #define OBJECTDB_VALIDATOR_MASK ((uint64_t(1) << OBJECTDB_VALIDATOR_BITS) - 1) #define OBJECTDB_SLOT_MAX_COUNT_BITS 24 #define OBJECTDB_SLOT_MAX_COUNT_MASK ((uint64_t(1) << OBJECTDB_SLOT_MAX_COUNT_BITS) - 1) #define OBJECTDB_REFERENCE_BIT (uint64_t(1) << (OBJECTDB_SLOT_MAX_COUNT_BITS + OBJECTDB_VALIDATOR_BITS)) - struct ObjectSlot { //128 bits per slot + struct ObjectSlot { // 128 bits per slot. uint64_t validator : OBJECTDB_VALIDATOR_BITS; uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS; uint64_t is_ref_counted : 1; @@ -873,7 +891,7 @@ public: uint64_t id = p_instance_id; uint32_t slot = id & OBJECTDB_SLOT_MAX_COUNT_MASK; - ERR_FAIL_COND_V(slot >= slot_max, nullptr); //this should never happen unless RID is corrupted + ERR_FAIL_COND_V(slot >= slot_max, nullptr); // This should never happen unless RID is corrupted. spin_lock.lock(); diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 9fec7c397d..11440c37fe 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -46,10 +46,12 @@ bool ScriptServer::languages_finished = false; ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr; void Script::_notification(int p_what) { - if (p_what == NOTIFICATION_POSTINITIALIZE) { - if (EngineDebugger::is_active()) { - EngineDebugger::get_script_debugger()->set_break_language(get_language()); - } + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + if (EngineDebugger::is_active()) { + EngineDebugger::get_script_debugger()->set_break_language(get_language()); + } + } break; } } @@ -308,20 +310,6 @@ void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) } } -Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - Callable::CallError error; - return call(p_method, argptr, argc, error); -} - void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) { if (r_valid) { *r_valid = false; diff --git a/core/object/script_language.h b/core/object/script_language.h index 4b18d9a5e8..2122f785b6 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -176,8 +176,20 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const = 0; virtual bool has_method(const StringName &p_method) const = 0; - virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST); - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0; + + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0; + + template <typename... VarArgs> + Variant call(const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + Callable::CallError cerr; + return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr); + } + virtual void notification(int p_notification) = 0; virtual String to_string(bool *r_valid) { if (r_valid) { @@ -419,8 +431,8 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; - virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); } - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index f72dec8edf..ee8eb97a93 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -34,6 +34,20 @@ #include "core/os/os.h" #include "core/templates/local_vector.h" +void UndoRedo::Operation::delete_reference() { + if (type != Operation::TYPE_REFERENCE) { + return; + } + if (ref.is_valid()) { + ref.unref(); + } else { + Object *obj = ObjectDB::get_instance(object); + if (obj) { + memdelete(obj); + } + } +} + void UndoRedo::_discard_redo() { if (current_action == actions.size() - 1) { return; @@ -41,16 +55,7 @@ void UndoRedo::_discard_redo() { for (int i = current_action + 1; i < actions.size(); i++) { for (Operation &E : actions.write[i].do_ops) { - if (E.type == Operation::TYPE_REFERENCE) { - if (E.ref.is_valid()) { - E.ref.unref(); - } else { - Object *obj = ObjectDB::get_instance(E.object); - if (obj) { - memdelete(obj); - } - } - } + E.delete_reference(); } //ERASE do data } @@ -97,13 +102,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { for (unsigned int i = 0; i < to_remove.size(); i++) { List<Operation>::Element *E = to_remove[i]; // Delete all object references - if (E->get().type == Operation::TYPE_REFERENCE) { - Object *obj = ObjectDB::get_instance(E->get().object); - - if (obj) { - memdelete(obj); - } - } + E->get().delete_reference(); E->erase(); } } @@ -127,8 +126,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { force_keep_in_merge_ends = false; } -void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS +void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { ERR_FAIL_COND(p_object == nullptr); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -141,14 +139,13 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA do_op.type = Operation::TYPE_METHOD; do_op.name = p_method; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - do_op.args[i] = *argptr[i]; + for (int i = 0; i < p_argcount; i++) { + do_op.args.push_back(*p_args[i]); } actions.write[current_action + 1].do_ops.push_back(do_op); } -void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS +void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { ERR_FAIL_COND(p_object == nullptr); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -168,8 +165,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_method; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - undo_op.args[i] = *argptr[i]; + for (int i = 0; i < p_argcount; i++) { + undo_op.args.push_back(*p_args[i]); } actions.write[current_action + 1].undo_ops.push_back(undo_op); } @@ -186,7 +183,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c do_op.type = Operation::TYPE_PROPERTY; do_op.name = p_property; - do_op.args[0] = p_value; + do_op.args.push_back(p_value); actions.write[current_action + 1].do_ops.push_back(do_op); } @@ -209,7 +206,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, undo_op.type = Operation::TYPE_PROPERTY; undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_property; - undo_op.args[0] = p_value; + undo_op.args.push_back(p_value); actions.write[current_action + 1].undo_ops.push_back(undo_op); } @@ -270,16 +267,7 @@ void UndoRedo::_pop_history_tail() { } for (Operation &E : actions.write[0].undo_ops) { - if (E.type == Operation::TYPE_REFERENCE) { - if (E.ref.is_valid()) { - E.ref.unref(); - } else { - Object *obj = ObjectDB::get_instance(E.object); - if (obj) { - memdelete(obj); - } - } - } + E.delete_reference(); } actions.remove_at(0); @@ -324,23 +312,18 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { switch (op.type) { case Operation::TYPE_METHOD: { + int argc = op.args.size(); Vector<const Variant *> argptrs; - argptrs.resize(VARIANT_ARG_MAX); - int argc = 0; + argptrs.resize(argc); - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (op.args[i].get_type() == Variant::NIL) { - break; - } + for (int i = 0; i < argc; i++) { argptrs.write[i] = &op.args[i]; - argc++; } - argptrs.resize(argc); Callable::CallError ce; - obj->call(op.name, (const Variant **)argptrs.ptr(), argc, ce); + obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce); if (ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT("Error calling method from signal '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce)); + ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce)); } #ifdef TOOLS_ENABLED Resource *res = Object::cast_to<Resource>(obj); @@ -351,7 +334,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { #endif if (method_callback) { - method_callback(method_callbck_ud, obj, op.name, VARIANT_ARGS_FROM_ARRAY(op.args)); + method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc); } } break; case Operation::TYPE_PROPERTY: { @@ -449,7 +432,7 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback, void void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback, void *p_ud) { method_callback = p_method_callback; - method_callbck_ud = p_ud; + method_callback_ud = p_ud; } void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback, void *p_ud) { @@ -487,14 +470,7 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callabl Object *object = *p_args[0]; StringName method = *p_args[1]; - Variant v[VARIANT_ARG_MAX]; - - for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) { - v[i] = *p_args[i + 2]; - } - - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); - add_do_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + add_do_methodp(object, method, p_args + 2, p_argcount - 2); return Variant(); } @@ -524,14 +500,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla Object *object = *p_args[0]; StringName method = *p_args[1]; - Variant v[VARIANT_ARG_MAX]; - - for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) { - v[i] = *p_args[i + 2]; - } - - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); - add_undo_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + add_undo_methodp(object, method, p_args + 2, p_argcount - 2); return Variant(); } diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index 75639f8abf..ecd7a21167 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -49,7 +49,7 @@ public: Variant _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, VARIANT_ARG_DECLARE); + typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount); typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value); private: @@ -65,7 +65,9 @@ private: Ref<RefCounted> ref; ObjectID object; StringName name; - Variant args[VARIANT_ARG_MAX]; + Vector<Variant> args; + + void delete_reference(); }; struct Action { @@ -90,7 +92,7 @@ private: CommitNotifyCallback callback = nullptr; void *callback_ud = nullptr; - void *method_callbck_ud = nullptr; + void *method_callback_ud = nullptr; void *prop_callback_ud = nullptr; MethodNotifyCallback method_callback = nullptr; @@ -104,8 +106,30 @@ protected: public: void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE); - void add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); - void add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST); + void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount); + void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount); + + template <typename... VarArgs> + void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + + add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + template <typename... VarArgs> + void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + + add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value); void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value); void add_do_reference(Object *p_object); |