summaryrefslogtreecommitdiffstats
path: root/core/object
diff options
context:
space:
mode:
Diffstat (limited to 'core/object')
-rw-r--r--core/object/SCsub5
-rw-r--r--core/object/class_db.cpp213
-rw-r--r--core/object/class_db.h114
-rw-r--r--core/object/make_virtuals.py161
-rw-r--r--core/object/method_bind.cpp29
-rw-r--r--core/object/method_bind.h3
-rw-r--r--core/object/object.cpp189
-rw-r--r--core/object/object.h163
-rw-r--r--core/object/ref_counted.cpp19
-rw-r--r--core/object/ref_counted.h12
-rw-r--r--core/object/script_language.cpp62
-rw-r--r--core/object/script_language.h19
-rw-r--r--core/object/undo_redo.cpp46
-rw-r--r--core/object/undo_redo.h4
14 files changed, 716 insertions, 323 deletions
diff --git a/core/object/SCsub b/core/object/SCsub
index 5d429960e5..dc116aeb19 100644
--- a/core/object/SCsub
+++ b/core/object/SCsub
@@ -2,6 +2,11 @@
Import("env")
+import make_virtuals
+from platform_methods import run_in_subprocess
+
+env.CommandNoCache(["gdvirtual.gen.inc"], "make_virtuals.py", run_in_subprocess(make_virtuals.run))
+
env_object = env.Clone()
env_object.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 5bf874ccae..8e92340c1e 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -359,9 +359,9 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
//must be alphabetically sorted for hash to compute
names.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- ClassInfo *t = classes.getptr(E->get());
- ERR_FAIL_COND_V_MSG(!t, 0, "Cannot get class '" + String(E->get()) + "'.");
+ for (const StringName &E : names) {
+ ClassInfo *t = classes.getptr(E);
+ ERR_FAIL_COND_V_MSG(!t, 0, "Cannot get class '" + String(E) + "'.");
if (t->api != p_api || !t->exposed) {
continue;
}
@@ -388,8 +388,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
snames.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
- MethodBind *mb = t->method_map[F->get()];
+ for (const StringName &F : snames) {
+ MethodBind *mb = t->method_map[F];
hash = hash_djb2_one_64(mb->get_name().hash(), hash);
hash = hash_djb2_one_64(mb->get_argument_count(), hash);
hash = hash_djb2_one_64(mb->get_argument_type(-1), hash); //return
@@ -426,9 +426,9 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
snames.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
- hash = hash_djb2_one_64(F->get().hash(), hash);
- hash = hash_djb2_one_64(t->constant_map[F->get()], hash);
+ for (const StringName &F : snames) {
+ hash = hash_djb2_one_64(F.hash(), hash);
+ hash = hash_djb2_one_64(t->constant_map[F], hash);
}
}
@@ -444,9 +444,9 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
snames.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
- MethodInfo &mi = t->signal_map[F->get()];
- hash = hash_djb2_one_64(F->get().hash(), hash);
+ for (const StringName &F : snames) {
+ MethodInfo &mi = t->signal_map[F];
+ hash = hash_djb2_one_64(F.hash(), hash);
for (int i = 0; i < mi.arguments.size(); i++) {
hash = hash_djb2_one_64(mi.arguments[i].type, hash);
}
@@ -465,23 +465,23 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
snames.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
- PropertySetGet *psg = t->property_setget.getptr(F->get());
+ for (const StringName &F : snames) {
+ PropertySetGet *psg = t->property_setget.getptr(F);
ERR_FAIL_COND_V(!psg, 0);
- hash = hash_djb2_one_64(F->get().hash(), hash);
+ hash = hash_djb2_one_64(F.hash(), hash);
hash = hash_djb2_one_64(psg->setter.hash(), hash);
hash = hash_djb2_one_64(psg->getter.hash(), hash);
}
}
//property list
- for (List<PropertyInfo>::Element *F = t->property_list.front(); F; F = F->next()) {
- hash = hash_djb2_one_64(F->get().name.hash(), hash);
- hash = hash_djb2_one_64(F->get().type, hash);
- hash = hash_djb2_one_64(F->get().hint, hash);
- hash = hash_djb2_one_64(F->get().hint_string.hash(), hash);
- hash = hash_djb2_one_64(F->get().usage, hash);
+ for (const PropertyInfo &F : t->property_list) {
+ hash = hash_djb2_one_64(F.name.hash(), hash);
+ hash = hash_djb2_one_64(F.type, hash);
+ hash = hash_djb2_one_64(F.hint, hash);
+ hash = hash_djb2_one_64(F.hint_string.hash(), hash);
+ hash = hash_djb2_one_64(F.usage, hash);
}
}
@@ -503,20 +503,21 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam
thread_local bool initializing_with_extension = false;
thread_local ObjectNativeExtension *initializing_extension = nullptr;
-thread_local void *initializing_extension_instance = nullptr;
+thread_local GDExtensionClassInstancePtr initializing_extension_instance = nullptr;
-void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance) {
+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::instance(const StringName &p_class) {
+Object *ClassDB::instantiate(const StringName &p_class) {
ClassInfo *ti;
{
OBJTYPE_RLOCK;
@@ -539,12 +540,12 @@ Object *ClassDB::instance(const StringName &p_class) {
if (ti->native_extension) {
initializing_with_extension = true;
initializing_extension = ti->native_extension;
- initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->create_instance_userdata);
+ initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->class_userdata);
}
return ti->creation_func();
}
-bool ClassDB::can_instance(const StringName &p_class) {
+bool ClassDB::can_instantiate(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
@@ -602,7 +603,7 @@ static MethodInfo info_from_bind(MethodBind *p_method) {
}
#endif
-void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
+void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
@@ -619,16 +620,16 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b
#ifdef DEBUG_METHODS_ENABLED
- for (List<MethodInfo>::Element *E = type->virtual_methods.front(); E; E = E->next()) {
- p_methods->push_back(E->get());
+ for (const MethodInfo &E : type->virtual_methods) {
+ p_methods->push_back(E);
}
- for (List<StringName>::Element *E = type->method_order.front(); E; E = E->next()) {
- if (p_exclude_from_properties && type->methods_in_properties.has(E->get())) {
+ for (const StringName &E : type->method_order) {
+ if (p_exclude_from_properties && type->methods_in_properties.has(E)) {
continue;
}
- MethodBind *method = type->method_map.get(E->get());
+ MethodBind *method = type->method_map.get(E);
MethodInfo minfo = info_from_bind(method);
p_methods->push_back(minfo);
@@ -655,7 +656,7 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b
}
}
-bool ClassDB::get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) {
+bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
@@ -706,7 +707,7 @@ bool ClassDB::get_method_info(StringName p_class, StringName p_method, MethodInf
return false;
}
-MethodBind *ClassDB::get_method(StringName p_class, StringName p_name) {
+MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_name) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
@@ -763,8 +764,8 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List<String>
while (type) {
#ifdef DEBUG_METHODS_ENABLED
- for (List<StringName>::Element *E = type->constant_order.front(); E; E = E->next()) {
- p_constants->push_back(E->get());
+ for (const StringName &E : type->constant_order) {
+ p_constants->push_back(E);
}
#else
const StringName *K = nullptr;
@@ -891,6 +892,32 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_
}
}
+void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values) {
+ OBJTYPE_RLOCK;
+#ifdef DEBUG_METHODS_ENABLED
+ ClassInfo *type = classes.getptr(p_class);
+
+ ERR_FAIL_COND(!type);
+
+ type->method_error_values[p_method] = p_values;
+#endif
+}
+
+Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) {
+#ifdef DEBUG_METHODS_ENABLED
+ ClassInfo *type = classes.getptr(p_class);
+
+ ERR_FAIL_COND_V(!type, Vector<Error>());
+
+ if (!type->method_error_values.has(p_method)) {
+ return Vector<Error>();
+ }
+ return type->method_error_values[p_method];
+#else
+ return Vector<Error>();
+#endif
+}
+
bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;
@@ -910,7 +937,7 @@ bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool
return false;
}
-void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) {
+void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
@@ -929,7 +956,7 @@ void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) {
type->signal_map[sname] = p_signal;
}
-void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance) {
+void ClassDB::get_signal_list(const StringName &p_class, List<MethodInfo> *p_signals, bool p_no_inheritance) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
@@ -951,7 +978,7 @@ void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, b
}
}
-bool ClassDB::has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance) {
+bool ClassDB::has_signal(const StringName &p_class, const StringName &p_signal, bool p_no_inheritance) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
@@ -968,7 +995,7 @@ bool ClassDB::has_signal(StringName p_class, StringName p_signal, bool p_no_inhe
return false;
}
-bool ClassDB::get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal) {
+bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal, MethodInfo *r_signal) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
@@ -985,7 +1012,7 @@ bool ClassDB::get_signal(StringName p_class, StringName p_signal, MethodInfo *r_
return false;
}
-void ClassDB::add_property_group(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) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_COND(!type);
@@ -993,7 +1020,7 @@ void ClassDB::add_property_group(StringName p_class, const String &p_name, const
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
}
-void ClassDB::add_property_subgroup(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) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_COND(!type);
@@ -1001,8 +1028,20 @@ void ClassDB::add_property_subgroup(StringName p_class, const String &p_name, co
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(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
+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();
ClassInfo *type = classes.getptr(p_class);
lock.read_unlock();
@@ -1060,26 +1099,41 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons
type->property_setget[p_pinfo.name] = psg;
}
-void ClassDB::set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default) {
+void ClassDB::set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default) {
if (!default_values.has(p_class)) {
default_values[p_class] = HashMap<StringName, Variant>();
}
default_values[p_class][p_name] = p_default;
}
-void ClassDB::get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
+void ClassDB::add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property) {
+#ifdef TOOLS_ENABLED
+ OBJTYPE_WLOCK;
+ ClassInfo *type = classes.getptr(p_class);
+ ERR_FAIL_COND(!type);
+
+ ERR_FAIL_COND(!type->property_map.has(p_property));
+ ERR_FAIL_COND(!type->property_map.has(p_linked_property));
+
+ PropertyInfo &pinfo = type->property_map[p_property];
+ pinfo.linked_properties.push_back(p_linked_property);
+#endif
+}
+
+void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
- for (List<PropertyInfo>::Element *E = check->property_list.front(); E; E = E->next()) {
+ for (const PropertyInfo &pi : check->property_list) {
if (p_validator) {
- PropertyInfo pi = E->get();
- p_validator->_validate_property(pi);
- p_list->push_back(pi);
+ // Making a copy as we may modify it.
+ PropertyInfo pi_mut = pi;
+ p_validator->_validate_property(pi_mut);
+ p_list->push_back(pi_mut);
} else {
- p_list->push_back(E->get());
+ p_list->push_back(pi);
}
}
@@ -1090,7 +1144,7 @@ void ClassDB::get_property_list(StringName p_class, List<PropertyInfo> *p_list,
}
}
-bool ClassDB::get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
+bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
ClassInfo *check = classes.getptr(p_class);
@@ -1258,7 +1312,7 @@ Variant::Type ClassDB::get_property_type(const StringName &p_class, const String
return Variant::NIL;
}
-StringName ClassDB::get_property_setter(StringName p_class, const StringName &p_property) {
+StringName ClassDB::get_property_setter(const StringName &p_class, const StringName &p_property) {
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
@@ -1273,7 +1327,7 @@ StringName ClassDB::get_property_setter(StringName p_class, const StringName &p_
return StringName();
}
-StringName ClassDB::get_property_getter(StringName p_class, const StringName &p_property) {
+StringName ClassDB::get_property_getter(const StringName &p_class, const StringName &p_property) {
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
@@ -1305,7 +1359,7 @@ bool ClassDB::has_property(const StringName &p_class, const StringName &p_proper
return false;
}
-void ClassDB::set_method_flags(StringName p_class, StringName p_method, int p_flags) {
+void ClassDB::set_method_flags(const StringName &p_class, const StringName &p_method, int p_flags) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
@@ -1314,7 +1368,7 @@ void ClassDB::set_method_flags(StringName p_class, StringName p_method, int p_fl
check->method_map[p_method]->set_hint_flags(p_flags);
}
-bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inheritance) {
+bool ClassDB::has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) {
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
@@ -1405,7 +1459,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
return p_bind;
}
-void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual) {
+void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector<String> &p_arg_names, bool p_object_core) {
ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
OBJTYPE_WLOCK;
@@ -1415,6 +1469,19 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
if (p_virtual) {
mi.flags |= METHOD_FLAG_VIRTUAL;
}
+ if (p_object_core) {
+ mi.flags |= METHOD_FLAG_OBJECT_CORE;
+ }
+ if (p_arg_names.size()) {
+ if (p_arg_names.size() != mi.arguments.size()) {
+ WARN_PRINT("Mismatch argument name count for virtual function: " + String(p_class) + "::" + p_method.name);
+ } else {
+ for (int i = 0; i < p_arg_names.size(); i++) {
+ mi.arguments[i].name = p_arg_names[i];
+ }
+ }
+ }
+
classes[p_class].virtual_methods.push_back(mi);
classes[p_class].virtual_methods_map[p_method.name] = mi;
@@ -1429,8 +1496,8 @@ void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
- for (List<MethodInfo>::Element *E = check->virtual_methods.front(); E; E = E->next()) {
- p_methods->push_back(E->get());
+ for (const MethodInfo &E : check->virtual_methods) {
+ p_methods->push_back(E);
}
if (p_no_inheritance) {
@@ -1442,14 +1509,14 @@ void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p
#endif
}
-void ClassDB::set_class_enabled(StringName p_class, bool p_enable) {
+void ClassDB::set_class_enabled(const StringName &p_class, bool p_enable) {
OBJTYPE_WLOCK;
ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
classes[p_class].disabled = !p_enable;
}
-bool ClassDB::is_class_enabled(StringName p_class) {
+bool ClassDB::is_class_enabled(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
@@ -1463,7 +1530,7 @@ bool ClassDB::is_class_enabled(StringName p_class) {
return !ti->disabled;
}
-bool ClassDB::is_class_exposed(StringName p_class) {
+bool ClassDB::is_class_exposed(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
@@ -1496,6 +1563,10 @@ void ClassDB::get_resource_base_extensions(List<String> *p_extensions) {
}
}
+bool ClassDB::is_resource_extension(const StringName &p_extension) {
+ return resource_base_extensions.has(p_extension);
+}
+
void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p_extensions) {
const StringName *K = nullptr;
@@ -1522,19 +1593,19 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
if (Engine::get_singleton()->has_singleton(p_class)) {
c = Engine::get_singleton()->get_singleton_object(p_class);
cleanup_c = false;
- } else if (ClassDB::can_instance(p_class)) {
- c = ClassDB::instance(p_class);
+ } else if (ClassDB::can_instantiate(p_class)) {
+ c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
if (c) {
List<PropertyInfo> plist;
c->get_property_list(&plist);
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
- if (E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
- if (!default_values[p_class].has(E->get().name)) {
- Variant v = c->get(E->get().name);
- default_values[p_class][E->get().name] = v;
+ for (const PropertyInfo &E : plist) {
+ if (E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
+ if (!default_values[p_class].has(E.name)) {
+ Variant v = c->get(E.name);
+ default_values[p_class][E.name] = v;
}
}
}
@@ -1587,7 +1658,7 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
GLOBAL_LOCK_FUNCTION;
ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name));
- ERR_FAIL_COND_MSG(classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name));
+ ERR_FAIL_COND_MSG(!classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name));
ClassInfo *parent = classes.getptr(p_extension->parent_class_name);
@@ -1599,10 +1670,16 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
+ c.exposed = true;
classes[p_extension->class_name] = c;
}
+void ClassDB::unregister_extension_class(const StringName &p_class) {
+ ERR_FAIL_COND(!classes.has(p_class));
+ classes.erase(p_class);
+}
+
RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 4355c9b0ea..e89c7fffd7 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -132,6 +132,7 @@ public:
List<MethodInfo> virtual_methods;
Map<StringName, MethodInfo> virtual_methods_map;
StringName category;
+ Map<StringName, Vector<Error>> method_error_values;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -204,6 +205,7 @@ public:
}
static void register_extension_class(ObjectNativeExtension *p_extension);
+ static void unregister_extension_class(const StringName &p_class);
template <class T>
static Object *_create_ptr_func() {
@@ -230,9 +232,10 @@ public:
static StringName get_compatibility_remapped_class(const StringName &p_class);
static bool class_exists(const StringName &p_class);
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
- static bool can_instance(const StringName &p_class);
- static Object *instance(const StringName &p_class);
- static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance);
+ 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 APIType get_api_type(const StringName &p_class);
static uint64_t get_api_hash(APIType p_api);
@@ -309,7 +312,7 @@ public:
}
template <class M>
- static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector<Variant> &p_default_args = Vector<Variant>(), bool p_return_nil_is_variant = true) {
+ static MethodBind *bind_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector<Variant> &p_default_args = Vector<Variant>(), bool p_return_nil_is_variant = true) {
GLOBAL_LOCK_FUNCTION;
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
@@ -328,7 +331,7 @@ public:
if (type->method_map.has(p_name)) {
memdelete(bind);
- // overloading not supported
+ // Overloading not supported
ERR_FAIL_V_MSG(nullptr, "Method already bound: " + instance_type + "::" + p_name + ".");
}
type->method_map[p_name] = bind;
@@ -343,33 +346,36 @@ public:
static void bind_method_custom(const StringName &p_class, MethodBind *p_method);
- static void add_signal(StringName p_class, const MethodInfo &p_signal);
- static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false);
- static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal);
- static void get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false);
-
- static void add_property_group(StringName p_class, const String &p_name, const String &p_prefix = "");
- static void add_property_subgroup(StringName p_class, const String &p_name, const String &p_prefix = "");
- static void add_property(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(StringName p_class, const StringName &p_name, const Variant &p_default);
- static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
- static bool get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
+ static bool has_signal(const StringName &p_class, const StringName &p_signal, bool p_no_inheritance = false);
+ 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_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_EDITOR);
+ 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);
+ static void get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static bool get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr);
static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr);
static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value);
static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false);
static int get_property_index(const StringName &p_class, const StringName &p_property, bool *r_is_valid = nullptr);
static Variant::Type get_property_type(const StringName &p_class, const StringName &p_property, bool *r_is_valid = nullptr);
- static StringName get_property_setter(StringName p_class, const StringName &p_property);
- static StringName get_property_getter(StringName p_class, const StringName &p_property);
+ static StringName get_property_setter(const StringName &p_class, const StringName &p_property);
+ static StringName get_property_getter(const StringName &p_class, const StringName &p_property);
- static bool has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false);
- static void set_method_flags(StringName p_class, StringName p_method, int p_flags);
+ static bool has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false);
+ static void set_method_flags(const StringName &p_class, const StringName &p_method, int p_flags);
- static void get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
- static bool get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
- static MethodBind *get_method(StringName p_class, StringName p_name);
+ static void get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
+ static bool get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
+ static MethodBind *get_method(const StringName &p_class, const StringName &p_name);
- static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true);
+ static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true, const Vector<String> &p_arg_names = Vector<String>(), bool p_object_core = false);
static void get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false);
static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant);
@@ -382,18 +388,21 @@ public:
static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false);
static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
+ static void set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values);
+ static Vector<Error> get_method_error_return_values(const StringName &p_class, const StringName &p_method);
static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr);
static StringName get_category(const StringName &p_node);
- static void set_class_enabled(StringName p_class, bool p_enable);
- static bool is_class_enabled(StringName p_class);
+ static void set_class_enabled(const StringName &p_class, bool p_enable);
+ static bool is_class_enabled(const StringName &p_class);
- static bool is_class_exposed(StringName p_class);
+ static bool is_class_exposed(const StringName &p_class);
static void add_resource_base_extension(const StringName &p_extension, const StringName &p_class);
static void get_resource_base_extensions(List<String> *p_extensions);
static void get_extensions_for_type(const StringName &p_class, List<String> *p_extensions);
+ static bool is_resource_extension(const StringName &p_extension);
static void add_compatibility_class(const StringName &p_class, const StringName &p_fallback);
@@ -406,30 +415,55 @@ public:
#ifdef DEBUG_METHODS_ENABLED
#define BIND_CONSTANT(m_constant) \
- ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
+ ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
#define BIND_ENUM_CONSTANT(m_constant) \
- ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
-
-#else
+ ::ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
-#define BIND_CONSTANT(m_constant) \
- ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
+_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr) {
+}
-#define BIND_ENUM_CONSTANT(m_constant) \
- ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
+_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr, const Error &p_err) {
+ arr.push_back(p_err);
+}
-#endif
+template <class... P>
+_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr, const Error &p_err, P... p_args) {
+ arr.push_back(p_err);
+ errarray_add_str(arr, p_args...);
+}
-#ifdef TOOLS_ENABLED
+template <class... P>
+_FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
+ Vector<Error> arr;
+ errarray_add_str(arr, p_args...);
+ return arr;
+}
-#define BIND_VMETHOD(m_method) \
- ClassDB::add_virtual_method(get_class_static(), m_method);
+#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...) \
+ ::ClassDB::set_method_error_return_values(get_class_static(), m_method, errarray(__VA_ARGS__));
#else
-#define BIND_VMETHOD(m_method)
+#define BIND_CONSTANT(m_constant) \
+ ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
+
+#define BIND_ENUM_CONSTANT(m_constant) \
+ ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
+
+#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...)
#endif
+#define GDREGISTER_CLASS(m_class) \
+ 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>(); \
+ }
+
+#include "core/disabled_classes.gen.h"
+
#endif // CLASS_DB_H
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
new file mode 100644
index 0000000000..86c2891e5d
--- /dev/null
+++ b/core/object/make_virtuals.py
@@ -0,0 +1,161 @@
+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;\\
+_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);\\
+ if (ce.error == Callable::CallError::CALL_OK) {\\
+ $CALLSIRET\\
+ return true;\\
+ } \\
+ }\\
+ if (_gdvirtual_##m_name) {\\
+ $CALLPTRARGS\\
+ $CALLPTRRETDEF\\
+ _gdvirtual_##m_name(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\
+ $CALLPTRRET\\
+ return true;\\
+ }\\
+\\
+ return false;\\
+}\\
+_FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\
+ ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
+ if (script_instance) {\\
+ return script_instance->has_method(_gdvirtual_##m_name##_sn);\\
+ }\\
+ if (_gdvirtual_##m_name) {\\
+ return true;\\
+ }\\
+ return false;\\
+}\\
+\\
+_FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() { \\
+ MethodInfo method_info;\\
+ method_info.name = #m_name;\\
+ method_info.flags = METHOD_FLAG_VIRTUAL;\\
+ $FILL_METHOD_INFO\\
+ return method_info;\\
+}
+
+"""
+
+
+def generate_version(argcount, const=False, returns=False):
+ s = proto
+ sproto = str(argcount)
+ method_info = ""
+ if returns:
+ sproto += "R"
+ s = s.replace("$RET", "m_ret, ")
+ s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
+ method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
+ else:
+ s = s.replace("$RET", "")
+ s = s.replace("$CALLPTRRETDEF", "")
+
+ if const:
+ sproto += "C"
+ s = s.replace("$CONST", "const")
+ method_info += "\tmethod_info.flags|=METHOD_FLAG_CONST;\\\n"
+ else:
+ s = s.replace("$CONST", "")
+
+ s = s.replace("$VER", sproto)
+ argtext = ""
+ callargtext = ""
+ callsiargs = ""
+ callsiargptrs = ""
+ callptrargsptr = ""
+ if argcount > 0:
+ argtext += ", "
+ callsiargs = "Variant vargs[" + str(argcount) + "]={"
+ callsiargptrs = "\t\tconst Variant *vargptrs[" + str(argcount) + "]={"
+ callptrargsptr = "\t\tconst GDNativeTypePtr argptrs[" + str(argcount) + "]={"
+ callptrargs = ""
+ for i in range(argcount):
+ if i > 0:
+ argtext += ", "
+ callargtext += ", "
+ callsiargs += ", "
+ callsiargptrs += ", "
+ callptrargs += "\t\t"
+ callptrargsptr += ", "
+ argtext += "m_type" + str(i + 1)
+ callargtext += "m_type" + str(i + 1) + " arg" + str(i + 1)
+ callsiargs += "Variant(arg" + str(i + 1) + ")"
+ callsiargptrs += "&vargs[" + str(i) + "]"
+ callptrargs += (
+ "PtrToArg<m_type" + str(i + 1) + ">::EncodeT argval" + str(i + 1) + " = arg" + str(i + 1) + ";\\\n"
+ )
+ callptrargsptr += "&argval" + str(i + 1)
+ method_info += "\tmethod_info.arguments.push_back(GetTypeInfo<m_type" + str(i + 1) + ">::get_class_info());\\\n"
+
+ if argcount:
+ callsiargs += "};\\\n"
+ callsiargptrs += "};\\\n"
+ s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs)
+ s = s.replace("$CALLSIARGPASS", "(const Variant **)vargptrs," + str(argcount))
+ callptrargsptr += "};\\\n"
+ s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr)
+ s = s.replace("$CALLPTRARGPASS", "(const GDNativeTypePtr*)argptrs")
+ else:
+ s = s.replace("$CALLSIARGS", "")
+ s = s.replace("$CALLSIARGPASS", "nullptr, 0")
+ s = s.replace("$CALLPTRARGS", "")
+ s = s.replace("$CALLPTRARGPASS", "nullptr")
+
+ if returns:
+ if argcount > 0:
+ callargtext += ","
+ callargtext += " m_ret& r_ret"
+ s = s.replace("$CALLSIBEGIN", "Variant ret = ")
+ s = s.replace("$CALLSIRET", "r_ret = ret;")
+ s = s.replace("$CALLPTRRETPASS", "&ret")
+ s = s.replace("$CALLPTRRET", "r_ret = ret;")
+ else:
+ s = s.replace("$CALLSIBEGIN", "")
+ s = s.replace("$CALLSIRET", "")
+ s = s.replace("$CALLPTRRETPASS", "nullptr")
+ s = s.replace("$CALLPTRRET", "")
+
+ s = s.replace("$ARG", argtext)
+ s = s.replace("$CALLARGS", callargtext)
+ s = s.replace("$FILL_METHOD_INFO", method_info)
+
+ return s
+
+
+def run(target, source, env):
+
+ max_versions = 12
+
+ txt = """
+#ifndef GDVIRTUAL_GEN_H
+#define GDVIRTUAL_GEN_H
+
+
+"""
+
+ for i in range(max_versions + 1):
+
+ txt += "/* " + str(i) + " Arguments */\n\n"
+ txt += generate_version(i, False, False)
+ txt += generate_version(i, False, True)
+ txt += generate_version(i, True, False)
+ txt += generate_version(i, True, True)
+
+ txt += "#endif"
+
+ with open(target[0], "w") as f:
+ f.write(txt)
+
+
+if __name__ == "__main__":
+ from platform_methods import subprocess_main
+
+ subprocess_main(globals())
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index 9c5ed60708..c53104fe3f 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -34,6 +34,35 @@
#include "method_bind.h"
+uint32_t MethodBind::get_hash() const {
+ uint32_t hash = hash_djb2_one_32(has_return() ? 1 : 0);
+ hash = hash_djb2_one_32(get_argument_count(), hash);
+
+#ifndef _MSC_VER
+#warning This needs proper class name and argument type for hashing
+#endif
+#if 0
+
+ for (int i = (has_return() ? -1 : 0); i < get_argument_count(); i++) {
+ PropertyInfo pi = i == -1 ? get_return_info() : get_argument_info(i);
+ hash = hash_djb2_one_32(get_argument_type(i), hash);
+ if (pi.class_name != StringName()) {
+ hash = hash_djb2_one_32(pi.class_name.operator String().hash(), hash);
+ }
+ }
+#endif
+ hash = hash_djb2_one_32(get_default_argument_count(), hash);
+ for (int i = 0; i < get_default_argument_count(); i++) {
+ Variant v = get_default_argument(i);
+ hash = hash_djb2_one_32(v.hash(), hash);
+ }
+
+ hash = hash_djb2_one_32(is_const(), hash);
+ hash = hash_djb2_one_32(is_vararg(), hash);
+
+ return hash;
+}
+
#ifdef DEBUG_METHODS_ENABLED
PropertyInfo MethodBind::get_argument_info(int p_argument) const {
ERR_FAIL_INDEX_V(p_argument, get_argument_count(), PropertyInfo());
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 7030ae201b..b0b379873e 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -43,6 +43,7 @@ enum MethodFlags {
METHOD_FLAG_FROM_SCRIPT = 64,
METHOD_FLAG_VARARG = 128,
METHOD_FLAG_STATIC = 256,
+ METHOD_FLAG_OBJECT_CORE = 512,
METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL,
};
@@ -135,6 +136,8 @@ public:
void set_default_arguments(const Vector<Variant> &p_defargs);
+ uint32_t get_hash() const;
+
MethodBind();
virtual ~MethodBind();
};
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 799e63a512..3335942fb3 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -386,12 +386,20 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
if (_extension && _extension->set) {
- if (_extension->set(_extension_instance, &p_name, &p_value)) {
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension->set(_extension_instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value)) {
if (r_valid) {
*r_valid = true;
}
return;
}
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
}
//try built-in setgetter
@@ -459,14 +467,22 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
return ret;
}
}
-
if (_extension && _extension->get) {
- if (_extension->get(_extension_instance, &p_name, &ret)) {
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+
+ if (_extension->get(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
if (r_valid) {
*r_valid = true;
}
return ret;
}
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
}
//try built-in setgetter
@@ -616,7 +632,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (_extension && _extension->get_property_list) {
uint32_t pcount;
- const ObjectNativeExtension::PInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
+ const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name));
}
@@ -871,7 +887,7 @@ void Object::set_script(const Variant &p_script) {
Ref<Script> s = script;
if (!s.is_null()) {
- if (s->can_instance()) {
+ if (s->can_instantiate()) {
OBJ_DEBUG_LOCK
script_instance = s->instance_create(this);
} else if (Engine::get_singleton()->is_editor_hint()) {
@@ -906,11 +922,11 @@ Variant Object::get_script() const {
return script;
}
-bool Object::has_meta(const String &p_name) const {
+bool Object::has_meta(const StringName &p_name) const {
return metadata.has(p_name);
}
-void Object::set_meta(const String &p_name, const Variant &p_value) {
+void Object::set_meta(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
metadata.erase(p_name);
return;
@@ -919,12 +935,12 @@ void Object::set_meta(const String &p_name, const Variant &p_value) {
metadata[p_name] = p_value;
}
-Variant Object::get_meta(const String &p_name) const {
- ERR_FAIL_COND_V(!metadata.has(p_name), Variant());
+Variant Object::get_meta(const StringName &p_name) const {
+ ERR_FAIL_COND_V_MSG(!metadata.has(p_name), Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
return metadata[p_name];
}
-void Object::remove_meta(const String &p_name) {
+void Object::remove_meta(const StringName &p_name) {
metadata.erase(p_name);
}
@@ -948,23 +964,23 @@ Array Object::_get_method_list_bind() const {
return ret;
}
-Vector<String> Object::_get_meta_list_bind() const {
- Vector<String> _metaret;
+Vector<StringName> Object::_get_meta_list_bind() const {
+ Vector<StringName> _metaret;
List<Variant> keys;
metadata.get_key_list(&keys);
- for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- _metaret.push_back(E->get());
+ for (const Variant &E : keys) {
+ _metaret.push_back(E);
}
return _metaret;
}
-void Object::get_meta_list(List<String> *p_list) const {
+void Object::get_meta_list(List<StringName> *p_list) const {
List<Variant> keys;
metadata.get_key_list(&keys);
- for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- p_list->push_back(E->get());
+ for (const Variant &E : keys) {
+ p_list->push_back(E);
}
}
@@ -1168,8 +1184,8 @@ Array Object::_get_signal_list() const {
get_signal_list(&signal_list);
Array ret;
- for (List<MethodInfo>::Element *E = signal_list.front(); E; E = E->next()) {
- ret.push_back(Dictionary(E->get()));
+ for (const MethodInfo &E : signal_list) {
+ ret.push_back(Dictionary(E));
}
return ret;
@@ -1181,8 +1197,7 @@ Array Object::_get_signal_connection_list(const String &p_signal) const {
Array ret;
- for (List<Connection>::Element *E = conns.front(); E; E = E->next()) {
- Connection &c = E->get();
+ for (const Connection &c : conns) {
if (c.signal.get_name() == p_signal) {
ret.push_back(c);
}
@@ -1281,16 +1296,16 @@ int Object::get_persistent_signal_connection_count() const {
}
void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
- for (const List<Connection>::Element *E = connections.front(); E; E = E->next()) {
- p_connections->push_back(E->get());
+ for (const Connection &E : connections) {
+ p_connections->push_back(E);
}
}
Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) {
- ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null.");
Object *target_object = p_callable.get_object();
- ERR_FAIL_COND_V(!target_object, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(!target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");
SignalData *s = signal_map.getptr(p_signal);
if (!s) {
@@ -1348,7 +1363,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co
}
bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const {
- ERR_FAIL_COND_V(p_callable.is_null(), false);
+ ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null.");
const SignalData *s = signal_map.getptr(p_signal);
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
@@ -1375,10 +1390,10 @@ void Object::disconnect(const StringName &p_signal, const Callable &p_callable)
}
void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) {
- ERR_FAIL_COND(p_callable.is_null());
+ ERR_FAIL_COND_MSG(p_callable.is_null(), "Cannot disconnect from '" + p_signal + "': the provided callable is null.");
Object *target_object = p_callable.get_object();
- ERR_FAIL_COND(!target_object);
+ ERR_FAIL_COND_MSG(!target_object, "Cannot disconnect '" + p_signal + "' from callable '" + p_callable + "': the callable object is null.");
SignalData *s = signal_map.getptr(p_signal);
if (!s) {
@@ -1484,9 +1499,9 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
List<Variant> keys;
d.get_key_list(&keys);
- for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- _clear_internal_resource_paths(E->get());
- _clear_internal_resource_paths(d[E->get()]);
+ for (const Variant &E : keys) {
+ _clear_internal_resource_paths(E);
+ _clear_internal_resource_paths(d[E]);
}
} break;
default: {
@@ -1515,8 +1530,8 @@ void Object::clear_internal_resource_paths() {
get_property_list(&pinfo);
- for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
- _clear_internal_resource_paths(get(E->get().name));
+ for (const PropertyInfo &E : pinfo) {
+ _clear_internal_resource_paths(get(E.name));
}
}
@@ -1604,22 +1619,25 @@ void Object::_bind_methods() {
ADD_SIGNAL(MethodInfo("script_changed"));
ADD_SIGNAL(MethodInfo("property_list_changed"));
- BIND_VMETHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what")));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value")));
+#define BIND_OBJ_CORE_METHOD(m_method) \
+ ::ClassDB::add_virtual_method(get_class_static(), m_method, true, Vector<String>(), true);
+
+ BIND_OBJ_CORE_METHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what")));
+ BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value")));
#ifdef TOOLS_ENABLED
MethodInfo miget("_get", PropertyInfo(Variant::STRING_NAME, "property"));
miget.return_val.name = "Variant";
miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(miget);
+ BIND_OBJ_CORE_METHOD(miget);
MethodInfo plget("_get_property_list");
plget.return_val.type = Variant::ARRAY;
- BIND_VMETHOD(plget);
+ BIND_OBJ_CORE_METHOD(plget);
#endif
- BIND_VMETHOD(MethodInfo("_init"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_to_string"));
+ BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
+ BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE);
BIND_CONSTANT(NOTIFICATION_PREDELETE);
@@ -1650,12 +1668,12 @@ void Object::get_translatable_strings(List<String> *p_strings) const {
List<PropertyInfo> plist;
get_property_list(&plist);
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
- if (!(E->get().usage & PROPERTY_USAGE_INTERNATIONALIZED)) {
+ for (const PropertyInfo &E : plist) {
+ if (!(E.usage & PROPERTY_USAGE_INTERNATIONALIZED)) {
continue;
}
- String text = get(E->get().name);
+ String text = get(E.name);
if (text == "") {
continue;
@@ -1753,44 +1771,69 @@ uint32_t Object::get_edited_version() const {
}
#endif
-void *Object::get_script_instance_binding(int p_script_language_index) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr);
-#endif
-
- //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync
- //just return the same pointer.
- //if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it
- //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards
+void Object::set_instance_binding(void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks) {
+ // This is only meant to be used on creation by the binder.
+ ERR_FAIL_COND(_instance_bindings != nullptr);
+ _instance_bindings = (InstanceBinding *)memalloc(sizeof(InstanceBinding));
+ _instance_bindings[0].binding = p_binding;
+ _instance_bindings[0].free_callback = p_callbacks->free_callback;
+ _instance_bindings[0].reference_callback = p_callbacks->reference_callback;
+ _instance_bindings[0].token = p_token;
+ _instance_binding_count = 1;
+}
+
+void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
+ void *binding = nullptr;
+ _instance_binding_mutex.lock();
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].token == p_token) {
+ binding = _instance_bindings[i].binding;
+ break;
+ }
+ }
+ if (unlikely(!binding)) {
+ uint32_t current_size = next_power_of_2(_instance_binding_count);
+ uint32_t new_size = next_power_of_2(_instance_binding_count + 1);
- if (!_script_instance_bindings[p_script_language_index]) {
- void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
- if (script_data) {
- instance_binding_count.increment();
- _script_instance_bindings[p_script_language_index] = script_data;
+ if (current_size == 0 || new_size > current_size) {
+ _instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding));
}
+
+ _instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback;
+ _instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback;
+ _instance_bindings[_instance_binding_count].token = p_token;
+
+ binding = p_callbacks->create_callback(p_token, this);
+ _instance_bindings[_instance_binding_count].binding = binding;
+
+ _instance_binding_count++;
}
- return _script_instance_bindings[p_script_language_index];
-}
+ _instance_binding_mutex.unlock();
-bool Object::has_script_instance_binding(int p_script_language_index) {
- return _script_instance_bindings[p_script_language_index] != nullptr;
+ return binding;
}
-void Object::set_script_instance_binding(int p_script_language_index, void *p_data) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(_script_instance_bindings[p_script_language_index] != nullptr);
-#endif
- _script_instance_bindings[p_script_language_index] = p_data;
+bool Object::has_instance_binding(void *p_token) {
+ bool found = false;
+ _instance_binding_mutex.lock();
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].token == p_token) {
+ found = true;
+ break;
+ }
+ }
+
+ _instance_binding_mutex.unlock();
+
+ return found;
}
void Object::_construct_object(bool p_reference) {
type_is_reference = p_reference;
_instance_id = ObjectDB::add_instance(this);
- memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
- ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance);
+ ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance, this);
#ifdef DEBUG_ENABLED
_lock_index.init(1);
@@ -1812,7 +1855,7 @@ Object::~Object() {
script_instance = nullptr;
if (_extension && _extension->free_instance) {
- _extension->free_instance(_extension->create_instance_userdata, _extension_instance);
+ _extension->free_instance(_extension->class_userdata, _extension_instance);
_extension = nullptr;
_extension_instance = nullptr;
}
@@ -1848,12 +1891,13 @@ Object::~Object() {
_instance_id = ObjectID();
_predelete_ok = 2;
- if (!ScriptServer::are_languages_finished()) {
- for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
- if (_script_instance_bindings[i]) {
- ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]);
+ if (_instance_bindings != nullptr) {
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].free_callback) {
+ _instance_bindings[i].free_callback(_instance_bindings[i].token, this, _instance_bindings[i].binding);
}
}
+ memfree(_instance_bindings);
}
}
@@ -1871,7 +1915,6 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
if (object_slots[i].validator) {
p_func(object_slots[i].object);
-
count--;
}
}
diff --git a/core/object/object.h b/core/object/object.h
index 37b2e61dfe..a44d921bff 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -31,6 +31,7 @@
#ifndef OBJECT_H
#define OBJECT_H
+#include "core/extension/gdnative_interface.h"
#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
#include "core/os/spin_lock.h"
@@ -43,13 +44,13 @@
#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()
-#define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5
-#define VARIANT_ARG_DECLARE const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5
-#define VARIANT_ARG_MAX 5
-#define VARIANT_ARGPTRS const Variant *argptr[5] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5 };
-#define VARIANT_ARGPTRS_PASS *argptr[0], *argptr[1], *argptr[2], *argptr[3], *argptr[4]
-#define VARIANT_ARGS_FROM_ARRAY(m_arr) m_arr[0], m_arr[1], m_arr[2], m_arr[3], m_arr[4]
+#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]
/**
@author Juan Linietsky <reduzio@gmail.com>
@@ -57,9 +58,9 @@
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional"
- PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
+ PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
@@ -96,11 +97,13 @@ enum PropertyHint {
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_INT_IS_OBJECTID,
PROPERTY_HINT_ARRAY_TYPE,
+ PROPERTY_HINT_INT_IS_POINTER,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
enum PropertyUsageFlags {
+ PROPERTY_USAGE_NONE = 0,
PROPERTY_USAGE_STORAGE = 1,
PROPERTY_USAGE_EDITOR = 2,
PROPERTY_USAGE_NETWORK = 4,
@@ -129,28 +132,39 @@ 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,
};
-#define ADD_SIGNAL(m_signal) ClassDB::add_signal(get_class_static(), m_signal)
-#define ADD_PROPERTY(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter))
-#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_SUBGROUP(m_name, m_prefix) ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
+#define ADD_SIGNAL(m_signal) ::ClassDB::add_signal(get_class_static(), m_signal)
+#define ADD_PROPERTY(m_property, m_setter, m_getter) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter))
+#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_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;
- StringName class_name; //for classes
+ StringName class_name; // For classes
PropertyHint hint = PROPERTY_HINT_NONE;
String hint_string;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
- _FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const {
+#ifdef TOOLS_ENABLED
+ Vector<String> linked_properties;
+#endif
+
+ _FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const {
PropertyInfo pi = *this;
pi.usage |= p_fl;
return pi;
@@ -162,7 +176,7 @@ struct PropertyInfo {
PropertyInfo() {}
- PropertyInfo(Variant::Type p_type, const String p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) :
+ PropertyInfo(const Variant::Type p_type, const String p_name, const PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", const uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) :
type(p_type),
name(p_name),
hint(p_hint),
@@ -243,29 +257,18 @@ class MethodBind;
struct ObjectNativeExtension {
ObjectNativeExtension *parent = nullptr;
+ List<ObjectNativeExtension *> children;
StringName parent_class_name;
StringName class_name;
bool editor_class = false;
- bool (*set)(void *instance, const void *name, const void *value) = nullptr;
- bool (*get)(void *instance, const void *name, void *ret_variant) = nullptr;
- struct PInfo {
- uint32_t type;
- const char *name;
- const char *class_name;
- uint32_t hint;
- const char *hint_string;
- uint32_t usage;
- };
- const PInfo *(*get_property_list)(void *instance, uint32_t *count) = nullptr;
- void (*free_property_list)(void *instance, const PInfo *) = nullptr;
-
- //call is not used, as all methods registered in ClassDB
-
- void (*notification)(void *instance, int32_t what) = nullptr;
- const char *(*to_string)(void *instance) = nullptr;
-
- void (*reference)(void *instance) = nullptr;
- void (*unreference)(void *instance) = nullptr;
+ GDNativeExtensionClassSet set;
+ GDNativeExtensionClassGet get;
+ GDNativeExtensionClassGetPropertyList get_property_list;
+ GDNativeExtensionClassFreePropertyList free_property_list;
+ GDNativeExtensionClassNotification notification;
+ GDNativeExtensionClassToString to_string;
+ GDNativeExtensionClassReference reference;
+ GDNativeExtensionClassReference unreference;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
const ObjectNativeExtension *e = this;
@@ -277,11 +280,24 @@ struct ObjectNativeExtension {
}
return false;
}
- void *create_instance_userdata = nullptr;
- void *(*create_instance)(void *create_instance_userdata) = nullptr;
- void (*free_instance)(void *create_instance_userdata, void *instance) = nullptr;
+ void *class_userdata = nullptr;
+
+ GDNativeExtensionClassCreateInstance create_instance;
+ GDNativeExtensionClassFreeInstance free_instance;
+ GDNativeExtensionClassObjectInstance set_object_instance;
+ 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__)
+#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
+#define GDVIRTUAL_BIND(m_name, ...)
+#endif
+#define GDVIRTUAL_IS_OVERRIDDEN(m_name) _gdvirtual_##m_name##_overridden()
+#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.
*/
@@ -302,7 +318,7 @@ private:
private: \
void operator=(const m_class &p_rval) {} \
mutable StringName _class_name; \
- friend class ClassDB; \
+ friend class ::ClassDB; \
\
public: \
virtual String get_class() const override { \
@@ -375,7 +391,7 @@ public:
return; \
} \
m_inherits::initialize_class(); \
- ClassDB::_add_class<m_class>(); \
+ ::ClassDB::_add_class<m_class>(); \
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
_bind_methods(); \
} \
@@ -418,13 +434,13 @@ protected:
} \
p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); \
if (!_is_gpl_reversed()) { \
- ClassDB::get_property_list(#m_class, p_list, true, this); \
+ ::ClassDB::get_property_list(#m_class, p_list, true, this); \
} \
if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
_get_property_list(p_list); \
} \
if (_is_gpl_reversed()) { \
- ClassDB::get_property_list(#m_class, p_list, true, this); \
+ ::ClassDB::get_property_list(#m_class, p_list, true, this); \
} \
if (p_reversed) { \
m_inherits::_get_property_listv(p_list, p_reversed); \
@@ -485,10 +501,6 @@ public:
};
private:
- enum {
- MAX_SCRIPT_INSTANCE_BINDINGS = 8
- };
-
#ifdef DEBUG_ENABLED
friend struct _ObjectDebugLock;
#endif
@@ -496,7 +508,7 @@ private:
friend void postinitialize_handler(Object *);
ObjectNativeExtension *_extension = nullptr;
- void *_extension_instance = nullptr;
+ GDExtensionClassInstancePtr _extension_instance = nullptr;
struct SignalData {
struct Slot {
@@ -547,14 +559,38 @@ private:
friend class RefCounted;
bool type_is_reference = false;
- SafeNumeric<uint32_t> instance_binding_count;
- void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
+
+ std::mutex _instance_binding_mutex;
+ struct InstanceBinding {
+ void *binding;
+ void *token;
+ GDNativeInstanceBindingFreeCallback free_callback = nullptr;
+ GDNativeInstanceBindingReferenceCallback reference_callback = nullptr;
+ };
+ InstanceBinding *_instance_bindings = nullptr;
+ uint32_t _instance_binding_count = 0;
Object(bool p_reference);
protected:
+ _FORCE_INLINE_ bool _instance_binding_reference(bool p_reference) {
+ bool can_die = true;
+ if (_instance_bindings) {
+ _instance_binding_mutex.lock();
+ for (uint32_t i = 0; i < _instance_binding_count; i++) {
+ if (_instance_bindings[i].reference_callback) {
+ if (!_instance_bindings[i].reference_callback(_instance_bindings[i].token, _instance_bindings[i].binding, p_reference)) {
+ can_die = false;
+ }
+ }
+ }
+ _instance_binding_mutex.unlock();
+ }
+ return can_die;
+ }
+ friend class NativeExtensionMethodBind;
_ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; }
- _ALWAYS_INLINE_ void *_get_extension_instance() const { return _extension_instance; }
+ _ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; }
virtual void _initialize_classv() { initialize_class(); }
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; };
@@ -599,7 +635,7 @@ protected:
return &_class_name;
}
- Vector<String> _get_meta_list_bind() const;
+ Vector<StringName> _get_meta_list_bind() const;
Array _get_property_list_bind() const;
Array _get_method_list_bind() const;
@@ -727,11 +763,11 @@ public:
/* SCRIPT */
- bool has_meta(const String &p_name) const;
- void set_meta(const String &p_name, const Variant &p_value);
- void remove_meta(const String &p_name);
- Variant get_meta(const String &p_name) const;
- void get_meta_list(List<String> *p_list) const;
+ 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);
+ Variant get_meta(const StringName &p_name) const;
+ void get_meta_list(List<StringName> *p_list) const;
#ifdef TOOLS_ENABLED
void set_edited(bool p_edited);
@@ -788,10 +824,11 @@ public:
#endif
- //used by script languages to store binding data
- void *get_script_instance_binding(int p_script_language_index);
- bool has_script_instance_binding(int p_script_language_index);
- void set_script_instance_binding(int p_script_language_index, void *p_data);
+ // Used by script languages to store binding data.
+ void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
+ // Used on creation by binding only.
+ void set_instance_binding(void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
+ bool has_instance_binding(void *p_token);
void clear_internal_resource_paths();
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index 9862624972..2833f774dc 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -65,13 +65,8 @@ bool RefCounted::reference() {
if (_get_extension() && _get_extension()->reference) {
_get_extension()->reference(_get_extension_instance());
}
- if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
- for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
- if (_script_instance_bindings[i]) {
- ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
- }
- }
- }
+
+ _instance_binding_reference(true);
}
return success;
@@ -89,14 +84,8 @@ bool RefCounted::unreference() {
if (_get_extension() && _get_extension()->unreference) {
_get_extension()->unreference(_get_extension_instance());
}
- if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
- for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
- if (_script_instance_bindings[i]) {
- bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
- die = die && script_ret;
- }
- }
- }
+
+ die = die && _instance_binding_reference(false);
}
return die;
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 3dd7cc456b..f2dd2aa324 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -213,7 +213,7 @@ public:
inline bool is_null() const { return reference == nullptr; }
void unref() {
- //TODO this should be moved to mutexes, since this engine does not really
+ // TODO: this should be moved to mutexes, since this engine does not really
// do a lot of referencing on references and stuff
// mutexes will avoid more crashes?
@@ -223,7 +223,7 @@ public:
reference = nullptr;
}
- void instance() {
+ void instantiate() {
ref(memnew(T));
}
@@ -258,6 +258,8 @@ struct PtrToArg<Ref<T>> {
return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr)));
}
+ typedef Ref<T> EncodeT;
+
_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
*(Ref<RefCounted> *)p_ptr = p_val;
}
@@ -265,13 +267,13 @@ struct PtrToArg<Ref<T>> {
template <class T>
struct PtrToArg<const Ref<T> &> {
+ typedef Ref<T> EncodeT;
+
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
return Ref<T>((T *)p_ptr);
}
};
-#ifdef DEBUG_METHODS_ENABLED
-
template <class T>
struct GetTypeInfo<Ref<T>> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
@@ -292,6 +294,4 @@ struct GetTypeInfo<const Ref<T> &> {
}
};
-#endif // DEBUG_METHODS_ENABLED
-
#endif // REF_COUNTED_H
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index aa91c6cbf7..0fb8c7350c 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -63,8 +63,8 @@ Array Script::_get_script_property_list() {
Array ret;
List<PropertyInfo> list;
get_script_property_list(&list);
- for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
- ret.append(E->get().operator Dictionary());
+ for (const PropertyInfo &E : list) {
+ ret.append(E.operator Dictionary());
}
return ret;
}
@@ -73,8 +73,8 @@ Array Script::_get_script_method_list() {
Array ret;
List<MethodInfo> list;
get_script_method_list(&list);
- for (List<MethodInfo>::Element *E = list.front(); E; E = E->next()) {
- ret.append(E->get().operator Dictionary());
+ for (const MethodInfo &E : list) {
+ ret.append(E.operator Dictionary());
}
return ret;
}
@@ -83,8 +83,8 @@ Array Script::_get_script_signal_list() {
Array ret;
List<MethodInfo> list;
get_script_signal_list(&list);
- for (List<MethodInfo>::Element *E = list.front(); E; E = E->next()) {
- ret.append(E->get().operator Dictionary());
+ for (const MethodInfo &E : list) {
+ ret.append(E.operator Dictionary());
}
return ret;
}
@@ -100,7 +100,7 @@ Dictionary Script::_get_script_constant_map() {
}
void Script::_bind_methods() {
- ClassDB::bind_method(D_METHOD("can_instance"), &Script::can_instance);
+ ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate);
//ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
ClassDB::bind_method(D_METHOD("instance_has", "base_object"), &Script::instance_has);
ClassDB::bind_method(D_METHOD("has_source_code"), &Script::has_source_code);
@@ -120,7 +120,7 @@ void Script::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code");
}
void ScriptServer::set_scripting_enabled(bool p_enabled) {
@@ -257,8 +257,8 @@ void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
classes.push_back(*K);
}
classes.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
- r_global_classes->push_back(E->get());
+ for (const StringName &E : classes) {
+ r_global_classes->push_back(E);
}
}
@@ -266,12 +266,12 @@ void ScriptServer::save_global_classes() {
List<StringName> gc;
get_global_class_list(&gc);
Array gcarr;
- for (List<StringName>::Element *E = gc.front(); E; E = E->next()) {
+ for (const StringName &E : gc) {
Dictionary d;
- d["class"] = E->get();
- d["language"] = global_classes[E->get()].language;
- d["path"] = global_classes[E->get()].path;
- d["base"] = global_classes[E->get()].base;
+ d["class"] = E;
+ d["language"] = global_classes[E].language;
+ d["path"] = global_classes[E].path;
+ d["base"] = global_classes[E].base;
gcarr.push_back(d);
}
@@ -297,10 +297,10 @@ void ScriptServer::save_global_classes() {
void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) {
List<PropertyInfo> pinfo;
get_property_list(&pinfo);
- for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
- if (E->get().usage & PROPERTY_USAGE_STORAGE) {
+ for (const PropertyInfo &E : pinfo) {
+ if (E.usage & PROPERTY_USAGE_STORAGE) {
Pair<StringName, Variant> p;
- p.first = E->get().name;
+ p.first = E.name;
if (get(p.first, p.second)) {
state.push_back(p);
}
@@ -353,10 +353,10 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const
p_core_type_words->push_back("Vector3i");
p_core_type_words->push_back("Transform2D");
p_core_type_words->push_back("Plane");
- p_core_type_words->push_back("Quat");
+ p_core_type_words->push_back("Quaternion");
p_core_type_words->push_back("AABB");
p_core_type_words->push_back("Basis");
- p_core_type_words->push_back("Transform");
+ p_core_type_words->push_back("Transform3D");
p_core_type_words->push_back("Color");
p_core_type_words->push_back("StringName");
p_core_type_words->push_back("NodePath");
@@ -430,16 +430,16 @@ bool PlaceHolderScriptInstance::get(const StringName &p_name, Variant &r_ret) co
void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
if (script->is_placeholder_fallback_enabled()) {
- for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- p_properties->push_back(E->get());
+ for (const PropertyInfo &E : properties) {
+ p_properties->push_back(E);
}
} else {
- for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- PropertyInfo pinfo = E->get();
+ for (const PropertyInfo &E : properties) {
+ PropertyInfo pinfo = E;
if (!values.has(pinfo.name)) {
pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE;
}
- p_properties->push_back(E->get());
+ p_properties->push_back(E);
}
}
}
@@ -489,11 +489,11 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) {
Set<StringName> new_values;
- for (const List<PropertyInfo>::Element *E = p_properties.front(); E; E = E->next()) {
- StringName n = E->get().name;
+ for (const PropertyInfo &E : p_properties) {
+ StringName n = E.name;
new_values.insert(n);
- if (!values.has(n) || values[n].get_type() != E->get().type) {
+ if (!values.has(n) || values[n].get_type() != E.type) {
if (p_values.has(n)) {
values[n] = p_values[n];
}
@@ -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->get()) {
+ if (defval == E) {
to_remove.push_back(E->key());
}
}
@@ -542,8 +542,8 @@ void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name,
}
bool found = false;
- for (const List<PropertyInfo>::Element *F = properties.front(); F; F = F->next()) {
- if (F->get().name == p_name) {
+ for (const PropertyInfo &F : properties) {
+ if (F.name == p_name) {
found = true;
break;
}
diff --git a/core/object/script_language.h b/core/object/script_language.h
index a22e91870e..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"
@@ -115,7 +115,7 @@ protected:
Dictionary _get_script_constant_map();
public:
- virtual bool can_instance() const = 0;
+ virtual bool can_instantiate() const = 0;
virtual Ref<Script> get_base_script() const = 0; //for script inheritance
@@ -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();
@@ -268,6 +268,12 @@ public:
String message;
};
+ struct ScriptError {
+ int line = -1;
+ int column = -1;
+ String message;
+ };
+
void get_core_type_words(List<String> *p_core_type_words) const;
virtual void get_reserved_words(List<String> *p_words) const = 0;
virtual bool is_control_flow_keyword(String p_string) const = 0;
@@ -276,7 +282,7 @@ public:
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {}
virtual bool is_using_templates() { return false; }
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
virtual Script *create_script() const = 0;
virtual bool has_named_classes() const = 0;
@@ -304,6 +310,7 @@ public:
Ref<Script> script;
String class_name;
String class_member;
+ String class_path;
int location;
};
@@ -412,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 96c96c1efb..b7d2bac96d 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -39,11 +39,15 @@ void UndoRedo::_discard_redo() {
}
for (int i = current_action + 1; i < actions.size(); i++) {
- for (List<Operation>::Element *E = actions.write[i].do_ops.front(); E; E = E->next()) {
- if (E->get().type == Operation::TYPE_REFERENCE) {
- Object *obj = ObjectDB::get_instance(E->get().object);
- if (obj) {
- memdelete(obj);
+ 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);
+ }
}
}
}
@@ -65,7 +69,7 @@ bool UndoRedo::_redo(bool p_execute) {
_process_operation_list(actions.write[current_action].do_ops.front());
}
version++;
- emit_signal("version_changed");
+ emit_signal(SNAME("version_changed"));
return true;
}
@@ -240,11 +244,15 @@ void UndoRedo::_pop_history_tail() {
return;
}
- for (List<Operation>::Element *E = actions.write[0].undo_ops.front(); E; E = E->next()) {
- if (E->get().type == Operation::TYPE_REFERENCE) {
- Object *obj = ObjectDB::get_instance(E->get().object);
- if (obj) {
- memdelete(obj);
+ 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);
+ }
}
}
}
@@ -352,7 +360,7 @@ bool UndoRedo::undo() {
_process_operation_list(actions.write[current_action].undo_ops.front());
current_action--;
version--;
- emit_signal("version_changed");
+ emit_signal(SNAME("version_changed"));
return true;
}
@@ -385,7 +393,7 @@ void UndoRedo::clear_history(bool p_increase_version) {
if (p_increase_version) {
version++;
- emit_signal("version_changed");
+ emit_signal(SNAME("version_changed"));
}
}
@@ -397,11 +405,11 @@ String UndoRedo::get_current_action_name() const {
return actions[current_action].name;
}
-bool UndoRedo::has_undo() {
+bool UndoRedo::has_undo() const {
return current_action >= 0;
}
-bool UndoRedo::has_redo() {
+bool UndoRedo::has_redo() const {
return (current_action + 1) < actions.size();
}
@@ -460,8 +468,8 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callabl
v[i] = *p_args[i + 2];
}
- static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5");
- add_do_method(object, method, v[0], v[1], v[2], v[3], v[4]);
+ 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]);
return Variant();
}
@@ -497,8 +505,8 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla
v[i] = *p_args[i + 2];
}
- static_assert(VARIANT_ARG_MAX == 5, "This code needs to be updated if VARIANT_ARG_MAX != 5");
- add_undo_method(object, method, v[0], v[1], v[2], v[3], v[4]);
+ 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]);
return Variant();
}
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 8f009830e3..d1ce252d86 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -121,8 +121,8 @@ public:
String get_action_name(int p_id);
void clear_history(bool p_increase_version = true);
- bool has_undo();
- bool has_redo();
+ bool has_undo() const;
+ bool has_redo() const;
uint64_t get_version() const;