Implements component serialization

Adds serialization and deserialization functionality to the ECS component system.

This allows components to be saved and loaded, enabling scene persistence.
The IdentityComponent is updated to support serialization/deserialization.
The scene saving logic in scene_manager is updated to serialize components instead of hardcoded values.
This commit is contained in:
2025-09-06 14:18:28 +02:00
parent ccd0d045f9
commit 25e7d97b71
6 changed files with 190 additions and 111 deletions

View File

@@ -5,16 +5,11 @@
</component>
<component name="ChangeListManager">
<list default="true" id="e81d6e08-efc7-40a0-909d-ec4943d948e9" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/Logger.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/Logger.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/Skybox.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/Skybox.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/camera_class.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/camera_class.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/d_3d_class.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/d_3d_class.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/display_plane_class.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/display_plane_class.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/fps_limiter.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/fps_limiter.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/frustum.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/frustum.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/frustumclass.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/frustumclass.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/imguiManager.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/imguiManager.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/scene_manager.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/scene_manager.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/imgui.ini" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/imgui.ini" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/identity_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/identity_component.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/enginecustom/src/src/system/scene_manager.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/src/system/scene_manager.cpp" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@@ -81,7 +76,7 @@
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.environmentSetup&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;MonitoringCountersPageId&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
@@ -242,6 +237,10 @@
<workItem from="1753700140931" duration="918000" />
<workItem from="1753701507863" duration="7153000" />
<workItem from="1753713925469" duration="1739000" />
<workItem from="1754572996727" duration="224000" />
<workItem from="1755617169013" duration="222000" />
<workItem from="1757101936080" duration="185000" />
<workItem from="1757158576637" duration="2501000" />
</task>
<task id="LOCAL-00001" summary="Minor update - viewport window tweak">
<option name="closed" value="true" />

View File

@@ -22,13 +22,13 @@ DockId=0x00000009,0
[Window][Objects]
Pos=0,19
Size=234,609
Size=234,842
Collapsed=0
DockId=0x0000000B,0
[Window][Terrain]
Pos=236,19
Size=266,609
Size=266,842
Collapsed=0
DockId=0x00000007,0
@@ -45,15 +45,15 @@ Collapsed=0
DockId=0x0000000B,1
[Window][Engine Settings]
Pos=1267,462
Size=317,166
Pos=1267,631
Size=317,230
Collapsed=0
DockId=0x00000006,0
[Docking][Data]
DockSpace ID=0xCCBD8CF7 Window=0x3DA2F1DE Pos=0,19 Size=1584,842 Split=Y
DockNode ID=0x00000003 Parent=0xCCBD8CF7 SizeRef=1584,609 Split=X
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=234,842 Selected=0x321620B2
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=234,842 Selected=0x031DC75C
DockNode ID=0x0000000C Parent=0x00000003 SizeRef=1348,842 Split=X
DockNode ID=0x00000007 Parent=0x0000000C SizeRef=266,842 Selected=0x393905AB
DockNode ID=0x00000008 Parent=0x0000000C SizeRef=1316,842 Split=X

View File

@@ -33,8 +33,19 @@ public:
*/
virtual void Update(float deltaTime) {}
// virtual std::string Serialize() {}
// virtual void Deserialize(const std::string& data) {}
/**
* Serialize the component to a string (for debugging or saving).
* @return A string representation of the component.
*/
virtual std::string Serialize() const { return ""; }
/**
* Deserialize the component from a string (for loading).
* @param data The string data to deserialize from.
* @return True if deserialization was successful, otherwise false.
*/
virtual bool Deserialize(const std::string& data) { return false;}
};
/**

View File

@@ -92,6 +92,52 @@ public:
return ObjectType::Unknown;
}
/**
* Serialize the component to a string.
* Format: "id:name:type"
* @return A string representation of the component.
*/
std::string Serialize() const override
{
std::stringstream ss;
ss << m_id << ":" << m_name << ":" << ObjectTypeToString(m_type);
return ss.str();
}
/**
* Deserialize the component from a string.
* Expected format: "id:name:type"
* @param data The string data to deserialize from.
* @return True if deserialization was successful, otherwise false.
*/
bool Deserialize(const std::string& data) override
{
std::stringstream ss(data);
std::string segment;
std::vector<std::string> segments;
while (std::getline(ss, segment, ':'))
{
segments.push_back(segment);
}
if (segments.empty()) return false;
if (segments.size() != 3) return false;
try
{
m_id = std::stoi(segments[0]);
m_name = segments[1];
m_type = StringToObjectType(segments[2]);
return true;
} catch (const std::exception&)
{
return false;
}
}
private:
int m_id; // ID unique de l'objet
std::string m_name; // Nom de l'objet

View File

@@ -124,6 +124,14 @@ public:
}
}
/**
* Get all components of the entity.
* @return A constant reference to the map of components.
*/
const std::unordered_map<ComponentTypeID, ComponentPtr>& GetAllComponents() const {
return m_Components;
}
private:
/**

View File

@@ -310,106 +310,121 @@ bool scene_manager::save_scene() {
return false;
}
for (const auto& object : entity_) {
XMFLOAT3 position, scale, rotation;
int id = 0;
int mass = 0;
float boundingRadius = 0;
std::string name = "NONE";
std::string shaderType = "NONE";
std::string objectType = "NONE";
std::wstring model_path = L"";
bool physics_enabled = false;
outFile << entity_.size() << std::endl;
auto transform = object->GetComponent<ecs::TransformComponent>();
if (transform) {
// convert XMVECTOR to XMFLOAT3
XMStoreFloat3(&position, transform->GetPosition());
XMStoreFloat3(&rotation, transform->GetRotation());
XMStoreFloat3(&scale, transform->GetScale());
}
for (const auto& entity : entity_)
{
const auto& components = entity->GetAllComponents();
auto identity = object->GetComponent<ecs::IdentityComponent>();
if (identity) {
outFile << components.size() << std::endl;
id = identity->GetId();
name = identity->GetName();
objectType = identity->ObjectTypeToString(identity->GetType());
}
auto model_path_component = object->GetComponent<ecs::ModelPathComponent>();
if (model_path_component) {
model_path = model_path_component->GetPath();
}
auto shader = object->GetComponent<ecs::ShaderComponent>();
if (shader)
for (const auto& component : components)
{
shaderType = shader->ShaderTypeToString(shader->GetActiveShader());
outFile << typeid(*component).name() << std::endl;
outFile << component->Serialize() << std::endl;
}
auto physics = object->GetComponent<ecs::PhysicsComponent>();
if (physics) {
physics_enabled = physics->IsPhysicsEnabled();
mass = physics->GetMass();
boundingRadius = physics->GetBoundingRadius();
}
// <20>crire les donn<6E>es de base de l'objet
outFile << id << " "
<< name << " "
<< position.x << " " << position.y << " " << position.z << " "
<< rotation.x << " " << rotation.y << " " << rotation.z << " "
<< scale.x << " " << scale.y << " " << scale.z << " "
<< convert_w_string_to_string(model_path) << " "
<< shaderType << " "
<< boundingRadius << " "
<< objectType << " "
<< mass << " "
<< physics_enabled;
// Sauvegarder les chemins des textures_
// Format: nombre de textures_ diffuses, puis les chemins
// M<>me chose pour les autres types de textures_
auto render = object->GetComponent<ecs::RenderComponent>();
if (render)
{
const auto& model = render->GetModel();
const auto& textureContainer = model->GetTextureContainer();
const auto& diffusePaths = textureContainer.GetPaths(TextureType::Diffuse);
outFile << " " << diffusePaths.size();
for (const auto& path : diffusePaths) {
outFile << " " << convert_w_string_to_string(path);
}
const auto& normalPaths = textureContainer.GetPaths(TextureType::Normal);
outFile << " " << normalPaths.size();
for (const auto& path : normalPaths) {
outFile << " " << convert_w_string_to_string(path);
}
const auto& specularPaths = textureContainer.GetPaths(TextureType::Specular);
outFile << " " << specularPaths.size();
for (const auto& path : specularPaths) {
outFile << " " << convert_w_string_to_string(path);
}
const auto& alphaPaths = textureContainer.GetPaths(TextureType::Alpha);
outFile << " " << alphaPaths.size();
for (const auto& path : alphaPaths) {
outFile << " " << convert_w_string_to_string(path);
}
}
outFile << std::endl;
}
// for (const auto& object : entity_) {
// XMFLOAT3 position, scale, rotation;
// int id = 0;
// int mass = 0;
// float boundingRadius = 0;
// std::string name = "NONE";
// std::string shaderType = "NONE";
// std::string objectType = "NONE";
// std::wstring model_path = L"";
// bool physics_enabled = false;
//
// auto transform = object->GetComponent<ecs::TransformComponent>();
// if (transform) {
// // convert XMVECTOR to XMFLOAT3
// XMStoreFloat3(&position, transform->GetPosition());
// XMStoreFloat3(&rotation, transform->GetRotation());
// XMStoreFloat3(&scale, transform->GetScale());
// }
//
//
// auto identity = object->GetComponent<ecs::IdentityComponent>();
// if (identity) {
//
// id = identity->GetId();
// name = identity->GetName();
// objectType = identity->ObjectTypeToString(identity->GetType());
//
// }
//
// auto model_path_component = object->GetComponent<ecs::ModelPathComponent>();
// if (model_path_component) {
//
// model_path = model_path_component->GetPath();
// }
//
// auto shader = object->GetComponent<ecs::ShaderComponent>();
// if (shader)
// {
// shaderType = shader->ShaderTypeToString(shader->GetActiveShader());
// }
//
// auto physics = object->GetComponent<ecs::PhysicsComponent>();
// if (physics) {
// physics_enabled = physics->IsPhysicsEnabled();
// mass = physics->GetMass();
// boundingRadius = physics->GetBoundingRadius();
// }
//
// // <20>crire les donn<6E>es de base de l'objet
// outFile << id << " "
// << name << " "
// << position.x << " " << position.y << " " << position.z << " "
// << rotation.x << " " << rotation.y << " " << rotation.z << " "
// << scale.x << " " << scale.y << " " << scale.z << " "
// << convert_w_string_to_string(model_path) << " "
// << shaderType << " "
// << boundingRadius << " "
// << objectType << " "
// << mass << " "
// << physics_enabled;
//
// // Sauvegarder les chemins des textures_
// // Format: nombre de textures_ diffuses, puis les chemins
// // M<>me chose pour les autres types de textures_
//
//
// auto render = object->GetComponent<ecs::RenderComponent>();
// if (render)
// {
// const auto& model = render->GetModel();
//
// const auto& textureContainer = model->GetTextureContainer();
//
// const auto& diffusePaths = textureContainer.GetPaths(TextureType::Diffuse);
// outFile << " " << diffusePaths.size();
// for (const auto& path : diffusePaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
//
// const auto& normalPaths = textureContainer.GetPaths(TextureType::Normal);
// outFile << " " << normalPaths.size();
// for (const auto& path : normalPaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
// const auto& specularPaths = textureContainer.GetPaths(TextureType::Specular);
// outFile << " " << specularPaths.size();
// for (const auto& path : specularPaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
// const auto& alphaPaths = textureContainer.GetPaths(TextureType::Alpha);
// outFile << " " << alphaPaths.size();
// for (const auto& path : alphaPaths) {
// outFile << " " << convert_w_string_to_string(path);
// }
// }
//
//
// outFile << std::endl;
// }
outFile.close();
Logger::Get().Log("Scene saved successfully to " + scene_path_, __FILE__, __LINE__, Logger::LogLevel::Info);
return true;