Improving entity manager and entity support for a simpler version, made some cleanup on the road to support serialization of world

This commit is contained in:
2026-08-31 23:05:20 -04:00
parent 4180622d6a
commit cb615091ca
17 changed files with 607 additions and 88 deletions
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include <Entity/Entity.h>
struct StaticMesh
{
DECLARE_ENTITY()
};
DEFINE_ENTITY(StaticMesh);
+278
View File
@@ -0,0 +1,278 @@
#include <Data/World.h>
#include <Core/Common/CoreUtils.h>
#include <Core/Common/serialization.h>
#include <Core/HAL/Filesystem/Filesystem.h>
#include <Core/HAL/IO/IOStream.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Thread/ThreadContext.h>
#include <Graphics/MeshRenderer.h>
#ifdef JULIET_ENABLE_IMGUI
#include <imgui.h>
#endif
void InitWorld(NonNullPtr<World> world, NonNullPtr<Arena> arena)
{
world->WorldArena = arena.Get();
}
void ShutdownWorld(NonNullPtr<World> world)
{
world->WorldArena = nullptr;
}
void AddToWorld(NonNullPtr<World> world, NonNullPtr<Entity> entity)
{
// RegisterEntity(*world->EntityManager, entity.Get());
}
void RemoveWorldEntity(World& world, size_t index) {}
void Serialize(archive& data, World& world, String filename)
{
Assert(IsValid(filename));
TempArena temp = scratch_begin(nullptr, 0);
if (data.loading)
{
// Load
ByteBuffer fileBuffer = LoadFile(temp.Arena, filename);
}
else
{
// Save
IOStream* stream = IOFromFile(temp.Arena, filename, WrapString("wb"));
index_t beginPos = ArenaPos(temp.Arena);
// Headers
auto* header = ArenaPushStruct<WorldFileHeader>(temp.Arena);
header->Magic = kWorldMagic;
header->Version = kWorldVersion;
index_t endPos = ArenaPos(temp.Arena);
// Write
ByteBuffer writeBuffer = { .Data = reinterpret_cast<Byte*>(header), .Size = endPos - beginPos };
size_t written = IOWrite(stream, writeBuffer);
Assert(writeBuffer.Size == written);
IOClose(stream);
}
scratch_end(temp);
//
// uint32 entityCount = static_cast<uint32>(world.Entities.Size());
// size_t totalBytes = sizeof(WorldFileHeader) + static_cast<size_t>(entityCount) * sizeof(WorldEntityDiskRecord);
//
// ArenaParams tempParams = { .ReserveSize = Megabytes(1), .Name = "WorldSaveArena" };
// Arena* tempArena = ArenaAllocate(tempParams);
// if (!tempArena)
// {
// LogError(LogCategory::Game, "SaveWorld: Failed to allocate memory for saving world.");
// return false;
// }
//
// auto deferRelease = Defer([&]() { ArenaRelease(tempArena); });
//
// uint8* bufferData = ArenaPushArray<uint8, false>(tempArena, totalBytes);
// if (!bufferData)
// {
// LogError(LogCategory::Game, "SaveWorld: Failed to allocate buffer in arena.");
// return false;
// }
//
// auto* header = reinterpret_cast<WorldFileHeader*>(bufferData);
// header->Magic = kWorldMagic;
// header->Version = kWorldVersion;
// header->EntityCount = entityCount;
// header->Reserved = 0;
//
// auto* records = reinterpret_cast<WorldEntityDiskRecord*>(bufferData + sizeof(WorldFileHeader));
// for (size_t i = 0; i < entityCount; ++i)
// {
// const Entity& ent = world.Entities[i];
// records[i].X = ent.X;
// records[i].Y = ent.Y;
// records[i].Z = ent.Z;
// }
//
// IOStream* stream = IOFromFile(tempArena, filename, WrapString("wb"));
// if (!stream)
// {
// LogError(LogCategory::Game, "SaveWorld: Failed to open file for writing: %s", CStr(filename));
// return false;
// }
//
// ByteBuffer writeBuffer = { .Data = reinterpret_cast<Byte*>(bufferData), .Size = totalBytes };
//
// size_t written = IOWrite(stream, writeBuffer);
// IOClose(stream);
//
// if (written != totalBytes)
// {
// LogError(LogCategory::Game, "SaveWorld: Failed to write complete world data to %s (wrote %zu / %zu bytes)",
// CStr(filename), written, totalBytes);
// return false;
// }
//
// LogMessage(LogCategory::Game, "World successfully saved to %s (%u entities)", CStr(filename), entityCount);
// return true;
}
[[nodiscard]] bool LoadWorld(World& world, String filename)
{
Assert(IsValid(filename));
// Assert(world.WorldArena != nullptr);
//
// TempArena loadArena = scratch_begin(nullptr, 0);
//
// ByteBuffer fileBuffer = LoadFile(loadArena.Arena, filename);
// if (fileBuffer.Data && fileBuffer.Size < sizeof(WorldFileHeader))
// {
// const WorldFileHeader* header = reinterpret_cast<const WorldFileHeader*>(fileBuffer.Data);
// const bool invalidMagicNum = header->Magic != kWorldMagic;
// const bool invalidVersion = header->Version != kWorldVersion;
// if (invalidMagicNum)
// {
// LogError(LogCategory::Game, "LoadWorld: Invalid magic in world file: %s (expected 0x%08X, got 0x%08X)",
// CStr(filename), kWorldMagic, header->Magic);
// }
//
// if (invalidVersion)
// {
// LogError(LogCategory::Game, "LoadWorld: Unsupported world file version: %u in %s", header->Version, CStr(filename));
// }
//
// size_t expectedSize = sizeof(WorldFileHeader) + static_cast<size_t>(header->EntityCount) * sizeof(WorldEntityDiskRecord);
// const bool invalidSize = fileBuffer.Size < expectedSize;
// if (invalidSize)
// {
// LogError(LogCategory::Game, "LoadWorld: Corrupted file %s: size %zu < expected %zu for %u entities",
// CStr(filename), fileBuffer.Size, expectedSize, header->EntityCount);
// }
//
// if (!invalidMagicNum && !invalidVersion && !invalidSize)
// {
//
// // world.Entities.Clear();
// //
// // const auto* records = reinterpret_cast<const WorldEntityDiskRecord*>(
// // reinterpret_cast<const uint8*>(fileBuffer.Data) + sizeof(WorldFileHeader));
// //
// // for (uint32 i = 0; i < header->EntityCount; ++i)
// // {
// // Entity ent;
// // (void)AddWorldEntity(world, records[i].X, records[i].Y, records[i].Z);
// // }
//
// LogMessage(LogCategory::Game, "World successfully loaded from %s (%u entities)", CStr(filename), header->EntityCount);
// }
// }
// else
// {
// LogError(LogCategory::Game, "LoadWorld: Failed to read world file or file is too small: %s", CStr(filename));
// }
//
// scratch_end(loadArena);
return true;
}
#ifdef JULIET_EDITOR
void RenderWorldEditorUI(World& world)
{
if (ImGui::Begin("World Editor"))
{
TempArena temp = scratch_begin(nullptr, 0);
static char worldFilePath[256] = "../world.bin";
ImGui::InputText("World File", worldFilePath, sizeof(worldFilePath));
String path = GetAssetPath(temp.Arena, WrapString(worldFilePath));
if (ImGui::Button("Save World"))
{
archive data{ .loading = false };
Serialize(data, world, path);
}
ImGui::SameLine();
if (ImGui::Button("Load World"))
{
archive data{ .loading = true };
Serialize(data, world, path);
}
scratch_end(temp);
// ImGui::SameLine();
// if (ImGui::Button("Clear All"))
// {
// ClearWorld(world);
// }
//
// ImGui::Separator();
//
// if (ImGui::Button("Add Entity"))
// {
// (void)AddWorldEntity(world, 0.0f, 0.0f, 0.0f);
// }
//
// ImGui::Text("Entity Count: %zu", world.Entities.Size());
// ImGui::Separator();
//
// static int selectedEntity = -1;
// if (selectedEntity >= static_cast<int>(world.Entities.Size()))
// {
// selectedEntity = -1;
// }
//
// ImGui::BeginChild("EntityList", ImVec2(180, 200), true);
// for (size_t i = 0; i < world.Entities.Size(); ++i)
// {
// char label[64];
// snprintf(label, sizeof(label), "Entity #%zu (ID: %llu)", i, world.Entities[i].ID);
// if (ImGui::Selectable(label, selectedEntity == static_cast<int>(i)))
// {
// selectedEntity = static_cast<int>(i);
// }
// }
// ImGui::EndChild();
//
// ImGui::SameLine();
//
// ImGui::BeginChild("EntityInspector", ImVec2(0, 200), true);
// if (selectedEntity >= 0 && selectedEntity < static_cast<int>(world.Entities.Size()))
// {
// Entity& ent = world.Entities[static_cast<size_t>(selectedEntity)];
// ImGui::Text("Selected: Entity #%d", selectedEntity);
// ImGui::Text("ID: %llu", ent.ID);
//
// float pos[3] = { ent.X, ent.Y, ent.Z };
// if (ImGui::DragFloat3("Position", pos, 0.1f))
// {
// ent.X = pos[0];
// ent.Y = pos[1];
// ent.Z = pos[2];
// UpdateWorld(world);
// }
//
// if (ImGui::Button("Delete Entity"))
// {
// RemoveWorldEntity(world, static_cast<size_t>(selectedEntity));
// selectedEntity = -1;
// UpdateWorld(world);
// }
// }
// else
// {
// ImGui::Text("Select an entity to edit its properties.");
// }
// ImGui::EndChild();
}
ImGui::End();
}
#endif
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include <Core/Common/CoreTypes.h>
#include <Core/Common/NonNullPtr.h>
#include <Core/Common/String.h>
#include <Core/Container/Vector.h>
#include <Core/Memory/MemoryArena.h>
#include <Entity/Entity.h>
struct archive;
struct EntityManager;
#pragma pack(push, 1)
struct WorldFileHeader
{
uint32 Magic = 0x444C574A; // 'JWLD' in little-endian
uint32 Version = 1;
};
struct WorldEntityDiskRecord
{
float X = 0.0f;
float Y = 0.0f;
float Z = 0.0f;
};
#pragma pack(pop)
constexpr uint32 kWorldMagic = 0x444C574A; // 'JWLD'
constexpr uint32 kWorldVersion = 1;
struct World
{
Arena* WorldArena = nullptr;
EntityManager* EntityManager = nullptr;
};
void InitWorld(NonNullPtr<World> world, NonNullPtr<Arena> arena);
void ShutdownWorld(NonNullPtr<World> world);
void AddToWorld(NonNullPtr<World> world, NonNullPtr<Entity> entity);
void RemoveWorldEntity(World& world, size_t index);
void Serialize(archive& data, World& world, String filename);
#if JULIET_EDITOR
void RenderWorldEditorUI(World& world);
#endif
+3
View File
@@ -0,0 +1,3 @@
#include <Entity/Entity.h>
DEFINE_ENTITY(Inert);
+59 -20
View File
@@ -1,10 +1,10 @@
#pragma once
#pragma once
#include <Core/Common/CoreUtils.h>
#include <Core/Common/EnumUtils.h>
#include <Core/Memory/Allocator.h>
#include <Core/Memory/MemoryArena.h>
#include <Engine/Class.h>
#include <Entity/EntityManager.h>
#define DECLARE_ENTITY() \
Entity* Base; \
@@ -12,57 +12,96 @@
// Will register the class globally at launch
#define DEFINE_ENTITY(entity) \
constexpr Class entityKind##entity(#entity, sizeof(#entity) / sizeof(char)); \
constexpr Class entityKind##entity = \
MakeClass(ConstString(#entity), (uint8)Entity_Type::entity, sizeof(entity), alignof(entity), nullptr); \
const Class* entity::Kind = &entityKind##entity;
#define DEFINE_ENTITY_SERIALIZED(entity, serialize_fct) \
constexpr Class entityKind##entity = \
MakeClass(ConstString(#entity), (uint8)Entity_Type::entity, sizeof(entity), alignof(entity), serialize_fct); \
const Class* entity::Kind = &entityKind##entity;
struct EntityManager;
using DerivedType = void*;
using EntityID = uint64_t;
// clang-format off
#define ENTITY_TYPE_LIST(X) X(Inert),
#define AS_ENUM(name) name
enum class Entity_Type : uint8
{
ENTITY_TYPE_LIST(AS_ENUM)
Count
};
#undef AS_ENUM
#define AS_STR(name) #name
inline const char* kEntity_type_names[] = {
ENTITY_TYPE_LIST(AS_STR)
"Count"
};
#define ENTITY(kind) ToUnderlying(Entity_Type::kind)
// clang-format on
struct Entity final
{
EntityID ID;
const Class* Kind;
DerivedType Derived;
float X, Y;
EntityID ID = 0;
const Class* Kind = nullptr;
DerivedType Derived = nullptr;
float X = 0.0f;
float Y = 0.0f;
float Z = 0.0f;
};
// Can reinterpret cast to this to have the offset of Base and Kind for any entity
struct entity_template
{
DECLARE_ENTITY();
};
struct Inert
{
DECLARE_ENTITY()
index_t MeshInstance = indexMax;
};
//
template <typename EntityType>
concept EntityConcept = requires(EntityType entity) {
requires std::same_as<decltype(entity.Kind), const Class*>;
{ EntityType::Kind } -> std::convertible_to<const Class*>;
requires std::same_as<decltype(entity.Base), Entity*>;
};
template <typename EntityType>
requires EntityConcept<EntityType>
bool IsA(const Entity* entity)
[[nodiscard]] bool IsA(const Entity* entity)
{
Assert(entity != nullptr);
return entity->Kind == EntityType::Kind;
}
template <typename EntityType>
requires EntityConcept<EntityType>
EntityType* MakeEntity(EntityManager& manager, float x, float y)
[[nodiscard]] EntityType* MakeEntity(EntityManager& manager, float x, float y, float z)
{
auto* arena = manager.Arena;
EntityType* result = ArenaPushStruct<EntityType>(arena);
EntityType result;
Entity base;
base.X = x;
base.Y = y;
base.Derived = result;
base.Z = z;
base.Kind = EntityType::Kind;
manager.Entities.PushBack(base);
result->Base = manager.Entities.Back();
RegisterEntity(manager, &base);
return result;
return (EntityType*)RegisterEntity(manager, &base, &result);
}
template <typename EntityType>
requires EntityConcept<EntityType>
EntityType* DownCast(Entity* entity)
[[nodiscard]] EntityType* DownCast(Entity* entity)
{
Assert(entity != nullptr);
Assert(IsA<EntityType>(entity));
return static_cast<EntityType*>(entity->Derived);
}
+40 -7
View File
@@ -1,6 +1,9 @@
#include <Entity/EntityManager.h>
#include <Entity/EntityManager.h>
#include <Core/Common/EnumUtils.h>
#include <Data/World.h>
#include <Entity/Entity.h>
#include <game.h>
#include <Graphics/MeshRenderer.h>
EntityID EntityManager::ID = 0;
@@ -12,7 +15,15 @@ void InitEntityManager(NonNullPtr<World> world)
newManager->Entities.Create(world->WorldArena JULIET_DEBUG_PARAM("Entities"));
newManager->Arena = ArenaAllocate({ .Name = "Entity Arena" });
ArenaParams by_type_params{ .ReserveSize = Kilobytes(1),
.CommitSize = Kilobytes(1),
.Name = "" JULIET_DEBUG_ONLY(, .CanReserveMore = false) };
for (uint8 i = 0; i < ENTITY(Count); ++i)
{
by_type_params.Name = kEntity_type_names[i];
newManager->by_type[i].arena = ArenaAllocate(by_type_params);
newManager->by_type[i].array = nullptr;
}
}
void ShutdownEntityManager()
@@ -26,18 +37,40 @@ EntityManager& GetEntityManager()
return *entityManager;
}
void RegisterEntity(EntityManager& /*manager*/, Entity* entity)
void Serialize(NonNullPtr<EntityManager> entityManager) {}
entity_template* RegisterEntity(EntityManager& manager, Entity* base, DerivedType entity)
{
entity->ID = EntityManager::ID++;
base->ID = EntityManager::ID++;
base->Derived = entity;
manager.Entities.PushBack(*base);
auto* ptr = (entity_template*)ArenaPushSize(manager.by_type[base->Kind->kind].arena, base->Kind->size_of, base->Kind->alignment,
false JULIET_DEBUG_PARAM(kEntity_type_names[base->Kind->kind]));
MemCopy(ptr, entity, base->Kind->size_of);
manager.by_type[base->Kind->kind].count += 1;
ptr->Base = manager.Entities.Back();
if (manager.by_type[base->Kind->kind].array == nullptr)
{
manager.by_type[base->Kind->kind].array = ptr;
}
return ptr;
}
void UpdateEntityManager(EntityManager& manager)
{
for (Entity& ent : manager.Entities)
// Todo : inert by definition dont move, but this is for test
auto& by_type = manager.by_type[ENTITY(Inert)];
for (index_t i = 0; i < by_type.count; ++i)
{
if (ent.MeshInstance != indexMax)
Inert* inert = reinterpret_cast<Inert*>(by_type.array) + i;
if (inert->MeshInstance != indexMax)
{
SetMeshInstanceTransform(ent.MeshInstance, MatrixTranslation(ent.X, ent.Y, 0.0f));
SetMeshInstanceTransform(inert->MeshInstance, MatrixTranslation(inert->Base->X, inert->Base->Y, inert->Base->Z));
}
}
}
+16 -8
View File
@@ -1,24 +1,32 @@
#pragma once
#pragma once
#include <Core/Common/CoreTypes.h>
#include <Core/Container/Vector.h>
#include <game.h>
using EntityID = uint64_t;
#include <Entity/Entity.h>
struct Entity;
struct World;
struct typed_entity_array
{
Arena* arena;
entity_template* array;
size_t count;
};
struct EntityManager
{
static EntityID ID;
Arena* Arena;
// TODO: Should be a pool
VectorArena<Entity, 1024> Entities;
VectorArena<Entity, 100'000> Entities;
typed_entity_array by_type[ENTITY(Count)];
};
void InitEntityManager(NonNullPtr<World> world);
void ShutdownEntityManager();
EntityManager& GetEntityManager();
void RegisterEntity(EntityManager& manager, Entity* entity);
void Serialize(NonNullPtr<EntityManager> entityManager);
entity_template* RegisterEntity(EntityManager& manager, Entity* base, DerivedType entity);
void UpdateEntityManager(EntityManager& manager);
+27
View File
@@ -0,0 +1,27 @@
#include <UnitTest/WorldUnitTest.h>
#if JULIET_DEBUG
#include <Core/Common/CoreUtils.h>
#include <Core/HAL/IO/IOStream.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Memory/MemoryArena.h>
#include <Data/World.h>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace UnitTest
{
void WorldUnitTest()
{
LogMessage(LogCategory::Game, "Running World Unit Tests...");
}
} // namespace UnitTest
#endif
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <Juliet.h>
#if JULIET_DEBUG
namespace UnitTest
{
void WorldUnitTest();
} // namespace UnitTest
#endif
+35 -6
View File
@@ -1,12 +1,13 @@
#include <game.h>
#include <game.h>
#include <Controller/DebugCameraController.h>
#include <Core/Common/serialization.h>
#include <Core/HAL/Filesystem/Filesystem.h>
#include <Core/HAL/Keyboard/Keyboard.h>
#include <Core/JulietInit.h>
#include <Core/Logging/LogManager.h>
#include <Core/Memory/MemoryArena.h>
#include <Data/StaticMesh.h>
#include <Data/World.h>
#include <Entity/Entity.h>
#include <Entity/EntityManager.h>
#include <Graphics/Camera.h>
@@ -15,8 +16,20 @@
#if JULIET_DEBUG
#include <Debug/DebugTopBar.h>
#include <UnitTest/WorldUnitTest.h>
#endif
// namespace
// {
// void serialize_test(archive* ar, void* payload)
// {
// SerializedEntityTest* test = reinterpret_cast<SerializedEntityTest*>(payload);
// serialize_elem(ar, test->A);
// }
// } // namespace
//
// DEFINE_ENTITY_SERIALIZED(SerializedEntityTest, serialize_test)
namespace
{
GameState* gGameState = nullptr;
@@ -31,13 +44,16 @@ extern "C" JULIET_API void __cdecl GameShutdown()
{
printf("Shutting down game...\n");
if (gGameState && gGameState->World)
{
ShutdownWorld(gGameState->World);
}
ShutdownEntityManager();
}
extern "C" JULIET_API void __cdecl GameUpdate(GameData* params, [[maybe_unused]] float deltaTime)
{
gGameState = params->GameState;
if (!gGameState)
{
@@ -58,17 +74,26 @@ extern "C" JULIET_API void __cdecl GameUpdate(GameData* params, [[maybe_unused]]
auto* worldArena = ArenaAllocate({ .ReserveSize = Megabytes(1), .Name = "World Arena" });
World* world = ArenaPushStruct<World>(worldArena JULIET_DEBUG_PARAM("World"));
gameState->World = world;
gameState->World->WorldArena = worldArena;
InitWorld(gameState->World, worldArena);
#if JULIET_DEBUG
UnitTest::WorldUnitTest();
#endif
// Entity Use case
InitEntityManager(gameState->World);
auto& manager = GetEntityManager();
NonNullPtr mesh = MakeEntity<StaticMesh>(manager, 1.f, 2.f);
NonNullPtr mesh = MakeEntity<Inert>(manager, 1.f, 2.f, 0.f);
MeshAssetID cubeAsset = GetCubePrimitiveMeshAssetID();
MeshInstanceID meshInst = CreateMeshInstance(cubeAsset, 0, MatrixIdentity());
mesh->Base->MeshInstance = meshInst;
mesh->MeshInstance = meshInst;
NonNullPtr mesh2 = MakeEntity<Inert>(manager, 4.f, 0.f, 2.f);
MeshInstanceID meshInst2 = CreateMeshInstance(cubeAsset, 0, MatrixIdentity());
mesh2->MeshInstance = meshInst2;
// Summer at 2pm lighting
Vector3 sunDirection = { -0.2f, -0.9f, -0.3f };
@@ -100,6 +125,10 @@ extern "C" JULIET_API void __cdecl GameUpdate(GameData* params, [[maybe_unused]]
{
gGameState->Mode = GameMode::Play;
}
#if JULIET_EDITOR
RenderWorldEditorUI(*gGameState->World);
#endif
}
if (gGameState->Mode == GameMode::Play)
+11 -9
View File
@@ -1,13 +1,15 @@
#pragma once
#pragma once
#include <Core/Memory/MemoryArena.h>
#include <Data/World.h>
struct EntityManager;
struct World
struct SerializedEntityTest
{
Arena* WorldArena;
EntityManager* EntityManager;
DECLARE_ENTITY()
int A = 0;
};
enum class GameMode
@@ -19,14 +21,14 @@ enum class GameMode
struct GameState
{
Arena* TotalArena;
Arena* TotalArena = nullptr;
World* World;
World* World = nullptr;
GameMode Mode = GameMode::Editor;
float TotalTime;
int Score;
float TotalTime = 0.0f;
int Score = 0;
};
extern GameState* GetGameState();
[[nodiscard]] extern GameState* GetGameState();
@@ -0,0 +1,13 @@
#pragma once
struct Arena;
struct archive
{
Arena* arena;
bool loading;
};
void serialize(archive* ar, void* data, size_t size);
#define serialize_elem(ar, val) serialize((ar), &(val), sizeof(val))
+2 -2
View File
@@ -17,5 +17,5 @@ void thread_context_select(NonNullPtr<thread_context> ctx);
thread_context* thread_context_current();
Arena* thread_context_get_scratch(Arena** conflicts, size_t count);
TempArena scratch_begin(Arena** conflicts, size_t count);
void scratch_end(TempArena scratch);
JULIET_API TempArena scratch_begin(Arena** conflicts, size_t count);
JULIET_API void scratch_end(TempArena scratch);
+27 -11
View File
@@ -1,27 +1,43 @@
#pragma once
#include <Core/Common/CRC32.h>
#include <Entity/Entity.h>
#include <Juliet.h>
struct archive;
using serialize_fct_type = void (*)(archive*, void* payload);
struct Class
{
uint32 CRC;
uint8 kind;
serialize_fct_type serialize_fct;
size_t size_of;
size_t alignment;
#if JULIET_DEBUG
String Name;
#endif
};
consteval Class MakeClass(String name, uint8 kind, size_t size, size_t align, serialize_fct_type fct)
{
Class cls = {};
cls.CRC = crc32(name.Str, name.Size);
cls.kind = kind;
cls.size_of = size;
cls.alignment = align;
cls.serialize_fct = fct;
#if JULIET_DEBUG
// TODO: string struct may be
const char* Name;
size_t Name_Length;
cls.Name = name;
#endif
consteval Class(const char* className, size_t name_length)
{
CRC = crc32(className, name_length);
#if JULIET_DEBUG
// TODO: string struct may be
Name = className;
Name_Length = name_length;
#endif
return cls;
}
};
template <typename type>
bool IsA(Class& cls)
+1
View File
@@ -24,6 +24,7 @@
#define JULIET_DEBUG_ONLY(...) __VA_ARGS__
#define JULIET_DEBUG_PARAM_FIRST(...) __VA_ARGS__
#define JULIET_DEBUG_PARAM(...) , __VA_ARGS__
#define JULIET_EDITOR 1
#else
#define JULIET_DEBUG 0
#define JULIET_DEBUG_ONLY(...)
+19
View File
@@ -0,0 +1,19 @@
#include <Core/Common/serialization.h>
#include <Core/Common/CoreUtils.h>
#include <Core/Memory/MemoryArena.h>
#include <Core/Memory/Utils.h>
void serialize(archive* ar, void* data, size_t size)
{
if (ar->loading)
{
auto* ptr = ArenaPushSize(ar->arena, size, 8, false JULIET_DEBUG_PARAM("serialized load field"));
MemCopy(data, ptr, size);
}
else
{
auto* ptr = ArenaPushSize(ar->arena, size, 8, false JULIET_DEBUG_PARAM("serialized save field"));
MemCopy(ptr, data, size);
}
}
@@ -36,6 +36,7 @@ String GetAssetBasePath()
[[nodiscard]] String GetAssetPath(NonNullPtr<Arena> arena, String filename)
{
// TODO: Path is Assets/Compiled, we need to fix that one day
Assert(IsValid(CachedAssetBasePath));
Assert(IsValid(filename));