diff options
Diffstat (limited to 'core/object')
-rw-r--r-- | core/object/class_db.cpp | 82 | ||||
-rw-r--r-- | core/object/class_db.h | 33 | ||||
-rw-r--r-- | core/object/make_virtuals.py | 11 | ||||
-rw-r--r-- | core/object/message_queue.cpp | 12 | ||||
-rw-r--r-- | core/object/method_bind.cpp | 11 | ||||
-rw-r--r-- | core/object/method_bind.h | 38 | ||||
-rw-r--r-- | core/object/object.cpp | 25 | ||||
-rw-r--r-- | core/object/object.h | 19 | ||||
-rw-r--r-- | core/object/script_language.cpp | 8 | ||||
-rw-r--r-- | core/object/script_language.h | 8 | ||||
-rw-r--r-- | core/object/undo_redo.cpp | 50 | ||||
-rw-r--r-- | core/object/undo_redo.h | 5 |
12 files changed, 155 insertions, 147 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index e268a8d292..bbd3b7b8de 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -37,8 +37,6 @@ #define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock); #define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock); -#ifdef DEBUG_METHODS_ENABLED - MethodDefinition D_METHOD(const char *p_name) { MethodDefinition md; md.name = StaticCString::create(p_name); @@ -226,8 +224,6 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ return md; } -#endif - ClassDB::APIType ClassDB::current_api = API_CORE; void ClassDB::set_current_api(APIType p_api) { @@ -501,22 +497,6 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam compat_classes[p_class] = p_fallback; } -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, Object *p_base) { - if (initializing_with_extension) { - *r_extension = initializing_extension; - *r_extension_instance = initializing_extension_instance; - initializing_with_extension = false; - initializing_extension->set_object_instance(*r_extension_instance, p_base); - } else { - *r_extension = nullptr; - *r_extension_instance = nullptr; - } -} - Object *ClassDB::instantiate(const StringName &p_class) { ClassInfo *ti; { @@ -529,7 +509,7 @@ Object *ClassDB::instantiate(const StringName &p_class) { } ERR_FAIL_COND_V_MSG(!ti, nullptr, "Cannot get class '" + String(p_class) + "'."); ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, "Class '" + String(p_class) + "' is disabled."); - ERR_FAIL_COND_V(!ti->creation_func, nullptr); + ERR_FAIL_COND_V_MSG(!ti->creation_func, nullptr, "Class '" + String(p_class) + "' or its base class cannot be instantiated."); } #ifdef TOOLS_ENABLED if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { @@ -537,12 +517,31 @@ Object *ClassDB::instantiate(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); + if (ti->native_extension && ti->native_extension->create_instance) { + return (Object *)ti->native_extension->create_instance(ti->native_extension->class_userdata); + } else { + return ti->creation_func(); + } +} + +void ClassDB::set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance) { + ERR_FAIL_COND(!p_object); + ClassInfo *ti; + { + OBJTYPE_RLOCK; + ti = classes.getptr(p_class); + 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]); + } + } + ERR_FAIL_COND_MSG(!ti, "Cannot get class '" + String(p_class) + "'."); + ERR_FAIL_COND_MSG(ti->disabled, "Class '" + String(p_class) + "' is disabled."); + ERR_FAIL_COND_MSG(!ti->native_extension, "Class '" + String(p_class) + "' has no native extension."); } - return ti->creation_func(); + + p_object->_extension = ti->native_extension; + p_object->_extension_instance = p_instance; } bool ClassDB::can_instantiate(const StringName &p_class) { @@ -580,7 +579,6 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit } } -#ifdef DEBUG_METHODS_ENABLED static MethodInfo info_from_bind(MethodBind *p_method) { MethodInfo minfo; minfo.name = p_method->get_name(); @@ -601,7 +599,6 @@ static MethodInfo info_from_bind(MethodBind *p_method) { return minfo; } -#endif void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { OBJTYPE_RLOCK; @@ -641,9 +638,8 @@ void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_met while ((K = type->method_map.next(K))) { MethodBind *m = type->method_map[*K]; - MethodInfo mi; - mi.name = m->get_name(); - p_methods->push_back(mi); + MethodInfo minfo = info_from_bind(m); + p_methods->push_back(minfo); } #endif @@ -689,9 +685,8 @@ bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_met if (type->method_map.has(p_method)) { if (r_info) { MethodBind *m = type->method_map[p_method]; - MethodInfo mi; - mi.name = m->get_name(); - *r_info = mi; + MethodInfo minfo = info_from_bind(m); + *r_info = minfo; } return true; } @@ -736,7 +731,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName type->constant_map[p_name] = p_constant; String enum_name = p_enum; - if (enum_name != String()) { + if (!enum_name.is_empty()) { if (enum_name.find(".") != -1) { enum_name = enum_name.get_slicec('.', 1); } @@ -1028,6 +1023,18 @@ void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_n type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_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) { + add_property(p_class, PropertyInfo(Variant::INT, p_count_property, PROPERTY_HINT_NONE, "", p_count_usage | PROPERTY_USAGE_ARRAY, vformat("%s,%s", p_label, p_array_element_prefix)), p_count_setter, p_count_getter); +} + +void ClassDB::add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) { + OBJTYPE_WLOCK; + ClassInfo *type = classes.getptr(p_class); + ERR_FAIL_COND(!type); + + type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix)); +} + // NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end. void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { lock.read_lock(); @@ -1390,13 +1397,8 @@ void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method 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; -#else -MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) { - StringName mdname = StaticCString::create(method_name); -#endif OBJTYPE_WLOCK; ERR_FAIL_COND_V(!p_bind, nullptr); diff --git a/core/object/class_db.h b/core/object/class_db.h index 166aa35469..ca9c1def29 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -45,8 +45,6 @@ #define DEFVAL(m_defval) (m_defval) -#ifdef DEBUG_METHODS_ENABLED - struct MethodDefinition { StringName name; Vector<StringName> args; @@ -72,26 +70,6 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12); MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13); -#else - -//#define NO_VARIADIC_MACROS - -#ifdef NO_VARIADIC_MACROS - -static _FORCE_INLINE_ const char *D_METHOD(const char *m_name, ...) { - return m_name; -} - -#else - -// When DEBUG_METHODS_ENABLED is set this will let the engine know -// the argument names for easier debugging. -#define D_METHOD(m_c, ...) m_c - -#endif - -#endif - class ClassDB { public: enum APIType { @@ -156,11 +134,7 @@ public: static HashMap<StringName, StringName> resource_base_extensions; static HashMap<StringName, StringName> compat_classes; -#ifdef DEBUG_METHODS_ENABLED static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount); -#else - static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount); -#endif static APIType current_api; @@ -190,6 +164,7 @@ public: t->creation_func = &creator<T>; t->exposed = true; t->class_ptr = T::get_class_ptr_static(); + t->api = current_api; T::register_custom_data_to_otdb(); } @@ -201,6 +176,7 @@ public: ERR_FAIL_COND(!t); t->exposed = true; t->class_ptr = T::get_class_ptr_static(); + t->api = current_api; //nothing } @@ -221,6 +197,7 @@ public: t->creation_func = &_create_ptr_func<T>; t->exposed = true; t->class_ptr = T::get_class_ptr_static(); + t->api = current_api; T::register_custom_data_to_otdb(); } @@ -234,7 +211,7 @@ public: static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); 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, Object *p_base); + static void set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance); static APIType get_api_type(const StringName &p_class); @@ -353,6 +330,8 @@ public: 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_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); static void set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default); static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property); diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index 86c2891e5d..e961745d96 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -1,7 +1,8 @@ proto = """ #define GDVIRTUAL$VER($RET m_name $ARG) \\ StringName _gdvirtual_##m_name##_sn = #m_name;\\ -GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\ +mutable bool _gdvirtual_##m_name##_initialized = false;\\ +mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\ if (script_instance) {\\ @@ -13,6 +14,10 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ return true;\\ } \\ }\\ + if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\ + _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\ + _gdvirtual_##m_name##_initialized = true;\\ + }\\ if (_gdvirtual_##m_name) {\\ $CALLPTRARGS\\ $CALLPTRRETDEF\\ @@ -28,6 +33,10 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\ if (script_instance) {\\ return script_instance->has_method(_gdvirtual_##m_name##_sn);\\ }\\ + if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\ + _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\ + _gdvirtual_##m_name##_initialized = true;\\ + }\\ if (_gdvirtual_##m_name) {\\ return true;\\ }\\ diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp index 4751c69f1e..736e940846 100644 --- a/core/object/message_queue.cpp +++ b/core/object/message_queue.cpp @@ -227,16 +227,16 @@ void MessageQueue::statistics() { print_line("TOTAL BYTES: " + itos(buffer_end)); print_line("NULL count: " + itos(null_count)); - for (Map<StringName, int>::Element *E = set_count.front(); E; E = E->next()) { - print_line("SET " + E->key() + ": " + itos(E->get())); + for (const KeyValue<StringName, int> &E : set_count) { + print_line("SET " + E.key + ": " + itos(E.value)); } - for (Map<Callable, int>::Element *E = call_count.front(); E; E = E->next()) { - print_line("CALL " + E->key() + ": " + itos(E->get())); + for (const KeyValue<Callable, int> &E : call_count) { + print_line("CALL " + E.key + ": " + itos(E.value)); } - for (Map<int, int>::Element *E = notify_count.front(); E; E = E->next()) { - print_line("NOTIFY " + itos(E->key()) + ": " + itos(E->get())); + for (const KeyValue<int, int> &E : notify_count) { + print_line("NOTIFY " + itos(E.key) + ": " + itos(E.value)); } } diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp index c53104fe3f..642e27c41d 100644 --- a/core/object/method_bind.cpp +++ b/core/object/method_bind.cpp @@ -63,12 +63,15 @@ uint32_t MethodBind::get_hash() const { 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()); PropertyInfo info = _gen_argument_type_info(p_argument); +#ifdef DEBUG_METHODS_ENABLED info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("arg" + itos(p_argument)); +#else + info.name = String("arg" + itos(p_argument)); +#endif return info; } @@ -76,7 +79,6 @@ PropertyInfo MethodBind::get_return_info() const { return _gen_argument_type_info(-1); } -#endif void MethodBind::_set_const(bool p_const) { _const = p_const; } @@ -109,7 +111,6 @@ void MethodBind::set_default_arguments(const Vector<Variant> &p_defargs) { default_argument_count = default_arguments.size(); } -#ifdef DEBUG_METHODS_ENABLED void MethodBind::_generate_argument_types(int p_count) { set_argument_count(p_count); @@ -123,17 +124,13 @@ void MethodBind::_generate_argument_types(int p_count) { argument_types = argt; } -#endif - MethodBind::MethodBind() { static int last_id = 0; method_id = last_id++; } MethodBind::~MethodBind() { -#ifdef DEBUG_METHODS_ENABLED if (argument_types) { memdelete_arr(argument_types); } -#endif } diff --git a/core/object/method_bind.h b/core/object/method_bind.h index b0b379873e..ee003099a0 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -64,18 +64,16 @@ class MethodBind { bool _returns = false; protected: -#ifdef DEBUG_METHODS_ENABLED Variant::Type *argument_types = nullptr; +#ifdef DEBUG_METHODS_ENABLED Vector<StringName> arg_names; #endif void _set_const(bool p_const); void _set_returns(bool p_returns); -#ifdef DEBUG_METHODS_ENABLED virtual Variant::Type _gen_argument_type(int p_arg) const = 0; virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0; void _generate_argument_types(int p_count); -#endif void set_argument_count(int p_count) { argument_count = p_count; } public: @@ -102,7 +100,6 @@ public: } } -#ifdef DEBUG_METHODS_ENABLED _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const { ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, Variant::NIL); return argument_types[p_argument + 1]; @@ -111,6 +108,7 @@ public: PropertyInfo get_argument_info(int p_argument) const; PropertyInfo get_return_info() const; +#ifdef DEBUG_METHODS_ENABLED void set_argument_names(const Vector<StringName> &p_names); // Set by ClassDB, can't be inferred otherwise. Vector<StringName> get_argument_names() const; @@ -149,12 +147,9 @@ public: protected: NativeCall call_method = nullptr; -#ifdef DEBUG_METHODS_ENABLED MethodInfo arguments; -#endif public: -#ifdef DEBUG_METHODS_ENABLED virtual PropertyInfo _gen_argument_type_info(int p_arg) const { if (p_arg < 0) { return arguments.return_val; @@ -169,13 +164,10 @@ public: return _gen_argument_type_info(p_arg).type; } +#ifdef DEBUG_METHODS_ENABLED virtual GodotTypeInfo::Metadata get_argument_meta(int) const { return GodotTypeInfo::METADATA_NONE; } -#else - virtual Variant::Type _gen_argument_type(int p_arg) const { - return Variant::NIL; - } #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { @@ -185,25 +177,29 @@ public: void set_method_info(const MethodInfo &p_info, bool p_return_nil_is_variant) { set_argument_count(p_info.arguments.size()); -#ifdef DEBUG_METHODS_ENABLED Variant::Type *at = memnew_arr(Variant::Type, p_info.arguments.size() + 1); at[0] = p_info.return_val.type; if (p_info.arguments.size()) { +#ifdef DEBUG_METHODS_ENABLED Vector<StringName> names; names.resize(p_info.arguments.size()); +#endif for (int i = 0; i < p_info.arguments.size(); i++) { at[i + 1] = p_info.arguments[i].type; +#ifdef DEBUG_METHODS_ENABLED names.write[i] = p_info.arguments[i].name; +#endif } +#ifdef DEBUG_METHODS_ENABLED set_argument_names(names); +#endif } argument_types = at; arguments = p_info; if (p_return_nil_is_variant) { arguments.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; } -#endif } virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { @@ -248,7 +244,6 @@ class MethodBindT : public MethodBind { void (MB_T::*method)(P...); protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -270,7 +265,6 @@ protected: call_get_argument_type_info<P...>(p_arg, pi); return pi; } -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -298,9 +292,7 @@ public: MethodBindT(void (MB_T::*p_method)(P...)) { method = p_method; -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; @@ -327,7 +319,6 @@ class MethodBindTC : public MethodBind { void (MB_T::*method)(P...) const; protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -349,7 +340,6 @@ protected: call_get_argument_type_info<P...>(p_arg, pi); return pi; } -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -378,9 +368,7 @@ public: MethodBindTC(void (MB_T::*p_method)(P...) const) { method = p_method; _set_const(true); -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; @@ -408,7 +396,6 @@ class MethodBindTR : public MethodBind { (P...); protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -434,7 +421,6 @@ protected: #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -468,9 +454,7 @@ public: MethodBindTR(R (MB_T::*p_method)(P...)) { method = p_method; _set_returns(true); -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; @@ -499,7 +483,6 @@ class MethodBindTRC : public MethodBind { (P...) const; protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -525,7 +508,6 @@ protected: #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -560,9 +542,7 @@ public: method = p_method; _set_returns(true); _set_const(true); -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; diff --git a/core/object/object.cpp b/core/object/object.cpp index 3335942fb3..14d4e0bee6 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -628,7 +628,10 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons script_instance->get_property_list(p_list); } - _get_property_listv(p_list, p_reversed); + 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); + } if (_extension && _extension->get_property_list) { uint32_t pcount; @@ -641,11 +644,13 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons } } + _get_property_listv(p_list, p_reversed); + 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)); } if (!metadata.is_empty()) { - p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } if (script_instance && !p_reversed) { p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); @@ -985,7 +990,7 @@ void Object::get_meta_list(List<StringName> *p_list) const { } void Object::add_user_signal(const MethodInfo &p_signal) { - ERR_FAIL_COND_MSG(p_signal.name == "", "Signal name cannot be empty."); + ERR_FAIL_COND_MSG(p_signal.name.is_empty(), "Signal name cannot be empty."); ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), "User signal's name conflicts with a built-in signal of '" + get_class_name() + "'."); ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), "Trying to add already existing signal '" + p_signal.name + "'."); SignalData s; @@ -1248,7 +1253,7 @@ void Object::get_signal_list(List<MethodInfo> *p_signals) const { const StringName *S = nullptr; while ((S = signal_map.next(S))) { - if (signal_map[*S].user.name != "") { + if (!signal_map[*S].user.name.is_empty()) { //user signal p_signals->push_back(signal_map[*S].user); } @@ -1398,18 +1403,18 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, SignalData *s = signal_map.getptr(p_signal); if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) || - (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)); + (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)); ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'."); } ERR_FAIL_COND_MSG(!s, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string())); ERR_FAIL_COND_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), "Disconnecting nonexistent signal '" + p_signal + "', callable: " + p_callable + "."); - SignalData::Slot *slot = &s->slot_map[p_callable]; + SignalData::Slot *slot = &s->slot_map[*p_callable.get_base_comparator()]; if (!p_force) { slot->reference_count--; // by default is zero, if it was not referenced it will go below it - if (slot->reference_count >= 0) { + if (slot->reference_count > 0) { return; } } @@ -1475,7 +1480,7 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) { return; } - if (!r->get_path().begins_with("res://") || r->get_path().find("::") == -1) { + if (!r->is_built_in()) { return; //not an internal resource } @@ -1675,7 +1680,7 @@ void Object::get_translatable_strings(List<String> *p_strings) const { String text = get(E.name); - if (text == "") { + if (text.is_empty()) { continue; } @@ -1833,8 +1838,6 @@ void Object::_construct_object(bool p_reference) { type_is_reference = p_reference; _instance_id = ObjectDB::add_instance(this); - ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance, this); - #ifdef DEBUG_ENABLED _lock_index.init(1); #endif diff --git a/core/object/object.h b/core/object/object.h index 102776a589..fc6e6a3660 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -132,10 +132,12 @@ enum PropertyUsageFlags { PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor. PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 28, //for project or editor settings, show when basic settings are selected + PROPERTY_USAGE_READ_ONLY = 1 << 29, // Mark a property as read-only in the inspector. + PROPERTY_USAGE_ARRAY = 1 << 30, // Used in the inspector to group properties as elements of an array. PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, - PROPERTY_USAGE_NOEDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK, + PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK, }; #define ADD_SIGNAL(m_signal) ::ClassDB::add_signal(get_class_static(), m_signal) @@ -146,6 +148,10 @@ enum PropertyUsageFlags { #define ADD_SUBGROUP(m_name, m_prefix) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix) #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) +#define ADD_ARRAY_COUNT_WITH_USAGE_FLAGS(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix, m_property_usage_flags) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix, m_property_usage_flags) +#define ADD_ARRAY(m_array_path, m_prefix) ClassDB::add_property_array(get_class_static(), m_array_path, m_prefix) + struct PropertyInfo { Variant::Type type = Variant::NIL; String name; @@ -278,7 +284,6 @@ struct ObjectNativeExtension { GDNativeExtensionClassCreateInstance create_instance; GDNativeExtensionClassFreeInstance free_instance; - GDNativeExtensionClassObjectInstance set_object_instance; GDNativeExtensionClassGetVirtual get_virtual; }; @@ -347,7 +352,7 @@ public: static String get_category_static() { \ String category = m_inherits::get_category_static(); \ if (_get_category != m_inherits::_get_category) { \ - if (category != "") { \ + if (!category.is_empty()) { \ category += "/"; \ } \ category += _get_category(); \ @@ -397,7 +402,7 @@ protected: initialize_class(); \ } \ _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \ - return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \ + return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_get; \ } \ virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \ if (m_class::_get_get() != m_inherits::_get_get()) { \ @@ -408,7 +413,7 @@ protected: return m_inherits::_getv(p_name, r_ret); \ } \ _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \ - return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \ + return (bool(Object::*)(const StringName &, const Variant &)) & m_class::_set; \ } \ virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \ if (m_inherits::_setv(p_name, p_property)) { \ @@ -420,7 +425,7 @@ protected: return false; \ } \ _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \ - return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \ + return (void(Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \ } \ virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const override { \ if (!p_reversed) { \ @@ -441,7 +446,7 @@ protected: } \ } \ _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \ - return (void (Object::*)(int)) & m_class::_notification; \ + return (void(Object::*)(int)) & m_class::_notification; \ } \ virtual void _notificationv(int p_notification, bool p_reversed) override { \ if (!p_reversed) { \ diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 0fb8c7350c..8ec1a973e7 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -93,8 +93,8 @@ Dictionary Script::_get_script_constant_map() { Dictionary ret; Map<StringName, Variant> map; get_constants(&map); - for (Map<StringName, Variant>::Element *E = map.front(); E; E = E->next()) { - ret[E->key()] = E->value(); + for (const KeyValue<StringName, Variant> &E : map) { + ret[E.key] = E.value; } return ret; } @@ -511,7 +511,7 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c Variant defval; if (script->get_property_default_value(E->key(), defval)) { //remove because it's the same as the default value - if (defval == E) { + if (defval == E->get()) { to_remove.push_back(E->key()); } } @@ -549,7 +549,7 @@ void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name, } } if (!found) { - properties.push_back(PropertyInfo(p_value.get_type(), p_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE)); + properties.push_back(PropertyInfo(p_value.get_type(), p_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE)); } } diff --git a/core/object/script_language.h b/core/object/script_language.h index 385bf79c1a..8d76cbf479 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -32,8 +32,8 @@ #define SCRIPT_LANGUAGE_H #include "core/doc_data.h" -#include "core/io/multiplayer_api.h" #include "core/io/resource.h" +#include "core/multiplayer/multiplayer.h" #include "core/templates/map.h" #include "core/templates/pair.h" @@ -159,7 +159,7 @@ public: virtual bool is_placeholder_fallback_enabled() const { return false; } - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const = 0; Script() {} }; @@ -200,7 +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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const = 0; virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); @@ -419,7 +419,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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); } + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const { return Vector<Multiplayer::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 b7d2bac96d..3459506860 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -32,6 +32,7 @@ #include "core/io/resource.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" void UndoRedo::_discard_redo() { if (current_action == actions.size() - 1) { @@ -75,7 +76,7 @@ bool UndoRedo::_redo(bool p_execute) { } void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { - uint32_t ticks = OS::get_singleton()->get_ticks_msec(); + uint64_t ticks = OS::get_singleton()->get_ticks_msec(); if (action_level == 0) { _discard_redo(); @@ -85,10 +86,17 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { current_action = actions.size() - 2; if (p_mode == MERGE_ENDS) { - // Clear all do ops from last action, and delete all object references - List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); + // Clear all do ops from last action if they are not forced kept + LocalVector<List<Operation>::Element *> to_remove; + for (List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); E; E = E->next()) { + if (!E->get().force_keep_in_merge_ends) { + to_remove.push_back(E); + } + } - while (E) { + 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); @@ -96,9 +104,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { memdelete(obj); } } - - E = E->next(); - actions.write[current_action + 1].do_ops.pop_front(); + E->erase(); } } @@ -117,6 +123,8 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { } action_level++; + + force_keep_in_merge_ends = false; } void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { @@ -146,7 +154,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -157,6 +165,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR } undo_op.type = Operation::TYPE_METHOD; + 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++) { @@ -187,7 +196,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -198,6 +207,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; actions.write[current_action + 1].undo_ops.push_back(undo_op); @@ -223,7 +233,7 @@ void UndoRedo::add_undo_reference(Object *p_object) { ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -234,9 +244,24 @@ void UndoRedo::add_undo_reference(Object *p_object) { } undo_op.type = Operation::TYPE_REFERENCE; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; actions.write[current_action + 1].undo_ops.push_back(undo_op); } +void UndoRedo::start_force_keep_in_merge_ends() { + ERR_FAIL_COND(action_level <= 0); + ERR_FAIL_COND((current_action + 1) >= actions.size()); + + force_keep_in_merge_ends = true; +} + +void UndoRedo::end_force_keep_in_merge_ends() { + ERR_FAIL_COND(action_level <= 0); + ERR_FAIL_COND((current_action + 1) >= actions.size()); + + force_keep_in_merge_ends = false; +} + void UndoRedo::_pop_history_tail() { _discard_redo(); @@ -257,7 +282,7 @@ void UndoRedo::_pop_history_tail() { } } - actions.remove(0); + actions.remove_at(0); if (current_action >= 0) { current_action--; } @@ -538,6 +563,9 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference); ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference); + ClassDB::bind_method(D_METHOD("start_force_keep_in_merge_ends"), &UndoRedo::start_force_keep_in_merge_ends); + ClassDB::bind_method(D_METHOD("end_force_keep_in_merge_ends"), &UndoRedo::end_force_keep_in_merge_ends); + ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count); ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action); ClassDB::bind_method(D_METHOD("get_action_name", "id"), &UndoRedo::get_action_name); diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index d1ce252d86..a757d154e2 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -61,6 +61,7 @@ private: }; Type type; + bool force_keep_in_merge_ends; Ref<RefCounted> ref; ObjectID object; StringName name; @@ -76,6 +77,7 @@ private: Vector<Action> actions; int current_action = -1; + bool force_keep_in_merge_ends = false; int action_level = 0; MergeMode merge_mode = MERGE_DISABLE; bool merging = false; @@ -109,6 +111,9 @@ public: void add_do_reference(Object *p_object); void add_undo_reference(Object *p_object); + void start_force_keep_in_merge_ends(); + void end_force_keep_in_merge_ends(); + bool is_committing_action() const; void commit_action(bool p_execute = true); |