summaryrefslogtreecommitdiff
path: root/core/object
diff options
context:
space:
mode:
Diffstat (limited to 'core/object')
-rw-r--r--core/object/class_db.cpp82
-rw-r--r--core/object/class_db.h33
-rw-r--r--core/object/make_virtuals.py11
-rw-r--r--core/object/message_queue.cpp12
-rw-r--r--core/object/method_bind.cpp11
-rw-r--r--core/object/method_bind.h38
-rw-r--r--core/object/object.cpp25
-rw-r--r--core/object/object.h19
-rw-r--r--core/object/script_language.cpp8
-rw-r--r--core/object/script_language.h8
-rw-r--r--core/object/undo_redo.cpp50
-rw-r--r--core/object/undo_redo.h5
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);