Fix editor selection system: SelectionManager ID types and Scene lookup
- SelectionManager now implements ISelectionManager interface with uint64_t IDs - Remove SelectionManager/SceneManager circular dependency via EventBus - Add Scene::FindByID() for proper ID-based entity lookup - SceneManager::GetEntity() now uses FindByID instead of name-based Find - Fix editor CMakeLists.txt XCEngine.lib path - EventBus now thread-safe with shared_mutex
This commit is contained in:
@@ -62,7 +62,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
|||||||
d3d12.lib
|
d3d12.lib
|
||||||
dxgi.lib
|
dxgi.lib
|
||||||
d3dcompiler.lib
|
d3dcompiler.lib
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../engine/build/Release/XCEngine.lib
|
${CMAKE_CURRENT_SOURCE_DIR}/../build/engine/Release/XCEngine.lib
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "ISceneManager.h"
|
#include "ISceneManager.h"
|
||||||
#include "Managers/SceneManager.h"
|
#include "Managers/SceneManager.h"
|
||||||
#include "Managers/ProjectManager.h"
|
#include "Managers/ProjectManager.h"
|
||||||
|
#include "EditorEvents.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -20,7 +21,16 @@ public:
|
|||||||
, m_selectionManager(std::make_unique<SelectionManager>(*m_eventBus))
|
, m_selectionManager(std::make_unique<SelectionManager>(*m_eventBus))
|
||||||
, m_sceneManager(std::make_unique<SceneManager>())
|
, m_sceneManager(std::make_unique<SceneManager>())
|
||||||
, m_projectManager(std::make_unique<ProjectManager>()) {
|
, m_projectManager(std::make_unique<ProjectManager>()) {
|
||||||
m_sceneManager->SetSelectionManager(m_selectionManager.get());
|
|
||||||
|
m_entityDeletedHandlerId = m_eventBus->Subscribe<EntityDeletedEvent>([this](const EntityDeletedEvent& event) {
|
||||||
|
if (m_selectionManager->GetSelectedEntity() == event.entityId) {
|
||||||
|
m_selectionManager->ClearSelection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
~EditorContext() {
|
||||||
|
m_eventBus->Unsubscribe<EntityDeletedEvent>(m_entityDeletedHandlerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBus& GetEventBus() override {
|
EventBus& GetEventBus() override {
|
||||||
@@ -53,7 +63,8 @@ private:
|
|||||||
std::unique_ptr<SceneManager> m_sceneManager;
|
std::unique_ptr<SceneManager> m_sceneManager;
|
||||||
std::unique_ptr<ProjectManager> m_projectManager;
|
std::unique_ptr<ProjectManager> m_projectManager;
|
||||||
std::string m_projectPath;
|
std::string m_projectPath;
|
||||||
|
uint64_t m_entityDeletedHandlerId;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,25 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <typeinfo>
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct EventTypeId {
|
||||||
|
static uint32_t Get() {
|
||||||
|
static const uint32_t id = s_nextId++;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static uint32_t s_nextId;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
uint32_t EventTypeId<T>::s_nextId = 0;
|
||||||
|
|
||||||
class EventBus {
|
class EventBus {
|
||||||
public:
|
public:
|
||||||
using EventHandler = std::function<void()>;
|
using EventHandler = std::function<void()>;
|
||||||
@@ -18,29 +32,35 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
uint64_t Subscribe(std::function<void(const T&)> handler) {
|
uint64_t Subscribe(std::function<void(const T&)> handler) {
|
||||||
static_assert(sizeof(T) > 0, "Event type must be defined");
|
static_assert(sizeof(T) > 0, "Event type must be defined");
|
||||||
size_t typeId = typeid(T).hash_code();
|
uint32_t typeId = EventTypeId<T>::Get();
|
||||||
uint64_t handlerId = m_nextHandlerId++;
|
uint64_t handlerId = 0;
|
||||||
|
|
||||||
auto it = m_handlers.find(typeId);
|
{
|
||||||
if (it == m_handlers.end()) {
|
std::lock_guard<std::shared_mutex> lock(m_mutex);
|
||||||
m_handlers[typeId] = std::vector<HandlerEntry>();
|
handlerId = m_nextHandlerId++;
|
||||||
|
|
||||||
|
auto it = m_handlers.find(typeId);
|
||||||
|
if (it == m_handlers.end()) {
|
||||||
|
m_handlers[typeId] = std::vector<HandlerEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerEntry entry;
|
||||||
|
entry.id = handlerId;
|
||||||
|
entry.handler = [handler](const void* data) {
|
||||||
|
handler(*static_cast<const T*>(data));
|
||||||
|
};
|
||||||
|
m_handlers[typeId].push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandlerEntry entry;
|
|
||||||
entry.id = handlerId;
|
|
||||||
entry.handler = [handler](const void* data) {
|
|
||||||
handler(*static_cast<const T*>(data));
|
|
||||||
};
|
|
||||||
m_handlers[typeId].push_back(entry);
|
|
||||||
|
|
||||||
return handlerId;
|
return handlerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Unsubscribe(uint64_t handlerId) {
|
void Unsubscribe(uint64_t handlerId) {
|
||||||
static_assert(sizeof(T) > 0, "Event type must be defined");
|
static_assert(sizeof(T) > 0, "Event type must be defined");
|
||||||
size_t typeId = typeid(T).hash_code();
|
uint32_t typeId = EventTypeId<T>::Get();
|
||||||
|
|
||||||
|
std::lock_guard<std::shared_mutex> lock(m_mutex);
|
||||||
auto it = m_handlers.find(typeId);
|
auto it = m_handlers.find(typeId);
|
||||||
if (it != m_handlers.end()) {
|
if (it != m_handlers.end()) {
|
||||||
auto& handlers = it->second;
|
auto& handlers = it->second;
|
||||||
@@ -55,8 +75,9 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
void Publish(const T& event) {
|
void Publish(const T& event) {
|
||||||
static_assert(sizeof(T) > 0, "Event type must be defined");
|
static_assert(sizeof(T) > 0, "Event type must be defined");
|
||||||
size_t typeId = typeid(T).hash_code();
|
uint32_t typeId = EventTypeId<T>::Get();
|
||||||
|
|
||||||
|
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
||||||
auto it = m_handlers.find(typeId);
|
auto it = m_handlers.find(typeId);
|
||||||
if (it != m_handlers.end()) {
|
if (it != m_handlers.end()) {
|
||||||
for (const auto& entry : it->second) {
|
for (const auto& entry : it->second) {
|
||||||
@@ -66,6 +87,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
|
std::lock_guard<std::shared_mutex> lock(m_mutex);
|
||||||
m_handlers.clear();
|
m_handlers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,8 +97,9 @@ private:
|
|||||||
std::function<void(const void*)> handler;
|
std::function<void(const void*)> handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<size_t, std::vector<HandlerEntry>> m_handlers;
|
std::unordered_map<uint32_t, std::vector<HandlerEntry>> m_handlers;
|
||||||
uint64_t m_nextHandlerId = 0;
|
uint64_t m_nextHandlerId = 0;
|
||||||
|
std::shared_mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "SceneManager.h"
|
#include "SceneManager.h"
|
||||||
#include "SelectionManager.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
@@ -7,10 +6,6 @@ namespace Editor {
|
|||||||
|
|
||||||
SceneManager::SceneManager() = default;
|
SceneManager::SceneManager() = default;
|
||||||
|
|
||||||
void SceneManager::SetSelectionManager(ISelectionManager* selectionManager) {
|
|
||||||
m_selectionManager = selectionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
::XCEngine::Components::GameObject* SceneManager::CreateEntity(const std::string& name, ::XCEngine::Components::GameObject* parent) {
|
::XCEngine::Components::GameObject* SceneManager::CreateEntity(const std::string& name, ::XCEngine::Components::GameObject* parent) {
|
||||||
if (!m_scene) {
|
if (!m_scene) {
|
||||||
m_scene = new ::XCEngine::Components::Scene("EditorScene");
|
m_scene = new ::XCEngine::Components::Scene("EditorScene");
|
||||||
@@ -41,12 +36,8 @@ void SceneManager::DeleteEntity(::XCEngine::Components::GameObject::ID id) {
|
|||||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), entity), m_rootEntities.end());
|
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), entity), m_rootEntities.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_selectionManager && m_selectionManager->GetSelectedEntity() == entity->GetID()) {
|
|
||||||
m_selectionManager->ClearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_scene->DestroyGameObject(entity);
|
m_scene->DestroyGameObject(entity);
|
||||||
OnEntityDeleted.Invoke(id);
|
OnEntityDeleted.Invoke(entity->GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneManager::ClipboardData SceneManager::CopyEntityRecursive(const ::XCEngine::Components::GameObject* entity) {
|
SceneManager::ClipboardData SceneManager::CopyEntityRecursive(const ::XCEngine::Components::GameObject* entity) {
|
||||||
|
|||||||
@@ -13,14 +13,11 @@
|
|||||||
#include <XCEngine/Components/GameObject.h>
|
#include <XCEngine/Components/GameObject.h>
|
||||||
#include <XCEngine/Scene/Scene.h>
|
#include <XCEngine/Scene/Scene.h>
|
||||||
|
|
||||||
#include "Core/ISelectionManager.h"
|
|
||||||
#include "Core/ISceneManager.h"
|
#include "Core/ISceneManager.h"
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
|
||||||
class ISelectionManager;
|
|
||||||
|
|
||||||
class SceneManager : public ISceneManager {
|
class SceneManager : public ISceneManager {
|
||||||
public:
|
public:
|
||||||
SceneManager();
|
SceneManager();
|
||||||
@@ -28,11 +25,11 @@ public:
|
|||||||
::XCEngine::Components::GameObject* CreateEntity(const std::string& name, ::XCEngine::Components::GameObject* parent = nullptr);
|
::XCEngine::Components::GameObject* CreateEntity(const std::string& name, ::XCEngine::Components::GameObject* parent = nullptr);
|
||||||
|
|
||||||
::XCEngine::Components::GameObject* GetEntity(::XCEngine::Components::GameObject::ID id) {
|
::XCEngine::Components::GameObject* GetEntity(::XCEngine::Components::GameObject::ID id) {
|
||||||
return m_scene ? m_scene->Find(std::to_string(id)) : nullptr;
|
return m_scene ? m_scene->FindByID(id) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ::XCEngine::Components::GameObject* GetEntity(::XCEngine::Components::GameObject::ID id) const {
|
const ::XCEngine::Components::GameObject* GetEntity(::XCEngine::Components::GameObject::ID id) const {
|
||||||
return m_scene ? m_scene->Find(std::to_string(id)) : nullptr;
|
return m_scene ? m_scene->FindByID(id) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<::XCEngine::Components::GameObject*>& GetRootEntities() const {
|
const std::vector<::XCEngine::Components::GameObject*>& GetRootEntities() const {
|
||||||
@@ -51,8 +48,6 @@ public:
|
|||||||
void CreateDemoScene();
|
void CreateDemoScene();
|
||||||
|
|
||||||
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
||||||
|
|
||||||
void SetSelectionManager(ISelectionManager* selectionManager);
|
|
||||||
|
|
||||||
::XCEngine::Core::Event<::XCEngine::Components::GameObject::ID> OnEntityCreated;
|
::XCEngine::Core::Event<::XCEngine::Components::GameObject::ID> OnEntityCreated;
|
||||||
::XCEngine::Core::Event<::XCEngine::Components::GameObject::ID> OnEntityDeleted;
|
::XCEngine::Core::Event<::XCEngine::Components::GameObject::ID> OnEntityDeleted;
|
||||||
@@ -74,7 +69,6 @@ private:
|
|||||||
::XCEngine::Components::Scene* m_scene = nullptr;
|
::XCEngine::Components::Scene* m_scene = nullptr;
|
||||||
std::vector<::XCEngine::Components::GameObject*> m_rootEntities;
|
std::vector<::XCEngine::Components::GameObject*> m_rootEntities;
|
||||||
std::optional<ClipboardData> m_clipboard;
|
std::optional<ClipboardData> m_clipboard;
|
||||||
ISelectionManager* m_selectionManager = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
@@ -23,8 +25,16 @@ public:
|
|||||||
void SetOpen(bool open) { m_isOpen = open; }
|
void SetOpen(bool open) { m_isOpen = open; }
|
||||||
void Toggle() { m_isOpen = !m_isOpen; }
|
void Toggle() { m_isOpen = !m_isOpen; }
|
||||||
|
|
||||||
void SetContext(IEditorContext* context) { m_context = context; }
|
void SetContext(IEditorContext* context) {
|
||||||
IEditorContext* GetContext() const { return m_context; }
|
assert(!m_context && "Context already set!");
|
||||||
|
m_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEditorContext* GetContext() const {
|
||||||
|
return m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasContext() const { return m_context != nullptr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public:
|
|||||||
void DestroyGameObject(GameObject* gameObject);
|
void DestroyGameObject(GameObject* gameObject);
|
||||||
|
|
||||||
GameObject* Find(const std::string& name) const;
|
GameObject* Find(const std::string& name) const;
|
||||||
|
GameObject* FindByID(GameObjectID id) const;
|
||||||
GameObject* FindGameObjectWithTag(const std::string& tag) const;
|
GameObject* FindGameObjectWithTag(const std::string& tag) const;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ GameObject* Scene::Find(const std::string& name) const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameObject* Scene::FindByID(GameObjectID id) const {
|
||||||
|
auto it = m_gameObjects.find(id);
|
||||||
|
if (it != m_gameObjects.end()) {
|
||||||
|
return it->second.get();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
GameObject* Scene::FindInChildren(GameObject* parent, const std::string& name) const {
|
GameObject* Scene::FindInChildren(GameObject* parent, const std::string& name) const {
|
||||||
for (size_t i = 0; i < parent->GetChildCount(); ++i) {
|
for (size_t i = 0; i < parent->GetChildCount(); ++i) {
|
||||||
GameObject* child = parent->GetChild(i);
|
GameObject* child = parent->GetChild(i);
|
||||||
|
|||||||
Reference in New Issue
Block a user