Files
XCEngine/editor/src/Utils/ProjectFileUtils.h

192 lines
5.7 KiB
C++

#pragma once
#include <filesystem>
#include <fstream>
#include <optional>
#include <string>
namespace XCEngine {
namespace Editor {
namespace ProjectFileUtils {
namespace fs = std::filesystem;
struct ProjectDescriptor {
std::string name;
std::string startupScene;
};
struct GraphicsSettingsDescriptor {
std::string renderPipelineAssetAssembly;
std::string renderPipelineAssetNamespace;
std::string renderPipelineAssetClass;
bool HasRenderPipelineAsset() const {
return !renderPipelineAssetAssembly.empty() &&
!renderPipelineAssetClass.empty();
}
};
inline fs::path GetProjectFilePath(const std::string& projectRoot) {
return fs::path(projectRoot) / "Project.xcproject";
}
inline fs::path GetProjectSettingsDirectory(const std::string& projectRoot) {
return fs::path(projectRoot) / "ProjectSettings";
}
inline fs::path GetGraphicsSettingsFilePath(const std::string& projectRoot) {
return GetProjectSettingsDirectory(projectRoot) / "GraphicsSettings.asset";
}
inline std::string GetProjectName(const std::string& projectRoot) {
const fs::path rootPath(projectRoot);
const fs::path folderName = rootPath.filename().empty() ? rootPath.parent_path().filename() : rootPath.filename();
return folderName.empty() ? "XCEngineProject" : folderName.string();
}
inline std::string Trim(const std::string& value) {
const size_t begin = value.find_first_not_of(" \t\r\n");
if (begin == std::string::npos) {
return {};
}
const size_t end = value.find_last_not_of(" \t\r\n");
return value.substr(begin, end - begin + 1);
}
inline bool SaveProjectDescriptor(const std::string& projectRoot, const ProjectDescriptor& descriptor) {
std::error_code ec;
fs::create_directories(fs::path(projectRoot), ec);
std::ofstream output(GetProjectFilePath(projectRoot), std::ios::out | std::ios::trunc);
if (!output.is_open()) {
return false;
}
output << "version=1\n";
output << "name=" << descriptor.name << "\n";
output << "startup_scene=" << descriptor.startupScene << "\n";
return output.good();
}
inline std::optional<ProjectDescriptor> LoadProjectDescriptor(const std::string& projectRoot) {
std::ifstream input(GetProjectFilePath(projectRoot));
if (!input.is_open()) {
return std::nullopt;
}
ProjectDescriptor descriptor;
descriptor.name = GetProjectName(projectRoot);
std::string line;
while (std::getline(input, line)) {
const size_t equalsPos = line.find('=');
if (equalsPos == std::string::npos) {
continue;
}
const std::string key = Trim(line.substr(0, equalsPos));
const std::string value = Trim(line.substr(equalsPos + 1));
if (key == "name") {
descriptor.name = value;
} else if (key == "startup_scene") {
descriptor.startupScene = value;
}
}
return descriptor;
}
inline bool SaveProjectGraphicsSettings(
const std::string& projectRoot,
const GraphicsSettingsDescriptor& descriptor) {
std::error_code ec;
fs::create_directories(GetProjectSettingsDirectory(projectRoot), ec);
std::ofstream output(
GetGraphicsSettingsFilePath(projectRoot),
std::ios::out | std::ios::trunc);
if (!output.is_open()) {
return false;
}
output << "version=1\n";
output << "render_pipeline_asset_assembly="
<< descriptor.renderPipelineAssetAssembly << "\n";
output << "render_pipeline_asset_namespace="
<< descriptor.renderPipelineAssetNamespace << "\n";
output << "render_pipeline_asset_class="
<< descriptor.renderPipelineAssetClass << "\n";
return output.good();
}
inline std::optional<GraphicsSettingsDescriptor> LoadProjectGraphicsSettings(
const std::string& projectRoot) {
std::ifstream input(GetGraphicsSettingsFilePath(projectRoot));
if (!input.is_open()) {
return std::nullopt;
}
GraphicsSettingsDescriptor descriptor;
std::string line;
while (std::getline(input, line)) {
const size_t equalsPos = line.find('=');
if (equalsPos == std::string::npos) {
continue;
}
const std::string key = Trim(line.substr(0, equalsPos));
const std::string value = Trim(line.substr(equalsPos + 1));
if (key == "render_pipeline_asset_assembly") {
descriptor.renderPipelineAssetAssembly = value;
} else if (key == "render_pipeline_asset_namespace") {
descriptor.renderPipelineAssetNamespace = value;
} else if (key == "render_pipeline_asset_class") {
descriptor.renderPipelineAssetClass = value;
}
}
return descriptor;
}
inline std::string MakeProjectRelativePath(const std::string& projectRoot, const std::string& fullPath) {
if (projectRoot.empty() || fullPath.empty()) {
return {};
}
std::error_code ec;
const fs::path root = fs::weakly_canonical(fs::path(projectRoot), ec);
ec.clear();
const fs::path target = fs::weakly_canonical(fs::path(fullPath), ec);
if (ec) {
return fullPath;
}
ec.clear();
const fs::path relative = fs::relative(target, root, ec);
if (ec) {
return fullPath;
}
return relative.lexically_normal().generic_string();
}
inline std::string ResolveProjectPath(const std::string& projectRoot, const std::string& pathValue) {
if (pathValue.empty()) {
return {};
}
const fs::path path(pathValue);
if (path.is_absolute()) {
return path.lexically_normal().string();
}
return (fs::path(projectRoot) / path).lexically_normal().string();
}
} // namespace ProjectFileUtils
} // namespace Editor
} // namespace XCEngine