summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp1
-rw-r--r--core/extension/gdextension.cpp3
-rw-r--r--core/extension/gdextension_interface.cpp14
-rw-r--r--core/extension/gdextension_interface.h13
-rw-r--r--core/io/resource_loader.cpp4
-rw-r--r--core/object/message_queue.cpp32
-rw-r--r--core/object/message_queue.h6
-rw-r--r--core/object/object.cpp4
-rw-r--r--core/object/object.h14
-rw-r--r--core/templates/self_list.h11
10 files changed, 95 insertions, 7 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 264259eb2f..c3df4a2ebe 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1290,6 +1290,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"), "res://default_bus_layout.tres");
+ GLOBAL_DEF_RST("audio/general/text_to_speech", false);
GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f);
GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f);
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 942ec95678..0cbcf58882 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -314,6 +314,7 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
parent_extension->gdextension.children.push_back(&extension->gdextension);
}
+ extension->gdextension.library = self;
extension->gdextension.parent_class_name = parent_class_name;
extension->gdextension.class_name = class_name;
extension->gdextension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
@@ -524,7 +525,7 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) {
}
void GDExtension::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "use_legacy_interface"), &GDExtension::open_library);
+ ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "use_legacy_interface"), &GDExtension::open_library, DEFVAL(false));
ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library_compat_76406);
ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library);
ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open);
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index c661bfa8c7..12ef1772e3 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -992,6 +992,19 @@ static GDExtensionObjectPtr gdextension_object_get_instance_from_id(GDObjectInst
return (GDExtensionObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
}
+static GDExtensionBool gdextension_object_get_class_name(GDExtensionConstObjectPtr p_object, GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringNamePtr r_class_name) {
+ if (!p_object) {
+ return false;
+ }
+ const Object *o = (const Object *)p_object;
+
+ memnew_placement(r_class_name, StringName);
+ StringName *class_name = reinterpret_cast<StringName *>(r_class_name);
+ *class_name = o->get_class_name_for_extension((GDExtension *)p_library);
+
+ return true;
+}
+
static GDExtensionObjectPtr gdextension_object_cast_to(GDExtensionConstObjectPtr p_object, void *p_class_tag) {
if (!p_object) {
return nullptr;
@@ -1176,6 +1189,7 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(object_get_instance_binding);
REGISTER_INTERFACE_FUNC(object_set_instance_binding);
REGISTER_INTERFACE_FUNC(object_set_instance);
+ REGISTER_INTERFACE_FUNC(object_get_class_name);
REGISTER_INTERFACE_FUNC(object_cast_to);
REGISTER_INTERFACE_FUNC(object_get_instance_from_id);
REGISTER_INTERFACE_FUNC(object_get_instance_id);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 4e4f300f5d..a5ea3918df 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -1902,6 +1902,19 @@ typedef void (*GDExtensionInterfaceObjectSetInstanceBinding)(GDExtensionObjectPt
typedef void (*GDExtensionInterfaceObjectSetInstance)(GDExtensionObjectPtr p_o, GDExtensionConstStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
/**
+ * @name object_get_class_name
+ *
+ * Gets the class name of an Object.
+ *
+ * @param p_object A pointer to the Object.
+ * @param p_library A pointer the library received by the GDExtension's entry point function.
+ * @param r_class_name A pointer to a String to receive the class name.
+ *
+ * @return true if successful in getting the class name; otherwise false.
+ */
+typedef GDExtensionBool (*GDExtensionInterfaceObjectGetClassName)(GDExtensionConstObjectPtr p_object, GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringNamePtr r_class_name);
+
+/**
* @name object_cast_to
*
* Casts an Object to a different type.
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index c68191554c..e9f812ab1c 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -309,6 +309,9 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
// --
Ref<Resource> res = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
+ if (mq_override) {
+ mq_override->flush();
+ }
thread_load_mutex.lock();
@@ -354,7 +357,6 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
if (load_nesting == 0 && mq_override) {
memdelete(mq_override);
- MessageQueue::set_thread_singleton_override(nullptr);
}
}
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index 78fdb08f85..18ba5d5b30 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -35,10 +35,22 @@
#include "core/object/class_db.h"
#include "core/object/script_language.h"
+#ifdef DEV_ENABLED
+// Includes sanity checks to ensure that a queue set as a thread singleton override
+// is only ever called from the thread it was set for.
+#define LOCK_MUTEX \
+ if (this != MessageQueue::thread_singleton) { \
+ DEV_ASSERT(!this->is_current_thread_override); \
+ mutex.lock(); \
+ } else { \
+ DEV_ASSERT(this->is_current_thread_override); \
+ }
+#else
#define LOCK_MUTEX \
if (this != MessageQueue::thread_singleton) { \
mutex.lock(); \
}
+#endif
#define UNLOCK_MUTEX \
if (this != MessageQueue::thread_singleton) { \
@@ -213,8 +225,8 @@ void CallQueue::_call_function(const Callable &p_callable, const Variant *p_args
Error CallQueue::flush() {
LOCK_MUTEX;
- // Non-main threads are not meant to be flushed, but appended to the main one.
- if (this != MessageQueue::main_singleton) {
+ // Thread overrides are not meant to be flushed, but appended to the main one.
+ if (this == MessageQueue::thread_singleton) {
if (pages.size() == 0) {
return OK;
}
@@ -237,6 +249,7 @@ Error CallQueue::flush() {
uint32_t dst_offset = mq->page_bytes[dst_page];
if (dst_offset + page_bytes[0] < uint32_t(PAGE_SIZE_BYTES)) {
memcpy(mq->pages[dst_page]->data + dst_offset, pages[0]->data, page_bytes[0]);
+ mq->page_bytes[dst_page] += page_bytes[0];
src_page++;
}
}
@@ -520,6 +533,10 @@ CallQueue::~CallQueue() {
if (!allocator_is_custom) {
memdelete(allocator);
}
+ // This is done here to avoid a circular dependency between the sanity checks and the thread singleton pointer.
+ if (this == MessageQueue::thread_singleton) {
+ MessageQueue::thread_singleton = nullptr;
+ }
}
//////////////////////
@@ -528,7 +545,18 @@ CallQueue *MessageQueue::main_singleton = nullptr;
thread_local CallQueue *MessageQueue::thread_singleton = nullptr;
void MessageQueue::set_thread_singleton_override(CallQueue *p_thread_singleton) {
+ DEV_ASSERT(p_thread_singleton); // To unset the thread singleton, don't call this with nullptr, but just memfree() it.
+#ifdef DEV_ENABLED
+ if (thread_singleton) {
+ thread_singleton->is_current_thread_override = false;
+ }
+#endif
thread_singleton = p_thread_singleton;
+#ifdef DEV_ENABLED
+ if (thread_singleton) {
+ thread_singleton->is_current_thread_override = true;
+ }
+#endif
}
MessageQueue::MessageQueue() :
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index c6fcccbd58..9f567e4dd0 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -40,6 +40,8 @@
class Object;
class CallQueue {
+ friend class MessageQueue;
+
public:
enum {
PAGE_SIZE_BYTES = 4096
@@ -75,6 +77,10 @@ private:
uint32_t pages_used = 0;
bool flushing = false;
+#ifdef DEV_ENABLED
+ bool is_current_thread_override = false;
+#endif
+
struct Message {
Callable callable;
int16_t type;
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 5a34328ec4..f276547e7b 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1350,7 +1350,7 @@ bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
}
ERR_FAIL_COND_V_MSG(!s, false, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
- ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, "Disconnecting nonexistent signal '" + p_signal + "', callable: " + p_callable + ".");
+ ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
SignalData::Slot *slot = &s->slot_map[*p_callable.get_base_comparator()];
@@ -1739,7 +1739,7 @@ void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindi
break;
}
}
- if (unlikely(!binding)) {
+ if (unlikely(!binding && p_callbacks)) {
uint32_t current_size = next_power_of_2(_instance_binding_count);
uint32_t new_size = next_power_of_2(_instance_binding_count + 1);
diff --git a/core/object/object.h b/core/object/object.h
index c4d287a71c..6f626b0ed0 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -304,8 +304,10 @@ struct MethodInfo {
// API used to extend in GDExtension and other C compatible compiled languages.
class MethodBind;
+class GDExtension;
struct ObjectGDExtension {
+ GDExtension *library = nullptr;
ObjectGDExtension *parent = nullptr;
List<ObjectGDExtension *> children;
StringName parent_class_name;
@@ -798,6 +800,18 @@ public:
return *_class_name_ptr;
}
+ _FORCE_INLINE_ const StringName &get_class_name_for_extension(const GDExtension *p_library) const {
+ // Only return the class name per the extension if it matches the given p_library.
+ if (_extension && _extension->library == p_library) {
+ return _extension->class_name;
+ }
+ // Otherwise, return the name of the built-in class.
+ if (unlikely(!_class_name_ptr)) {
+ return *_get_class_namev();
+ }
+ return *_class_name_ptr;
+ }
+
/* IAPI */
void set(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr);
diff --git a/core/templates/self_list.h b/core/templates/self_list.h
index c3d7391d6c..ff6fa953ae 100644
--- a/core/templates/self_list.h
+++ b/core/templates/self_list.h
@@ -99,11 +99,20 @@ public:
p_elem->_root = nullptr;
}
+ void clear() {
+ while (_first) {
+ remove(_first);
+ }
+ }
+
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
_FORCE_INLINE_ List() {}
- _FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
+ _FORCE_INLINE_ ~List() {
+ // A self list must be empty on destruction.
+ DEV_ASSERT(_first == nullptr);
+ }
};
private: