Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ZEngine/ZEngine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ if(ZENGINE_TRACY)
target_compile_definitions(zEngineLib PRIVATE ZENGINE_TRACY=1)
endif()

# Editor-only engine code (YAMLSceneSerializer).
option(ZENGINE_BUILD_EDITOR "Compile editor-only engine code" ON)
if (ZENGINE_BUILD_EDITOR)
target_compile_definitions(zEngineLib PUBLIC ZENGINE_EDITOR=1)
endif()

# Logging defaults
# it expands in
# ZENGINE_LOG_LEVEL_${CHANNEL}=ZENGINE_LOG_LEVEL_${ZENGINE_LOG_LEVEL_${CHANNEL}} => ZENGINE_LOG_LEVEL_ENGINE=ZENGINE_LOG_LEVEL_WARN
Expand Down
78 changes: 78 additions & 0 deletions ZEngine/ZEngine/ECS/ComponentSerializerRegistry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <ZEngine/ECS/ComponentSerializerRegistry.h>
#include <ZEngine/Logging/LoggerDefinition.h>
#include <ZEngine/ZEngineDef.h>

namespace ZEngine::ECS
{
ComponentSerializerRegistry& ComponentSerializerRegistry::Get()
{
static ComponentSerializerRegistry s_instance;
return s_instance;
}

bool ComponentSerializerRegistry::IsInitialized() const
{
return m_arena != nullptr;
}

void ComponentSerializerRegistry::Initialize(Core::Memory::ArenaAllocator* arena, uint32_t capacity)
{
ZENGINE_VALIDATE_ASSERT(arena != nullptr, "ComponentSerializerRegistry::Initialize: arena must not be null")
ZENGINE_VALIDATE_ASSERT(capacity > 0, "ComponentSerializerRegistry::Initialize: capacity must be > 0")

if (m_arena)
{
return;
}

m_arena = arena;
m_ids.init(arena, capacity);
m_fns.init(arena, capacity);
}

void ComponentSerializerRegistry::Register(ComponentTypeID type_id, ComponentSerializeFns fns)
{
ZENGINE_VALIDATE_ASSERT(m_arena != nullptr, "ComponentSerializerRegistry::Register: Initialize() must be called first")

if (Lookup(type_id))
{
ZENGINE_CORE_WARN("ComponentSerializerRegistry: TypeID {} already registered, ignoring", type_id);
return;
}

ZENGINE_VALIDATE_ASSERT(m_ids.size() < m_ids.capacity(), "ComponentSerializerRegistry::Register: exceeded the capacity reserved by Initialize() — pass a larger capacity there")

m_ids.push(type_id);
m_fns.push(fns);
}

const ComponentSerializeFns* ComponentSerializerRegistry::Lookup(ComponentTypeID type_id) const
{
for (uint32_t i = 0; i < m_ids.size(); ++i)
{
if (m_ids[i] == type_id)
{
return &m_fns[i];
}
}
return nullptr;
}

void ComponentSerializerRegistry::ForEach(ForEachSerializerFn fn, void* ctx) const
{
if (!fn)
{
return;
}

for (uint32_t i = 0; i < m_ids.size(); ++i)
{
fn(ctx, m_ids[i], m_fns[i]);
}
}

uint32_t ComponentSerializerRegistry::Count() const
{
return static_cast<uint32_t>(m_ids.size());
}
} // namespace ZEngine::ECS
52 changes: 52 additions & 0 deletions ZEngine/ZEngine/ECS/ComponentSerializerRegistry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once
#include <ZEngine/Core/Containers/Array.h>
#include <ZEngine/Core/Memory/Allocator.h>
#include <ZEngine/ECS/ComponentTypeID.h>
#include <ZEngine/ECS/EntityID.h>
#include <yaml-cpp/yaml.h>
#include <cstdint>

namespace ZEngine::ECS
{
class Scene;

using SerializeYAMLFn = void (*)(void* ctx, EntityID id, const Scene& scene, YAML::Node& out);
using DeserializeYAMLFn = void (*)(void* ctx, EntityID id, Scene& scene, const YAML::Node& in);
using SerializeBinaryFn = void (*)(void* ctx, EntityID id, const Scene& scene, Core::Containers::Array<uint8_t>& out);
using DeserializeBinaryFn = void (*)(void* ctx, EntityID id, Scene& scene, const uint8_t* data, uint32_t size);

struct ComponentSerializeFns
{
SerializeYAMLFn SerializeYAML = nullptr;
DeserializeYAMLFn DeserializeYAML = nullptr;
SerializeBinaryFn SerializeBinary = nullptr;
DeserializeBinaryFn DeserializeBinary = nullptr;
void* Context = nullptr; // first arg to every callback
};

using ForEachSerializerFn = void (*)(void* ctx, ComponentTypeID type_id, const ComponentSerializeFns& fns);

class ComponentSerializerRegistry
{
public:
static ComponentSerializerRegistry& Get();

void Initialize(Core::Memory::ArenaAllocator* arena, uint32_t capacity = 64);

[[nodiscard]] bool IsInitialized() const;

void Register(ComponentTypeID type_id, ComponentSerializeFns fns);

[[nodiscard]] const ComponentSerializeFns* Lookup(ComponentTypeID type_id) const;

// Iterates all registered type IDs in registration order.
void ForEach(ForEachSerializerFn fn, void* ctx) const;

[[nodiscard]] uint32_t Count() const;

private:
Core::Containers::Array<ComponentTypeID> m_ids;
Core::Containers::Array<ComponentSerializeFns> m_fns;
Core::Memory::ArenaAllocator* m_arena = nullptr;
};
} // namespace ZEngine::ECS
18 changes: 18 additions & 0 deletions ZEngine/ZEngine/ECS/ISceneSerializer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include <ZEngine/Core/VFS/IVFSContext.h>
#include <ZEngine/Core/VFS/VFSError.h>
#include <ZEngine/Core/VFS/VFSPath.h>
#include <ZEngine/ECS/SceneSnapshot.h>

namespace ZEngine::ECS
{
class ISceneSerializer
{
public:
virtual ~ISceneSerializer() = default;

virtual Core::VFS::VFSResult<void> Serialize(Core::VFS::IVFSContext& ctx, const Core::VFS::VFSPath& path, const SceneSnapshot& scene) = 0;

virtual Core::VFS::VFSResult<void> Deserialize(Core::VFS::IVFSContext& ctx, const Core::VFS::VFSPath& path, SceneSnapshot& out_scene) = 0;
};
} // namespace ZEngine::ECS
18 changes: 15 additions & 3 deletions ZEngine/ZEngine/ECS/Reflection/ComponentReflectionRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,23 @@ namespace ZEngine::ECS
return s_instance;
}

void ComponentReflectionRegistry::Initialize(Core::Memory::ArenaAllocator* arena)
bool ComponentReflectionRegistry::IsInitialized() const
{
return m_arena != nullptr;
}

void ComponentReflectionRegistry::Initialize(Core::Memory::ArenaAllocator* arena, uint32_t capacity)
{
ZENGINE_VALIDATE_ASSERT(arena != nullptr, "ComponentReflectionRegistry::Initialize: arena must not be null")
ZENGINE_VALIDATE_ASSERT(capacity > 0, "ComponentReflectionRegistry::Initialize: capacity must be > 0")

if (m_arena)
{
return; // already initialized
}

m_arena = arena;
m_meta.init(arena, 64);
m_meta.init(arena, capacity);
}

void ComponentReflectionRegistry::Register(const ComponentMeta& meta)
Expand All @@ -32,7 +44,7 @@ namespace ZEngine::ECS
return;
}

ZENGINE_VALIDATE_ASSERT(m_meta.size() < m_meta.capacity(), "ComponentReflectionRegistry::Register: exceeded reserved capacity")
ZENGINE_VALIDATE_ASSERT(m_meta.size() < m_meta.capacity(), "ComponentReflectionRegistry::Register: exceeded the capacity reserved by Initialize() — pass a larger capacity there")

m_meta.push(meta);
}
Expand Down
8 changes: 3 additions & 5 deletions ZEngine/ZEngine/ECS/Reflection/ComponentReflectionRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@ namespace ZEngine::ECS
class ComponentReflectionRegistry
{
public:
// Process-wide singleton. Get() is safe at any time, but the instance is
// unusable until Initialize() supplies an arena.
static ComponentReflectionRegistry& Get();

void Initialize(Core::Memory::ArenaAllocator* arena);
void Initialize(Core::Memory::ArenaAllocator* arena, uint32_t capacity = 64);

[[nodiscard]] bool IsInitialized() const;

void Register(const ComponentMeta& meta);

// Returned pointers dangle once Register() grows past the 64 slots
// reserved in Initialize(). Keep component types <= 64.
[[nodiscard]] const ComponentMeta* Lookup(ComponentTypeID id) const;
[[nodiscard]] const ComponentMeta* LookupByName(const char* type_name) const;

Expand Down
25 changes: 25 additions & 0 deletions ZEngine/ZEngine/ECS/SceneSnapshot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once
#include <ZEngine/Core/Containers/Array.h>
#include <ZEngine/Core/Containers/Strings.h>
#include <ZEngine/Core/Memory/Allocator.h>
#include <ZEngine/ECS/EntityID.h>
#include <uuid.h>

namespace ZEngine::ECS
{
struct SceneSnapshot
{
uuids::uuid SceneUUID = {};
Core::Containers::String Name = {};

Core::Containers::Array<EntityID> Entities = {};
Comment thread
jnyfah marked this conversation as resolved.

static SceneSnapshot Create(Core::Memory::ArenaAllocator* arena, cstring name, uint32_t entity_capacity = 64)
{
SceneSnapshot snapshot{};
snapshot.Name.init(arena, name ? name : "");
snapshot.Entities.init(arena, entity_capacity ? entity_capacity : 1);
return snapshot;
}
};
} // namespace ZEngine::ECS
Loading
Loading