From 70aabf66e2282061312e65d8514f623625b8b13c Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Sat, 9 May 2026 18:45:28 +0300 Subject: [PATCH 1/4] Engine: Component Tags #1321 --- engine/includes/components/component.h | 10 +++++ engine/includes/components/scene.h | 17 +++++++- engine/includes/components/world.h | 2 + engine/src/components/actor.cpp | 11 +++-- engine/src/components/component.cpp | 57 +++++++++++++++++++++++--- engine/src/components/scene.cpp | 52 +++++++++++++++++++++++ engine/src/components/world.cpp | 46 +++++++++++---------- 7 files changed, 165 insertions(+), 30 deletions(-) diff --git a/engine/includes/components/component.h b/engine/includes/components/component.h index b924aac1e..16ebcbc83 100644 --- a/engine/includes/components/component.h +++ b/engine/includes/components/component.h @@ -56,6 +56,9 @@ class ENGINE_EXPORT Component : public Object { TString tr(const TString &source); + void addTag(const TString &tag); + void removeTag(const TString &tag); + virtual void composeComponent(); virtual void drawGizmos(); @@ -68,6 +71,13 @@ class ENGINE_EXPORT Component : public Object { virtual void onReferenceDestroyed(); private: + void changeScene(Scene *current, Scene *changed); + +private: + friend class Actor; + + std::vector m_tags; + bool m_enable; }; diff --git a/engine/includes/components/scene.h b/engine/includes/components/scene.h index 2b7bba1c7..c51df0caf 100644 --- a/engine/includes/components/scene.h +++ b/engine/includes/components/scene.h @@ -12,14 +12,26 @@ class ENGINE_EXPORT Scene : public Object { A_NOPROPERTIES() A_METHODS( A_METHOD(Object *, Scene::find), - A_METHOD(World *, Scene::world) + A_METHOD(World *, Scene::world), + A_METHOD(void, Scene::addToGroup), + A_METHOD(void, Scene::removeFromGroup) ) public: Scene(); + Scene(const Scene &origin); World *world() const; + void addToGroup(Object *object, const TString &group); + void addToGroupByHash(Object *object, uint32_t hash); + + void removeFromGroup(Object *object, const TString &group); + void removeFromGroupByHash(Object *object, uint32_t hash); + + ObjectList &getObjectsInGroup(const TString &group); + ObjectList &getObjectsInGroupByHash(uint32_t hash); + Map *map() const; void setMap(Map *map); @@ -27,6 +39,9 @@ class ENGINE_EXPORT Scene : public Object { void setModified(bool flag); private: + std::mutex m_mutex; + std::unordered_map m_groups; + mutable Map *m_map; bool m_modified; diff --git a/engine/includes/components/world.h b/engine/includes/components/world.h index 6be7bface..586c9872b 100644 --- a/engine/includes/components/world.h +++ b/engine/includes/components/world.h @@ -60,6 +60,8 @@ class ENGINE_EXPORT World : public Object { void addChild(Object *child, int32_t position = -1) override; private: + std::list m_scenes; + RayCastCallback m_rayCastCallback; System *m_rayCastSystem; diff --git a/engine/src/components/actor.cpp b/engine/src/components/actor.cpp index 31ddfa61c..760c4f5c2 100644 --- a/engine/src/components/actor.cpp +++ b/engine/src/components/actor.cpp @@ -144,16 +144,21 @@ void Actor::setHierarchyEnabled(bool enabled) { */ void Actor::setScene(Scene *scene) { if(m_scene != scene) { - m_scene = scene; - if(m_scene && m_scene->world()) { - m_scene->world()->graphUpdated(); + if(scene && scene->world()) { + scene->world()->graphUpdated(); } for(auto it : getChildren()) { Actor *child = dynamic_cast(it); if(child) { child->setScene(scene); + } else { + Component *component = dynamic_cast(it); + if(component) { + component->changeScene(m_scene, scene); + } } } + m_scene = scene; } } diff --git a/engine/src/components/component.cpp b/engine/src/components/component.cpp index 654153061..b89227a5a 100644 --- a/engine/src/components/component.cpp +++ b/engine/src/components/component.cpp @@ -41,7 +41,11 @@ Actor *Component::actor() const { Returns a Scene which the Component is attached to. */ Scene *Component::scene() const { - return actor()->scene(); + Actor *actor = Component::actor(); + if(actor) { + return actor->scene(); + } + return nullptr; } /*! Returns a World which the Component is attached to. @@ -80,9 +84,9 @@ bool Component::isEnabledInHierarchy() const { Returns a transform attached to this Actor. */ Transform *Component::transform() const { - Actor *act = actor(); - if(act) { - return act->transform(); + Actor *actor = Component::actor(); + if(actor) { + return actor->transform(); } return nullptr; } @@ -112,11 +116,41 @@ Actor *Component::instantiate(Prefab *prefab, Vector3 position, Quaternion rotat return result; } /*! - Returns a translated version of \a source text; otherwise returns source text if no appropriate translated std::string is available. + Returns a translated version of \a source text; otherwise returns source text if no appropriate translated string is available. */ TString Component::tr(const TString &source) { return Engine::translate(source); } +/*! + Adds a \a tag for current component. + Automatically adds component to specific Scene group. +*/ +void Component::addTag(const TString &tag) { + uint32_t hash = Mathf::hashString(tag); + auto it = std::find(m_tags.begin(), m_tags.end(), hash); + if(it == m_tags.end()) { + Scene *scene = Component::scene(); + if(scene) { + scene->addToGroupByHash(this, hash); + } + } +} +/*! + Removes a \a tag for current component. + Automatically removes component from specific Scene group. +*/ +void Component::removeTag(const TString &tag) { + uint32_t hash = Mathf::hashString(tag); + auto it = std::find(m_tags.begin(), m_tags.end(), hash); + if(it != m_tags.end()) { + m_tags.erase(it); + + Scene *scene = Component::scene(); + if(scene) { + scene->removeFromGroupByHash(this, hash); + } + } +} /*! \internal */ @@ -285,6 +319,19 @@ VariantMap Component::saveUserData() const { } return result; } +/*! + This method will be called automatically when \a current scene will be \a changed to a new one. +*/ +void Component::changeScene(Scene *current, Scene *changed) { + for(auto it : m_tags) { + if(current) { + current->removeFromGroupByHash(this, it); + } + if(current) { + changed->addToGroupByHash(this, it); + } + } +} /*! \internal */ diff --git a/engine/src/components/scene.cpp b/engine/src/components/scene.cpp index a2decfbf6..4fda548f7 100644 --- a/engine/src/components/scene.cpp +++ b/engine/src/components/scene.cpp @@ -13,6 +13,13 @@ Scene::Scene() : m_map(nullptr), m_modified(false) { +} + +Scene::Scene(const Scene &origin) : + m_groups(origin.m_groups), + m_map(origin.m_map), + m_modified(origin.m_modified) { + } /*! Returns the World to which the scene belongs. @@ -20,6 +27,51 @@ Scene::Scene() : World *Scene::world() const { return static_cast(parent()); } +/*! + Adds \a object to \a group. +*/ +void Scene::addToGroup(Object *object, const TString &group) { + addToGroupByHash(object, static_cast(Mathf::hashString(group))); +} +/*! + Adds \a object to a group with specific \a hash. +*/ +void Scene::addToGroupByHash(Object *object, uint32_t hash) { + std::lock_guard lock(m_mutex); + + m_groups[hash].push_back(object); +} +/*! + Removes \a object from \a group. +*/ +void Scene::removeFromGroup(Object *object, const TString &group) { + removeFromGroupByHash(object, static_cast(Mathf::hashString(group))); +} +/*! + Removes \a object from a group with specific \a hash. +*/ +void Scene::removeFromGroupByHash(Object *object, uint32_t hash) { + std::lock_guard lock(m_mutex); + + auto it = m_groups.find(hash); + if(it != m_groups.end()) { + it->second.remove(object); + } +} +/*! + Returns a list of objects in \a group. +*/ +Object::ObjectList &Scene::getObjectsInGroup(const TString &group) { + return getObjectsInGroupByHash(static_cast(Mathf::hashString(group))); +} +/*! + Returns a list of objects from a group with specific \a hash. +*/ +Object::ObjectList &Scene::getObjectsInGroupByHash(uint32_t hash) { + std::lock_guard lock(m_mutex); + + return m_groups[hash]; +} /*! \internal */ diff --git a/engine/src/components/world.cpp b/engine/src/components/world.cpp index 3419b546a..9ab139dd5 100644 --- a/engine/src/components/world.cpp +++ b/engine/src/components/world.cpp @@ -40,7 +40,9 @@ void World::setActive(bool flag) { Create an empty new Scene at runtime with the given \a name. */ Scene *World::createScene(const TString &name) { - return Engine::objectCreate(name, this); + Scene *result = Engine::objectCreate(name, this); + m_scenes.push_back(result); + return result; } /*! Loads the scene stored in the .map files by the it's \a path. @@ -54,13 +56,14 @@ Scene *World::loadScene(const TString &path, bool additive) { if(additive) { scene->setParent(this); } else { - for(auto it : getChildren()) { + for(auto it : m_scenes) { if(it != scene) { - unloadScene(dynamic_cast(it)); + unloadScene(it); } } scene->setParent(this); } + m_scenes.push_back(scene); sceneLoaded(); return scene; } @@ -73,17 +76,15 @@ Scene *World::loadScene(const TString &path, bool additive) { void World::unloadScene(Scene *scene) { Map *map = scene->map(); if(map) { + m_scenes.remove(scene); scene->setParent(map); Engine::unloadResource(map); sceneUnloaded(); if(m_activeScene == scene) { Scene *newScene = nullptr; - for(auto it : getChildren()) { - newScene = dynamic_cast(it); - if(newScene != nullptr) { - break; - } + if(!m_scenes.empty()) { + newScene = m_scenes.front(); } setActiveScene(newScene); } @@ -93,19 +94,14 @@ void World::unloadScene(Scene *scene) { Unloads all from the World. */ void World::unloadAll() { - Object::ObjectList copyList(getChildren()); - for(auto it : copyList) { - Scene *scene = dynamic_cast(it); - if(scene) { - Map *map = scene->map(); - if(map) { - scene->setParent(map); - Engine::unloadResource(map); - } - } else { - delete it; + for(auto it : m_scenes) { + Map *map = it->map(); + if(map) { + it->setParent(map); + Engine::unloadResource(map); } } + m_scenes.clear(); setActiveScene(nullptr); } /*! @@ -191,8 +187,16 @@ void World::graphUpdated() { */ void World::addChild(Object *child, int32_t position) { Object::addChild(child, position); - if(m_activeScene == nullptr && dynamic_cast(child)) { - setActiveScene(static_cast(child)); + + Scene *scene = dynamic_cast(child); + if(scene) { + auto it = std::find(m_scenes.begin(), m_scenes.end(), scene); + if(it != m_scenes.end()) { + m_scenes.push_back(scene); + } + } + if(m_activeScene == nullptr && scene) { + setActiveScene(scene); } } From 7709410d7b5741802b8ed0237ad6a8c1a03efb55 Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Sat, 9 May 2026 18:52:58 +0300 Subject: [PATCH 2/4] update --- engine/src/components/component.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/src/components/component.cpp b/engine/src/components/component.cpp index b89227a5a..7a7052c48 100644 --- a/engine/src/components/component.cpp +++ b/engine/src/components/component.cpp @@ -6,6 +6,8 @@ #include "system.h" +#include + namespace { const char *gResource("Resource"); }; From ab50ac3160b0c4f7ff97e0948eb87067d0532103 Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Sat, 9 May 2026 19:08:33 +0300 Subject: [PATCH 3/4] update --- engine/src/components/world.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/src/components/world.cpp b/engine/src/components/world.cpp index 9ab139dd5..2566c5bb9 100644 --- a/engine/src/components/world.cpp +++ b/engine/src/components/world.cpp @@ -4,6 +4,8 @@ #include "components/scene.h" #include "resources/map.h" +#include + /*! \class World \brief A root object in the scene graph hierarchy. From c46c23671d741b24d30dc8d150b929b56a8f1030 Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Sat, 9 May 2026 21:30:59 +0300 Subject: [PATCH 4/4] update --- engine/includes/components/world.h | 2 ++ engine/src/components/world.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/engine/includes/components/world.h b/engine/includes/components/world.h index 586c9872b..e0d078ea3 100644 --- a/engine/includes/components/world.h +++ b/engine/includes/components/world.h @@ -48,6 +48,8 @@ class ENGINE_EXPORT World : public Object { void setRayCastHandler(RayCastCallback callback, System *system); + std::list &scenes(); + public: // signals void sceneLoaded(); void sceneUnloaded(); diff --git a/engine/src/components/world.cpp b/engine/src/components/world.cpp index 2566c5bb9..93013cdd8 100644 --- a/engine/src/components/world.cpp +++ b/engine/src/components/world.cpp @@ -160,6 +160,12 @@ void World::setRayCastHandler(RayCastCallback callback, System *system) { m_rayCastCallback = callback; m_rayCastSystem = system; } +/*! + Returns list of all scenes. +*/ +std::list &World::scenes() { + return m_scenes; +} /*! Emmits signal when scene has been loaded. */