Added AutoLoad Projects

This commit is contained in:
OusmBlueNinja 2025-05-10 15:07:03 -05:00
parent 39c80d823a
commit e7bf00516b
10 changed files with 347 additions and 254 deletions

View File

@ -10,24 +10,24 @@ Collapsed=1
[Window][WindowOverViewport_11111111]
Pos=0,19
Size=1920,1158
Size=1280,701
Collapsed=0
[Window][Inspector]
Pos=1553,19
Size=367,537
Pos=913,19
Size=367,163
Collapsed=0
DockId=0x0000001B,0
[Window][Scene Tree]
Pos=0,19
Size=341,444
Size=341,268
Collapsed=0
DockId=0x0000000F,0
[Window][Viewport]
Pos=343,19
Size=1208,659
Size=568,202
Collapsed=0
DockId=0x00000017,0
@ -36,14 +36,14 @@ Size=1280,19
Collapsed=0
[Window][Performance Info]
Pos=1628,680
Size=292,268
Pos=1107,223
Size=173,268
Collapsed=0
DockId=0x00000019,0
[Window][Console]
Pos=343,680
Size=1206,497
Pos=343,223
Size=716,497
Collapsed=0
DockId=0x00000013,0
@ -78,8 +78,8 @@ Collapsed=0
DockId=0x00000015,1
[Window][Color Correction]
Pos=1628,950
Size=292,227
Pos=1107,493
Size=173,227
Collapsed=0
DockId=0x0000001A,0
@ -113,8 +113,8 @@ Collapsed=0
DockId=0x0000000E,0
[Window][Audio Output]
Pos=1551,680
Size=75,497
Pos=1061,223
Size=44,497
Collapsed=0
DockId=0x00000012,0
@ -125,8 +125,8 @@ Collapsed=0
DockId=0x0000000D,0
[Window][Resources]
Pos=0,465
Size=341,712
Pos=0,289
Size=341,431
Collapsed=0
DockId=0x00000010,0
@ -136,8 +136,8 @@ Size=550,695
Collapsed=0
[Window][Lua Globals]
Pos=1553,558
Size=367,120
Pos=913,184
Size=367,37
Collapsed=0
DockId=0x0000001C,0
@ -181,7 +181,7 @@ Column 1 Width=86
Column 2 Weight=1.0000
[Docking][Data]
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=989,1158 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=341,701 Split=Y Selected=0x12EF0F59
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,637 Split=Y Selected=0x12EF0F59

View File

@ -1,2 +1,3 @@
[COMPILE] g++ -std=c++20 -Wall -g -DGLM_ENABLE_EXPERIMENTAL -O2 -static -static-libstdc++ -static-libgcc -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -Isrc/vendor/imguizmo -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\functions\ProjectManager.cpp -o src\build\core\functions\ProjectManager.o
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\AudioPlayerComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PathFollowerComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\audio\AudioEngine.o src\build\core\functions\Prefab.o src\build\core\functions\ProjectManager.o src\build\core\functions\ScenePacker.o src\build\core\scripts\LuaGlobalBridge.o src\build\core\scripts\ScriptCore.o src\build\core\utils\AssetManager.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\LoadingWindow.o src\build\core\utils\Logging.o src\build\core\utils\Popup.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\utils\Themes.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\AudioInfo.o src\build\editor\windows\Inspector.o src\build\editor\windows\LuaGlobals.o src\build\editor\windows\SceneTree.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o src\build\xxhash.o src\build\miniaudio.o src\build\ImGuizmo.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto -ldbghelp -lz -lfreetype
[COMPILE] g++ -std=c++20 -Wall -g -DGLM_ENABLE_EXPERIMENTAL -O2 -static -static-libstdc++ -static-libgcc -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -Isrc/vendor/imguizmo -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\audio\AudioEngine.cpp -o src\build\core\audio\AudioEngine.o
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\AudioPlayerComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PathFollowerComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\audio\AudioEngine.o src\build\core\functions\Prefab.o src\build\core\functions\ProjectManager.o src\build\core\functions\ScenePacker.o src\build\core\functions\SceneSerializer.o src\build\core\scripts\LuaGlobalBridge.o src\build\core\scripts\ScriptCore.o src\build\core\utils\AssetManager.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\LoadingWindow.o src\build\core\utils\Logging.o src\build\core\utils\Popup.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\utils\Themes.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\AudioInfo.o src\build\editor\windows\Inspector.o src\build\editor\windows\LuaGlobals.o src\build\editor\windows\SceneTree.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o src\build\xxhash.o src\build\miniaudio.o src\build\ImGuizmo.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto -ldbghelp -lz -lfreetype
[ERROR] Interrupted by user.

View File

@ -20,8 +20,11 @@
#include "core/utils/EngineConfig.h"
#include "core/functions/Prefab.h"
#include "core/functions/ProjectManager.h"
#include "core/functions/SceneSerializer.h"
#include "utils/GameObjectsList.h"
#include "core/utils/Profiler.h"
@ -727,7 +730,7 @@ void Engine::Run()
{
std::string file = CreateFileDialog(FileDialogType::Scenes);
if (!file.empty())
SaveScene(file);
SceneLoader::SaveScene(file);
selected = nullptr;
}
if (ImGui::MenuItem("Load Scene"))
@ -735,7 +738,7 @@ void Engine::Run()
std::string file = OpenFileDialog(FileDialogType::Scenes);
Logger::LogInfo("Loading Scene.");
if (!file.empty())
LoadScene(file);
SceneLoader::LoadScene(file);
selected = nullptr;
}
ImGui::Separator();
@ -1587,219 +1590,7 @@ void Engine::Run()
}
}
bool VerifySceneHash(const YAML::Node &root)
{
if (!root["scene_hash"] || !root["objects"])
return false;
YAML::Emitter sceneOnly;
sceneOnly << root["objects"];
std::string sceneString = sceneOnly.c_str();
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(sceneString.c_str()), sceneString.size(), hash);
std::ostringstream hashHex;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
return hashHex.str() == root["scene_hash"].as<std::string>();
}
void Engine::SaveScene(const std::string &path)
{
YAML::Emitter out;
YAML::Emitter sceneData;
// Serialize object list only
sceneData << YAML::BeginSeq;
for (const auto &obj : objects)
obj->Save(sceneData);
sceneData << YAML::EndSeq;
std::string objectData = sceneData.c_str();
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(objectData.c_str()), objectData.size(), hash);
std::ostringstream hashHex;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
out << YAML::BeginMap;
out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version;
out << YAML::Key << "scene_name" << YAML::Value << std::filesystem::path(path).stem().string();
out << YAML::Key << "scene_hash" << YAML::Value << hashHex.str();
out << YAML::Key << "format_version" << YAML::Value << 1;
out << YAML::Key << "objects" << YAML::Value << YAML::Load(objectData);
Logger::LogVerbose("[SaveScene] Saving Color Correction Attributes");
out << YAML::Key << "color_correction" << YAML::BeginMap;
out << YAML::Key << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness;
out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation;
out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma;
out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom;
out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity;
out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold;
out << YAML::EndMap;
AssetManager::Save(out);
out << YAML::EndMap;
std::ofstream file(path);
file << out.c_str();
Logger::LogOk("Scene Saved");
}
void Engine::LoadScene(const std::string &path)
{
bool legacyLoad = false;
Logger::LogDebug("Reading Scene File.");
YAML::Node root = YAML::LoadFile(path);
LoadingWindow loadingUI;
loadingUI.Create("Loading Scene");
std::string currentStep = "Verifying Scene";
std::string currentDetail = "";
loadingUI.Update(currentStep, currentDetail, 0.0f);
if (!root["engine_version"] || !root["format_version"] || !root["scene_name"])
{
Logger::LogError("Missing required metadata!");
loadingUI.Destroy();
return;
}
std::string loadedVersion = root["engine_version"].as<std::string>();
std::string expectedVersion = g_engineConfig.version;
if (loadedVersion != expectedVersion)
{
Logger::LogWarning("Version mismatch! Expected %s, got %s",
expectedVersion.c_str(), loadedVersion.c_str());
if (!g_engineConfig.settings.ignore_invalid_versions_popups)
{
loadingUI.Destroy(); // Close visual loading before blocking popup
int result = Popup::Show("Version Mismatch",
"Scene was created with engine version: " + loadedVersion +
"\nExpected: " + expectedVersion +
"\n\nLoad anyway?",
{Popup::Option("Yes", 1),
Popup::Option("Yes (Don't Ask Again)", 2),
Popup::Option("No", 0)});
if (result == 0)
{
Logger::LogInfo("User cancelled scene load.");
return;
}
if (result == 2)
{
g_engineConfig.settings.ignore_invalid_versions_popups = true;
}
loadingUI.Create("Loading Scene (Legacy Recovery)");
loadingUI.Update("Attempting Recovery", "Loading scene with fallback...", 0.02f);
}
else
{
Logger::LogInfo("Version mismatch ignored due to user setting.");
}
}
if (!VerifySceneHash(root))
{
Logger::LogWarning("Scene hash does not match! File may be corrupted or tampered.");
}
if (root["Assets"])
{
currentStep = "Loading Assets";
currentDetail = "Parsing asset data...";
loadingUI.Update(currentStep, currentDetail, 0.05f);
Logger::LogDebug("Loading Assets");
AssetManager::Load(root["Assets"]);
}
Logger::LogDebug("Reseting Scene.");
currentStep = "Clearing Previous Scene";
currentDetail = "Removing existing objects";
loadingUI.Update(currentStep, currentDetail, 0.1f);
objects.clear();
Object::usedIDs.clear();
Logger::LogDebug("Recreating Objects");
currentStep = "Creating Scene Objects";
const auto &objectArray = root["objects"];
int objectIndex = 0;
int totalObjects = static_cast<int>(objectArray.size());
for (const auto &node : objectArray)
{
std::string objName = node["name"] ? node["name"].as<std::string>() : ("Unnamed_" + std::to_string(objectIndex));
currentDetail = "Loading: " + objName;
float progress = 0.1f + (0.75f * (objectIndex / static_cast<float>(std::max(1, totalObjects))));
loadingUI.Update(currentStep, currentDetail, progress);
try
{
auto obj = std::make_shared<Object>(objName);
obj->Load(node);
objects.push_back(obj);
}
catch (const std::exception &e)
{
Logger::LogWarning("Failed to load object '%s': %s", objName.c_str(), e.what());
}
objectIndex++;
}
// Color correction settings
if (root["color_correction"])
{
Logger::LogVerbose("Loading Color Correction Attributes");
currentStep = "Color Correction";
currentDetail = "Applying settings...";
loadingUI.Update(currentStep, currentDetail, 0.9f);
ColorCorrection *cc = Renderer::GetColorCorrection();
const auto &data = root["color_correction"];
if (cc)
{
if (data["brightness"])
cc->brightness = data["brightness"].as<float>();
if (data["saturation"])
cc->saturation = data["saturation"].as<float>();
if (data["gamma"])
cc->gamma = data["gamma"].as<float>();
if (data["bloom"])
cc->bloom = data["bloom"].as<bool>();
if (data["intensity"])
cc->intensity = data["intensity"].as<float>();
if (data["threshold"])
cc->threshold = data["threshold"].as<float>();
}
}
// Finalize
currentStep = "Done";
currentDetail = "Finalizing load...";
loadingUI.Update(currentStep, currentDetail, 1.0f);
Logger::LogOk("Scene Loaded: %s", root["scene_name"].as<std::string>().c_str());
loadingUI.Destroy();
}
void Engine::SaveState()
{

View File

@ -26,8 +26,7 @@ public:
void Stop() {running = false;}
void SaveScene(const std::string &path);
void LoadScene(const std::string &path);
private:

View File

@ -63,7 +63,6 @@ void AudioEngine::Shutdown()
void AudioEngine::Play(uint64_t uaid, bool loop)
{
Cleanup(uaid);
const AssetInfo *asset = AssetManager::GetAssetByID(uaid);
if (!asset || !asset->loaded || asset->type != AssetType::Audio)
@ -72,6 +71,8 @@ void AudioEngine::Play(uint64_t uaid, bool loop)
return;
}
Cleanup(uaid);
ma_sound *sound = new ma_sound;
if (ma_sound_init_from_file(
&s_Engine,
@ -104,6 +105,8 @@ void AudioEngine::Play(uint64_t uaid, bool loop)
info.sound = sound;
s_PlayingInfoMap[uaid] = info;
}
void AudioEngine::Stop(uint64_t uaid)
@ -137,9 +140,10 @@ void AudioEngine::CleanupSound(uint64_t uaid)
s_SoundMap.erase(itSound);
}
else
{
Logger::LogError("[AudioEngine] Invalid Asset ID");
}
{
Logger::LogVerbose("[AudioEngine] No sound found for ID %llu", uaid);
}
}
void AudioEngine::Update()
@ -203,9 +207,10 @@ void AudioEngine::Cleanup(uint64_t uaid)
s_SoundMap.erase(it);
}
else
{
Logger::LogError("[AudioEngine] Invalid Asset ID");
}
{
Logger::LogVerbose("[AudioEngine] No sound found for ID %llu", uaid);
}
s_PlayingInfoMap.erase(uaid);
}
@ -240,7 +245,10 @@ void AudioEngine::EngineProcessCallback(
}
}
const std::vector<float> &AudioEngine::GetMasterVU()
{
return s_MasterVU;
}

View File

@ -4,6 +4,9 @@
#include "../../core/utils/EngineConfig.h"
#include "../../core/utils/Logging.h"
#include "../../Engine.h"
#include "SceneSerializer.h"
#include <yaml-cpp/yaml.h>
#include <filesystem>
#include <fstream>
@ -51,6 +54,27 @@ bool CreateDirectories(const fs::path& baseDir)
return allOk;
}
std::string ProjectManager::ResolveResPath(const std::string& resPath)
{
constexpr const char* prefix = "res://";
if (resPath.rfind(prefix, 0) != 0)
return resPath;
if (s_currentProjectPath.empty() || s_currentProjectName.empty())
{
Logger::LogError("Cannot resolve res path: 'project not loaded!'");
return resPath;
}
fs::path baseDir = fs::path(s_currentProjectPath) / s_currentProjectName;
std::string relativePart = resPath.substr(strlen(prefix));
fs::path fullPath = baseDir / relativePart;
return fullPath.lexically_normal().string();
}
bool ProjectManager::Init()
@ -89,25 +113,40 @@ bool ProjectManager::LoadProject(const std::string& projectPath,
std::string createdDate = config["CreatedDate"].as<std::string>("unknown");
std::string s_defaultScene = config["s_defaultScene"].as<std::string>("s_defaultScene");
if (!s_defaultScene.empty())
s_currentProjectPath = projectPath;
s_currentProjectName = savedName;
std::string resScenePath = config["s_defaultScene"].as<std::string>("");
if (!resScenePath.empty())
{
Logger::LogInfo("Loading Default Scene '%s'", s_defaultScene.c_str());
Logger::LogWarning("TODO: Migrate Scene loading to scene Manager or ProjectManager class instead of engine class, then actualy load the scene here");
}
else
{
Logger::LogWarning("Invalid Deafult Scene");
s_defaultScene = ResolveResPath(resScenePath);
Logger::LogInfo("Loading Scene: %s", s_defaultScene.c_str());
if (!std::filesystem::exists(s_defaultScene))
{
Logger::LogError("Scene file does not exist: %s", s_defaultScene.c_str());
return false;
}
SceneLoader::LoadScene(s_defaultScene);
}
Logger::LogInfo("Loaded project '%s' at '%s' (created %s)",
savedName.c_str(),
projectPath.c_str(),
createdDate.c_str());
s_currentProjectPath = projectPath;
s_currentProjectName = savedName;
CreateDirectories(baseDir);
@ -132,7 +171,10 @@ bool ProjectManager::SaveProject(const std::string& projectPath,
out << YAML::BeginMap;
out << YAML::Key << "Name" << YAML::Value << projectName;
out << YAML::Key << "EngineVersion" << YAML::Value << g_engineConfig.version;
out << YAML::Key << "s_defaultScene" << YAML::Value << s_defaultScene;
fs::path relPath = fs::relative(s_defaultScene,
fs::path(s_currentProjectPath) / s_currentProjectName);
out << YAML::Key << "s_defaultScene" << YAML::Value << ("res://" + relPath.generic_string());
auto now = std::chrono::system_clock::now();

View File

@ -3,6 +3,7 @@
#include <string>
#include <filesystem>
#include <cstring>
class ProjectManager
{
@ -23,6 +24,10 @@ public:
static const std::string& GetCurrentProjectName();
static const std::string& GetCurrentAssetsPath();
static std::string ResolveResPath(const std::string& resPath);
private:
static std::string s_currentProjectPath;
static std::string s_currentProjectName;

View File

@ -0,0 +1,234 @@
#include "SceneSerializer.h"
#include <yaml-cpp/yaml.h>
#include "../../Entitys/Object.h"
#include "../../Renderer.h"
#include "../../utils/GameObjectsList.h"
#include "../../core/utils/LoadingWindow.h"
#include "../../core/utils/Popup.h"
#include <filesystem>
#include <openssl/sha.h>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <memory>
bool VerifySceneHash(const YAML::Node &root)
{
if (!root["scene_hash"] || !root["objects"])
return false;
YAML::Emitter sceneOnly;
sceneOnly << root["objects"];
std::string sceneString = sceneOnly.c_str();
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(sceneString.c_str()), sceneString.size(), hash);
std::ostringstream hashHex;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
return hashHex.str() == root["scene_hash"].as<std::string>();
}
void SceneLoader::SaveScene(const std::string &path)
{
YAML::Emitter out;
YAML::Emitter sceneData;
// Serialize object list only
sceneData << YAML::BeginSeq;
for (const auto &obj : objects)
obj->Save(sceneData);
sceneData << YAML::EndSeq;
std::string objectData = sceneData.c_str();
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(objectData.c_str()), objectData.size(), hash);
std::ostringstream hashHex;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
out << YAML::BeginMap;
out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version;
out << YAML::Key << "scene_name" << YAML::Value << std::filesystem::path(path).stem().string();
out << YAML::Key << "scene_hash" << YAML::Value << hashHex.str();
out << YAML::Key << "format_version" << YAML::Value << 1;
out << YAML::Key << "objects" << YAML::Value << YAML::Load(objectData);
Logger::LogVerbose("[SaveScene] Saving Color Correction Attributes");
out << YAML::Key << "color_correction" << YAML::BeginMap;
out << YAML::Key << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness;
out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation;
out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma;
out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom;
out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity;
out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold;
out << YAML::EndMap;
AssetManager::Save(out);
out << YAML::EndMap;
std::ofstream file(path);
file << out.c_str();
Logger::LogOk("Scene Saved");
}
void SceneLoader::LoadScene(const std::string &path)
{
bool legacyLoad = false;
Logger::LogDebug("Reading Scene File.");
YAML::Node root = YAML::LoadFile(path);
LoadingWindow loadingUI;
loadingUI.Create("Loading Scene");
std::string currentStep = "Verifying Scene";
std::string currentDetail = "";
loadingUI.Update(currentStep, currentDetail, 0.0f);
if (!root["engine_version"] || !root["format_version"] || !root["scene_name"])
{
Logger::LogError("Missing required metadata!");
loadingUI.Destroy();
return;
}
std::string loadedVersion = root["engine_version"].as<std::string>();
std::string expectedVersion = g_engineConfig.version;
if (loadedVersion != expectedVersion)
{
Logger::LogWarning("Version mismatch! Expected %s, got %s",
expectedVersion.c_str(), loadedVersion.c_str());
if (!g_engineConfig.settings.ignore_invalid_versions_popups)
{
loadingUI.Destroy(); // Close visual loading before blocking popup
int result = Popup::Show("Version Mismatch",
"Scene was created with engine version: " + loadedVersion +
"\nExpected: " + expectedVersion +
"\n\nLoad anyway?",
{Popup::Option("Yes", 1),
Popup::Option("Yes (Don't Ask Again)", 2),
Popup::Option("No", 0)});
if (result == 0)
{
Logger::LogInfo("User cancelled scene load.");
return;
}
if (result == 2)
{
g_engineConfig.settings.ignore_invalid_versions_popups = true;
}
loadingUI.Create("Loading Scene (Legacy Recovery)");
loadingUI.Update("Attempting Recovery", "Loading scene with fallback...", 0.02f);
}
else
{
Logger::LogInfo("Version mismatch ignored due to user setting.");
}
}
if (!VerifySceneHash(root))
{
Logger::LogWarning("Scene hash does not match! File may be corrupted or tampered.");
}
if (root["Assets"])
{
currentStep = "Loading Assets";
currentDetail = "Parsing asset data...";
loadingUI.Update(currentStep, currentDetail, 0.05f);
Logger::LogDebug("Loading Assets");
AssetManager::Load(root["Assets"]);
}
Logger::LogDebug("Reseting Scene.");
currentStep = "Clearing Previous Scene";
currentDetail = "Removing existing objects";
loadingUI.Update(currentStep, currentDetail, 0.1f);
objects.clear();
Object::usedIDs.clear();
Logger::LogDebug("Recreating Objects");
currentStep = "Creating Scene Objects";
const auto &objectArray = root["objects"];
int objectIndex = 0;
int totalObjects = static_cast<int>(objectArray.size());
for (const auto &node : objectArray)
{
std::string objName = node["name"] ? node["name"].as<std::string>() : ("Unnamed_" + std::to_string(objectIndex));
currentDetail = "Loading: " + objName;
float progress = 0.1f + (0.75f * (objectIndex / static_cast<float>(std::max(1, totalObjects))));
loadingUI.Update(currentStep, currentDetail, progress);
try
{
auto obj = std::make_shared<Object>(objName);
obj->Load(node);
objects.push_back(obj);
}
catch (const std::exception &e)
{
Logger::LogWarning("Failed to load object '%s': %s", objName.c_str(), e.what());
}
objectIndex++;
}
// Color correction settings
if (root["color_correction"])
{
Logger::LogVerbose("Loading Color Correction Attributes");
currentStep = "Color Correction";
currentDetail = "Applying settings...";
loadingUI.Update(currentStep, currentDetail, 0.9f);
ColorCorrection *cc = Renderer::GetColorCorrection();
const auto &data = root["color_correction"];
if (cc)
{
if (data["brightness"])
cc->brightness = data["brightness"].as<float>();
if (data["saturation"])
cc->saturation = data["saturation"].as<float>();
if (data["gamma"])
cc->gamma = data["gamma"].as<float>();
if (data["bloom"])
cc->bloom = data["bloom"].as<bool>();
if (data["intensity"])
cc->intensity = data["intensity"].as<float>();
if (data["threshold"])
cc->threshold = data["threshold"].as<float>();
}
}
// Finalize
currentStep = "Done";
currentDetail = "Finalizing load...";
loadingUI.Update(currentStep, currentDetail, 1.0f);
Logger::LogOk("Scene Loaded: %s", root["scene_name"].as<std::string>().c_str());
loadingUI.Destroy();
}

View File

@ -0,0 +1,11 @@
#pragma once
#include <string>
class SceneLoader
{
public:
static void SaveScene(const std::string &path);
static void LoadScene(const std::string &path);
};

View File

@ -308,6 +308,8 @@ void ShowAssetBrowser()
ImGui::EndChild();
ImGui::End();
if (ImGui::BeginPopupModal("Import Assets", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize))
{
ImGui::TextWrapped("Confirm Imports");