summaryrefslogtreecommitdiff
path: root/core/object
diff options
context:
space:
mode:
Diffstat (limited to 'core/object')
-rw-r--r--core/object/callable_method_pointer.cpp4
-rw-r--r--core/object/callable_method_pointer.h14
-rw-r--r--core/object/class_db.cpp143
-rw-r--r--core/object/class_db.h133
-rw-r--r--core/object/make_virtuals.py25
-rw-r--r--core/object/message_queue.cpp45
-rw-r--r--core/object/message_queue.h51
-rw-r--r--core/object/method_bind.cpp8
-rw-r--r--core/object/method_bind.h267
-rw-r--r--core/object/object.cpp192
-rw-r--r--core/object/object.h149
-rw-r--r--core/object/object_id.h4
-rw-r--r--core/object/ref_counted.cpp4
-rw-r--r--core/object/ref_counted.h6
-rw-r--r--core/object/script_language.cpp30
-rw-r--r--core/object/script_language.h188
-rw-r--r--core/object/script_language_extension.cpp180
-rw-r--r--core/object/script_language_extension.h835
-rw-r--r--core/object/undo_redo.cpp121
-rw-r--r--core/object/undo_redo.h42
20 files changed, 1855 insertions, 586 deletions
diff --git a/core/object/callable_method_pointer.cpp b/core/object/callable_method_pointer.cpp
index 2bfaef744d..1bf926cafc 100644
--- a/core/object/callable_method_pointer.cpp
+++ b/core/object/callable_method_pointer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 8ba01be4e4..577d4b9fbd 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,7 +38,7 @@
#include "core/variant/callable.h"
class CallableCustomMethodPointerBase : public CallableCustom {
- uint32_t *comp_ptr;
+ uint32_t *comp_ptr = nullptr;
uint32_t comp_size;
uint32_t h;
#ifdef DEBUG_METHODS_ENABLED
@@ -51,6 +51,14 @@ protected:
void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);
public:
+ virtual StringName get_method() const {
+#ifdef DEBUG_METHODS_ENABLED
+ return StringName(text);
+#else
+ return StringName();
+#endif
+ }
+
#ifdef DEBUG_METHODS_ENABLED
void set_text(const char *p_text) {
text = p_text;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 4b3c8b123f..fd86a02b90 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -497,22 +497,6 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam
compat_classes[p_class] = p_fallback;
}
-thread_local bool initializing_with_extension = false;
-thread_local ObjectNativeExtension *initializing_extension = nullptr;
-thread_local GDExtensionClassInstancePtr initializing_extension_instance = nullptr;
-
-void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance, Object *p_base) {
- if (initializing_with_extension) {
- *r_extension = initializing_extension;
- *r_extension_instance = initializing_extension_instance;
- initializing_with_extension = false;
- initializing_extension->set_object_instance(*r_extension_instance, p_base);
- } else {
- *r_extension = nullptr;
- *r_extension_instance = nullptr;
- }
-}
-
Object *ClassDB::instantiate(const StringName &p_class) {
ClassInfo *ti;
{
@@ -533,21 +517,31 @@ Object *ClassDB::instantiate(const StringName &p_class) {
return nullptr;
}
#endif
- if (ti->native_extension) {
- initializing_with_extension = true;
- initializing_extension = ti->native_extension;
- initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->class_userdata);
+ if (ti->native_extension && ti->native_extension->create_instance) {
+ return (Object *)ti->native_extension->create_instance(ti->native_extension->class_userdata);
+ } else {
+ return ti->creation_func();
}
- return ti->creation_func();
}
-Object *ClassDB::construct_object(Object *(*p_create_func)(), ObjectNativeExtension *p_extension) {
- if (p_extension) {
- initializing_with_extension = true;
- initializing_extension = p_extension;
- initializing_extension_instance = p_extension->create_instance(p_extension->class_userdata);
+void ClassDB::set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance) {
+ ERR_FAIL_COND(!p_object);
+ ClassInfo *ti;
+ {
+ OBJTYPE_RLOCK;
+ ti = classes.getptr(p_class);
+ if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) {
+ if (compat_classes.has(p_class)) {
+ ti = classes.getptr(compat_classes[p_class]);
+ }
+ }
+ ERR_FAIL_COND_MSG(!ti, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_COND_MSG(ti->disabled, "Class '" + String(p_class) + "' is disabled.");
+ ERR_FAIL_COND_MSG(!ti->native_extension, "Class '" + String(p_class) + "' has no native extension.");
}
- return p_create_func();
+
+ p_object->_extension = ti->native_extension;
+ p_object->_extension_instance = p_instance;
}
bool ClassDB::can_instantiate(const StringName &p_class) {
@@ -563,6 +557,19 @@ bool ClassDB::can_instantiate(const StringName &p_class) {
return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance));
}
+bool ClassDB::is_virtual(const StringName &p_class) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *ti = classes.getptr(p_class);
+ ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+#ifdef TOOLS_ENABLED
+ if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
+ return false;
+ }
+#endif
+ return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance) && ti->is_virtual);
+}
+
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
OBJTYPE_WLOCK;
@@ -737,8 +744,8 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName
type->constant_map[p_name] = p_constant;
String enum_name = p_enum;
- if (enum_name != String()) {
- if (enum_name.find(".") != -1) {
+ if (!enum_name.is_empty()) {
+ if (enum_name.contains(".")) {
enum_name = enum_name.get_slicec('.', 1);
}
@@ -1013,20 +1020,30 @@ bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal,
return false;
}
-void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix) {
+void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_COND(!type);
- type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
+ String prefix = p_prefix;
+ if (p_indent_depth > 0) {
+ prefix = vformat("%s,%d", p_prefix, p_indent_depth);
+ }
+
+ type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_GROUP));
}
-void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix) {
+void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_COND(!type);
- type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP));
+ String prefix = p_prefix;
+ if (p_indent_depth > 0) {
+ prefix = vformat("%s,%d", p_prefix, p_indent_depth);
+ }
+
+ type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_SUBGROUP));
}
void ClassDB::add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage) {
@@ -1193,7 +1210,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
if (psg->_setptr) {
psg->_setptr->call(p_object, arg, 2, ce);
} else {
- p_object->call(psg->setter, arg, 2, ce);
+ p_object->callp(psg->setter, arg, 2, ce);
}
} else {
@@ -1201,7 +1218,7 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
if (psg->_setptr) {
psg->_setptr->call(p_object, arg, 1, ce);
} else {
- p_object->call(psg->setter, arg, 1, ce);
+ p_object->callp(psg->setter, arg, 1, ce);
}
}
@@ -1234,14 +1251,14 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia
Variant index = psg->index;
const Variant *arg[1] = { &index };
Callable::CallError ce;
- r_value = p_object->call(psg->getter, arg, 1, ce);
+ r_value = p_object->callp(psg->getter, arg, 1, ce);
} else {
Callable::CallError ce;
if (psg->_getptr) {
r_value = psg->_getptr->call(p_object, nullptr, 0, ce);
} else {
- r_value = p_object->call(psg->getter, nullptr, 0, ce);
+ r_value = p_object->callp(psg->getter, nullptr, 0, ce);
}
}
return true;
@@ -1468,9 +1485,10 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
if (p_object_core) {
mi.flags |= METHOD_FLAG_OBJECT_CORE;
}
- if (p_arg_names.size()) {
+
+ if (!p_object_core) {
if (p_arg_names.size() != mi.arguments.size()) {
- WARN_PRINT("Mismatch argument name count for virtual function: " + String(p_class) + "::" + p_method.name);
+ WARN_PRINT("Mismatch argument name count for virtual method: " + 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];
@@ -1478,6 +1496,10 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
}
}
+ if (classes[p_class].virtual_methods_map.has(p_method.name)) {
+ // overloading not supported
+ ERR_FAIL_MSG("Virtual method already bound '" + String(p_class) + "::" + p_method.name + "'.");
+ }
classes[p_class].virtual_methods.push_back(mi);
classes[p_class].virtual_methods_map[p_method.name] = mi;
@@ -1534,15 +1556,6 @@ bool ClassDB::is_class_exposed(const StringName &p_class) {
return ti->exposed;
}
-StringName ClassDB::get_category(const StringName &p_node) {
- ERR_FAIL_COND_V(!classes.has(p_node), StringName());
-#ifdef DEBUG_ENABLED
- return classes[p_node].category;
-#else
- return StringName();
-#endif
-}
-
void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) {
if (resource_base_extensions.has(p_extension)) {
return;
@@ -1589,7 +1602,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)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
@@ -1638,7 +1651,8 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
// Some properties may have an instantiated Object as default value,
// (like Path2D's `curve` used to have), but that's not a good practice.
// Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
- // to be auto-instantiated when created in the editor.
+ // to be auto-instantiated when created in the editor with the following method:
+ // EditorNode::get_editor_data().instantiate_object_properties(obj);
if (var.get_type() == Variant::OBJECT) {
Object *obj = var.get_validated_object();
if (obj) {
@@ -1676,6 +1690,30 @@ void ClassDB::unregister_extension_class(const StringName &p_class) {
classes.erase(p_class);
}
+Map<StringName, ClassDB::NativeStruct> ClassDB::native_structs;
+void ClassDB::register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size) {
+ NativeStruct ns;
+ ns.ccode = p_code;
+ ns.struct_size = p_current_size;
+ native_structs[p_name] = ns;
+}
+
+void ClassDB::get_native_struct_list(List<StringName> *r_names) {
+ for (const KeyValue<StringName, NativeStruct> &E : native_structs) {
+ r_names->push_back(E.key);
+ }
+}
+
+String ClassDB::get_native_struct_code(const StringName &p_name) {
+ ERR_FAIL_COND_V(!native_structs.has(p_name), String());
+ return native_structs[p_name].ccode;
+}
+
+uint64_t ClassDB::get_native_struct_size(const StringName &p_name) {
+ ERR_FAIL_COND_V(!native_structs.has(p_name), 0);
+ return native_structs[p_name].struct_size;
+}
+
RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {
@@ -1699,6 +1737,7 @@ void ClassDB::cleanup() {
classes.clear();
resource_base_extensions.clear();
compat_classes.clear();
+ native_structs.clear();
}
//
diff --git a/core/object/class_db.h b/core/object/class_db.h
index dae75ba564..5da8523743 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -85,8 +85,8 @@ public:
int index;
StringName setter;
StringName getter;
- MethodBind *_setptr;
- MethodBind *_getptr;
+ MethodBind *_setptr = nullptr;
+ MethodBind *_getptr = nullptr;
Variant::Type type;
};
@@ -109,7 +109,6 @@ public:
Set<StringName> methods_in_properties;
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;
@@ -118,6 +117,7 @@ public:
StringName name;
bool disabled = false;
bool exposed = false;
+ bool is_virtual = false;
Object *(*creation_func)() = nullptr;
ClassInfo() {}
@@ -143,6 +143,13 @@ public:
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static Set<StringName> default_values_cached;
+ // Native structs, used by binder
+ struct NativeStruct {
+ String ccode; // C code to create the native struct, fields separated by ; Arrays accepted (even containing other structs), also function pointers. All types must be Godot types.
+ uint64_t struct_size; // local size of struct, for comparison
+ };
+ static Map<StringName, NativeStruct> native_structs;
+
private:
// Non-locking variants of get_parent_class and is_parent_class.
static StringName _get_parent_class(const StringName &p_class);
@@ -156,20 +163,21 @@ public:
}
template <class T>
- static void register_class() {
+ static void register_class(bool p_virtual = false) {
GLOBAL_LOCK_FUNCTION;
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
ERR_FAIL_COND(!t);
t->creation_func = &creator<T>;
t->exposed = true;
+ t->is_virtual = p_virtual;
t->class_ptr = T::get_class_ptr_static();
t->api = current_api;
T::register_custom_data_to_otdb();
}
template <class T>
- static void register_virtual_class() {
+ static void register_abstract_class() {
GLOBAL_LOCK_FUNCTION;
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@@ -210,83 +218,35 @@ public:
static bool class_exists(const StringName &p_class);
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
static bool can_instantiate(const StringName &p_class);
+ static bool is_virtual(const StringName &p_class);
static Object *instantiate(const StringName &p_class);
- static Object *construct_object(Object *(*p_create_func)(), ObjectNativeExtension *p_extension);
- static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance, Object *p_base);
+ static void set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance);
static APIType get_api_type(const StringName &p_class);
static uint64_t get_api_hash(APIType p_api);
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method) {
- MethodBind *bind = create_method_bind(p_method);
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, nullptr, 0); //use static function, much smaller binary usage
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[1] = { &p_def1 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 1);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[2] = { &p_def1, &p_def2 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 2);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[3] = { &p_def1, &p_def2, &p_def3 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 3);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[4] = { &p_def1, &p_def2, &p_def3, &p_def4 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 4);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[5] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 5);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[6] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 6);
- }
-
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6, const Variant &p_def7) {
+ template <class N, class M, typename... VarArgs>
+ static MethodBind *bind_method(N p_method_name, M 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];
+ }
MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[7] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6, &p_def7 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 7);
+ return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
- template <class N, class M>
- static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6, const Variant &p_def7, const Variant &p_def8) {
- MethodBind *bind = create_method_bind(p_method);
- const Variant *ptr[8] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6, &p_def7, &p_def8 };
-
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 8);
+ template <class N, class M, typename... VarArgs>
+ static MethodBind *bind_static_method(const StringName &p_class, N p_method_name, M 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];
+ }
+ MethodBind *bind = create_static_method_bind(p_method);
+ bind->set_instance_class(p_class);
+ return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
template <class M>
@@ -329,8 +289,8 @@ public:
static bool get_signal(const StringName &p_class, const StringName &p_signal, MethodInfo *r_signal);
static void get_signal_list(const StringName &p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false);
- static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix = "");
- static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = "");
+ static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix = "", int p_indent_depth = 0);
+ static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = "", int p_indent_depth = 0);
static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_DEFAULT);
static void add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix);
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
@@ -370,8 +330,6 @@ public:
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(const StringName &p_class, bool p_enable);
static bool is_class_enabled(const StringName &p_class);
@@ -388,6 +346,11 @@ public:
static APIType get_current_api();
static void cleanup_defaults();
static void cleanup();
+
+ static void register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size);
+ static void get_native_struct_list(List<StringName> *r_names);
+ static String get_native_struct_code(const StringName &p_name);
+ static uint64_t get_native_struct_size(const StringName &p_name); // Used for asserting
};
#ifdef DEBUG_METHODS_ENABLED
@@ -437,10 +400,16 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
::ClassDB::register_class<m_class>(); \
}
-#define GDREGISTER_VIRTUAL_CLASS(m_class) \
- if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
- ::ClassDB::register_virtual_class<m_class>(); \
+#define GDREGISTER_VIRTUAL_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ::ClassDB::register_class<m_class>(true); \
}
+#define GDREGISTER_ABSTRACT_CLASS(m_class) \
+ if (!GD_IS_DEFINED(ClassDB_Disable_##m_class)) { \
+ ::ClassDB::register_abstract_class<m_class>(); \
+ }
+
+#define GDREGISTER_NATIVE_STRUCT(m_class, m_code) ClassDB::register_native_struct(#m_class, m_code, sizeof(m_class))
#include "core/disabled_classes.gen.h"
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 86c2891e5d..c18d70d9f6 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -1,18 +1,24 @@
proto = """
#define GDVIRTUAL$VER($RET m_name $ARG) \\
StringName _gdvirtual_##m_name##_sn = #m_name;\\
-GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+mutable bool _gdvirtual_##m_name##_initialized = false;\\
+mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
+template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
if (script_instance) {\\
Callable::CallError ce; \\
$CALLSIARGS\\
- $CALLSIBEGINscript_instance->call(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
+ $CALLSIBEGINscript_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
if (ce.error == Callable::CallError::CALL_OK) {\\
$CALLSIRET\\
return true;\\
} \\
}\\
+ if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ _gdvirtual_##m_name##_initialized = true;\\
+ }\\
if (_gdvirtual_##m_name) {\\
$CALLPTRARGS\\
$CALLPTRRETDEF\\
@@ -20,6 +26,11 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
$CALLPTRRET\\
return true;\\
}\\
+ \\
+ if (required) {\\
+ ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");\\
+ $RVOID\\
+ }\\
\\
return false;\\
}\\
@@ -28,6 +39,10 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\
if (script_instance) {\\
return script_instance->has_method(_gdvirtual_##m_name##_sn);\\
}\\
+ if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ _gdvirtual_##m_name##_initialized = true;\\
+ }\\
if (_gdvirtual_##m_name) {\\
return true;\\
}\\
@@ -52,10 +67,12 @@ def generate_version(argcount, const=False, returns=False):
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret, ")
+ s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
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("$RVOID", "")
s = s.replace("$CALLPTRRETDEF", "")
if const:
@@ -114,9 +131,9 @@ def generate_version(argcount, const=False, returns=False):
callargtext += ","
callargtext += " m_ret& r_ret"
s = s.replace("$CALLSIBEGIN", "Variant ret = ")
- s = s.replace("$CALLSIRET", "r_ret = ret;")
+ s = s.replace("$CALLSIRET", "r_ret = VariantCaster<m_ret>::cast(ret);")
s = s.replace("$CALLPTRRETPASS", "&ret")
- s = s.replace("$CALLPTRRET", "r_ret = ret;")
+ s = s.replace("$CALLPTRRET", "r_ret = (m_ret)ret;")
else:
s = s.replace("$CALLSIBEGIN", "")
s = s.replace("$CALLSIRET", "")
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index 736e940846..79c36ac81f 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
+#include "core/object/class_db.h"
#include "core/object/script_language.h"
MessageQueue *MessageQueue::singleton = nullptr;
@@ -40,23 +41,8 @@ MessageQueue *MessageQueue::get_singleton() {
return singleton;
}
-Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
- return push_callable(Callable(p_id, p_method), p_args, p_argcount, p_show_error);
-}
-
-Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return push_call(p_id, p_method, argptr, argc, false);
+Error MessageQueue::push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
+ return push_callablep(Callable(p_id, p_method), p_args, p_argcount, p_show_error);
}
Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value) {
@@ -113,8 +99,8 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
return OK;
}
-Error MessageQueue::push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- return push_call(p_object->get_instance_id(), p_method, VARIANT_ARG_PASS);
+Error MessageQueue::push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error) {
+ return push_callp(p_object->get_instance_id(), p_method, p_args, p_argcount, p_show_error);
}
Error MessageQueue::push_notification(Object *p_object, int p_notification) {
@@ -125,7 +111,7 @@ Error MessageQueue::push_set(Object *p_object, const StringName &p_prop, const V
return push_set(p_object->get_instance_id(), p_prop, p_value);
}
-Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) {
+Error MessageQueue::push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error) {
_THREAD_SAFE_METHOD_
int room_needed = sizeof(Message) + sizeof(Variant) * p_argcount;
@@ -155,21 +141,6 @@ Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_
return OK;
}
-Error MessageQueue::push_callable(const Callable &p_callable, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return push_callable(p_callable, argptr, argc);
-}
-
void MessageQueue::statistics() {
Map<StringName, int> set_count;
Map<int, int> notify_count;
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index 1b8def62d3..2219cdb8f6 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,8 +31,11 @@
#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H
-#include "core/object/class_db.h"
+#include "core/object/object_id.h"
#include "core/os/thread_safe.h"
+#include "core/variant/variant.h"
+
+class Object;
class MessageQueue {
_THREAD_SAFE_CLASS_
@@ -59,10 +62,10 @@ class MessageQueue {
};
};
- uint8_t *buffer;
+ uint8_t *buffer = nullptr;
uint32_t buffer_end = 0;
uint32_t buffer_max_used = 0;
- uint32_t buffer_size;
+ uint32_t buffer_size = 0;
void _call_function(const Callable &p_callable, const Variant *p_args, int p_argcount, bool p_show_error);
@@ -73,14 +76,42 @@ class MessageQueue {
public:
static MessageQueue *get_singleton();
- Error push_call(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
- Error push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_LIST);
+ Error push_callp(ObjectID p_id, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ template <typename... VarArgs>
+ Error push_call(ObjectID p_id, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callp(p_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
Error push_notification(ObjectID p_id, int p_notification);
Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value);
- Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
- Error push_callable(const Callable &p_callable, VARIANT_ARG_LIST);
+ Error push_callablep(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
+
+ template <typename... VarArgs>
+ Error push_callable(const Callable &p_callable, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callablep(p_callable, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ Error push_callp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ template <typename... VarArgs>
+ Error push_call(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return push_callp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
- Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
Error push_notification(Object *p_object, int p_notification);
Error push_set(Object *p_object, const StringName &p_prop, const Variant &p_value);
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index 642e27c41d..a79adb7c6c 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -83,6 +83,10 @@ void MethodBind::_set_const(bool p_const) {
_const = p_const;
}
+void MethodBind::_set_static(bool p_static) {
+ _static = p_static;
+}
+
void MethodBind::_set_returns(bool p_returns) {
_returns = p_returns;
}
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index ee003099a0..bde6cba199 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -60,6 +60,7 @@ class MethodBind {
int default_argument_count = 0;
int argument_count = 0;
+ bool _static = false;
bool _const = false;
bool _returns = false;
@@ -69,6 +70,7 @@ protected:
Vector<StringName> arg_names;
#endif
void _set_const(bool p_const);
+ void _set_static(bool p_static);
void _set_returns(bool p_returns);
virtual Variant::Type _gen_argument_type(int p_arg) const = 0;
virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0;
@@ -116,7 +118,7 @@ public:
#endif
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
- uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
+ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0) | (is_static() ? METHOD_FLAG_STATIC : 0); }
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
_FORCE_INLINE_ void set_instance_class(const StringName &p_class) { instance_class = p_class; }
@@ -129,6 +131,7 @@ public:
void set_name(const StringName &p_name);
_FORCE_INLINE_ int get_method_id() const { return method_id; }
_FORCE_INLINE_ bool is_const() const { return _const; }
+ _FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool has_return() const { return _returns; }
virtual bool is_vararg() const { return false; }
@@ -140,21 +143,20 @@ public:
virtual ~MethodBind();
};
-template <class T>
-class MethodBindVarArg : public MethodBind {
-public:
- typedef Variant (T::*NativeCall)(const Variant **, int, Callable::CallError &);
-
+// MethodBindVarArg base CRTP
+template <class Derived, class T, class R, bool should_returns>
+class MethodBindVarArgBase : public MethodBind {
protected:
- NativeCall call_method = nullptr;
- MethodInfo arguments;
+ R(T::*method)
+ (const Variant **, int, Callable::CallError &);
+ MethodInfo method_info;
public:
virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
if (p_arg < 0) {
- return arguments.return_val;
- } else if (p_arg < arguments.arguments.size()) {
- return arguments.arguments[p_arg];
+ return _gen_return_type_info();
+ } else if (p_arg < method_info.arguments.size()) {
+ return method_info.arguments[p_arg];
} else {
return PropertyInfo(Variant::NIL, "arg_" + itos(p_arg), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
@@ -170,24 +172,31 @@ public:
}
#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- T *instance = static_cast<T *>(p_object);
- return (instance->*call_method)(p_args, p_arg_count, r_error);
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ ERR_FAIL(); // Can't call.
}
- void set_method_info(const MethodInfo &p_info, bool p_return_nil_is_variant) {
- set_argument_count(p_info.arguments.size());
- Variant::Type *at = memnew_arr(Variant::Type, p_info.arguments.size() + 1);
- at[0] = p_info.return_val.type;
- if (p_info.arguments.size()) {
+ virtual bool is_const() const { return false; }
+
+ virtual bool is_vararg() const { return true; }
+
+ MethodBindVarArgBase(
+ R (T::*p_method)(const Variant **, int, Callable::CallError &),
+ const MethodInfo &p_method_info,
+ bool p_return_nil_is_variant) :
+ method(p_method), method_info(p_method_info) {
+ set_argument_count(method_info.arguments.size());
+ Variant::Type *at = memnew_arr(Variant::Type, method_info.arguments.size() + 1);
+ at[0] = _gen_return_type_info().type;
+ if (method_info.arguments.size()) {
#ifdef DEBUG_METHODS_ENABLED
Vector<StringName> names;
- names.resize(p_info.arguments.size());
+ names.resize(method_info.arguments.size());
#endif
- for (int i = 0; i < p_info.arguments.size(); i++) {
- at[i + 1] = p_info.arguments[i].type;
+ for (int i = 0; i < method_info.arguments.size(); i++) {
+ at[i + 1] = method_info.arguments[i].type;
#ifdef DEBUG_METHODS_ENABLED
- names.write[i] = p_info.arguments[i].name;
+ names.write[i] = method_info.arguments[i].name;
#endif
}
@@ -196,31 +205,76 @@ public:
#endif
}
argument_types = at;
- arguments = p_info;
if (p_return_nil_is_variant) {
- arguments.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
}
+
+ _set_returns(should_returns);
}
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
- ERR_FAIL(); // Can't call.
+private:
+ PropertyInfo _gen_return_type_info() const {
+ return Derived::_gen_return_type_info_impl();
}
+};
- void set_method(NativeCall p_method) { call_method = p_method; }
- virtual bool is_const() const { return false; }
+// variadic, no return
+template <class T>
+class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
+ friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
- virtual bool is_vararg() const { return true; }
+public:
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)(p_args, p_arg_count, r_error);
+ return {};
+ }
- MethodBindVarArg() {
- _set_returns(true);
+ MethodBindVarArgT(
+ void (T::*p_method)(const Variant **, int, Callable::CallError &),
+ const MethodInfo &p_method_info,
+ bool p_return_nil_is_variant) :
+ MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>(p_method, p_method_info, p_return_nil_is_variant) {
+ }
+
+private:
+ static PropertyInfo _gen_return_type_info_impl() {
+ return {};
}
};
template <class T>
-MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
- MethodBindVarArg<T> *a = memnew((MethodBindVarArg<T>));
- a->set_method(p_method);
- a->set_method_info(p_info, p_return_nil_is_variant);
+MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
+ MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+// variadic, return
+template <class T, class R>
+class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
+ friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
+
+public:
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
+ }
+
+ MethodBindVarArgTR(
+ R (T::*p_method)(const Variant **, int, Callable::CallError &),
+ const MethodInfo &p_info,
+ bool p_return_nil_is_variant) :
+ MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>(p_method, p_info, p_return_nil_is_variant) {
+ }
+
+private:
+ static PropertyInfo _gen_return_type_info_impl() {
+ return GetTypeInfo<R>::get_class_info();
+ }
+};
+
+template <class T, class R>
+MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
+ MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
return a;
}
@@ -308,7 +362,7 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
return a;
}
-// no return, not const
+// no return, const
#ifdef TYPED_METHOD_BIND
template <class T, class... P>
@@ -558,4 +612,139 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
return a;
}
+/* STATIC BINDS */
+
+// no return
+
+template <class... P>
+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 {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return Variant::NIL;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ }
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ return call_get_argument_metadata<P...>(p_arg);
+ }
+
+#endif
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ (void)p_object; // unused
+ call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
+ return Variant();
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ (void)p_object;
+ (void)r_ret;
+ call_with_ptr_args_static_method(function, p_args);
+ }
+
+ MethodBindTS(void (*p_function)(P...)) {
+ function = p_function;
+ _generate_argument_types(sizeof...(P));
+ set_argument_count(sizeof...(P));
+ _set_static(true);
+ }
+};
+
+template <class... P>
+MethodBind *create_static_method_bind(void (*p_method)(P...)) {
+ MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
+ return a;
+}
+
+// return
+
+template <class R, class... P>
+class MethodBindTRS : public MethodBind {
+ R(*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 {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ 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 {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ } else {
+ return GetTypeInfo<R>::get_class_info();
+ }
+ }
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ if (p_arg >= 0) {
+ return call_get_argument_metadata<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::METADATA;
+ }
+ }
+
+#endif
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ Variant ret;
+ call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
+ return ret;
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ (void)p_object;
+ call_with_ptr_args_static_method_ret(function, p_args, r_ret);
+ }
+
+ MethodBindTRS(R (*p_function)(P...)) {
+ function = p_function;
+ _generate_argument_types(sizeof...(P));
+ set_argument_count(sizeof...(P));
+ _set_static(true);
+ _set_returns(true);
+ }
+};
+
+template <class R, class... P>
+MethodBind *create_static_method_bind(R (*p_method)(P...)) {
+ MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
+ return a;
+}
+
#endif // METHOD_BIND_H
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 90bd697d37..897b5d18de 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -402,13 +402,9 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
#endif
}
- //try built-in setgetter
+ // Try built-in setter.
{
if (ClassDB::set_property(this, p_name, p_value, r_valid)) {
- /*
- if (r_valid)
- *r_valid=true;
- */
return;
}
}
@@ -420,16 +416,25 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
return;
- } else if (p_name == CoreStringNames::get_singleton()->_meta) {
- //set_meta(p_name,p_value);
- metadata = p_value.duplicate();
- if (r_valid) {
- *r_valid = true;
+ } else {
+ OrderedHashMap<StringName, Variant>::Element *E = metadata_properties.getptr(p_name);
+ if (E) {
+ E->get() = p_value;
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
+ } else if (p_name.operator String().begins_with("metadata/")) {
+ // Must exist, otherwise duplicate() will not work.
+ set_meta(p_name.operator String().replace_first("metadata/", ""), p_value);
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
}
- return;
}
- //something inside the object... :|
+ // Something inside the object... :|
bool success = _setv(p_name, p_value);
if (success) {
if (r_valid) {
@@ -485,7 +490,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
#endif
}
- //try built-in setgetter
+ // Try built-in getter.
{
if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) {
if (r_valid) {
@@ -501,16 +506,19 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
*r_valid = true;
}
return ret;
+ }
+
+ const OrderedHashMap<StringName, Variant>::Element *E = metadata_properties.getptr(p_name);
- } else if (p_name == CoreStringNames::get_singleton()->_meta) {
- ret = metadata;
+ if (E) {
+ ret = E->get();
if (r_valid) {
*r_valid = true;
}
return ret;
} else {
- //something inside the object... :|
+ // Something inside the object... :|
bool success = _getv(p_name, ret);
if (success) {
if (r_valid) {
@@ -629,8 +637,12 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (_extension) {
- p_list->push_back(PropertyInfo(Variant::NIL, _extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
- ClassDB::get_property_list(_extension->class_name, p_list, true, this);
+ const ObjectNativeExtension *current_extension = _extension;
+ while (current_extension) {
+ p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
+ ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
+ current_extension = current_extension->parent;
+ }
}
if (_extension && _extension->get_property_list) {
@@ -649,13 +661,20 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
- if (!metadata.is_empty()) {
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- }
+
if (script_instance && !p_reversed) {
p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
+
+ for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
+ PropertyInfo pi = PropertyInfo(K.value().get_type(), "metadata/" + K.key().operator String());
+ if (K.value().get_type() == Variant::OBJECT) {
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Resource";
+ }
+ p_list->push_back(pi);
+ }
}
void Object::_validate_property(PropertyInfo &property) const {
@@ -684,7 +703,7 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal
StringName method = *p_args[0];
- return call(method, &p_args[1], p_argcount - 1, r_error);
+ return callp(method, &p_args[1], p_argcount - 1, r_error);
}
Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -705,7 +724,7 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call
StringName method = *p_args[0];
- MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
+ MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
return Variant();
}
@@ -755,31 +774,14 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) {
}
Callable::CallError ce;
- Variant ret = call(p_method, argptrs, p_args.size(), ce);
+ Variant ret = callp(p_method, argptrs, p_args.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + ".");
}
return ret;
}
-Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
-
- Variant ret = call(p_name, argptr, argc, error);
- return ret;
-}
-
-Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
if (p_method == CoreStringNames::get_singleton()->_free) {
@@ -813,7 +815,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
OBJ_DEBUG_LOCK
if (script_instance) {
- ret = script_instance->call(p_method, p_args, p_argcount, r_error);
+ ret = script_instance->callp(p_method, p_args, p_argcount, r_error);
//force jumptable
switch (r_error.error) {
case Callable::CallError::CALL_OK:
@@ -863,7 +865,9 @@ String Object::to_string() {
}
}
if (_extension && _extension->to_string) {
- return _extension->to_string(_extension_instance);
+ String ret;
+ _extension->to_string(_extension_instance, &ret);
+ return ret;
}
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}
@@ -933,20 +937,38 @@ bool Object::has_meta(const StringName &p_name) const {
void Object::set_meta(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
- metadata.erase(p_name);
+ if (metadata.has(p_name)) {
+ metadata.erase(p_name);
+ metadata_properties.erase("metadata/" + p_name.operator String());
+ notify_property_list_changed();
+ }
return;
}
- metadata[p_name] = p_value;
+ OrderedHashMap<StringName, Variant>::Element E = metadata.find(p_name);
+ if (E) {
+ E.value() = p_value;
+ } else {
+ ERR_FAIL_COND(!p_name.operator String().is_valid_identifier());
+ E = metadata.insert(p_name, p_value);
+ metadata_properties["metadata/" + p_name.operator String()] = E;
+ notify_property_list_changed();
+ }
}
-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 + "'.");
+Variant Object::get_meta(const StringName &p_name, const Variant &p_default) const {
+ if (!metadata.has(p_name)) {
+ if (p_default != Variant()) {
+ return p_default;
+ } else {
+ ERR_FAIL_V_MSG(Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
+ }
+ }
return metadata[p_name];
}
void Object::remove_meta(const StringName &p_name) {
- metadata.erase(p_name);
+ set_meta(p_name, Variant());
}
Array Object::_get_property_list_bind() const {
@@ -972,25 +994,21 @@ Array Object::_get_method_list_bind() const {
Vector<StringName> Object::_get_meta_list_bind() const {
Vector<StringName> _metaret;
- List<Variant> keys;
- metadata.get_key_list(&keys);
- for (const Variant &E : keys) {
- _metaret.push_back(E);
+ for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
+ _metaret.push_back(K.key());
}
return _metaret;
}
void Object::get_meta_list(List<StringName> *p_list) const {
- List<Variant> keys;
- metadata.get_key_list(&keys);
- for (const Variant &E : keys) {
- p_list->push_back(E);
+ for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
+ p_list->push_back(K.key());
}
}
void Object::add_user_signal(const MethodInfo &p_signal) {
- ERR_FAIL_COND_MSG(p_signal.name == "", "Signal name cannot be empty.");
+ ERR_FAIL_COND_MSG(p_signal.name.is_empty(), "Signal name cannot be empty.");
ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), "User signal's name conflicts with a built-in signal of '" + get_class_name() + "'.");
ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), "Trying to add already existing signal '" + p_signal.name + "'.");
SignalData s;
@@ -1010,15 +1028,15 @@ struct _ObjectSignalDisconnectData {
Callable callable;
};
-Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- ERR_FAIL_COND_V(p_argcount < 1, Variant());
+ ERR_FAIL_COND_V(p_argcount < 1, Error::ERR_INVALID_PARAMETER);
if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING_NAME;
- ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Variant());
+ ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Error::ERR_INVALID_PARAMETER);
}
r_error.error = Callable::CallError::CALL_OK;
@@ -1032,12 +1050,10 @@ Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::C
args = &p_args[1];
}
- emit_signal(signal, args, argc);
-
- return Variant();
+ return emit_signalp(signal, args, argc);
}
-Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount) {
+Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
if (_block_signals) {
return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked
}
@@ -1096,7 +1112,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
}
if (c.flags & CONNECT_DEFERRED) {
- MessageQueue::get_singleton()->push_callable(c.callable, args, argc, true);
+ MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
} else {
Callable::CallError ce;
_emitting = true;
@@ -1144,21 +1160,6 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
return err;
}
-Error Object::emit_signal(const StringName &p_name, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
-
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- return emit_signal(p_name, argptr, argc);
-}
-
void Object::_add_user_signal(const String &p_name, const Array &p_args) {
// this version of add_user_signal is meant to be used from scripts or external apis
// without access to ADD_SIGNAL in bind_methods
@@ -1253,7 +1254,7 @@ void Object::get_signal_list(List<MethodInfo> *p_signals) const {
const StringName *S = nullptr;
while ((S = signal_map.next(S))) {
- if (signal_map[*S].user.name != "") {
+ if (!signal_map[*S].user.name.is_empty()) {
//user signal
p_signals->push_back(signal_map[*S].user);
}
@@ -1562,7 +1563,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
- ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta);
+ ClassDB::bind_method(D_METHOD("get_meta", "name", "default"), &Object::get_meta, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
@@ -1653,10 +1654,6 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
-void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) {
- MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS);
-}
-
void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
MessageQueue::get_singleton()->push_set(this, p_property, p_value);
}
@@ -1680,7 +1677,7 @@ void Object::get_translatable_strings(List<String> *p_strings) const {
String text = get(E.name);
- if (text == "") {
+ if (text.is_empty()) {
continue;
}
@@ -1838,8 +1835,6 @@ void Object::_construct_object(bool p_reference) {
type_is_reference = p_reference;
_instance_id = ObjectDB::add_instance(this);
- ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance, this);
-
#ifdef DEBUG_ENABLED
_lock_index.init(1);
#endif
@@ -1853,6 +1848,13 @@ Object::Object() {
_construct_object(false);
}
+void Object::detach_from_objectdb() {
+ if (_instance_id != ObjectID()) {
+ ObjectDB::remove_instance(this);
+ _instance_id = ObjectID();
+ }
+}
+
Object::~Object() {
if (script_instance) {
memdelete(script_instance);
@@ -1892,8 +1894,10 @@ Object::~Object() {
c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
}
- ObjectDB::remove_instance(this);
- _instance_id = ObjectID();
+ if (_instance_id != ObjectID()) {
+ ObjectDB::remove_instance(this);
+ _instance_id = ObjectID();
+ }
_predelete_ok = 2;
if (_instance_bindings != nullptr) {
diff --git a/core/object/object.h b/core/object/object.h
index 218bc26dec..c3e3c68b59 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,30 +32,20 @@
#define OBJECT_H
#include "core/extension/gdnative_interface.h"
+#include "core/object/message_queue.h"
#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
#include "core/os/spin_lock.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
+#include "core/templates/ordered_hash_map.h"
#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
#include "core/templates/vmap.h"
#include "core/variant/callable_bind.h"
#include "core/variant/variant.h"
-#define VARIANT_ARG_LIST const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant()
-#define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5, p_arg6, p_arg7, p_arg8
-#define VARIANT_ARG_DECLARE const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8
-#define VARIANT_ARG_MAX 8
-#define VARIANT_ARGPTRS const Variant *argptr[8] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5, &p_arg6, &p_arg7, &p_arg8 };
-#define VARIANT_ARGPTRS_PASS *argptr[0], *argptr[1], *argptr[2], *argptr[3], *argptr[4], *argptr[5], *argptr[6]], *argptr[7]
-#define VARIANT_ARGS_FROM_ARRAY(m_arr) m_arr[0], m_arr[1], m_arr[2], m_arr[3], m_arr[4], m_arr[5], m_arr[6], m_arr[7]
-
-/**
-@author Juan Linietsky <reduzio@gmail.com>
-*/
-
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range.
@@ -98,6 +88,8 @@ enum PropertyHint {
PROPERTY_HINT_INT_IS_OBJECTID,
PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
+ PROPERTY_HINT_LOCALE_ID,
+ PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -145,7 +137,9 @@ enum PropertyUsageFlags {
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index)
#define ADD_PROPERTY_DEFAULT(m_property, m_default) ::ClassDB::set_property_default_value(get_class_static(), m_property, m_default)
#define ADD_GROUP(m_name, m_prefix) ::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
+#define ADD_GROUP_INDENT(m_name, m_prefix, m_depth) ::ClassDB::add_property_group(get_class_static(), m_name, m_prefix, m_depth)
#define ADD_SUBGROUP(m_name, m_prefix) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
+#define ADD_SUBGROUP_INDENT(m_name, m_prefix, m_depth) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix, m_depth)
#define ADD_LINKED_PROPERTY(m_property, m_linked_property) ::ClassDB::add_linked_property(get_class_static(), m_property, m_linked_property)
#define ADD_ARRAY_COUNT(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix)
@@ -246,13 +240,7 @@ struct MethodInfo {
MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5);
};
-// old cast_to
-//if ( is_type(T::get_class_static()) )
-//return static_cast<T*>(this);
-////else
-//return nullptr;
-
-// API used to extend in GDNative and other C compatible compiled languages
+// API used to extend in GDNative and other C compatible compiled languages.
class MethodBind;
struct ObjectNativeExtension {
@@ -269,6 +257,7 @@ struct ObjectNativeExtension {
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
GDNativeExtensionClassReference unreference;
+ GDNativeExtensionClassGetRID get_rid;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
const ObjectNativeExtension *e = this;
@@ -284,12 +273,15 @@ struct ObjectNativeExtension {
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__)
+#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
+#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<false>(__VA_ARGS__)
+
+#define GDVIRTUAL_REQUIRED_CALL(m_name, ...) _gdvirtual_##m_name##_call<true>(__VA_ARGS__)
+#define GDVIRTUAL_REQUIRED_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call<true>(__VA_ARGS__)
+
#ifdef DEBUG_METHODS_ENABLED
#define GDVIRTUAL_BIND(m_name, ...) ::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), true, sarray(__VA_ARGS__));
#else
@@ -299,8 +291,10 @@ struct ObjectNativeExtension {
#define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden()
/*
- the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model.
-*/
+ * The following is an incomprehensible blob of hacks and workarounds to
+ * compensate for many of the fallacies in C++. As a plus, this macro pretty
+ * much alone defines the object model.
+ */
#define REVERSE_GET_PROPERTY_LIST \
public: \
@@ -350,19 +344,6 @@ public:
m_inherits::get_inheritance_list_static(p_inheritance_list); \
p_inheritance_list->push_back(String(#m_class)); \
} \
- static String get_category_static() { \
- String category = m_inherits::get_category_static(); \
- if (_get_category != m_inherits::_get_category) { \
- if (category != "") { \
- category += "/"; \
- } \
- category += _get_category(); \
- } \
- return category; \
- } \
- static String inherits_static() { \
- return String(#m_inherits); \
- } \
virtual bool is_class(const String &p_class) const override { \
if (_get_extension() && _get_extension()->is_class(p_class)) { \
return true; \
@@ -463,12 +444,6 @@ protected:
\
private:
-#define OBJ_CATEGORY(m_category) \
-protected: \
- _FORCE_INLINE_ static String _get_category() { return m_category; } \
- \
-private:
-
#define OBJ_SAVE_TYPE(m_class) \
public: \
virtual String get_save_class() const override { return #m_class; } \
@@ -539,14 +514,15 @@ private:
Set<String> editor_section_folding;
#endif
ScriptInstance *script_instance = nullptr;
- Variant script; //reference does not yet exist, store it in a
- Dictionary metadata;
+ Variant script; // Reference does not exist yet, store it in a Variant.
+ OrderedHashMap<StringName, Variant> metadata;
+ HashMap<StringName, OrderedHashMap<StringName, Variant>::Element> metadata_properties;
mutable StringName _class_name;
mutable const StringName *_class_ptr = nullptr;
void _add_user_signal(const String &p_name, const Array &p_args = Array());
bool _has_user_signal(const StringName &p_name) const;
- Variant _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ 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 String &p_signal) const;
Array _get_incoming_connections() const;
@@ -562,8 +538,8 @@ private:
std::mutex _instance_binding_mutex;
struct InstanceBinding {
- void *binding;
- void *token;
+ void *binding = nullptr;
+ void *token = nullptr;
GDNativeInstanceBindingFreeCallback free_callback = nullptr;
GDNativeInstanceBindingReferenceCallback reference_callback = nullptr;
};
@@ -588,6 +564,7 @@ protected:
}
return can_die;
}
+
friend class NativeExtensionMethodBind;
_ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; }
_ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; }
@@ -597,7 +574,6 @@ protected:
virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const {};
virtual void _notificationv(int p_notification, bool p_reversed) {}
- static String _get_category() { return ""; }
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; };
@@ -622,9 +598,6 @@ protected:
static void get_valid_parents_static(List<String> *p_parents);
static void _get_valid_parents_static(List<String> *p_parents);
- //Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
- //void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
-
Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
@@ -646,7 +619,7 @@ protected:
void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);
-public: //should be protected, but bug in clang++
+public: // Should be protected, but bug in clang++.
static void initialize_class();
_FORCE_INLINE_ static void register_custom_data_to_otdb() {}
@@ -660,6 +633,7 @@ public:
bool _is_gpl_reversed() const { return false; }
+ void detach_from_objectdb();
_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
template <class T>
@@ -704,11 +678,11 @@ public:
static String get_class_static() { return "Object"; }
static String get_parent_class_static() { return String(); }
- static String get_category_static() { return String(); }
virtual String get_class() const {
- if (_extension)
+ if (_extension) {
return _extension->class_name.operator String();
+ }
return "Object";
}
virtual String get_save_class() const { return get_class(); } //class stored when saving
@@ -733,8 +707,6 @@ public:
}
/* IAPI */
- //void set(const String& p_name, const Variant& p_value);
- //Variant get(const String& p_name) const;
void set(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr);
Variant get(const StringName &p_name, bool *r_valid = nullptr) const;
@@ -746,13 +718,23 @@ public:
bool has_method(const StringName &p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName &p_method, const Array &p_args);
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
+ }
void notification(int p_notification, bool p_reversed = false);
virtual String to_string();
- //used mainly by script, get and set all INCLUDING string
+ // Used mainly by script, get and set all INCLUDING string.
virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
virtual void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = nullptr);
@@ -761,28 +743,38 @@ public:
void set_script(const Variant &p_script);
Variant get_script() const;
- /* SCRIPT */
-
bool has_meta(const StringName &p_name) const;
void set_meta(const StringName &p_name, const Variant &p_value);
void remove_meta(const StringName &p_name);
- Variant get_meta(const StringName &p_name) const;
+ Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const;
void get_meta_list(List<StringName> *p_list) const;
#ifdef TOOLS_ENABLED
void set_edited(bool p_edited);
bool is_edited() const;
- uint32_t get_edited_version() const; //this function is used to check when something changed beyond a point, it's used mainly for generating previews
+ // This function is used to check when something changed beyond a point, it's used mainly for generating previews.
+ uint32_t get_edited_version() const;
#endif
void set_script_instance(ScriptInstance *p_instance);
_FORCE_INLINE_ ScriptInstance *get_script_instance() const { return script_instance; }
- void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process
+ // Some script languages can't control instance creation, so this function eases the process.
+ void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance);
void add_user_signal(const MethodInfo &p_signal);
- Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST);
- Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ Error emit_signal(const StringName &p_name, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
bool has_signal(const StringName &p_name) const;
void get_signal_list(List<MethodInfo> *p_signals) const;
void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
@@ -794,7 +786,11 @@ public:
void disconnect(const StringName &p_signal, const Callable &p_callable);
bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
- void call_deferred(const StringName &p_method, VARIANT_ARG_LIST);
+ template <typename... VarArgs>
+ void call_deferred(const StringName &p_name, VarArgs... p_args) {
+ MessageQueue::get_singleton()->push_call(this, p_name, p_args...);
+ }
+
void set_deferred(const StringName &p_property, const Variant &p_value);
void set_block_signals(bool p_block);
@@ -807,10 +803,11 @@ public:
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
- String tr(const StringName &p_message, const StringName &p_context = "") const; // translate message (internationalization)
+ // Translate message (internationalization).
+ String tr(const StringName &p_message, const StringName &p_context = "") const;
String tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
- bool _is_queued_for_deletion = false; // set to true by SceneTree::queue_delete()
+ bool _is_queued_for_deletion = false; // Set to true by SceneTree::queue_delete().
bool is_queued_for_deletion() const;
_FORCE_INLINE_ void set_message_translation(bool p_enable) { _can_translate = p_enable; }
@@ -842,18 +839,18 @@ bool predelete_handler(Object *p_object);
void postinitialize_handler(Object *p_object);
class ObjectDB {
-//this needs to add up to 63, 1 bit is for reference
+// This needs to add up to 63, 1 bit is for reference.
#define OBJECTDB_VALIDATOR_BITS 39
#define OBJECTDB_VALIDATOR_MASK ((uint64_t(1) << OBJECTDB_VALIDATOR_BITS) - 1)
#define OBJECTDB_SLOT_MAX_COUNT_BITS 24
#define OBJECTDB_SLOT_MAX_COUNT_MASK ((uint64_t(1) << OBJECTDB_SLOT_MAX_COUNT_BITS) - 1)
#define OBJECTDB_REFERENCE_BIT (uint64_t(1) << (OBJECTDB_SLOT_MAX_COUNT_BITS + OBJECTDB_VALIDATOR_BITS))
- struct ObjectSlot { //128 bits per slot
+ struct ObjectSlot { // 128 bits per slot.
uint64_t validator : OBJECTDB_VALIDATOR_BITS;
uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS;
uint64_t is_ref_counted : 1;
- Object *object;
+ Object *object = nullptr;
};
static SpinLock spin_lock;
@@ -879,7 +876,7 @@ public:
uint64_t id = p_instance_id;
uint32_t slot = id & OBJECTDB_SLOT_MAX_COUNT_MASK;
- ERR_FAIL_COND_V(slot >= slot_max, nullptr); //this should never happen unless RID is corrupted
+ ERR_FAIL_COND_V(slot >= slot_max, nullptr); // This should never happen unless RID is corrupted.
spin_lock.lock();
diff --git a/core/object/object_id.h b/core/object/object_id.h
index 0666ec0855..a36997630f 100644
--- a/core/object/object_id.h
+++ b/core/object/object_id.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index 2833f774dc..c9a7b2a608 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index f2dd2aa324..dcacf19890 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -261,7 +261,7 @@ struct PtrToArg<Ref<T>> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
- *(Ref<RefCounted> *)p_ptr = p_val;
+ *(const_cast<Ref<RefCounted> *>(reinterpret_cast<const Ref<RefCounted> *>(p_ptr))) = p_val;
}
};
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 8ec1a973e7..a5d25bf533 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,10 +46,12 @@ bool ScriptServer::languages_finished = false;
ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr;
void Script::_notification(int p_what) {
- if (p_what == NOTIFICATION_POSTINITIALIZE) {
- if (EngineDebugger::is_active()) {
- EngineDebugger::get_script_debugger()->set_break_language(get_language());
- }
+ switch (p_what) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ if (EngineDebugger::is_active()) {
+ EngineDebugger::get_script_debugger()->set_break_language(get_language());
+ }
+ } break;
}
}
@@ -142,7 +144,7 @@ void ScriptServer::register_language(ScriptLanguage *p_language) {
_languages[_language_count++] = p_language;
}
-void ScriptServer::unregister_language(ScriptLanguage *p_language) {
+void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
for (int i = 0; i < _language_count; i++) {
if (_languages[i] == p_language) {
_language_count--;
@@ -308,20 +310,6 @@ void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state)
}
}
-Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- Callable::CallError error;
- return call(p_method, argptr, argc, error);
-}
-
void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) {
if (r_valid) {
*r_valid = false;
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 8d76cbf479..69002c81f4 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,7 +68,7 @@ public:
_FORCE_INLINE_ static int get_language_count() { return _language_count; }
static ScriptLanguage *get_language(int p_idx);
static void register_language(ScriptLanguage *p_language);
- static void unregister_language(ScriptLanguage *p_language);
+ static void unregister_language(const ScriptLanguage *p_language);
static void set_reload_scripts_on_save(bool p_enable);
static bool is_reload_scripts_on_save_enabled();
@@ -132,7 +132,7 @@ public:
virtual Error reload(bool p_keep_state = false) = 0;
#ifdef TOOLS_ENABLED
- virtual const Vector<DocData::ClassDoc> &get_documentation() const = 0;
+ virtual Vector<DocData::ClassDoc> get_documentation() const = 0;
#endif // TOOLS_ENABLED
virtual bool has_method(const StringName &p_method) const = 0;
@@ -176,8 +176,20 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const = 0;
virtual bool has_method(const StringName &p_method) const = 0;
- virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST);
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
+
+ template <typename... VarArgs>
+ Variant call(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ Callable::CallError cerr;
+ return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
+ }
+
virtual void notification(int p_notification) = 0;
virtual String to_string(bool *r_valid) {
if (r_valid) {
@@ -200,43 +212,12 @@ 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 = 0;
+ virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const { return get_script()->get_rpc_methods(); }
virtual ScriptLanguage *get_language() = 0;
virtual ~ScriptInstance();
};
-struct ScriptCodeCompletionOption {
- /* Keep enum in Sync with: */
- /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
- enum Kind {
- KIND_CLASS,
- KIND_FUNCTION,
- KIND_SIGNAL,
- KIND_VARIABLE,
- KIND_MEMBER,
- KIND_ENUM,
- KIND_CONSTANT,
- KIND_NODE_PATH,
- KIND_FILE_PATH,
- KIND_PLAIN_TEXT,
- };
- Kind kind = KIND_PLAIN_TEXT;
- String display;
- String insert_text;
- Color font_color;
- RES icon;
- Variant default_value;
-
- ScriptCodeCompletionOption() {}
-
- ScriptCodeCompletionOption(const String &p_text, Kind p_kind) {
- display = p_text;
- insert_text = p_text;
- kind = p_kind;
- }
-};
-
class ScriptCodeCompletionCache {
static ScriptCodeCompletionCache *singleton;
@@ -248,7 +229,8 @@ public:
virtual ~ScriptCodeCompletionCache() {}
};
-class ScriptLanguage {
+class ScriptLanguage : public Object {
+ GDCLASS(ScriptLanguage, Object)
public:
virtual String get_name() const = 0;
@@ -274,13 +256,32 @@ public:
String message;
};
+ enum TemplateLocation {
+ TEMPLATE_BUILT_IN,
+ TEMPLATE_EDITOR,
+ TEMPLATE_PROJECT
+ };
+
+ struct ScriptTemplate {
+ String inherit = "Object";
+ String name;
+ String description;
+ String content;
+ int id = 0;
+ TemplateLocation origin = TemplateLocation::TEMPLATE_BUILT_IN;
+
+ String get_hash() const {
+ return itos(origin) + inherit + name;
+ }
+ };
+
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;
virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0;
virtual void get_string_delimiters(List<String> *p_delimiters) const = 0;
- 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 Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { return Ref<Script>(); }
+ virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) { return Vector<ScriptTemplate>(); }
virtual bool is_using_templates() { return false; }
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 ""; }
@@ -294,19 +295,64 @@ public:
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
virtual bool overrides_external_editor() { return false; }
- virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
+ /* Keep enum in Sync with: */
+ /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
+ enum CodeCompletionKind {
+ CODE_COMPLETION_KIND_CLASS,
+ CODE_COMPLETION_KIND_FUNCTION,
+ CODE_COMPLETION_KIND_SIGNAL,
+ CODE_COMPLETION_KIND_VARIABLE,
+ CODE_COMPLETION_KIND_MEMBER,
+ CODE_COMPLETION_KIND_ENUM,
+ CODE_COMPLETION_KIND_CONSTANT,
+ CODE_COMPLETION_KIND_NODE_PATH,
+ CODE_COMPLETION_KIND_FILE_PATH,
+ CODE_COMPLETION_KIND_PLAIN_TEXT,
+ CODE_COMPLETION_KIND_MAX
+ };
+
+ enum CodeCompletionLocation {
+ LOCATION_LOCAL = 0,
+ LOCATION_PARENT_MASK = 1 << 8,
+ LOCATION_OTHER_USER_CODE = 1 << 9,
+ LOCATION_OTHER = 1 << 10,
+ };
+
+ struct CodeCompletionOption {
+ CodeCompletionKind kind = CODE_COMPLETION_KIND_PLAIN_TEXT;
+ String display;
+ String insert_text;
+ Color font_color;
+ RES icon;
+ Variant default_value;
+ Vector<Pair<int, int>> matches;
+ int location = LOCATION_OTHER;
+
+ CodeCompletionOption() {}
+
+ CodeCompletionOption(const String &p_text, CodeCompletionKind p_kind, int p_location = LOCATION_OTHER) {
+ display = p_text;
+ insert_text = p_text;
+ kind = p_kind;
+ location = p_location;
+ }
+ };
+
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
+
+ enum LookupResultType {
+ LOOKUP_RESULT_SCRIPT_LOCATION,
+ LOOKUP_RESULT_CLASS,
+ LOOKUP_RESULT_CLASS_CONSTANT,
+ LOOKUP_RESULT_CLASS_PROPERTY,
+ LOOKUP_RESULT_CLASS_METHOD,
+ LOOKUP_RESULT_CLASS_ENUM,
+ LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE,
+ LOOKUP_RESULT_MAX
+ };
struct LookupResult {
- enum Type {
- RESULT_SCRIPT_LOCATION,
- RESULT_CLASS,
- RESULT_CLASS_CONSTANT,
- RESULT_CLASS_PROPERTY,
- RESULT_CLASS_METHOD,
- RESULT_CLASS_ENUM,
- RESULT_CLASS_TBD_GLOBALSCOPE
- };
- Type type;
+ LookupResultType type;
Ref<Script> script;
String class_name;
String class_member;
@@ -384,42 +430,42 @@ public:
extern uint8_t script_encryption_key[32];
class PlaceHolderScriptInstance : public ScriptInstance {
- Object *owner;
+ Object *owner = nullptr;
List<PropertyInfo> properties;
Map<StringName, Variant> values;
Map<StringName, Variant> constants;
- ScriptLanguage *language;
+ ScriptLanguage *language = nullptr;
Ref<Script> script;
public:
- virtual bool set(const StringName &p_name, const Variant &p_value);
- virtual bool get(const StringName &p_name, Variant &r_ret) const;
- virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
-
- virtual void get_method_list(List<MethodInfo> *p_list) const;
- virtual bool has_method(const StringName &p_method) const;
- virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); }
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ virtual bool set(const StringName &p_name, const Variant &p_value) override;
+ virtual bool get(const StringName &p_name, Variant &r_ret) const override;
+ 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 void get_method_list(List<MethodInfo> *p_list) const override;
+ virtual bool has_method(const StringName &p_method) const override;
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
- virtual void notification(int p_notification) {}
+ virtual void notification(int p_notification) override {}
- virtual Ref<Script> get_script() const { return script; }
+ virtual Ref<Script> get_script() const override { return script; }
- virtual ScriptLanguage *get_language() { return language; }
+ virtual ScriptLanguage *get_language() override { return language; }
- Object *get_owner() { return owner; }
+ Object *get_owner() override { return owner; }
void update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values); //likely changed in editor
- virtual bool is_placeholder() const { return true; }
+ virtual bool is_placeholder() const override { return true; }
- 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 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 { return Vector<Multiplayer::RPCConfig>(); }
+ virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override { return Vector<Multiplayer::RPCConfig>(); }
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
new file mode 100644
index 0000000000..21d7685674
--- /dev/null
+++ b/core/object/script_language_extension.cpp
@@ -0,0 +1,180 @@
+/*************************************************************************/
+/* script_language_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "script_language_extension.h"
+
+void ScriptExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_editor_can_reload_from_file);
+ GDVIRTUAL_BIND(_placeholder_erased, "placeholder");
+
+ GDVIRTUAL_BIND(_can_instantiate);
+ GDVIRTUAL_BIND(_get_base_script);
+ GDVIRTUAL_BIND(_inherits_script, "script");
+
+ GDVIRTUAL_BIND(_get_instance_base_type);
+ GDVIRTUAL_BIND(_instance_create, "for_object");
+ GDVIRTUAL_BIND(_placeholder_instance_create, "for_object");
+
+ GDVIRTUAL_BIND(_instance_has, "object");
+
+ GDVIRTUAL_BIND(_has_source_code);
+ GDVIRTUAL_BIND(_get_source_code);
+
+ GDVIRTUAL_BIND(_set_source_code, "code");
+ GDVIRTUAL_BIND(_reload, "keep_state");
+
+ GDVIRTUAL_BIND(_get_documentation);
+
+ GDVIRTUAL_BIND(_has_method, "method");
+ GDVIRTUAL_BIND(_get_method_info, "method");
+
+ GDVIRTUAL_BIND(_is_tool);
+ GDVIRTUAL_BIND(_is_valid);
+ GDVIRTUAL_BIND(_get_language);
+
+ GDVIRTUAL_BIND(_has_script_signal, "signal");
+ GDVIRTUAL_BIND(_get_script_signal_list);
+
+ GDVIRTUAL_BIND(_get_property_default_value, "property");
+
+ GDVIRTUAL_BIND(_update_exports);
+ GDVIRTUAL_BIND(_get_script_method_list);
+ GDVIRTUAL_BIND(_get_script_property_list);
+
+ GDVIRTUAL_BIND(_get_member_line, "member");
+
+ GDVIRTUAL_BIND(_get_constants);
+ GDVIRTUAL_BIND(_get_members);
+ GDVIRTUAL_BIND(_is_placeholder_fallback_enabled);
+
+ GDVIRTUAL_BIND(_get_rpc_methods);
+}
+
+void ScriptLanguageExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_name);
+ GDVIRTUAL_BIND(_init);
+ GDVIRTUAL_BIND(_get_type);
+ GDVIRTUAL_BIND(_get_extension);
+ GDVIRTUAL_BIND(_execute_file, "path");
+ GDVIRTUAL_BIND(_finish);
+
+ GDVIRTUAL_BIND(_get_reserved_words);
+ GDVIRTUAL_BIND(_is_control_flow_keyword, "keyword");
+ GDVIRTUAL_BIND(_get_comment_delimiters);
+ GDVIRTUAL_BIND(_get_string_delimiters);
+ GDVIRTUAL_BIND(_make_template, "template", "class_name", "base_class_name");
+ GDVIRTUAL_BIND(_get_built_in_templates, "object");
+ GDVIRTUAL_BIND(_is_using_templates);
+ GDVIRTUAL_BIND(_validate, "script", "path", "validate_functions", "validate_errors", "validate_warnings", "validate_safe_lines");
+
+ GDVIRTUAL_BIND(_validate_path, "path");
+ GDVIRTUAL_BIND(_create_script);
+ GDVIRTUAL_BIND(_has_named_classes);
+ GDVIRTUAL_BIND(_supports_builtin_mode);
+ GDVIRTUAL_BIND(_supports_documentation);
+ GDVIRTUAL_BIND(_can_inherit_from_file);
+ GDVIRTUAL_BIND(_find_function, "class_name", "function_name");
+ GDVIRTUAL_BIND(_make_function, "class_name", "function_name", "function_args");
+ GDVIRTUAL_BIND(_open_in_external_editor, "script", "line", "column");
+ GDVIRTUAL_BIND(_overrides_external_editor);
+
+ GDVIRTUAL_BIND(_complete_code, "code", "path", "owner");
+ GDVIRTUAL_BIND(_lookup_code, "code", "symbol", "path", "owner");
+ GDVIRTUAL_BIND(_auto_indent_code, "code", "from_line", "to_line");
+
+ GDVIRTUAL_BIND(_add_global_constant, "name", "value");
+ GDVIRTUAL_BIND(_add_named_global_constant, "name", "value");
+ GDVIRTUAL_BIND(_remove_named_global_constant, "name");
+
+ GDVIRTUAL_BIND(_thread_enter);
+ GDVIRTUAL_BIND(_thread_exit);
+ GDVIRTUAL_BIND(_debug_get_error);
+ GDVIRTUAL_BIND(_debug_get_stack_level_count);
+
+ GDVIRTUAL_BIND(_debug_get_stack_level_line, "level");
+ GDVIRTUAL_BIND(_debug_get_stack_level_function, "level");
+ GDVIRTUAL_BIND(_debug_get_stack_level_locals, "level", "max_subitems", "max_depth");
+ GDVIRTUAL_BIND(_debug_get_stack_level_members, "level", "max_subitems", "max_depth");
+ GDVIRTUAL_BIND(_debug_get_stack_level_instance, "level");
+ GDVIRTUAL_BIND(_debug_get_globals, "max_subitems", "max_depth");
+ GDVIRTUAL_BIND(_debug_parse_stack_level_expression, "level", "expression", "max_subitems", "max_depth");
+
+ GDVIRTUAL_BIND(_debug_get_current_stack_info);
+
+ GDVIRTUAL_BIND(_reload_all_scripts);
+ GDVIRTUAL_BIND(_reload_tool_script, "script", "soft_reload");
+
+ GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_get_public_functions);
+ GDVIRTUAL_BIND(_get_public_constants);
+
+ GDVIRTUAL_BIND(_profiling_start);
+ GDVIRTUAL_BIND(_profiling_stop);
+
+ GDVIRTUAL_BIND(_profiling_get_accumulated_data, "info_array", "info_max");
+ GDVIRTUAL_BIND(_profiling_get_frame_data, "info_array", "info_max");
+
+ GDVIRTUAL_BIND(_alloc_instance_binding_data, "object");
+ GDVIRTUAL_BIND(_free_instance_binding_data, "data");
+
+ GDVIRTUAL_BIND(_refcount_incremented_instance_binding, "object");
+ GDVIRTUAL_BIND(_refcount_decremented_instance_binding, "object");
+
+ GDVIRTUAL_BIND(_frame);
+
+ GDVIRTUAL_BIND(_handles_global_class_type, "type");
+ GDVIRTUAL_BIND(_get_global_class_name, "path");
+
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_SCRIPT_LOCATION);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_CONSTANT);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_PROPERTY);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_METHOD);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ENUM);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_MAX);
+
+ BIND_ENUM_CONSTANT(LOCATION_LOCAL);
+ BIND_ENUM_CONSTANT(LOCATION_PARENT_MASK);
+ BIND_ENUM_CONSTANT(LOCATION_OTHER_USER_CODE);
+ BIND_ENUM_CONSTANT(LOCATION_OTHER);
+
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_CLASS);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_FUNCTION);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_SIGNAL);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_VARIABLE);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_MEMBER);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_ENUM);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_CONSTANT);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_NODE_PATH);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_FILE_PATH);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_PLAIN_TEXT);
+ BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_MAX);
+}
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
new file mode 100644
index 0000000000..40f18ab30d
--- /dev/null
+++ b/core/object/script_language_extension.h
@@ -0,0 +1,835 @@
+/*************************************************************************/
+/* script_language_extension.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SCRIPT_LANGUAGE_EXTENSION_H
+#define SCRIPT_LANGUAGE_EXTENSION_H
+
+#include "core/extension/ext_wrappers.gen.inc"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+#include "core/variant/typed_array.h"
+
+class ScriptExtension : public Script {
+ GDCLASS(ScriptExtension, Script)
+
+protected:
+ EXBIND0R(bool, editor_can_reload_from_file)
+
+ GDVIRTUAL1(_placeholder_erased, GDNativePtr<void>)
+ virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override {
+ GDVIRTUAL_CALL(_placeholder_erased, p_placeholder);
+ }
+
+ static void _bind_methods();
+
+public:
+ EXBIND0RC(bool, can_instantiate)
+ EXBIND0RC(Ref<Script>, get_base_script)
+ EXBIND1RC(bool, inherits_script, const Ref<Script> &)
+ EXBIND0RC(StringName, get_instance_base_type)
+
+ GDVIRTUAL1RC(GDNativePtr<void>, _instance_create, Object *)
+ virtual ScriptInstance *instance_create(Object *p_this) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_instance_create, p_this, ret);
+ return reinterpret_cast<ScriptInstance *>(ret.operator void *());
+ }
+ GDVIRTUAL1RC(GDNativePtr<void>, _placeholder_instance_create, Object *)
+ PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_placeholder_instance_create, p_this, ret);
+ return reinterpret_cast<PlaceHolderScriptInstance *>(ret.operator void *());
+ }
+
+ EXBIND1RC(bool, instance_has, const Object *)
+ EXBIND0RC(bool, has_source_code)
+ EXBIND0RC(String, get_source_code)
+ EXBIND1(set_source_code, const String &)
+ EXBIND1R(Error, reload, bool)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_documentation)
+#ifdef TOOLS_ENABLED
+ virtual Vector<DocData::ClassDoc> get_documentation() const override {
+ TypedArray<Dictionary> doc;
+ GDVIRTUAL_REQUIRED_CALL(_get_documentation, doc);
+
+ Vector<DocData::ClassDoc> class_doc;
+#ifndef _MSC_VER
+#warning missing conversion from documentation to ClassDoc
+#endif
+ return class_doc;
+ }
+#endif // TOOLS_ENABLED
+
+ EXBIND1RC(bool, has_method, const StringName &)
+
+ GDVIRTUAL1RC(Dictionary, _get_method_info, const StringName &)
+ virtual MethodInfo get_method_info(const StringName &p_method) const override {
+ Dictionary mi;
+ GDVIRTUAL_REQUIRED_CALL(_get_method_info, p_method, mi);
+ return MethodInfo::from_dict(mi);
+ }
+
+ EXBIND0RC(bool, is_tool)
+ EXBIND0RC(bool, is_valid)
+
+ EXBIND0RC(ScriptLanguage *, get_language)
+ EXBIND1RC(bool, has_script_signal, const StringName &)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_script_signal_list)
+
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override {
+ TypedArray<Dictionary> sl;
+ GDVIRTUAL_REQUIRED_CALL(_get_script_signal_list, sl);
+ for (int i = 0; i < sl.size(); i++) {
+ r_signals->push_back(MethodInfo::from_dict(sl[i]));
+ }
+ }
+
+ GDVIRTUAL1RC(bool, _has_property_default_value, const StringName &)
+ GDVIRTUAL1RC(Variant, _get_property_default_value, const StringName &)
+
+ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const override {
+ bool has_dv = false;
+ if (!GDVIRTUAL_REQUIRED_CALL(_has_property_default_value, p_property, has_dv) || !has_dv) {
+ return false;
+ }
+ Variant ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_property_default_value, p_property, ret);
+ return ret;
+ }
+
+ EXBIND0(update_exports)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_script_method_list)
+
+ virtual void get_script_method_list(List<MethodInfo> *r_methods) const override {
+ TypedArray<Dictionary> sl;
+ GDVIRTUAL_REQUIRED_CALL(_get_script_method_list, sl);
+ for (int i = 0; i < sl.size(); i++) {
+ r_methods->push_back(MethodInfo::from_dict(sl[i]));
+ }
+ }
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_script_property_list)
+
+ virtual void get_script_property_list(List<PropertyInfo> *r_propertys) const override {
+ TypedArray<Dictionary> sl;
+ GDVIRTUAL_REQUIRED_CALL(_get_script_property_list, sl);
+ for (int i = 0; i < sl.size(); i++) {
+ r_propertys->push_back(PropertyInfo::from_dict(sl[i]));
+ }
+ }
+
+ EXBIND1RC(int, get_member_line, const StringName &)
+
+ GDVIRTUAL0RC(Dictionary, _get_constants)
+
+ virtual void get_constants(Map<StringName, Variant> *p_constants) override {
+ Dictionary constants;
+ GDVIRTUAL_REQUIRED_CALL(_get_constants, constants);
+ List<Variant> keys;
+ constants.get_key_list(&keys);
+ for (const Variant &K : keys) {
+ p_constants->insert(K, constants[K]);
+ }
+ }
+ GDVIRTUAL0RC(TypedArray<StringName>, _get_members)
+ virtual void get_members(Set<StringName> *p_members) override {
+ TypedArray<StringName> members;
+ GDVIRTUAL_REQUIRED_CALL(_get_members, members);
+ for (int i = 0; i < members.size(); i++) {
+ p_members->insert(members[i]);
+ }
+ }
+
+ EXBIND0RC(bool, is_placeholder_fallback_enabled)
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_rpc_methods)
+
+ 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;
+ }
+
+ ScriptExtension() {}
+};
+
+typedef ScriptLanguage::ProfilingInfo ScriptLanguageExtensionProfilingInfo;
+
+GDVIRTUAL_NATIVE_PTR(ScriptLanguageExtensionProfilingInfo)
+
+class ScriptLanguageExtension : public ScriptLanguage {
+ GDCLASS(ScriptLanguageExtension, ScriptLanguage)
+protected:
+ static void _bind_methods();
+
+public:
+ EXBIND0RC(String, get_name)
+
+ EXBIND0(init)
+ EXBIND0RC(String, get_type)
+ EXBIND0RC(String, get_extension)
+ EXBIND1R(Error, execute_file, const String &)
+ EXBIND0(finish)
+
+ /* EDITOR FUNCTIONS */
+
+ GDVIRTUAL0RC(Vector<String>, _get_reserved_words)
+
+ virtual void get_reserved_words(List<String> *p_words) const override {
+ Vector<String> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_reserved_words, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_words->push_back(ret[i]);
+ }
+ }
+ EXBIND1RC(bool, is_control_flow_keyword, String)
+
+ GDVIRTUAL0RC(Vector<String>, _get_comment_delimiters)
+
+ virtual void get_comment_delimiters(List<String> *p_words) const override {
+ Vector<String> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_comment_delimiters, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_words->push_back(ret[i]);
+ }
+ }
+
+ GDVIRTUAL0RC(Vector<String>, _get_string_delimiters)
+
+ virtual void get_string_delimiters(List<String> *p_words) const override {
+ Vector<String> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_string_delimiters, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_words->push_back(ret[i]);
+ }
+ }
+
+ EXBIND3RC(Ref<Script>, make_template, const String &, const String &, const String &)
+
+ GDVIRTUAL1RC(TypedArray<Dictionary>, _get_built_in_templates, StringName)
+
+ virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_built_in_templates, p_object, ret);
+ Vector<ScriptTemplate> stret;
+ for (int i = 0; i < ret.size(); i++) {
+ Dictionary d = ret[i];
+ ScriptTemplate st;
+ ERR_CONTINUE(!d.has("inherit"));
+ st.inherit = d["inherit"];
+ ERR_CONTINUE(!d.has("name"));
+ st.name = d["name"];
+ ERR_CONTINUE(!d.has("description"));
+ st.description = d["description"];
+ ERR_CONTINUE(!d.has("content"));
+ st.content = d["content"];
+ ERR_CONTINUE(!d.has("id"));
+ st.id = d["id"];
+ ERR_CONTINUE(!d.has("origin"));
+ st.origin = TemplateLocation(int(d["origin"]));
+ stret.push_back(st);
+ }
+ return stret;
+ }
+
+ EXBIND0R(bool, is_using_templates)
+
+ GDVIRTUAL6RC(Dictionary, _validate, const String &, const String &, bool, bool, bool, bool)
+ 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 override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_validate, p_script, p_path, r_functions != nullptr, r_errors != nullptr, r_warnings != nullptr, r_safe_lines != nullptr, ret);
+ if (!ret.has("valid")) {
+ return false;
+ }
+ if (r_functions != nullptr && ret.has("functions")) {
+ Vector<String> functions = ret["functions"];
+ for (int i = 0; i < functions.size(); i++) {
+ r_functions->push_back(functions[i]);
+ }
+ }
+ if (r_errors != nullptr && ret.has("errors")) {
+ Array errors = ret["errors"];
+ for (int i = 0; i < errors.size(); i++) {
+ Dictionary err = errors[i];
+ ERR_CONTINUE(!err.has("line"));
+ ERR_CONTINUE(!err.has("column"));
+ ERR_CONTINUE(!err.has("message"));
+
+ ScriptError serr;
+ serr.line = err["line"];
+ serr.column = err["column"];
+ serr.message = err["message"];
+
+ r_errors->push_back(serr);
+ }
+ }
+ if (r_warnings != nullptr && ret.has("warnings")) {
+ ERR_FAIL_COND_V(!ret.has("warnings"), false);
+ Array warnings = ret["warnings"];
+ for (int i = 0; i < warnings.size(); i++) {
+ Dictionary warn = warnings[i];
+ ERR_CONTINUE(!warn.has("start_line"));
+ ERR_CONTINUE(!warn.has("end_line"));
+ ERR_CONTINUE(!warn.has("leftmost_column"));
+ ERR_CONTINUE(!warn.has("rightmost_column"));
+ ERR_CONTINUE(!warn.has("code"));
+ ERR_CONTINUE(!warn.has("string_code"));
+ ERR_CONTINUE(!warn.has("message"));
+
+ Warning swarn;
+ swarn.start_line = warn["start_line"];
+ swarn.end_line = warn["end_line"];
+ swarn.leftmost_column = warn["leftmost_column"];
+ swarn.rightmost_column = warn["rightmost_column"];
+ swarn.code = warn["code"];
+ swarn.string_code = warn["string_code"];
+ swarn.message = warn["message"];
+
+ r_warnings->push_back(swarn);
+ }
+ }
+ if (r_safe_lines != nullptr && ret.has("safe_lines")) {
+ PackedInt32Array safe_lines = ret["safe_lines"];
+ for (int i = 0; i < safe_lines.size(); i++) {
+ r_safe_lines->insert(safe_lines[i]);
+ }
+ }
+ return ret["valid"];
+ }
+
+ EXBIND1RC(String, validate_path, const String &)
+ GDVIRTUAL0RC(Object *, _create_script)
+ Script *create_script() const override {
+ Object *ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_create_script, ret);
+ return Object::cast_to<Script>(ret);
+ }
+ EXBIND0RC(bool, has_named_classes)
+ EXBIND0RC(bool, supports_builtin_mode)
+ EXBIND0RC(bool, supports_documentation)
+ EXBIND0RC(bool, can_inherit_from_file)
+
+ EXBIND2RC(int, find_function, const String &, const String &)
+ EXBIND3RC(String, make_function, const String &, const String &, const PackedStringArray &)
+ EXBIND3R(Error, open_in_external_editor, const Ref<Script> &, int, int)
+ EXBIND0R(bool, overrides_external_editor)
+
+ GDVIRTUAL3RC(Dictionary, _complete_code, const String &, const String &, Object *)
+
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_complete_code, p_code, p_path, p_owner, ret);
+ if (!ret.has("result")) {
+ return ERR_UNAVAILABLE;
+ }
+
+ if (r_options != nullptr && ret.has("options")) {
+ Array options = ret["options"];
+ for (int i = 0; i < options.size(); i++) {
+ Dictionary op = options[i];
+ CodeCompletionOption option;
+ ERR_CONTINUE(!op.has("kind"));
+ option.kind = CodeCompletionKind(int(op["kind"]));
+ ERR_CONTINUE(!op.has("display"));
+ option.display = op["display"];
+ ERR_CONTINUE(!op.has("insert_text"));
+ option.insert_text = op["insert_text"];
+ ERR_CONTINUE(!op.has("font_color"));
+ option.font_color = op["font_color"];
+ ERR_CONTINUE(!op.has("icon"));
+ option.icon = op["icon"];
+ ERR_CONTINUE(!op.has("default_value"));
+ option.default_value = op["default_value"];
+ ERR_CONTINUE(!op.has("location"));
+ option.location = op["location"];
+ if (op.has("matches")) {
+ PackedInt32Array matches = op["matches"];
+ ERR_CONTINUE(matches.size() & 1);
+ for (int j = 0; j < matches.size(); j += 2) {
+ option.matches.push_back(Pair<int, int>(matches[j], matches[j + 1]));
+ }
+ }
+ r_options->push_back(option);
+ }
+ }
+
+ ERR_FAIL_COND_V(!ret.has("force"), ERR_UNAVAILABLE);
+ r_force = ret["force"];
+ ERR_FAIL_COND_V(!ret.has("call_hint"), ERR_UNAVAILABLE);
+ r_call_hint = ret["call_hint"];
+ ERR_FAIL_COND_V(!ret.has("result"), ERR_UNAVAILABLE);
+ Error result = Error(int(ret["result"]));
+
+ return result;
+ }
+
+ GDVIRTUAL4RC(Dictionary, _lookup_code, const String &, const String &, const String &, Object *)
+
+ virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_lookup_code, p_code, p_symbol, p_path, p_owner, ret);
+ if (!ret.has("result")) {
+ return ERR_UNAVAILABLE;
+ }
+
+ ERR_FAIL_COND_V(!ret.has("type"), ERR_UNAVAILABLE);
+ r_result.type = LookupResultType(int(ret["type"]));
+ ERR_FAIL_COND_V(!ret.has("script"), ERR_UNAVAILABLE);
+ r_result.script = ret["script"];
+ ERR_FAIL_COND_V(!ret.has("class_name"), ERR_UNAVAILABLE);
+ r_result.class_name = ret["class_name"];
+ ERR_FAIL_COND_V(!ret.has("class_path"), ERR_UNAVAILABLE);
+ r_result.class_path = ret["class_path"];
+ ERR_FAIL_COND_V(!ret.has("location"), ERR_UNAVAILABLE);
+ r_result.location = ret["location"];
+
+ Error result = Error(int(ret["result"]));
+
+ return result;
+ }
+
+ GDVIRTUAL3RC(String, _auto_indent_code, const String &, int, int)
+ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override {
+ String ret;
+ GDVIRTUAL_REQUIRED_CALL(_auto_indent_code, p_code, p_from_line, p_to_line, ret);
+ p_code = ret;
+ }
+ EXBIND2(add_global_constant, const StringName &, const Variant &)
+ EXBIND2(add_named_global_constant, const StringName &, const Variant &)
+ EXBIND1(remove_named_global_constant, const StringName &)
+
+ /* MULTITHREAD FUNCTIONS */
+
+ //some VMs need to be notified of thread creation/exiting to allocate a stack
+ EXBIND0(thread_enter)
+ EXBIND0(thread_exit)
+
+ EXBIND0RC(String, debug_get_error)
+ EXBIND0RC(int, debug_get_stack_level_count)
+ EXBIND1RC(int, debug_get_stack_level_line, int)
+ EXBIND1RC(String, debug_get_stack_level_function, int)
+ EXBIND1RC(String, debug_get_stack_level_source, int)
+
+ GDVIRTUAL3R(Dictionary, _debug_get_stack_level_locals, int, int, int)
+ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_locals, p_level, p_max_subitems, p_max_depth, ret);
+ if (ret.size() == 0) {
+ return;
+ }
+ if (p_locals != nullptr && ret.has("locals")) {
+ PackedStringArray strings = ret["locals"];
+ for (int i = 0; i < strings.size(); i++) {
+ p_locals->push_back(strings[i]);
+ }
+ }
+ if (p_values != nullptr && ret.has("values")) {
+ Array values = ret["values"];
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+ }
+ GDVIRTUAL3R(Dictionary, _debug_get_stack_level_members, int, int, int)
+ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_members, p_level, p_max_subitems, p_max_depth, ret);
+ if (ret.size() == 0) {
+ return;
+ }
+ if (p_members != nullptr && ret.has("members")) {
+ PackedStringArray strings = ret["members"];
+ for (int i = 0; i < strings.size(); i++) {
+ p_members->push_back(strings[i]);
+ }
+ }
+ if (p_values != nullptr && ret.has("values")) {
+ Array values = ret["values"];
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+ }
+ GDVIRTUAL1R(GDNativePtr<void>, _debug_get_stack_level_instance, int)
+
+ virtual ScriptInstance *debug_get_stack_level_instance(int p_level) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_stack_level_instance, p_level, ret);
+ return reinterpret_cast<ScriptInstance *>(ret.operator void *());
+ }
+ GDVIRTUAL2R(Dictionary, _debug_get_globals, int, int)
+ virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_globals, p_max_subitems, p_max_depth, ret);
+ if (ret.size() == 0) {
+ return;
+ }
+ if (p_globals != nullptr && ret.has("globals")) {
+ PackedStringArray strings = ret["globals"];
+ for (int i = 0; i < strings.size(); i++) {
+ p_globals->push_back(strings[i]);
+ }
+ }
+ if (p_values != nullptr && ret.has("values")) {
+ Array values = ret["values"];
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+ }
+
+ EXBIND4R(String, debug_parse_stack_level_expression, int, const String &, int, int)
+
+ GDVIRTUAL0R(TypedArray<Dictionary>, _debug_get_current_stack_info)
+ virtual Vector<StackInfo> debug_get_current_stack_info() override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_debug_get_current_stack_info, ret);
+ Vector<StackInfo> sret;
+ for (int i = 0; i < ret.size(); i++) {
+ StackInfo si;
+ Dictionary d = ret[i];
+ ERR_CONTINUE(!d.has("file"));
+ ERR_CONTINUE(!d.has("func"));
+ ERR_CONTINUE(!d.has("line"));
+ si.file = d["file"];
+ si.func = d["func"];
+ si.line = d["line"];
+ sret.push_back(si);
+ }
+ return sret;
+ }
+
+ EXBIND0(reload_all_scripts)
+ EXBIND2(reload_tool_script, const Ref<Script> &, bool)
+ /* LOADER FUNCTIONS */
+
+ GDVIRTUAL0RC(PackedStringArray, _get_recognized_extensions)
+
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override {
+ PackedStringArray ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_recognized_extensions, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_extensions->push_back(ret[i]);
+ }
+ }
+
+ GDVIRTUAL0RC(TypedArray<Dictionary>, _get_public_functions)
+ virtual void get_public_functions(List<MethodInfo> *p_functions) const override {
+ TypedArray<Dictionary> ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_public_functions, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ MethodInfo mi = MethodInfo::from_dict(ret[i]);
+ p_functions->push_back(mi);
+ }
+ }
+ GDVIRTUAL0RC(Dictionary, _get_public_constants)
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_public_constants, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ Dictionary d = ret[i];
+ ERR_CONTINUE(!d.has("name"));
+ ERR_CONTINUE(!d.has("value"));
+ p_constants->push_back(Pair<String, Variant>(d["name"], d["value"]));
+ }
+ }
+
+ EXBIND0(profiling_start)
+ EXBIND0(profiling_stop)
+
+ GDVIRTUAL2R(int, _profiling_get_accumulated_data, GDNativePtr<ScriptLanguageExtensionProfilingInfo>, int)
+
+ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override {
+ int ret = 0;
+ GDVIRTUAL_REQUIRED_CALL(_profiling_get_accumulated_data, p_info_arr, p_info_max, ret);
+ return ret;
+ }
+
+ GDVIRTUAL2R(int, _profiling_get_frame_data, GDNativePtr<ScriptLanguageExtensionProfilingInfo>, int)
+
+ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override {
+ int ret = 0;
+ GDVIRTUAL_REQUIRED_CALL(_profiling_get_accumulated_data, p_info_arr, p_info_max, ret);
+ return ret;
+ }
+
+ GDVIRTUAL1R(GDNativePtr<void>, _alloc_instance_binding_data, Object *)
+
+ virtual void *alloc_instance_binding_data(Object *p_object) override {
+ GDNativePtr<void> ret = nullptr;
+ GDVIRTUAL_REQUIRED_CALL(_alloc_instance_binding_data, p_object, ret);
+ return ret.operator void *();
+ }
+
+ GDVIRTUAL1(_free_instance_binding_data, GDNativePtr<void>)
+
+ virtual void free_instance_binding_data(void *p_data) override {
+ GDVIRTUAL_REQUIRED_CALL(_free_instance_binding_data, p_data);
+ }
+
+ EXBIND1(refcount_incremented_instance_binding, Object *)
+ EXBIND1R(bool, refcount_decremented_instance_binding, Object *)
+
+ EXBIND0(frame)
+
+ EXBIND1RC(bool, handles_global_class_type, const String &)
+
+ GDVIRTUAL1RC(Dictionary, _get_global_class_name, const String &)
+
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const override {
+ Dictionary ret;
+ GDVIRTUAL_REQUIRED_CALL(_get_global_class_name, p_path, ret);
+ if (!ret.has("name")) {
+ return String();
+ }
+ if (r_base_type != nullptr && ret.has("base_type")) {
+ *r_base_type = ret["base_type"];
+ }
+ if (r_icon_path != nullptr && ret.has("icon_path")) {
+ *r_icon_path = ret["icon_path"];
+ }
+ return ret["name"];
+ }
+};
+
+VARIANT_ENUM_CAST(ScriptLanguageExtension::LookupResultType)
+VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionKind)
+VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionLocation)
+
+class ScriptInstanceExtension : public ScriptInstance {
+public:
+ const GDNativeExtensionScriptInstanceInfo *native_info;
+ GDNativeExtensionScriptInstanceDataPtr instance = nullptr;
+
+// There should not be warnings on explicit casts.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+
+ virtual bool set(const StringName &p_name, const Variant &p_value) override {
+ if (native_info->set_func) {
+ return native_info->set_func(instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value);
+ }
+ return false;
+ }
+ virtual bool get(const StringName &p_name, Variant &r_ret) const override {
+ if (native_info->get_func) {
+ return native_info->get_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ }
+ return false;
+ }
+ virtual void get_property_list(List<PropertyInfo> *p_list) const override {
+ if (native_info->get_property_list_func) {
+ uint32_t pcount;
+ const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(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));
+ }
+ if (native_info->free_property_list_func) {
+ native_info->free_property_list_func(instance, pinfo);
+ }
+ }
+ }
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override {
+ if (native_info->get_property_type_func) {
+ GDNativeBool is_valid = 0;
+ GDNativeVariantType type = native_info->get_property_type_func(instance, (const GDNativeStringNamePtr)&p_name, &is_valid);
+ if (r_is_valid) {
+ *r_is_valid = is_valid != 0;
+ }
+
+ return Variant::Type(type);
+ }
+ return Variant::NIL;
+ }
+
+ virtual Object *get_owner() override {
+ if (native_info->get_owner_func) {
+ return (Object *)native_info->get_owner_func(instance);
+ }
+ return nullptr;
+ }
+ static void _add_property_with_state(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata) {
+ List<Pair<StringName, Variant>> *state = (List<Pair<StringName, Variant>> *)p_userdata;
+ state->push_back(Pair<StringName, Variant>(*(const StringName *)p_name, *(const Variant *)p_value));
+ }
+ virtual void get_property_state(List<Pair<StringName, Variant>> &state) override {
+ if (native_info->get_property_state_func) {
+ native_info->get_property_state_func(instance, _add_property_with_state, &state);
+ }
+ }
+
+ virtual void get_method_list(List<MethodInfo> *p_list) const override {
+ if (native_info->get_method_list_func) {
+ 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(Variant::Type(minfo[i].return_value.type), minfo[i].return_value.class_name, PropertyHint(minfo[i].return_value.hint), minfo[i].return_value.hint_string, minfo[i].return_value.usage, minfo[i].return_value.class_name);
+ for (uint32_t j = 0; j < minfo[i].argument_count; j++) {
+ m.arguments.push_back(PropertyInfo(Variant::Type(minfo[i].arguments[j].type), minfo[i].arguments[j].class_name, PropertyHint(minfo[i].arguments[j].hint), minfo[i].arguments[j].hint_string, minfo[i].arguments[j].usage, minfo[i].arguments[j].class_name));
+ }
+ 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);
+ }
+ if (native_info->free_method_list_func) {
+ native_info->free_method_list_func(instance, minfo);
+ }
+ }
+ }
+ virtual bool has_method(const StringName &p_method) const override {
+ if (native_info->has_method_func) {
+ return native_info->has_method_func(instance, (GDNativeStringNamePtr)&p_method);
+ }
+ return false;
+ }
+
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
+ Variant ret;
+ if (native_info->call_func) {
+ GDNativeCallError ce;
+ native_info->call_func(instance, (const GDNativeStringNamePtr)&p_method, (const GDNativeVariantPtr *)p_args, p_argcount, (GDNativeVariantPtr)&ret, &ce);
+ r_error.error = Callable::CallError::Error(ce.error);
+ r_error.argument = ce.argument;
+ r_error.expected = ce.expected;
+ }
+ return ret;
+ }
+
+ virtual void notification(int p_notification) override {
+ if (native_info->notification_func) {
+ native_info->notification_func(instance, p_notification);
+ }
+ }
+ 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);
+ if (r_valid) {
+ *r_valid = valid != 0;
+ }
+ return ret;
+ }
+ return String();
+ }
+
+ virtual void refcount_incremented() override {
+ if (native_info->refcount_incremented_func) {
+ native_info->refcount_incremented_func(instance);
+ }
+ }
+ virtual bool refcount_decremented() override {
+ if (native_info->refcount_decremented_func) {
+ return native_info->refcount_decremented_func(instance);
+ }
+ return false;
+ }
+
+ virtual Ref<Script> get_script() const override {
+ if (native_info->get_script_func) {
+ GDNativeObjectPtr script = native_info->get_script_func(instance);
+ return Ref<Script>(reinterpret_cast<Script *>(script));
+ }
+ return Ref<Script>();
+ }
+
+ virtual bool is_placeholder() const override {
+ if (native_info->is_placeholder_func) {
+ return native_info->is_placeholder_func(instance);
+ }
+ return false;
+ }
+
+ virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) override {
+ if (native_info->set_fallback_func) {
+ bool ret = native_info->set_fallback_func(instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value);
+ if (r_valid) {
+ *r_valid = ret;
+ }
+ }
+ }
+ virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid) override {
+ Variant ret;
+ if (native_info->get_fallback_func) {
+ bool valid = native_info->get_fallback_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret);
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ }
+ return ret;
+ }
+
+ virtual ScriptLanguage *get_language() override {
+ if (native_info->get_language_func) {
+ GDNativeExtensionScriptLanguagePtr lang = native_info->get_language_func(instance);
+ return reinterpret_cast<ScriptLanguage *>(lang);
+ }
+ return nullptr;
+ ;
+ }
+ virtual ~ScriptInstanceExtension() {
+ if (native_info->free_func) {
+ native_info->free_func(instance);
+ }
+ }
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+};
+
+#endif // SCRIPT_LANGUAGE_EXTENSION_H
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 3459506860..d3c48853f1 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,20 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+void UndoRedo::Operation::delete_reference() {
+ if (type != Operation::TYPE_REFERENCE) {
+ return;
+ }
+ if (ref.is_valid()) {
+ ref.unref();
+ } else {
+ Object *obj = ObjectDB::get_instance(object);
+ if (obj) {
+ memdelete(obj);
+ }
+ }
+}
+
void UndoRedo::_discard_redo() {
if (current_action == actions.size() - 1) {
return;
@@ -41,16 +55,7 @@ void UndoRedo::_discard_redo() {
for (int i = current_action + 1; i < actions.size(); i++) {
for (Operation &E : actions.write[i].do_ops) {
- if (E.type == Operation::TYPE_REFERENCE) {
- if (E.ref.is_valid()) {
- E.ref.unref();
- } else {
- Object *obj = ObjectDB::get_instance(E.object);
- if (obj) {
- memdelete(obj);
- }
- }
- }
+ E.delete_reference();
}
//ERASE do data
}
@@ -97,13 +102,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
for (unsigned int i = 0; i < to_remove.size(); i++) {
List<Operation>::Element *E = to_remove[i];
// Delete all object references
- if (E->get().type == Operation::TYPE_REFERENCE) {
- Object *obj = ObjectDB::get_instance(E->get().object);
-
- if (obj) {
- memdelete(obj);
- }
- }
+ E->get().delete_reference();
E->erase();
}
}
@@ -127,8 +126,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
force_keep_in_merge_ends = false;
}
-void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS
+void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -141,14 +139,13 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA
do_op.type = Operation::TYPE_METHOD;
do_op.name = p_method;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- do_op.args[i] = *argptr[i];
+ for (int i = 0; i < p_argcount; i++) {
+ do_op.args.push_back(*p_args[i]);
}
actions.write[current_action + 1].do_ops.push_back(do_op);
}
-void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS
+void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -168,8 +165,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_method;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- undo_op.args[i] = *argptr[i];
+ for (int i = 0; i < p_argcount; i++) {
+ undo_op.args.push_back(*p_args[i]);
}
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -186,7 +183,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
do_op.type = Operation::TYPE_PROPERTY;
do_op.name = p_property;
- do_op.args[0] = p_value;
+ do_op.args.push_back(p_value);
actions.write[current_action + 1].do_ops.push_back(do_op);
}
@@ -209,7 +206,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
undo_op.type = Operation::TYPE_PROPERTY;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_property;
- undo_op.args[0] = p_value;
+ undo_op.args.push_back(p_value);
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -270,16 +267,7 @@ void UndoRedo::_pop_history_tail() {
}
for (Operation &E : actions.write[0].undo_ops) {
- if (E.type == Operation::TYPE_REFERENCE) {
- if (E.ref.is_valid()) {
- E.ref.unref();
- } else {
- Object *obj = ObjectDB::get_instance(E.object);
- if (obj) {
- memdelete(obj);
- }
- }
- }
+ E.delete_reference();
}
actions.remove_at(0);
@@ -324,23 +312,18 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
switch (op.type) {
case Operation::TYPE_METHOD: {
+ int argc = op.args.size();
Vector<const Variant *> argptrs;
- argptrs.resize(VARIANT_ARG_MAX);
- int argc = 0;
+ argptrs.resize(argc);
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (op.args[i].get_type() == Variant::NIL) {
- break;
- }
+ for (int i = 0; i < argc; i++) {
argptrs.write[i] = &op.args[i];
- argc++;
}
- argptrs.resize(argc);
Callable::CallError ce;
- obj->call(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+ obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT("Error calling method from signal '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+ ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
}
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
@@ -351,7 +334,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
#endif
if (method_callback) {
- method_callback(method_callbck_ud, obj, op.name, VARIANT_ARGS_FROM_ARRAY(op.args));
+ method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
}
} break;
case Operation::TYPE_PROPERTY: {
@@ -449,7 +432,7 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback, void
void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback, void *p_ud) {
method_callback = p_method_callback;
- method_callbck_ud = p_ud;
+ method_callback_ud = p_ud;
}
void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback, void *p_ud) {
@@ -461,25 +444,25 @@ UndoRedo::~UndoRedo() {
clear_history();
}
-Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+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 Variant();
+ 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 Variant();
+ 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 Variant();
+ return;
}
r_error.error = Callable::CallError::CALL_OK;
@@ -487,36 +470,28 @@ Variant UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callabl
Object *object = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) {
- v[i] = *p_args[i + 2];
- }
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- add_do_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- return Variant();
+ add_do_methodp(object, method, p_args + 2, p_argcount - 2);
}
-Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+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 Variant();
+ 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 Variant();
+ 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 Variant();
+ return;
}
r_error.error = Callable::CallError::CALL_OK;
@@ -524,15 +499,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla
Object *object = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(VARIANT_ARG_MAX, p_argcount - 2); ++i) {
- v[i] = *p_args[i + 2];
- }
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- add_undo_method(object, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- return Variant();
+ add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
}
void UndoRedo::_bind_methods() {
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index a757d154e2..63cf3e5cbe 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,10 +46,10 @@ public:
};
typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name);
- Variant _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ 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, VARIANT_ARG_DECLARE);
+ typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
private:
@@ -65,7 +65,9 @@ private:
Ref<RefCounted> ref;
ObjectID object;
StringName name;
- Variant args[VARIANT_ARG_MAX];
+ Vector<Variant> args;
+
+ void delete_reference();
};
struct Action {
@@ -90,7 +92,7 @@ private:
CommitNotifyCallback callback = nullptr;
void *callback_ud = nullptr;
- void *method_callbck_ud = nullptr;
+ void *method_callback_ud = nullptr;
void *prop_callback_ud = nullptr;
MethodNotifyCallback method_callback = nullptr;
@@ -104,8 +106,30 @@ protected:
public:
void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
- void add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
- void add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
+ void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+ void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+ template <typename... VarArgs>
+ void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_do_reference(Object *p_object);