summaryrefslogtreecommitdiff
path: root/core/object
diff options
context:
space:
mode:
Diffstat (limited to 'core/object')
-rw-r--r--core/object/class_db.cpp51
-rw-r--r--core/object/class_db.h2
-rw-r--r--core/object/make_virtuals.py18
-rw-r--r--core/object/message_queue.cpp2
-rw-r--r--core/object/method_bind.cpp4
-rw-r--r--core/object/method_bind.h56
-rw-r--r--core/object/object.cpp171
-rw-r--r--core/object/object.h136
-rw-r--r--core/object/ref_counted.cpp6
-rw-r--r--core/object/ref_counted.h2
-rw-r--r--core/object/script_language.cpp51
-rw-r--r--core/object/script_language.h22
-rw-r--r--core/object/script_language_extension.cpp3
-rw-r--r--core/object/script_language_extension.h72
-rw-r--r--core/object/undo_redo.cpp164
-rw-r--r--core/object/undo_redo.h35
-rw-r--r--core/object/worker_thread_pool.cpp10
17 files changed, 443 insertions, 362 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index d67315f20d..ac6ad0fdd2 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -31,6 +31,7 @@
#include "class_db.h"
#include "core/config/engine.h"
+#include "core/object/script_language.h"
#include "core/os/mutex.h"
#include "core/version.h"
@@ -376,7 +377,12 @@ bool ClassDB::is_virtual(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ if (!ti) {
+ if (!ScriptServer::is_global_class(p_class)) {
+ ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
+ }
+ return false;
+ }
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
return false;
@@ -963,8 +969,11 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro
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);
+ if (!type->linked_properties.has(p_property)) {
+ type->linked_properties.insert(p_property, List<StringName>());
+ }
+ type->linked_properties[p_property].push_back(p_linked_property);
+
#endif
}
@@ -978,7 +987,7 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
if (p_validator) {
// Making a copy as we may modify it.
PropertyInfo pi_mut = pi;
- p_validator->_validate_property(pi_mut);
+ p_validator->validate_property(pi_mut);
p_list->push_back(pi_mut);
} else {
p_list->push_back(pi);
@@ -992,6 +1001,25 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
}
}
+void ClassDB::get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance) {
+#ifdef TOOLS_ENABLED
+ ClassInfo *check = classes.getptr(p_class);
+ while (check) {
+ if (!check->linked_properties.has(p_property)) {
+ return;
+ }
+ for (const StringName &E : check->linked_properties[p_property]) {
+ r_properties->push_back(E);
+ }
+
+ if (p_no_inheritance) {
+ break;
+ }
+ check = check->inherits_ptr;
+ }
+#endif
+}
+
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;
@@ -1000,7 +1028,7 @@ bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_p
if (check->property_map.has(p_property)) {
PropertyInfo pinfo = check->property_map[p_property];
if (p_validator) {
- p_validator->_validate_property(pinfo);
+ p_validator->validate_property(pinfo);
}
if (r_info) {
*r_info = pinfo;
@@ -1432,7 +1460,7 @@ 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_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value.
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
@@ -1506,7 +1534,10 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
c.native_extension = p_extension;
c.name = p_extension->class_name;
- c.creation_func = parent->creation_func;
+ c.is_virtual = p_extension->is_virtual;
+ if (!p_extension->is_abstract) {
+ c.creation_func = parent->creation_func;
+ }
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
@@ -1516,7 +1547,11 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
}
void ClassDB::unregister_extension_class(const StringName &p_class) {
- ERR_FAIL_COND(!classes.has(p_class));
+ ClassInfo *c = classes.getptr(p_class);
+ ERR_FAIL_COND_MSG(!c, "Class " + p_class + "does not exist");
+ for (KeyValue<StringName, MethodBind *> &F : c->method_map) {
+ memdelete(F.value);
+ }
classes.erase(p_class);
}
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 8b6a260d86..5fba52e23e 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -120,6 +120,7 @@ public:
List<MethodInfo> virtual_methods;
HashMap<StringName, MethodInfo> virtual_methods_map;
HashMap<StringName, Vector<Error>> method_error_values;
+ HashMap<StringName, List<StringName>> linked_properties;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -312,6 +313,7 @@ public:
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 void get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance = false);
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);
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index c18d70d9f6..61bf6d900a 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -5,18 +5,19 @@ mutable bool _gdvirtual_##m_name##_initialized = false;\\
mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
- ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
- if (script_instance) {\\
+ ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\
+ if (_script_instance) {\\
Callable::CallError ce; \\
$CALLSIARGS\\
- $CALLSIBEGINscript_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
+ $CALLSIBEGIN_script_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
if (ce.error == Callable::CallError::CALL_OK) {\\
$CALLSIRET\\
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;\\
+ /* TODO: C-style cast because GDNativeStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDNativeStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDNativeExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
@@ -35,12 +36,13 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
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);\\
+ ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\
+ 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;\\
+ /* TODO: C-style cast because GDNativeStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDNativeStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDNativeExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index fa1945cf79..13dc921c9f 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -226,7 +226,7 @@ void MessageQueue::_call_function(const Callable &p_callable, const Variant *p_a
Callable::CallError ce;
Variant ret;
- p_callable.call(argptrs, p_argcount, ret, ce);
+ p_callable.callp(argptrs, p_argcount, ret, ce);
if (p_show_error && ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT("Error calling deferred method: " + Variant::get_callable_error_text(p_callable, argptrs, p_argcount, ce) + ".");
}
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index a4474ea53b..5381c596ce 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -63,7 +63,9 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
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));
+ if (info.name.is_empty()) {
+ info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ }
#endif
return info;
}
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index d60550c899..598e8a224d 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -241,9 +241,17 @@ class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>,
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
public:
+#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+ // Workaround GH-66343 raised only with UBSAN, seems to be a false positive.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
}
+#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
MethodBindVarArgTR(
R (T::*p_method)(const Variant **, int, Callable::CallError &),
@@ -284,11 +292,6 @@ class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -296,9 +299,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -359,11 +359,6 @@ class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -371,9 +366,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -436,11 +428,6 @@ class MethodBindTR : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -458,9 +445,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -523,11 +507,6 @@ class MethodBindTRC : public MethodBind {
(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -545,9 +524,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -607,11 +583,6 @@ class MethodBindTS : public MethodBind {
void (*function)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -619,9 +590,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -670,11 +638,6 @@ class MethodBindTRS : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -682,9 +645,6 @@ protected:
return GetTypeInfo<R>::VARIANT_TYPE;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 5f2287c9d3..d27e0d7621 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -38,6 +38,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "core/variant/typed_array.h"
#ifdef DEBUG_ENABLED
@@ -102,8 +103,8 @@ PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
return pi;
}
-Array convert_property_list(const List<PropertyInfo> *p_list) {
- Array va;
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
+ TypedArray<Dictionary> va;
for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
va.push_back(Dictionary(E->get()));
}
@@ -166,7 +167,6 @@ Object::Connection::operator Variant() const {
d["signal"] = signal;
d["callable"] = callable;
d["flags"] = flags;
- d["binds"] = binds;
return d;
}
@@ -189,9 +189,6 @@ Object::Connection::Connection(const Variant &p_variant) {
if (d.has("flags")) {
flags = d["flags"];
}
- if (d.has("binds")) {
- binds = d["binds"];
- }
}
bool Object::_predelete() {
@@ -476,7 +473,6 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
if (script_instance && p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -507,7 +503,6 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (script_instance && !p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -521,7 +516,61 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
}
-void Object::_validate_property(PropertyInfo &property) const {
+void Object::validate_property(PropertyInfo &p_property) const {
+ _validate_propertyv(p_property);
+}
+
+bool Object::property_can_revert(const StringName &p_name) const {
+ if (script_instance) {
+ if (script_instance->property_can_revert(p_name)) {
+ return true;
+ }
+ }
+
+// 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 && _extension->property_can_revert) {
+ if (_extension->property_can_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name)) {
+ return true;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ return _property_can_revertv(p_name);
+}
+
+Variant Object::property_get_revert(const StringName &p_name) const {
+ Variant ret;
+
+ if (script_instance) {
+ if (script_instance->property_get_revert(p_name, ret)) {
+ return 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 && _extension->property_get_revert) {
+ if (_extension->property_get_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
+ return ret;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ if (_property_get_revertv(p_name, ret)) {
+ return ret;
+ }
+ return Variant();
}
void Object::get_method_list(List<MethodInfo> *p_list) const {
@@ -759,10 +808,11 @@ String Object::to_string() {
}
if (_extension && _extension->to_string) {
String ret;
- _extension->to_string(_extension_instance, &ret);
+ GDNativeBool is_valid;
+ _extension->to_string(_extension_instance, &is_valid, &ret);
return ret;
}
- return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
+ return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
}
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
@@ -864,16 +914,16 @@ void Object::remove_meta(const StringName &p_name) {
set_meta(p_name, Variant());
}
-Array Object::_get_property_list_bind() const {
+TypedArray<Dictionary> Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
get_property_list(&lpi);
return convert_property_list(&lpi);
}
-Array Object::_get_method_list_bind() const {
+TypedArray<Dictionary> Object::_get_method_list_bind() const {
List<MethodInfo> ml;
get_method_list(&ml);
- Array ret;
+ TypedArray<Dictionary> ret;
for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
Dictionary d = E->get();
@@ -973,8 +1023,6 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
OBJ_DEBUG_LOCK
- Vector<const Variant *> bind_mem;
-
Error err = OK;
for (int i = 0; i < ssize; i++) {
@@ -989,28 +1037,13 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
const Variant **args = p_args;
int argc = p_argcount;
- if (c.binds.size()) {
- //handle binds
- bind_mem.resize(p_argcount + c.binds.size());
-
- for (int j = 0; j < p_argcount; j++) {
- bind_mem.write[j] = p_args[j];
- }
- for (int j = 0; j < c.binds.size(); j++) {
- bind_mem.write[p_argcount + j] = &c.binds[j];
- }
-
- args = (const Variant **)bind_mem.ptr();
- argc = bind_mem.size();
- }
-
if (c.flags & CONNECT_DEFERRED) {
MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
} else {
Callable::CallError ce;
_emitting = true;
Variant ret;
- c.callable.call(args, argc, ret, ce);
+ c.callable.callp(args, argc, ret, ce);
_emitting = false;
if (ce.error != Callable::CallError::CALL_OK) {
@@ -1028,7 +1061,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
}
}
- bool disconnect = c.flags & CONNECT_ONESHOT;
+ bool disconnect = c.flags & CONNECT_ONE_SHOT;
#ifdef TOOLS_ENABLED
if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
//this signal was connected from the editor, and is being edited. just don't disconnect for now
@@ -1078,11 +1111,11 @@ void Object::_add_user_signal(const String &p_name, const Array &p_args) {
add_user_signal(mi);
}
-Array Object::_get_signal_list() const {
+TypedArray<Dictionary> Object::_get_signal_list() const {
List<MethodInfo> signal_list;
get_signal_list(&signal_list);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : signal_list) {
ret.push_back(Dictionary(E));
}
@@ -1090,11 +1123,11 @@ Array Object::_get_signal_list() const {
return ret;
}
-Array Object::_get_signal_connection_list(const StringName &p_signal) const {
+TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const {
List<Connection> conns;
get_all_signal_connections(&conns);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const Connection &c : conns) {
if (c.signal.get_name() == p_signal) {
@@ -1105,8 +1138,8 @@ Array Object::_get_signal_connection_list(const StringName &p_signal) const {
return ret;
}
-Array Object::_get_incoming_connections() const {
- Array ret;
+TypedArray<Dictionary> Object::_get_incoming_connections() const {
+ TypedArray<Dictionary> ret;
int connections_amount = connections.size();
for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) {
ret.push_back(connections[idx_conn]);
@@ -1196,7 +1229,7 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons
}
}
-Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) {
+Error Object::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
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();
@@ -1244,7 +1277,6 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co
conn.callable = target;
conn.signal = ::Signal(this, p_signal);
conn.flags = p_flags;
- conn.binds = p_binds;
slot.conn = conn;
slot.cE = target_object->connections.push_back(conn);
if (p_flags & CONNECT_REFERENCE_COUNTED) {
@@ -1437,8 +1469,8 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
- ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind);
- ClassDB::bind_method(D_METHOD("get_indexed", "property"), &Object::_get_indexed_bind);
+ ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
+ ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
@@ -1492,7 +1524,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections);
- ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "binds", "flags"), &Object::connect, DEFVAL(Array()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0));
ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect);
ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected);
@@ -1524,10 +1556,17 @@ void Object::_bind_methods() {
BIND_OBJ_CORE_METHOD(miget);
MethodInfo plget("_get_property_list");
-
plget.return_val.type = Variant::ARRAY;
+ plget.return_val.hint = PROPERTY_HINT_ARRAY_TYPE;
+ plget.return_val.hint_string = "Dictionary";
BIND_OBJ_CORE_METHOD(plget);
+ BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property")));
+ MethodInfo mipgr("_property_get_revert", PropertyInfo(Variant::STRING_NAME, "property"));
+ mipgr.return_val.name = "Variant";
+ mipgr.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_OBJ_CORE_METHOD(mipgr);
+
#endif
BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
@@ -1537,7 +1576,7 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
- BIND_ENUM_CONSTANT(CONNECT_ONESHOT);
+ BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
@@ -1818,6 +1857,46 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
}
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ if (p_idx == 0) {
+ if (p_function == "connect" || p_function == "is_connected" || p_function == "disconnect" || p_function == "emit_signal" || p_function == "has_signal") {
+ List<MethodInfo> signals;
+ get_signal_list(&signals);
+ for (const MethodInfo &E : signals) {
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "call" || p_function == "call_deferred" || p_function == "callv" || p_function == "has_method") {
+ List<MethodInfo> methods;
+ get_method_list(&methods);
+ for (const MethodInfo &E : methods) {
+ if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
+ continue;
+ }
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "set" || p_function == "set_deferred" || p_function == "get") {
+ List<PropertyInfo> properties;
+ get_property_list(&properties);
+ for (const PropertyInfo &E : properties) {
+ if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
+ r_options->push_back(E.name.quote());
+ }
+ }
+ } else if (p_function == "set_meta" || p_function == "get_meta" || p_function == "has_meta" || p_function == "remove_meta") {
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ r_options->push_back(String(K.key).quote());
+ }
+ }
+ } else if (p_idx == 2) {
+ if (p_function == "connect") {
+ // Ideally, the constants should be inferred by the parameter.
+ // But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
+ List<StringName> constants;
+ ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
+ for (const StringName &E : constants) {
+ r_options->push_back(String(E));
+ }
+ }
+ }
}
SpinLock ObjectDB::spin_lock;
diff --git a/core/object/object.h b/core/object/object.h
index 17f75a4e1d..9416eb7762 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -45,12 +45,15 @@
#include "core/variant/callable_bind.h"
#include "core/variant/variant.h"
+template <typename T>
+class TypedArray;
+
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,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_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only")
PROPERTY_HINT_LINK,
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
@@ -68,8 +71,6 @@ enum PropertyHint {
PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines
PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties
PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
- PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
- PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
PROPERTY_HINT_OBJECT_ID,
PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose
PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts)
@@ -86,11 +87,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_GLOBAL_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_ARRAY_TYPE,
PROPERTY_HINT_LOCALE_ID,
PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_NODE_TYPE, ///< a node object type
+ PROPERTY_HINT_HIDE_QUATERNION_EDIT, /// Only Node3D::transform should hide the quaternion editor.
+ PROPERTY_HINT_PASSWORD,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -128,7 +131,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_ARRAY = 1 << 29, // Used in the inspector to group properties as elements of an array.
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR,
- PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNATIONALIZED,
+ PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNATIONALIZED,
PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE,
};
@@ -146,6 +149,10 @@ enum PropertyUsageFlags {
#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)
+// Helper macro to use with PROPERTY_HINT_ARRAY_TYPE for arrays of specific resources:
+// PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")
+#define MAKE_RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type)
+
struct PropertyInfo {
Variant::Type type = Variant::NIL;
String name;
@@ -154,9 +161,7 @@ struct PropertyInfo {
String hint_string;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
-#ifdef TOOLS_ENABLED
- Vector<String> linked_properties;
-#endif
+ // If you are thinking about adding another member to this class, ask the maintainer (Juan) first.
_FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const {
PropertyInfo pi = *this;
@@ -189,10 +194,10 @@ struct PropertyInfo {
explicit PropertyInfo(const GDNativePropertyInfo &pinfo) :
type((Variant::Type)pinfo.type),
- name(pinfo.name),
- class_name(pinfo.class_name), // can be null
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ class_name(*reinterpret_cast<StringName *>(pinfo.class_name)),
hint((PropertyHint)pinfo.hint),
- hint_string(pinfo.hint_string), // can be null
+ hint_string(*reinterpret_cast<String *>(pinfo.hint_string)),
usage(pinfo.usage) {}
bool operator==(const PropertyInfo &p_info) const {
@@ -209,7 +214,7 @@ struct PropertyInfo {
}
};
-Array convert_property_list(const List<PropertyInfo> *p_list);
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list);
enum MethodFlags {
METHOD_FLAG_NORMAL = 1,
@@ -239,6 +244,20 @@ struct MethodInfo {
MethodInfo() {}
+ explicit MethodInfo(const GDNativeMethodInfo &pinfo) :
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ return_val(PropertyInfo(pinfo.return_value)),
+ flags(pinfo.flags),
+ id(pinfo.id) {
+ for (uint32_t j = 0; j < pinfo.argument_count; j++) {
+ arguments.push_back(PropertyInfo(pinfo.arguments[j]));
+ }
+ const Variant *def_values = (const Variant *)pinfo.default_arguments;
+ for (uint32_t j = 0; j < pinfo.default_argument_count; j++) {
+ default_arguments.push_back(def_values[j]);
+ }
+ }
+
void _push_params(const PropertyInfo &p_param) {
arguments.push_back(p_param);
}
@@ -292,10 +311,14 @@ struct ObjectNativeExtension {
StringName parent_class_name;
StringName class_name;
bool editor_class = false;
+ bool is_virtual = false;
+ bool is_abstract = false;
GDNativeExtensionClassSet set;
GDNativeExtensionClassGet get;
GDNativeExtensionClassGetPropertyList get_property_list;
GDNativeExtensionClassFreePropertyList free_property_list;
+ GDNativeExtensionClassPropertyCanRevert property_can_revert;
+ GDNativeExtensionClassPropertyGetRevert property_get_revert;
GDNativeExtensionClassNotification notification;
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
@@ -471,6 +494,37 @@ protected:
m_inherits::_get_property_listv(p_list, p_reversed); \
} \
} \
+ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \
+ return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \
+ } \
+ virtual void _validate_propertyv(PropertyInfo &p_property) const override { \
+ m_inherits::_validate_propertyv(p_property); \
+ if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
+ _validate_property(p_property); \
+ } \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { \
+ return (bool(Object::*)(const StringName &) const) & m_class::_property_can_revert; \
+ } \
+ virtual bool _property_can_revertv(const StringName &p_name) const override { \
+ if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
+ if (_property_can_revert(p_name)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_property_can_revertv(p_name); \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const { \
+ return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \
+ } \
+ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_ret) const override { \
+ if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
+ if (_property_get_revert(p_name, r_ret)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_property_get_revertv(p_name, r_ret); \
+ } \
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \
return (void(Object::*)(int)) & m_class::_notification; \
} \
@@ -501,7 +555,7 @@ public:
enum ConnectFlags {
CONNECT_DEFERRED = 1,
CONNECT_PERSIST = 2, // hint for scene to save this connection
- CONNECT_ONESHOT = 4,
+ CONNECT_ONE_SHOT = 4,
CONNECT_REFERENCE_COUNTED = 8,
};
@@ -510,7 +564,6 @@ public:
Callable callable;
uint32_t flags = 0;
- Vector<Variant> binds;
bool operator<(const Connection &p_conn) const;
operator Variant() const;
@@ -567,9 +620,9 @@ private:
void _add_user_signal(const String &p_name, const Array &p_args = Array());
bool _has_user_signal(const StringName &p_name) const;
Error _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Array _get_signal_list() const;
- Array _get_signal_connection_list(const StringName &p_signal) const;
- Array _get_incoming_connections() const;
+ TypedArray<Dictionary> _get_signal_list() const;
+ TypedArray<Dictionary> _get_signal_connection_list(const StringName &p_signal) const;
+ TypedArray<Dictionary> _get_incoming_connections() const;
void _set_bind(const StringName &p_set, const Variant &p_value);
Variant _get_bind(const StringName &p_name) const;
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
@@ -616,12 +669,18 @@ protected:
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; };
virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const {};
+ virtual void _validate_propertyv(PropertyInfo &p_property) const {};
+ virtual bool _property_can_revertv(const StringName &p_name) const { return false; };
+ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_property) const { return false; };
virtual void _notificationv(int p_notification, bool p_reversed) {}
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_property) { return false; };
bool _get(const StringName &p_name, Variant &r_property) const { return false; };
void _get_property_list(List<PropertyInfo> *p_list) const {};
+ void _validate_property(PropertyInfo &p_property) const {};
+ bool _property_can_revert(const StringName &p_name) const { return false; };
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; };
void _notification(int p_notification) {}
_FORCE_INLINE_ static void (*_get_bind_methods())() {
@@ -636,6 +695,15 @@ protected:
_FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> *p_list) const {
return &Object::_get_property_list;
}
+ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo &p_property) const {
+ return &Object::_validate_property;
+ }
+ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const {
+ return &Object::_property_can_revert;
+ }
+ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const {
+ return &Object::_property_get_revert;
+ }
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) {
return &Object::_notification;
}
@@ -653,13 +721,12 @@ protected:
}
Vector<StringName> _get_meta_list_bind() const;
- Array _get_property_list_bind() const;
- Array _get_method_list_bind() const;
+ TypedArray<Dictionary> _get_property_list_bind() const;
+ TypedArray<Dictionary> _get_method_list_bind() const;
void _clear_internal_resource_paths(const Variant &p_var);
friend class ClassDB;
- virtual void _validate_property(PropertyInfo &property) const;
void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);
@@ -684,34 +751,12 @@ public:
template <class T>
static T *cast_to(Object *p_object) {
-#ifndef NO_SAFE_CAST
return dynamic_cast<T *>(p_object);
-#else
- if (!p_object) {
- return nullptr;
- }
- if (p_object->is_class_ptr(T::get_class_ptr_static())) {
- return static_cast<T *>(p_object);
- } else {
- return nullptr;
- }
-#endif
}
template <class T>
static const T *cast_to(const Object *p_object) {
-#ifndef NO_SAFE_CAST
return dynamic_cast<const T *>(p_object);
-#else
- if (!p_object) {
- return nullptr;
- }
- if (p_object->is_class_ptr(T::get_class_ptr_static())) {
- return static_cast<const T *>(p_object);
- } else {
- return nullptr;
- }
-#endif
}
enum {
@@ -760,6 +805,9 @@ public:
Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = nullptr) const;
void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const;
+ void validate_property(PropertyInfo &p_property) const;
+ bool property_can_revert(const StringName &p_name) const;
+ Variant property_get_revert(const StringName &p_name) const;
bool has_method(const StringName &p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
@@ -829,7 +877,7 @@ public:
int get_persistent_signal_connection_count() const;
void get_signals_connected_to_this(List<Connection> *p_connections) const;
- Error connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0);
+ Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0);
void disconnect(const StringName &p_signal, const Callable &p_callable);
bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index 726e2c012c..50467d795d 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -48,9 +48,10 @@ void RefCounted::_bind_methods() {
ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref);
ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference);
ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference);
+ ClassDB::bind_method(D_METHOD("get_reference_count"), &RefCounted::get_reference_count);
}
-int RefCounted::reference_get_count() const {
+int RefCounted::get_reference_count() const {
return refcount.get();
}
@@ -85,7 +86,8 @@ bool RefCounted::unreference() {
_get_extension()->unreference(_get_extension_instance());
}
- die = die && _instance_binding_reference(false);
+ bool binding_ret = _instance_binding_reference(false);
+ die = die && binding_ret;
}
return die;
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index bd06a84bd8..71790fb825 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -47,7 +47,7 @@ public:
bool init_ref();
bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference();
- int reference_get_count() const;
+ int get_reference_count() const;
RefCounted();
~RefCounted() {}
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 226fd8b791..36a0d03aaf 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -34,6 +34,7 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/variant/typed_array.h"
#include <stdint.h>
@@ -61,8 +62,8 @@ Variant Script::_get_property_default_value(const StringName &p_property) {
return ret;
}
-Array Script::_get_script_property_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_property_list() {
+ TypedArray<Dictionary> ret;
List<PropertyInfo> list;
get_script_property_list(&list);
for (const PropertyInfo &E : list) {
@@ -71,8 +72,8 @@ Array Script::_get_script_property_list() {
return ret;
}
-Array Script::_get_script_method_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_method_list() {
+ TypedArray<Dictionary> ret;
List<MethodInfo> list;
get_script_method_list(&list);
for (const MethodInfo &E : list) {
@@ -81,8 +82,8 @@ Array Script::_get_script_method_list() {
return ret;
}
-Array Script::_get_script_signal_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_signal_list() {
+ TypedArray<Dictionary> ret;
List<MethodInfo> list;
get_script_signal_list(&list);
for (const MethodInfo &E : list) {
@@ -101,6 +102,31 @@ Dictionary Script::_get_script_constant_map() {
return ret;
}
+#ifdef TOOLS_ENABLED
+
+PropertyInfo Script::get_class_category() const {
+ String path = get_path();
+ String scr_name;
+
+ if (is_built_in()) {
+ if (get_name().is_empty()) {
+ scr_name = TTR("Built-in script");
+ } else {
+ scr_name = vformat("%s (%s)", get_name(), TTR("Built-in"));
+ }
+ } else {
+ if (get_name().is_empty()) {
+ scr_name = path.get_file();
+ } else {
+ scr_name = get_name();
+ }
+ }
+
+ return PropertyInfo(Variant::NIL, scr_name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
+}
+
+#endif // TOOLS_ENABLED
+
void Script::_bind_methods() {
ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate);
//ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
@@ -140,6 +166,7 @@ ScriptLanguage *ScriptServer::get_language(int p_idx) {
}
void ScriptServer::register_language(ScriptLanguage *p_language) {
+ ERR_FAIL_NULL(p_language);
ERR_FAIL_COND(_language_count >= MAX_LANGUAGES);
_languages[_language_count++] = p_language;
}
@@ -157,10 +184,10 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
}
void ScriptServer::init_languages() {
- { //load global classes
+ { // Load global classes.
global_classes_clear();
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
+ Array script_classes = GLOBAL_GET("_global_script_classes");
for (int i = 0; i < script_classes.size(); i++) {
Dictionary c = script_classes[i];
@@ -278,7 +305,7 @@ void ScriptServer::save_global_classes() {
Array old;
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ old = GLOBAL_GET("_global_script_classes");
}
if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
return;
@@ -382,7 +409,9 @@ bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_v
if (values.has(p_name)) {
Variant defval;
if (script->get_property_default_value(p_name, defval)) {
- if (defval == p_value) {
+ // The evaluate function ensures that a NIL variant is equal to e.g. an empty Resource.
+ // Simply doing defval == p_value does not do this.
+ if (Variant::evaluate(Variant::OP_EQUAL, defval, p_value)) {
values.erase(p_name);
return true;
}
@@ -392,7 +421,7 @@ bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_v
} else {
Variant defval;
if (script->get_property_default_value(p_name, defval)) {
- if (defval != p_value) {
+ if (Variant::evaluate(Variant::OP_NOT_EQUAL, defval, p_value)) {
values[p_name] = p_value;
}
return true;
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 686ab5b8d3..12a21150bc 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -33,11 +33,12 @@
#include "core/doc_data.h"
#include "core/io/resource.h"
-#include "core/multiplayer/multiplayer.h"
#include "core/templates/pair.h"
#include "core/templates/rb_map.h"
class ScriptLanguage;
+template <typename T>
+class TypedArray;
typedef void (*ScriptEditRequestFunction)(const String &p_path);
@@ -109,9 +110,9 @@ protected:
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {}
Variant _get_property_default_value(const StringName &p_property);
- Array _get_script_property_list();
- Array _get_script_method_list();
- Array _get_script_signal_list();
+ TypedArray<Dictionary> _get_script_property_list();
+ TypedArray<Dictionary> _get_script_method_list();
+ TypedArray<Dictionary> _get_script_signal_list();
Dictionary _get_script_constant_map();
public:
@@ -133,6 +134,7 @@ public:
#ifdef TOOLS_ENABLED
virtual Vector<DocData::ClassDoc> get_documentation() const = 0;
+ virtual PropertyInfo get_class_category() const;
#endif // TOOLS_ENABLED
virtual bool has_method(const StringName &p_method) const = 0;
@@ -159,7 +161,7 @@ public:
virtual bool is_placeholder_fallback_enabled() const { return false; }
- virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const = 0;
+ virtual const Variant get_rpc_config() const = 0;
Script() {}
};
@@ -171,6 +173,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const = 0;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const = 0;
+ virtual bool property_can_revert(const StringName &p_name) const = 0;
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const = 0;
+
virtual Object *get_owner() { return nullptr; }
virtual void get_property_state(List<Pair<StringName, Variant>> &state);
@@ -213,7 +218,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<Multiplayer::RPCConfig> get_rpc_methods() const { return get_script()->get_rpc_methods(); }
+ virtual const Variant get_rpc_config() const { return get_script()->get_rpc_config(); }
virtual ScriptLanguage *get_language() = 0;
virtual ~ScriptInstance();
@@ -447,6 +452,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const override;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override;
+ virtual bool property_can_revert(const StringName &p_name) const override { return false; };
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override { return false; };
+
virtual void get_method_list(List<MethodInfo> *p_list) const override;
virtual bool has_method(const StringName &p_method) const override;
@@ -469,7 +477,7 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr) override;
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr) override;
- virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override { return Vector<Multiplayer::RPCConfig>(); }
+ virtual const Variant get_rpc_config() const override { return Variant(); }
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
~PlaceHolderScriptInstance();
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index ab8dd6d1ee..78e9038b66 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -62,6 +62,7 @@ void ScriptExtension::_bind_methods() {
GDVIRTUAL_BIND(_has_script_signal, "signal");
GDVIRTUAL_BIND(_get_script_signal_list);
+ GDVIRTUAL_BIND(_has_property_default_value, "property");
GDVIRTUAL_BIND(_get_property_default_value, "property");
GDVIRTUAL_BIND(_update_exports);
@@ -74,7 +75,7 @@ void ScriptExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_members);
GDVIRTUAL_BIND(_is_placeholder_fallback_enabled);
- GDVIRTUAL_BIND(_get_rpc_methods);
+ GDVIRTUAL_BIND(_get_rpc_config);
}
void ScriptLanguageExtension::_bind_methods() {
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 2c53139ec2..9a2a176096 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -82,9 +82,10 @@ public:
GDVIRTUAL_REQUIRED_CALL(_get_documentation, doc);
Vector<DocData::ClassDoc> class_doc;
-#ifndef _MSC_VER
-#warning missing conversion from documentation to ClassDoc
-#endif
+ for (int i = 0; i < doc.size(); i++) {
+ class_doc.append(DocData::ClassDoc::from_dict(doc[i]));
+ }
+
return class_doc;
}
#endif // TOOLS_ENABLED
@@ -173,28 +174,12 @@ public:
EXBIND0RC(bool, is_placeholder_fallback_enabled)
- GDVIRTUAL0RC(TypedArray<Dictionary>, _get_rpc_methods)
+ GDVIRTUAL0RC(Variant, _get_rpc_config)
- virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override {
- TypedArray<Dictionary> ret;
- GDVIRTUAL_REQUIRED_CALL(_get_rpc_methods, ret);
- Vector<Multiplayer::RPCConfig> rpcret;
- for (int i = 0; i < ret.size(); i++) {
- Dictionary d = ret[i];
- Multiplayer::RPCConfig rpc;
- ERR_CONTINUE(!d.has("name"));
- rpc.name = d["name"];
- ERR_CONTINUE(!d.has("rpc_mode"));
- rpc.rpc_mode = Multiplayer::RPCMode(int(d["rpc_mode"]));
- ERR_CONTINUE(!d.has("call_local"));
- rpc.call_local = d["call_local"];
- ERR_CONTINUE(!d.has("transfer_mode"));
- rpc.transfer_mode = Multiplayer::TransferMode(int(d["transfer_mode"]));
- ERR_CONTINUE(!d.has("channel"));
- rpc.channel = d["channel"];
- rpcret.push_back(rpc);
- }
- return rpcret;
+ virtual const Variant get_rpc_config() const override {
+ Variant ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_rpc_config, ret);
+ return ret;
}
ScriptExtension() {}
@@ -679,6 +664,14 @@ public:
if (native_info->get_property_list_func) {
uint32_t pcount;
const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount);
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_script();
+ if (script->is_valid() && pcount > 0) {
+ p_list->push_back(script->get_class_category());
+ }
+#endif // TOOLS_ENABLED
+
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(pinfo[i]));
}
@@ -694,12 +687,24 @@ public:
if (r_is_valid) {
*r_is_valid = is_valid != 0;
}
-
return Variant::Type(type);
}
return Variant::NIL;
}
+ virtual bool property_can_revert(const StringName &p_name) const override {
+ if (native_info->property_can_revert_func) {
+ return native_info->property_can_revert_func(instance, (const GDNativeStringNamePtr)&p_name);
+ }
+ return false;
+ }
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override {
+ if (native_info->property_get_revert_func) {
+ return native_info->property_get_revert_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ }
+ return false;
+ }
+
virtual Object *get_owner() override {
if (native_info->get_owner_func) {
return (Object *)native_info->get_owner_func(instance);
@@ -721,19 +726,7 @@ public:
uint32_t mcount;
const GDNativeMethodInfo *minfo = native_info->get_method_list_func(instance, &mcount);
for (uint32_t i = 0; i < mcount; i++) {
- MethodInfo m;
- m.name = minfo[i].name;
- m.flags = minfo[i].flags;
- m.id = minfo[i].id;
- m.return_val = PropertyInfo(minfo[i].return_value);
- for (uint32_t j = 0; j < minfo[i].argument_count; j++) {
- m.arguments.push_back(PropertyInfo(minfo[i].arguments[j]));
- }
- const Variant *def_values = (const Variant *)minfo[i].default_arguments;
- for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) {
- m.default_arguments.push_back(def_values[j]);
- }
- p_list->push_back(m);
+ p_list->push_back(MethodInfo(minfo[i]));
}
if (native_info->free_method_list_func) {
native_info->free_method_list_func(instance, minfo);
@@ -767,7 +760,8 @@ public:
virtual String to_string(bool *r_valid) override {
if (native_info->to_string_func) {
GDNativeBool valid;
- String ret = native_info->to_string_func(instance, &valid);
+ String ret;
+ native_info->to_string_func(instance, &valid, reinterpret_cast<GDNativeStringPtr>(&ret));
if (r_valid) {
*r_valid = valid != 0;
}
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index d3c48853f1..9f8a1de697 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -126,27 +126,28 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
force_keep_in_merge_ends = false;
}
-void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_do_method(const Callable &p_callable) {
+ ERR_FAIL_COND(p_callable.is_null());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
+
+ Object *object = p_callable.get_object();
+ ERR_FAIL_NULL(object);
+
Operation do_op;
- do_op.object = p_object->get_instance_id();
- if (Object::cast_to<RefCounted>(p_object)) {
- do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+ do_op.callable = p_callable;
+ do_op.object = p_callable.get_object_id();
+ if (Object::cast_to<RefCounted>(object)) {
+ do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
}
-
do_op.type = Operation::TYPE_METHOD;
- do_op.name = p_method;
+ do_op.name = p_callable.get_method();
- for (int i = 0; i < p_argcount; i++) {
- do_op.args.push_back(*p_args[i]);
- }
actions.write[current_action + 1].do_ops.push_back(do_op);
}
-void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_undo_method(const Callable &p_callable) {
+ ERR_FAIL_COND(p_callable.is_null());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -155,19 +156,19 @@ void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, co
return;
}
+ Object *object = p_callable.get_object();
+ ERR_FAIL_NULL(object);
+
Operation undo_op;
- undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<RefCounted>(p_object)) {
- undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+ undo_op.callable = p_callable;
+ undo_op.object = p_callable.get_object_id();
+ if (Object::cast_to<RefCounted>(object)) {
+ undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
}
-
undo_op.type = Operation::TYPE_METHOD;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
- undo_op.name = p_method;
+ undo_op.name = p_callable.get_method();
- for (int i = 0; i < p_argcount; i++) {
- undo_op.args.push_back(*p_args[i]);
- }
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -183,7 +184,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
do_op.type = Operation::TYPE_PROPERTY;
do_op.name = p_property;
- do_op.args.push_back(p_value);
+ do_op.value = p_value;
actions.write[current_action + 1].do_ops.push_back(do_op);
}
@@ -206,7 +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.push_back(p_value);
+ undo_op.value = p_value;
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -312,33 +313,42 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
switch (op.type) {
case Operation::TYPE_METHOD: {
- int argc = op.args.size();
- Vector<const Variant *> argptrs;
- argptrs.resize(argc);
-
- for (int i = 0; i < argc; i++) {
- argptrs.write[i] = &op.args[i];
- }
-
Callable::CallError ce;
- obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+ Variant ret;
+ op.callable.callp(nullptr, 0, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+ ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, nullptr, 0, ce));
}
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
if (res) {
res->set_edited(true);
}
-
#endif
if (method_callback) {
- method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
+ Vector<Variant> binds;
+ if (op.callable.is_custom()) {
+ CallableCustomBind *ccb = dynamic_cast<CallableCustomBind *>(op.callable.get_custom());
+ if (ccb) {
+ binds = ccb->get_binds();
+ }
+ }
+
+ if (binds.is_empty()) {
+ method_callback(method_callback_ud, obj, op.name, nullptr, 0);
+ } else {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size());
+ for (int i = 0; i < binds.size(); i++) {
+ args[i] = (const Variant *)&binds[i];
+ }
+
+ method_callback(method_callback_ud, obj, op.name, args, binds.size());
+ }
}
} break;
case Operation::TYPE_PROPERTY: {
- obj->set(op.name, op.args[0]);
+ obj->set(op.name, op.value);
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
if (res) {
@@ -346,7 +356,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
}
#endif
if (property_callback) {
- property_callback(prop_callback_ud, obj, op.name, op.args[0]);
+ property_callback(prop_callback_ud, obj, op.name, op.value);
}
} break;
case Operation::TYPE_REFERENCE: {
@@ -413,6 +423,10 @@ String UndoRedo::get_current_action_name() const {
return actions[current_action].name;
}
+int UndoRedo::get_action_level() const {
+ return action_level;
+}
+
bool UndoRedo::has_undo() const {
return current_action >= 0;
}
@@ -444,87 +458,13 @@ UndoRedo::~UndoRedo() {
clear_history();
}
-void UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
- return;
- }
-
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return;
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING_NAME;
- return;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Object *object = *p_args[0];
- StringName method = *p_args[1];
-
- add_do_methodp(object, method, p_args + 2, p_argcount - 2);
-}
-
-void UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
- return;
- }
-
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return;
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING_NAME;
- return;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Object *object = *p_args[0];
- StringName method = *p_args[1];
-
- add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
-}
-
void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
- {
- MethodInfo mi;
- mi.name = "add_do_method";
- mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
-
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &UndoRedo::_add_do_method, mi, varray(), false);
- }
-
- {
- MethodInfo mi;
- mi.name = "add_undo_method";
- mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
-
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &UndoRedo::_add_undo_method, mi, varray(), false);
- }
-
+ ClassDB::bind_method(D_METHOD("add_do_method", "callable"), &UndoRedo::add_do_method);
+ ClassDB::bind_method(D_METHOD("add_undo_method", "callable"), &UndoRedo::add_undo_method);
ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &UndoRedo::add_do_property);
ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property);
ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 63cf3e5cbe..9c6d2d10ed 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -46,8 +46,6 @@ public:
};
typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name);
- void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
@@ -58,14 +56,14 @@ private:
TYPE_METHOD,
TYPE_PROPERTY,
TYPE_REFERENCE
- };
+ } type;
- Type type;
bool force_keep_in_merge_ends;
Ref<RefCounted> ref;
ObjectID object;
StringName name;
- Vector<Variant> args;
+ Callable callable;
+ Variant value;
void delete_reference();
};
@@ -106,30 +104,8 @@ protected:
public:
void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
- void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
- void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
-
- template <typename... VarArgs>
- void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
-
- add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
- }
- template <typename... VarArgs>
- void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
-
- add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
- }
-
+ void add_do_method(const Callable &p_callable);
+ void add_undo_method(const Callable &p_callable);
void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_do_reference(Object *p_object);
@@ -144,6 +120,7 @@ public:
bool redo();
bool undo();
String get_current_action_name() const;
+ int get_action_level() const;
int get_history_count();
int get_current_action();
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index 54738a673e..0218a4c8f6 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -72,7 +72,7 @@ void WorkerThreadPool::_process_task(Task *p_task) {
p_task->template_userdata->callback_indexed(work_index);
} else {
arg = work_index;
- p_task->callable.call((const Variant **)&argptr, 1, ret, ce);
+ p_task->callable.callp((const Variant **)&argptr, 1, ret, ce);
}
// This is the only way to ensure posting is done when all tasks are really complete.
@@ -123,7 +123,7 @@ void WorkerThreadPool::_process_task(Task *p_task) {
} else {
Callable::CallError ce;
Variant ret;
- p_task->callable.call(nullptr, 0, ret, ce);
+ p_task->callable.callp(nullptr, 0, ret, ce);
}
p_task->completed = true;
@@ -395,14 +395,16 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
uint32_t finished_users = group->finished.increment(); // fetch happens before inc, so increment later.
if (finished_users == max_users) {
- // All tasks using this group are gone (finished before the group), so clear the gorup too.
+ // All tasks using this group are gone (finished before the group), so clear the group too.
task_mutex.lock();
group_allocator.free(group);
task_mutex.unlock();
}
}
- groups.erase(p_group); // Threads do not access this, so safe to erase here.
+ task_mutex.lock(); // This mutex is needed when Physics 2D and/or 3D is selected to run on a separate thread.
+ groups.erase(p_group);
+ task_mutex.unlock();
}
void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) {