Files
Juliet/Game/Data/World.cpp
T

279 lines
9.5 KiB
C++

#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