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
|
||||
dxgi.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
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ISceneManager.h"
|
||||
#include "Managers/SceneManager.h"
|
||||
#include "Managers/ProjectManager.h"
|
||||
#include "EditorEvents.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -20,7 +21,16 @@ public:
|
||||
, m_selectionManager(std::make_unique<SelectionManager>(*m_eventBus))
|
||||
, m_sceneManager(std::make_unique<SceneManager>())
|
||||
, 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 {
|
||||
@@ -53,6 +63,7 @@ private:
|
||||
std::unique_ptr<SceneManager> m_sceneManager;
|
||||
std::unique_ptr<ProjectManager> m_projectManager;
|
||||
std::string m_projectPath;
|
||||
uint64_t m_entityDeletedHandlerId;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,25 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <typeinfo>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace XCEngine {
|
||||
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 {
|
||||
public:
|
||||
using EventHandler = std::function<void()>;
|
||||
@@ -18,29 +32,35 @@ public:
|
||||
template<typename T>
|
||||
uint64_t Subscribe(std::function<void(const T&)> handler) {
|
||||
static_assert(sizeof(T) > 0, "Event type must be defined");
|
||||
size_t typeId = typeid(T).hash_code();
|
||||
uint64_t handlerId = m_nextHandlerId++;
|
||||
uint32_t typeId = EventTypeId<T>::Get();
|
||||
uint64_t handlerId = 0;
|
||||
|
||||
auto it = m_handlers.find(typeId);
|
||||
if (it == m_handlers.end()) {
|
||||
m_handlers[typeId] = std::vector<HandlerEntry>();
|
||||
{
|
||||
std::lock_guard<std::shared_mutex> lock(m_mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Unsubscribe(uint64_t handlerId) {
|
||||
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);
|
||||
if (it != m_handlers.end()) {
|
||||
auto& handlers = it->second;
|
||||
@@ -55,8 +75,9 @@ public:
|
||||
template<typename T>
|
||||
void Publish(const T& event) {
|
||||
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);
|
||||
if (it != m_handlers.end()) {
|
||||
for (const auto& entry : it->second) {
|
||||
@@ -66,6 +87,7 @@ public:
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
std::lock_guard<std::shared_mutex> lock(m_mutex);
|
||||
m_handlers.clear();
|
||||
}
|
||||
|
||||
@@ -75,8 +97,9 @@ private:
|
||||
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;
|
||||
std::shared_mutex m_mutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "SceneManager.h"
|
||||
#include "SelectionManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -7,10 +6,6 @@ namespace Editor {
|
||||
|
||||
SceneManager::SceneManager() = default;
|
||||
|
||||
void SceneManager::SetSelectionManager(ISelectionManager* selectionManager) {
|
||||
m_selectionManager = selectionManager;
|
||||
}
|
||||
|
||||
::XCEngine::Components::GameObject* SceneManager::CreateEntity(const std::string& name, ::XCEngine::Components::GameObject* parent) {
|
||||
if (!m_scene) {
|
||||
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());
|
||||
}
|
||||
|
||||
if (m_selectionManager && m_selectionManager->GetSelectedEntity() == entity->GetID()) {
|
||||
m_selectionManager->ClearSelection();
|
||||
}
|
||||
|
||||
m_scene->DestroyGameObject(entity);
|
||||
OnEntityDeleted.Invoke(id);
|
||||
OnEntityDeleted.Invoke(entity->GetID());
|
||||
}
|
||||
|
||||
SceneManager::ClipboardData SceneManager::CopyEntityRecursive(const ::XCEngine::Components::GameObject* entity) {
|
||||
|
||||
@@ -13,14 +13,11 @@
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
|
||||
#include "Core/ISelectionManager.h"
|
||||
#include "Core/ISceneManager.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
class ISelectionManager;
|
||||
|
||||
class SceneManager : public ISceneManager {
|
||||
public:
|
||||
SceneManager();
|
||||
@@ -28,11 +25,11 @@ public:
|
||||
::XCEngine::Components::GameObject* CreateEntity(const std::string& name, ::XCEngine::Components::GameObject* parent = nullptr);
|
||||
|
||||
::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 {
|
||||
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 {
|
||||
@@ -52,8 +49,6 @@ public:
|
||||
|
||||
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> OnEntityDeleted;
|
||||
::XCEngine::Core::Event<::XCEngine::Components::GameObject::ID> OnEntityChanged;
|
||||
@@ -74,7 +69,6 @@ private:
|
||||
::XCEngine::Components::Scene* m_scene = nullptr;
|
||||
std::vector<::XCEngine::Components::GameObject*> m_rootEntities;
|
||||
std::optional<ClipboardData> m_clipboard;
|
||||
ISelectionManager* m_selectionManager = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
@@ -23,8 +25,16 @@ public:
|
||||
void SetOpen(bool open) { m_isOpen = open; }
|
||||
void Toggle() { m_isOpen = !m_isOpen; }
|
||||
|
||||
void SetContext(IEditorContext* context) { m_context = context; }
|
||||
IEditorContext* GetContext() const { return m_context; }
|
||||
void SetContext(IEditorContext* context) {
|
||||
assert(!m_context && "Context already set!");
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
IEditorContext* GetContext() const {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
bool HasContext() const { return m_context != nullptr; }
|
||||
|
||||
protected:
|
||||
std::string m_name;
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
void DestroyGameObject(GameObject* gameObject);
|
||||
|
||||
GameObject* Find(const std::string& name) const;
|
||||
GameObject* FindByID(GameObjectID id) const;
|
||||
GameObject* FindGameObjectWithTag(const std::string& tag) const;
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -79,6 +79,14 @@ GameObject* Scene::Find(const std::string& name) const {
|
||||
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 {
|
||||
for (size_t i = 0; i < parent->GetChildCount(); ++i) {
|
||||
GameObject* child = parent->GetChild(i);
|
||||
|
||||
Reference in New Issue
Block a user