diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 495670bc884..d8fbb50a75e 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -199,17 +199,41 @@ bool Engine::is_printing_error_messages() const { } void Engine::add_singleton(const Singleton &p_singleton) { + ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), "Can't register singleton that already exists: " + String(p_singleton.name)); singletons.push_back(p_singleton); singleton_ptrs[p_singleton.name] = p_singleton.ptr; } -Object *Engine::get_singleton_object(const String &p_name) const { +Object *Engine::get_singleton_object(const StringName &p_name) const { const Map::Element *E = singleton_ptrs.find(p_name); - ERR_FAIL_COND_V_MSG(!E, nullptr, "Failed to retrieve non-existent singleton '" + p_name + "'."); + ERR_FAIL_COND_V_MSG(!E, nullptr, "Failed to retrieve non-existent singleton '" + String(p_name) + "'."); return E->get(); } -bool Engine::has_singleton(const String &p_name) const { +bool Engine::is_singleton_user_created(const StringName &p_name) const { + ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false); + + for (const Singleton &E : singletons) { + if (E.name == p_name && E.user_created) { + return true; + } + } + + return false; +} +void Engine::remove_singleton(const StringName &p_name) { + ERR_FAIL_COND(!singleton_ptrs.has(p_name)); + + for (List::Element *E = singletons.front(); E; E = E->next()) { + if (E->get().name == p_name) { + singletons.erase(E); + singleton_ptrs.erase(p_name); + return; + } + } +} + +bool Engine::has_singleton(const StringName &p_name) const { return singleton_ptrs.has(p_name); } diff --git a/core/config/engine.h b/core/config/engine.h index e6b5df2d5ac..ae33acede2e 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -42,6 +42,7 @@ public: StringName name; Object *ptr; StringName class_name; //used for binding generation hinting + bool user_created = false; Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName()); }; @@ -109,8 +110,10 @@ public: void add_singleton(const Singleton &p_singleton); void get_singletons(List *p_singletons); - bool has_singleton(const String &p_name) const; - Object *get_singleton_object(const String &p_name) const; + bool has_singleton(const StringName &p_name) const; + Object *get_singleton_object(const StringName &p_name) const; + void remove_singleton(const StringName &p_name); + bool is_singleton_user_created(const StringName &p_name) const; #ifdef TOOLS_ENABLED _FORCE_INLINE_ void set_editor_hint(bool p_enabled) { editor_hint = p_enabled; } diff --git a/core/core_bind.cpp b/core/core_bind.cpp index efb4b847168..83a3b80803f 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -2165,14 +2165,41 @@ bool Engine::is_in_physics_frame() const { return ::Engine::get_singleton()->is_in_physics_frame(); } -bool Engine::has_singleton(const String &p_name) const { +bool Engine::has_singleton(const StringName &p_name) const { return ::Engine::get_singleton()->has_singleton(p_name); } -Object *Engine::get_singleton_object(const String &p_name) const { +Object *Engine::get_singleton_object(const StringName &p_name) const { return ::Engine::get_singleton()->get_singleton_object(p_name); } +void Engine::register_singleton(const StringName &p_name, Object *p_object) { + ERR_FAIL_COND_MSG(has_singleton(p_name), "Singleton already registered: " + String(p_name)); + ERR_FAIL_COND_MSG(p_name.operator String().is_valid_identifier(), "Singleton name is not a valid identifier: " + String(p_name)); + ::Engine::Singleton s; + s.class_name = p_name; + s.name = p_name; + s.ptr = p_object; + s.user_created = true; + ::Engine::get_singleton()->add_singleton(s); + ; +} +void Engine::unregister_singleton(const StringName &p_name) { + ERR_FAIL_COND_MSG(!has_singleton(p_name), "Attempt to remove unregisteres singleton: " + String(p_name)); + ERR_FAIL_COND_MSG(!::Engine::get_singleton()->is_singleton_user_created(p_name), "Attempt to remove non-user created singleton: " + String(p_name)); + ::Engine::get_singleton()->remove_singleton(p_name); +} + +Vector Engine::get_singleton_list() const { + List<::Engine::Singleton> singletons; + ::Engine::get_singleton()->get_singletons(&singletons); + Vector ret; + for (List<::Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { + ret.push_back(E->get().name); + } + return ret; +} + void Engine::set_editor_hint(bool p_enabled) { ::Engine::get_singleton()->set_editor_hint(p_enabled); } @@ -2220,6 +2247,10 @@ void Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("has_singleton", "name"), &Engine::has_singleton); ClassDB::bind_method(D_METHOD("get_singleton", "name"), &Engine::get_singleton_object); + ClassDB::bind_method(D_METHOD("register_singleton", "name", "instance"), &Engine::register_singleton); + ClassDB::bind_method(D_METHOD("unregister_singleton", "name"), &Engine::unregister_singleton); + ClassDB::bind_method(D_METHOD("get_singleton_list"), &Engine::get_singleton_list); + ClassDB::bind_method(D_METHOD("set_editor_hint", "enabled"), &Engine::set_editor_hint); ClassDB::bind_method(D_METHOD("is_editor_hint"), &Engine::is_editor_hint); diff --git a/core/core_bind.h b/core/core_bind.h index 1dbe49f418d..a6fac63edd8 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -639,8 +639,11 @@ public: bool is_in_physics_frame() const; - bool has_singleton(const String &p_name) const; - Object *get_singleton_object(const String &p_name) const; + bool has_singleton(const StringName &p_name) const; + Object *get_singleton_object(const StringName &p_name) const; + void register_singleton(const StringName &p_name, Object *p_object); + void unregister_singleton(const StringName &p_name); + Vector get_singleton_list() const; void set_editor_hint(bool p_enabled); bool is_editor_hint() const; diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 886a18900e1..8b399f64c98 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -84,11 +84,16 @@ - + Returns a global singleton with given [code]name[/code]. Often used for plugins, e.g. GodotPayments. + + + + + @@ -125,7 +130,7 @@ - + Returns [code]true[/code] if a singleton with given [code]name[/code] exists in global scope. @@ -136,6 +141,19 @@ Returns [code]true[/code] if the game is inside the fixed process and physics phase of the game loop. + + + + + + + + + + + + +