diff options
Diffstat (limited to 'core/object')
| -rw-r--r-- | core/object/class_db.cpp | 101 | ||||
| -rw-r--r-- | core/object/class_db.h | 5 | ||||
| -rw-r--r-- | core/object/make_virtuals.py | 14 | ||||
| -rw-r--r-- | core/object/method_bind.h | 4 | ||||
| -rw-r--r-- | core/object/object.cpp | 134 | ||||
| -rw-r--r-- | core/object/object.h | 29 | ||||
| -rw-r--r-- | core/object/script_language.cpp | 1 | ||||
| -rw-r--r-- | core/object/script_language.h | 6 | ||||
| -rw-r--r-- | core/object/script_language_extension.cpp | 4 | ||||
| -rw-r--r-- | core/object/script_language_extension.h | 26 | ||||
| -rw-r--r-- | core/object/worker_thread_pool.cpp | 11 |
11 files changed, 294 insertions, 41 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 6a6043e42d..c594f4a9b4 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -31,6 +31,7 @@ #include "class_db.h" #include "core/config/engine.h" +#include "core/io/resource_loader.h" #include "core/object/script_language.h" #include "core/os/mutex.h" #include "core/version.h" @@ -348,7 +349,13 @@ Object *ClassDB::instantiate(const StringName &p_class) { } #endif if (ti->gdextension && ti->gdextension->create_instance) { - return (Object *)ti->gdextension->create_instance(ti->gdextension->class_userdata); + Object *obj = (Object *)ti->gdextension->create_instance(ti->gdextension->class_userdata); +#ifdef TOOLS_ENABLED + if (ti->gdextension->track_instance) { + ti->gdextension->track_instance(ti->gdextension->tracking_userdata, obj); + } +#endif + return obj; } else { return ti->creation_func(); } @@ -378,7 +385,14 @@ bool ClassDB::can_instantiate(const StringName &p_class) { OBJTYPE_RLOCK; ClassInfo *ti = classes.getptr(p_class); - ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'."); + if (!ti) { + if (!ScriptServer::is_global_class(p_class)) { + ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'."); + } + String path = ScriptServer::get_global_class_path(p_class); + Ref<Script> scr = ResourceLoader::load(path); + return scr.is_valid() && scr->is_valid() && !scr->is_abstract(); + } #ifdef TOOLS_ENABLED if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { return false; @@ -395,7 +409,9 @@ bool ClassDB::is_virtual(const StringName &p_class) { if (!ScriptServer::is_global_class(p_class)) { ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'."); } - return false; + String path = ScriptServer::get_global_class_path(p_class); + Ref<Script> scr = ResourceLoader::load(path); + return scr.is_valid() && scr->is_valid() && scr->is_abstract(); } #ifdef TOOLS_ENABLED if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { @@ -464,7 +480,6 @@ void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_met } #ifdef DEBUG_METHODS_ENABLED - for (const MethodInfo &E : type->virtual_methods) { p_methods->push_back(E); } @@ -479,17 +494,74 @@ void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_met p_methods->push_back(minfo); } - #else - for (KeyValue<StringName, MethodBind *> &E : type->method_map) { MethodBind *m = E.value; MethodInfo minfo = info_from_bind(m); p_methods->push_back(minfo); } +#endif + + if (p_no_inheritance) { + break; + } + + type = type->inherits_ptr; + } +} + +void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List<Pair<MethodInfo, uint32_t>> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + + while (type) { + if (type->disabled) { + if (p_no_inheritance) { + break; + } + + type = type->inherits_ptr; + continue; + } +#ifdef DEBUG_METHODS_ENABLED + for (const MethodInfo &E : type->virtual_methods) { + Pair<MethodInfo, uint32_t> pair(E, 0); + p_methods->push_back(pair); + } + + for (const StringName &E : type->method_order) { + if (p_exclude_from_properties && type->methods_in_properties.has(E)) { + continue; + } + + MethodBind *method = type->method_map.get(E); + MethodInfo minfo = info_from_bind(method); + + Pair<MethodInfo, uint32_t> pair(minfo, method->get_hash()); + p_methods->push_back(pair); + } +#else + for (KeyValue<StringName, MethodBind *> &E : type->method_map) { + MethodBind *method = E.value; + MethodInfo minfo = info_from_bind(method); + + Pair<MethodInfo, uint32_t> pair(minfo, method->get_hash()); + p_methods->push_back(pair); + } #endif + for (const KeyValue<StringName, LocalVector<MethodBind *, unsigned int, false, false>> &E : type->method_map_compatibility) { + LocalVector<MethodBind *> compat = E.value; + for (MethodBind *method : compat) { + MethodInfo minfo = info_from_bind(method); + + Pair<MethodInfo, uint32_t> pair(minfo, method->get_hash()); + p_methods->push_back(pair); + } + } + if (p_no_inheritance) { break; } @@ -1545,6 +1617,14 @@ bool ClassDB::is_class_exposed(const StringName &p_class) { return ti->exposed; } +bool ClassDB::is_class_reloadable(const StringName &p_class) { + OBJTYPE_RLOCK; + + ClassInfo *ti = classes.getptr(p_class); + ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'."); + return ti->reloadable; +} + void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) { if (resource_base_extensions.has(p_extension)) { return; @@ -1683,15 +1763,18 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) { parent = classes.getptr(parent->name); } } + c.reloadable = p_extension->reloadable; classes[p_extension->class_name] = c; } -void ClassDB::unregister_extension_class(const StringName &p_class) { +void ClassDB::unregister_extension_class(const StringName &p_class, bool p_free_method_binds) { ClassInfo *c = classes.getptr(p_class); ERR_FAIL_NULL_MSG(c, "Class '" + String(p_class) + "' does not exist."); - for (KeyValue<StringName, MethodBind *> &F : c->method_map) { - memdelete(F.value); + if (p_free_method_binds) { + for (KeyValue<StringName, MethodBind *> &F : c->method_map) { + memdelete(F.value); + } } classes.erase(p_class); } diff --git a/core/object/class_db.h b/core/object/class_db.h index b112cddf38..5c2c59d508 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -131,6 +131,7 @@ public: StringName name; bool disabled = false; bool exposed = false; + bool reloadable = false; bool is_virtual = false; Object *(*creation_func)() = nullptr; @@ -228,7 +229,7 @@ public: } static void register_extension_class(ObjectGDExtension *p_extension); - static void unregister_extension_class(const StringName &p_class); + static void unregister_extension_class(const StringName &p_class, bool p_free_method_binds = true); template <class T> static Object *_create_ptr_func() { @@ -398,6 +399,7 @@ public: static void set_method_flags(const StringName &p_class, const StringName &p_method, int p_flags); static void get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false); + static void get_method_list_with_compatibility(const StringName &p_class, List<Pair<MethodInfo, uint32_t>> *p_methods_with_hash, bool p_no_inheritance = false, bool p_exclude_from_properties = false); static bool get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false); static MethodBind *get_method(const StringName &p_class, const StringName &p_name); static MethodBind *get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists = nullptr, bool *r_is_deprecated = nullptr); @@ -426,6 +428,7 @@ public: static bool is_class_enabled(const StringName &p_class); static bool is_class_exposed(const StringName &p_class); + static bool is_class_reloadable(const StringName &p_class); static void add_resource_base_extension(const StringName &p_extension, const StringName &p_class); static void get_resource_base_extensions(List<String> *p_extensions); diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index c2e69dc8e2..0f3cf3916a 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -22,6 +22,7 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ } else if (_get_extension()->get_virtual) {\\ _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ }\\ + GDVIRTUAL_TRACK(_gdvirtual_##m_name, _gdvirtual_##m_name##_initialized); \\ _gdvirtual_##m_name##_initialized = true;\\ }\\ if (_gdvirtual_##m_name) {\\ @@ -56,6 +57,7 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\ } else if (_get_extension()->get_virtual) {\\ _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ }\\ + GDVIRTUAL_TRACK(_gdvirtual_##m_name, _gdvirtual_##m_name##_initialized); \\ _gdvirtual_##m_name##_initialized = true;\\ }\\ if (_gdvirtual_##m_name) {\\ @@ -175,6 +177,18 @@ def run(target, source, env): #include "core/object/script_instance.h" +#ifdef TOOLS_ENABLED +#define GDVIRTUAL_TRACK(m_virtual, m_initialized) \\ + if (_get_extension()->reloadable) {\\ + VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\ + tracker->method = (void **)&m_virtual;\\ + tracker->initialized = &m_initialized;\\ + tracker->next = virtual_method_list;\\ + virtual_method_list = tracker;\\ + } +#else +#define GDVIRTUAL_TRACK(m_virtual, m_initialized) +#endif """ diff --git a/core/object/method_bind.h b/core/object/method_bind.h index 84f0941b94..d67fd003c8 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -111,6 +111,10 @@ public: _FORCE_INLINE_ int get_argument_count() const { return argument_count; }; +#ifdef TOOLS_ENABLED + virtual bool is_valid() const { return true; } +#endif + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const = 0; virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const = 0; diff --git a/core/object/object.cpp b/core/object/object.cpp index 3fd7fe36e0..056334c8e1 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -31,6 +31,7 @@ #include "object.h" #include "core/core_string_names.h" +#include "core/extension/gdextension_manager.h" #include "core/io/resource.h" #include "core/object/class_db.h" #include "core/object/message_queue.h" @@ -616,7 +617,7 @@ void Object::get_method_list(List<MethodInfo> *p_list) const { Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 0; + r_error.expected = 1; return Variant(); } @@ -635,7 +636,7 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 0; + r_error.expected = 1; return Variant(); } @@ -665,8 +666,16 @@ bool Object::has_method(const StringName &p_method) const { } MethodBind *method = ClassDB::get_method(get_class_name(), p_method); + if (method != nullptr) { + return true; + } - return method != nullptr; + const Script *scr = Object::cast_to<Script>(this); + if (scr != nullptr) { + return scr->has_static_method(p_method); + } + + return false; } Variant Object::getvar(const Variant &p_key, bool *r_valid) const { @@ -714,12 +723,11 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_ //free must be here, before anything, always ready #ifdef DEBUG_ENABLED if (p_argcount != 0) { - r_error.argument = 0; r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.expected = 0; return Variant(); } if (Object::cast_to<RefCounted>(this)) { - r_error.argument = 0; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); } @@ -880,7 +888,10 @@ void Object::set_script(const Variant &p_script) { } Ref<Script> s = p_script; - ERR_FAIL_COND_MSG(s.is_null() && !p_script.is_null(), "Invalid parameter, it should be a reference to a valid script (or null)."); + if (!p_script.is_null()) { + ERR_FAIL_COND_MSG(s.is_null(), "Cannot set object script. Parameter should be null or a reference to a valid script."); + ERR_FAIL_COND_MSG(s->is_abstract(), vformat("Cannot set object script. Script '%s' should not be abstract.", s->get_path())); + } script = p_script; @@ -1032,14 +1043,17 @@ struct _ObjectSignalDisconnectData { }; 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; + if (unlikely(p_argcount < 1)) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.expected = 1; + ERR_FAIL_V(Error::ERR_INVALID_PARAMETER); + } - 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) { + if (unlikely(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, Error::ERR_INVALID_PARAMETER); + ERR_FAIL_V(Error::ERR_INVALID_PARAMETER); } r_error.error = Callable::CallError::CALL_OK; @@ -1791,14 +1805,17 @@ StringName Object::get_class_name_for_extension(const GDExtension *p_library) co } void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) { - // This is only meant to be used on creation by the binder. - ERR_FAIL_COND(_instance_bindings != nullptr); - _instance_bindings = (InstanceBinding *)memalloc(sizeof(InstanceBinding)); + // This is only meant to be used on creation by the binder, but we also + // need to account for reloading (where the 'binding' will be cleared). + ERR_FAIL_COND(_instance_bindings != nullptr && _instance_bindings[0].binding != nullptr); + if (_instance_bindings == nullptr) { + _instance_bindings = (InstanceBinding *)memalloc(sizeof(InstanceBinding)); + _instance_binding_count = 1; + } _instance_bindings[0].binding = p_binding; _instance_bindings[0].free_callback = p_callbacks->free_callback; _instance_bindings[0].reference_callback = p_callbacks->reference_callback; _instance_bindings[0].token = p_token; - _instance_binding_count = 1; } void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) { @@ -1825,6 +1842,12 @@ void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindi binding = p_callbacks->create_callback(p_token, this); _instance_bindings[_instance_binding_count].binding = binding; +#ifdef TOOLS_ENABLED + if (!_extension && Engine::get_singleton()->is_extension_reloading_enabled()) { + GDExtensionManager::get_singleton()->track_instance_binding(p_token, this); + } +#endif + _instance_binding_count++; } @@ -1848,6 +1871,71 @@ bool Object::has_instance_binding(void *p_token) { return found; } +void Object::free_instance_binding(void *p_token) { + bool found = false; + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (!found && _instance_bindings[i].token == p_token) { + if (_instance_bindings[i].free_callback) { + _instance_bindings[i].free_callback(_instance_bindings[i].token, this, _instance_bindings[i].binding); + } + found = true; + } + if (found) { + if (i + 1 < _instance_binding_count) { + _instance_bindings[i] = _instance_bindings[i + 1]; + } else { + _instance_bindings[i] = { nullptr }; + } + } + } + if (found) { + _instance_binding_count--; + } + _instance_binding_mutex.unlock(); +} + +#ifdef TOOLS_ENABLED +void Object::clear_internal_extension() { + ERR_FAIL_NULL(_extension); + + // Free the instance inside the GDExtension. + if (_extension->free_instance) { + _extension->free_instance(_extension->class_userdata, _extension_instance); + } + _extension = nullptr; + _extension_instance = nullptr; + + // Clear the instance bindings. + _instance_binding_mutex.lock(); + if (_instance_bindings[0].free_callback) { + _instance_bindings[0].free_callback(_instance_bindings[0].token, this, _instance_bindings[0].binding); + } + _instance_bindings[0].binding = nullptr; + _instance_bindings[0].token = nullptr; + _instance_bindings[0].free_callback = nullptr; + _instance_bindings[0].reference_callback = nullptr; + _instance_binding_mutex.unlock(); + + // Clear the virtual methods. + while (virtual_method_list) { + (*virtual_method_list->method) = nullptr; + (*virtual_method_list->initialized) = false; + virtual_method_list = virtual_method_list->next; + } +} + +void Object::reset_internal_extension(ObjectGDExtension *p_extension) { + ERR_FAIL_COND(_extension != nullptr); + + if (p_extension) { + _extension_instance = p_extension->recreate_instance ? p_extension->recreate_instance(p_extension->class_userdata, (GDExtensionObjectPtr)this) : nullptr; + ERR_FAIL_NULL_MSG(_extension_instance, "Unable to recreate GDExtension instance - does this extension support hot reloading?"); + _extension = p_extension; + } +} +#endif + void Object::_construct_object(bool p_reference) { type_is_reference = p_reference; _instance_id = ObjectDB::add_instance(this); @@ -1878,11 +1966,25 @@ Object::~Object() { } script_instance = nullptr; - if (_extension && _extension->free_instance) { - _extension->free_instance(_extension->class_userdata, _extension_instance); + if (_extension) { +#ifdef TOOLS_ENABLED + if (_extension->untrack_instance) { + _extension->untrack_instance(_extension->tracking_userdata, this); + } +#endif + if (_extension->free_instance) { + _extension->free_instance(_extension->class_userdata, _extension_instance); + } _extension = nullptr; _extension_instance = nullptr; } +#ifdef TOOLS_ENABLED + else if (_instance_bindings != nullptr && Engine::get_singleton()->is_extension_reloading_enabled()) { + for (uint32_t i = 0; i < _instance_binding_count; i++) { + GDExtensionManager::get_singleton()->untrack_instance_binding(_instance_bindings[i].token, this); + } + } +#endif if (_emitting) { //@todo this may need to actually reach the debugger prioritarily somehow because it may crash before diff --git a/core/object/object.h b/core/object/object.h index 7da1c68edf..a444db0f70 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -49,7 +49,7 @@ class TypedArray; enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. - PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians][,degrees][,exp][,suffix:<keyword>] range. + PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians_as_degrees][,degrees][,exp][,suffix:<keyword>] range. PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only") @@ -313,6 +313,7 @@ struct ObjectGDExtension { StringName parent_class_name; StringName class_name; bool editor_class = false; + bool reloadable = false; bool is_virtual = false; bool is_abstract = false; bool is_exposed = true; @@ -349,6 +350,13 @@ struct ObjectGDExtension { GDExtensionClassGetVirtual get_virtual; GDExtensionClassGetVirtualCallData get_virtual_call_data; GDExtensionClassCallVirtualWithData call_virtual_with_data; + GDExtensionClassRecreateInstance recreate_instance; + +#ifdef TOOLS_ENABLED + void *tracking_userdata = nullptr; + void (*track_instance)(void *p_userdata, void *p_instance); + void (*untrack_instance)(void *p_userdata, void *p_instance); +#endif }; #define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__) @@ -750,6 +758,16 @@ protected: bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); +#ifdef TOOLS_ENABLED + struct VirtualMethodTracker { + void **method; + bool *initialized; + VirtualMethodTracker *next; + }; + + mutable VirtualMethodTracker *virtual_method_list = nullptr; +#endif + public: // Should be protected, but bug in clang++. static void initialize_class(); _FORCE_INLINE_ static void register_custom_data_to_otdb() {} @@ -781,7 +799,8 @@ public: enum { NOTIFICATION_POSTINITIALIZE = 0, - NOTIFICATION_PREDELETE = 1 + NOTIFICATION_PREDELETE = 1, + NOTIFICATION_EXTENSION_RELOADED = 2, }; /* TYPE API */ @@ -951,6 +970,12 @@ public: // Used on creation by binding only. void set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks); bool has_instance_binding(void *p_token); + void free_instance_binding(void *p_token); + +#ifdef TOOLS_ENABLED + void clear_internal_extension(); + void reset_internal_extension(ObjectGDExtension *p_extension); +#endif void clear_internal_resource_paths(); diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index abf2b7b054..011f4203ea 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -146,6 +146,7 @@ void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("get_property_default_value", "property"), &Script::_get_property_default_value); ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool); + ClassDB::bind_method(D_METHOD("is_abstract"), &Script::is_abstract); ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code"); } diff --git a/core/object/script_language.h b/core/object/script_language.h index e0c4d650dd..5ff7cd8582 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -145,11 +145,15 @@ public: virtual PropertyInfo get_class_category() const; #endif // TOOLS_ENABLED + // TODO: In the next compat breakage rename to `*_script_*` to disambiguate from `Object::has_method()`. virtual bool has_method(const StringName &p_method) const = 0; + virtual bool has_static_method(const StringName &p_method) const { return false; } + virtual MethodInfo get_method_info(const StringName &p_method) const = 0; virtual bool is_tool() const = 0; virtual bool is_valid() const = 0; + virtual bool is_abstract() const = 0; virtual ScriptLanguage *get_language() const = 0; @@ -242,7 +246,9 @@ public: 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, HashSet<int> *r_safe_lines = nullptr) const = 0; virtual String validate_path(const String &p_path) const { return ""; } virtual Script *create_script() const = 0; +#ifndef DISABLE_DEPRECATED virtual bool has_named_classes() const = 0; +#endif virtual bool supports_builtin_mode() const = 0; virtual bool supports_documentation() const { return false; } virtual bool can_inherit_from_file() const { return false; } diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp index bf8bac476a..a07bf63a02 100644 --- a/core/object/script_language_extension.cpp +++ b/core/object/script_language_extension.cpp @@ -55,10 +55,12 @@ void ScriptExtension::_bind_methods() { GDVIRTUAL_BIND(_get_class_icon_path); GDVIRTUAL_BIND(_has_method, "method"); + GDVIRTUAL_BIND(_has_static_method, "method"); GDVIRTUAL_BIND(_get_method_info, "method"); GDVIRTUAL_BIND(_is_tool); GDVIRTUAL_BIND(_is_valid); + GDVIRTUAL_BIND(_is_abstract); GDVIRTUAL_BIND(_get_language); GDVIRTUAL_BIND(_has_script_signal, "signal"); @@ -98,7 +100,9 @@ void ScriptLanguageExtension::_bind_methods() { GDVIRTUAL_BIND(_validate_path, "path"); GDVIRTUAL_BIND(_create_script); +#ifndef DISABLE_DEPRECATED GDVIRTUAL_BIND(_has_named_classes); +#endif GDVIRTUAL_BIND(_supports_builtin_mode); GDVIRTUAL_BIND(_supports_documentation); GDVIRTUAL_BIND(_can_inherit_from_file); diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index e06f005320..89bba80b90 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -99,6 +99,7 @@ public: #endif // TOOLS_ENABLED EXBIND1RC(bool, has_method, const StringName &) + EXBIND1RC(bool, has_static_method, const StringName &) GDVIRTUAL1RC(Dictionary, _get_method_info, const StringName &) virtual MethodInfo get_method_info(const StringName &p_method) const override { @@ -110,6 +111,12 @@ public: EXBIND0RC(bool, is_tool) EXBIND0RC(bool, is_valid) + virtual bool is_abstract() const override { + bool abst; + return GDVIRTUAL_CALL(_is_abstract, abst) && abst; + } + GDVIRTUAL0RC(bool, _is_abstract) + EXBIND0RC(ScriptLanguage *, get_language) EXBIND1RC(bool, has_script_signal, const StringName &) @@ -344,7 +351,9 @@ public: GDVIRTUAL_REQUIRED_CALL(_create_script, ret); return Object::cast_to<Script>(ret); } +#ifndef DISABLE_DEPRECATED EXBIND0RC(bool, has_named_classes) +#endif EXBIND0RC(bool, supports_builtin_mode) EXBIND0RC(bool, supports_documentation) EXBIND0RC(bool, can_inherit_from_file) @@ -633,7 +642,7 @@ public: const GDExtensionScriptInstanceInfo2 *native_info; bool free_native_info = false; struct { - GDExtensionClassNotification notification_func; + GDExtensionScriptInstanceNotification notification_func = nullptr; } deprecated_native_info; GDExtensionScriptInstanceDataPtr instance = nullptr; @@ -662,9 +671,18 @@ public: const GDExtensionPropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount); #ifdef TOOLS_ENABLED - Ref<Script> script = get_script(); - if (script.is_valid() && pcount > 0) { - p_list->push_back(script->get_class_category()); + if (pcount > 0) { + if (native_info->get_class_category_func) { + GDExtensionPropertyInfo gdext_class_category; + if (native_info->get_class_category_func(instance, &gdext_class_category)) { + p_list->push_back(PropertyInfo(gdext_class_category)); + } + } else { + Ref<Script> script = get_script(); + if (script.is_valid()) { + p_list->push_back(script->get_class_category()); + } + } } #endif // TOOLS_ENABLED diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index cfc3ac3bcf..2fcd0867e6 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -75,10 +75,6 @@ void WorkerThreadPool::_process_task(Task *p_task) { if (p_task->group) { // Handling a group bool do_post = false; - Callable::CallError ce; - Variant ret; - Variant arg; - Variant *argptr = &arg; while (true) { uint32_t work_index = p_task->group->index.postincrement(); @@ -91,8 +87,7 @@ void WorkerThreadPool::_process_task(Task *p_task) { } else if (p_task->template_userdata) { p_task->template_userdata->callback_indexed(work_index); } else { - arg = work_index; - p_task->callable.callp((const Variant **)&argptr, 1, ret, ce); + p_task->callable.call(work_index); } // This is the only way to ensure posting is done when all tasks are really complete. @@ -141,9 +136,7 @@ void WorkerThreadPool::_process_task(Task *p_task) { p_task->template_userdata->callback(); memdelete(p_task->template_userdata); } else { - Callable::CallError ce; - Variant ret; - p_task->callable.callp(nullptr, 0, ret, ce); + p_task->callable.call(); } task_mutex.lock(); |
