#include "Project.h" #include "src/FileSystem/FileSystem.h" #include "Engine.h" #include "src/Core/Logger.h" #include "src/Audio/AudioManager.h" #include "src/Scripting/ScriptingEngineNet.h" #include #include #include #include namespace Nuake { Project::Project(const std::string& Name, const std::string& Description, const std::string& FullPath, const std::string& defaultScenePath) { this->Name = Name; this->Description = Description; this->FullPath = FullPath; this->TrenchbroomPath = ""; if (defaultScenePath != "") { Ref scene = CreateRef(); scene->Deserialize(defaultScenePath); } this->EntityDefinitionsFile = CreateRef(); SaveAs(FullPath); } Project::Project() { this->Name = ""; this->Description = ""; this->FullPath = ""; this->TrenchbroomPath = ""; this->EntityDefinitionsFile = CreateRef(); } void Project::Save() { SaveAs(this->FullPath); } void Project::SaveAs(const std::string& FullPath) { json j = Serialize(); std::string serialized_string = j.dump(4); // TODO: Use file interface here... // Write to file. std::ofstream projectFile; projectFile.open(FullPath); projectFile << serialized_string; projectFile.close(); } bool Project::FileExist() { return std::filesystem::exists(this->FullPath.c_str()); } Ref Project::New(const std::string& Name, const std::string& Description, const std::string& FullPath) { return CreateRef(Name, Description, FullPath); } Ref Project::New() { return CreateRef(); } Ref Project::Load(std::string& path) { std::ifstream i(path); json j; i >> j; // validation std::string projectName; if (!j.contains("ProjectName")) return nullptr; projectName = j["ProjectName"]; std::string description; if (j.contains("Description")) description = j["Description"]; Ref project = CreateRef(projectName, description, path); project->Settings = ProjectSettings(); if (j.contains("Settings")) { project->Settings.Deserialize(j["Settings"]); Engine::SetPhysicsStep(project->Settings.PhysicsStep); AudioManager::Get().SetGlobalVolume(project->Settings.GlobalVolume); } return project; } void Project::ExportEntitiesToTrenchbroom() { Ref file = EntityDefinitionsFile; file->BrushEntities.clear(); for (auto& [name, type] : ScriptingEngineNet::Get().GetBrushEntities()) { FGDBrushEntity brushEntity = FGDBrushEntity(name); brushEntity.Script = name; brushEntity.Description = type.Description; brushEntity.IsTrigger = type.isTrigger; for (auto& t : type.exposedVars) { ClassProperty classProp; classProp.name = t.Name; classProp.type = ClassPropertyType::String; if (t.Type == ExposedVarTypes::String && t.Value.has_value()) { classProp.value = std::any_cast(t.Value); } else if (t.Type == ExposedVarTypes::Float && t.Value.has_value()) { classProp.value = std::any_cast(t.Value); classProp.type = ClassPropertyType::Float; } else if (t.Type == ExposedVarTypes::Int) { classProp.value = std::to_string(std::any_cast(t.Value)); } else { classProp.value = ""; } brushEntity.Properties.push_back(classProp); } file->BrushEntities.push_back(brushEntity); } file->PointEntities.clear(); std::vector bases; for (auto& [name, type] : ScriptingEngineNet::Get().GetPointEntities()) { FGDPointEntity pointEntity = FGDPointEntity(name); pointEntity.Script = name; pointEntity.Description = type.Description; for (auto& t : type.exposedVars) { ClassProperty classProp; classProp.name = t.Name; classProp.type = ClassPropertyType::String; if (t.Type == ExposedVarTypes::String) { if (t.Value.has_value()) { classProp.value = std::any_cast(t.Value); } classProp.type = ClassPropertyType::String; } else if (t.Type == ExposedVarTypes::Int) { if (t.Value.has_value()) { classProp.value = std::to_string(std::any_cast(t.Value)); } classProp.type = ClassPropertyType::Integer; } else if (t.Type == ExposedVarTypes::Float) { if (t.Value.has_value()) { classProp.value = std::to_string(std::any_cast(t.Value)); } classProp.type = ClassPropertyType::Float; } else if (t.Type == ExposedVarTypes::Bool) { if (t.Value.has_value()) { classProp.value = std::to_string(std::any_cast(t.Value)); } classProp.type = ClassPropertyType::Float; } else { classProp.value = ""; } pointEntity.Properties.push_back(classProp); } file->PointEntities.push_back(pointEntity); } for (auto& b : bases) { FGDBaseEntity baseEntity; baseEntity.Name = b; file->BaseEntities.push_back(baseEntity); } file->Export(); } json Project::Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(Name); SERIALIZE_VAL(Description); if(DefaultScene) SERIALIZE_VAL_LBL("DefaultScene", DefaultScene->Path); if(EntityDefinitionsFile) SERIALIZE_VAL_LBL("EntityDefinition", EntityDefinitionsFile->Path); SERIALIZE_VAL(TrenchbroomPath); // Project Settings j["Settings"] = Settings.Serialize(); END_SERIALIZE(); } bool Project::Deserialize(const json& j) { Logger::Log("Starting deserializing project", "window", VERBOSE); if (!j.contains("Name") || !j.contains("Description")) return false; Name = j["Name"]; Description = j["Description"]; if (j.contains("EntityDefinition") && j["EntityDefinition"] != "") { std::string path = j["EntityDefinition"]; EntityDefinitionsFile = CreateRef(path); std::string content = FileSystem::ReadFile(path, false); EntityDefinitionsFile->Deserialize(nlohmann::json::parse(content)); } if (j.contains("TrenchbroomPath")) { this->TrenchbroomPath = j["TrenchbroomPath"]; } if (j.contains("Settings")) { Settings = ProjectSettings(); Settings.Deserialize(j["Settings"]); Engine::GetCurrentWindow()->SetVSync(Settings.VSync); Engine::SetPhysicsStep(Settings.PhysicsStep); AudioManager::Get().SetGlobalVolume(Settings.GlobalVolume); } DefaultScene = Scene::New(); // Load default scene, a project can have no default scene set. if (!j.contains("DefaultScene") ) return true; std::string scenePath = j["DefaultScene"]; if (scenePath == "") // Not set correctly. return true; if (!FileSystem::FileExists(scenePath)) return true; Logger::Log("Starting deserializing scene", "window", VERBOSE); std::string sceneContent = FileSystem::ReadFile(scenePath, false); if (!DefaultScene->Deserialize(nlohmann::json::parse(sceneContent))) { Logger::Log("Error loading scene: " + scenePath, "project", CRITICAL); } DefaultScene->Path = scenePath; Logger::Log("Loaded scene: " + scenePath); return true; // Success } json ProjectSettings::Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(VSync); SERIALIZE_VAL(ShowGizmos); SERIALIZE_VAL(ShowAxis); SERIALIZE_VAL(ResolutionScale); SERIALIZE_VAL(GizmoSize); SERIALIZE_VAL(OutlineRadius); SERIALIZE_VEC4(PrimaryColor); SERIALIZE_VAL(SmoothCamera); SERIALIZE_VAL(SmoothCameraSpeed); SERIALIZE_VAL(PhysicsStep); SERIALIZE_VAL(MaxPhysicsSubStep); SERIALIZE_VAL(MaxPhysicsBodies); SERIALIZE_VAL(MaxPhysicsBodyPair); SERIALIZE_VAL(MaxPhysicsContactConstraints); SERIALIZE_VAL(GlobalVolume); SERIALIZE_VAL(MaxActiveVoiceCount); END_SERIALIZE(); } bool ProjectSettings::Deserialize(const json& j) { DESERIALIZE_VAL(VSync); DESERIALIZE_VAL(ShowGizmos); DESERIALIZE_VAL(ShowAxis); DESERIALIZE_VAL(ResolutionScale); DESERIALIZE_VAL(OutlineRadius); DESERIALIZE_VAL(GizmoSize); DESERIALIZE_VAL(SmoothCamera); DESERIALIZE_VAL(SmoothCameraSpeed); DESERIALIZE_VAL(PhysicsStep); DESERIALIZE_VAL(MaxPhysicsSubStep); DESERIALIZE_VAL(MaxPhysicsBodies); DESERIALIZE_VAL(MaxPhysicsBodyPair); DESERIALIZE_VAL(MaxPhysicsContactConstraints); DESERIALIZE_VAL(GlobalVolume); DESERIALIZE_VAL(MaxActiveVoiceCount); if (j.contains("PrimaryColor")) { DESERIALIZE_VEC4(j["PrimaryColor"], PrimaryColor); } return true; } }