feat(editor): unify component registration pipeline

This commit is contained in:
2026-03-26 02:24:11 +08:00
parent 1ef3048da1
commit d018a4c82c
17 changed files with 268 additions and 116 deletions

View File

@@ -247,6 +247,7 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Components/LightComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Components/AudioSourceComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Components/AudioListenerComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Components/ComponentFactoryRegistry.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/Component.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/TransformComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/GameObject.cpp
@@ -254,6 +255,7 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/LightComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/AudioSourceComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/AudioListenerComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Components/ComponentFactoryRegistry.cpp
# Scene
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scene/Scene.h

View File

@@ -0,0 +1,32 @@
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
namespace XCEngine {
namespace Components {
class Component;
class GameObject;
class ComponentFactoryRegistry {
public:
using CreateComponentFn = Component* (*)(GameObject* gameObject);
static ComponentFactoryRegistry& Get();
void RegisterFactory(const std::string& typeName, CreateComponentFn createFn);
Component* CreateComponent(GameObject* gameObject, const std::string& typeName) const;
bool IsRegistered(const std::string& typeName) const;
const std::vector<std::string>& GetRegisteredTypes() const;
private:
ComponentFactoryRegistry();
std::unordered_map<std::string, CreateComponentFn> m_factories;
std::vector<std::string> m_registrationOrder;
};
} // namespace Components
} // namespace XCEngine

View File

@@ -0,0 +1,67 @@
#include "Components/ComponentFactoryRegistry.h"
#include "Components/AudioListenerComponent.h"
#include "Components/AudioSourceComponent.h"
#include "Components/CameraComponent.h"
#include "Components/GameObject.h"
#include "Components/LightComponent.h"
namespace XCEngine {
namespace Components {
namespace {
template<typename T>
Component* CreateBuiltInComponent(GameObject* gameObject) {
return gameObject ? gameObject->AddComponent<T>() : nullptr;
}
} // namespace
ComponentFactoryRegistry& ComponentFactoryRegistry::Get() {
static ComponentFactoryRegistry registry;
return registry;
}
ComponentFactoryRegistry::ComponentFactoryRegistry() {
RegisterFactory("Camera", &CreateBuiltInComponent<CameraComponent>);
RegisterFactory("Light", &CreateBuiltInComponent<LightComponent>);
RegisterFactory("AudioSource", &CreateBuiltInComponent<AudioSourceComponent>);
RegisterFactory("AudioListener", &CreateBuiltInComponent<AudioListenerComponent>);
}
void ComponentFactoryRegistry::RegisterFactory(const std::string& typeName, CreateComponentFn createFn) {
if (typeName.empty() || !createFn) {
return;
}
const auto [it, inserted] = m_factories.insert_or_assign(typeName, createFn);
(void)it;
if (inserted) {
m_registrationOrder.push_back(typeName);
}
}
Component* ComponentFactoryRegistry::CreateComponent(GameObject* gameObject, const std::string& typeName) const {
if (!gameObject) {
return nullptr;
}
const auto it = m_factories.find(typeName);
if (it == m_factories.end() || !it->second) {
return nullptr;
}
return it->second(gameObject);
}
bool ComponentFactoryRegistry::IsRegistered(const std::string& typeName) const {
return m_factories.find(typeName) != m_factories.end();
}
const std::vector<std::string>& ComponentFactoryRegistry::GetRegisteredTypes() const {
return m_registrationOrder;
}
} // namespace Components
} // namespace XCEngine

View File

@@ -1,10 +1,7 @@
#include "Scene/Scene.h"
#include "Components/ComponentFactoryRegistry.h"
#include "Components/GameObject.h"
#include "Components/TransformComponent.h"
#include "Components/CameraComponent.h"
#include "Components/LightComponent.h"
#include "Components/AudioSourceComponent.h"
#include "Components/AudioListenerComponent.h"
#include <sstream>
#include <algorithm>
#include <unordered_map>
@@ -66,27 +63,6 @@ std::string UnescapeString(const std::string& value) {
return unescaped;
}
Component* CreateComponentByType(GameObject* gameObject, const std::string& type) {
if (!gameObject) {
return nullptr;
}
if (type == "Camera") {
return gameObject->AddComponent<CameraComponent>();
}
if (type == "Light") {
return gameObject->AddComponent<LightComponent>();
}
if (type == "AudioSource") {
return gameObject->AddComponent<AudioSourceComponent>();
}
if (type == "AudioListener") {
return gameObject->AddComponent<AudioListenerComponent>();
}
return nullptr;
}
void SerializeGameObjectRecursive(std::ostream& os, GameObject* gameObject) {
if (!gameObject) {
return;
@@ -345,7 +321,7 @@ void Scene::DeserializeFromString(const std::string& data) {
}
for (const PendingComponentData& componentData : pending.components) {
if (Component* component = CreateComponentByType(go.get(), componentData.type)) {
if (Component* component = ComponentFactoryRegistry::Get().CreateComponent(go.get(), componentData.type)) {
if (!componentData.payload.empty()) {
std::istringstream componentStream(componentData.payload);
component->Deserialize(componentStream);