mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
- Updated JsonConfigWriterService to structure the JSON output with new sections for scripts, window settings, input bindings, paths, rendering, and GUI configurations. - Introduced a new method in ICrashRecoveryService to record frame heartbeats, allowing for better tracking of long-running operations. - Refactored existing code to improve readability and maintainability, including the addition of helper functions for adding string members to JSON objects.
263 lines
13 KiB
C++
263 lines
13 KiB
C++
#include "json_config_writer_service.hpp"
|
|
|
|
#include <rapidjson/document.h>
|
|
#include <rapidjson/stringbuffer.h>
|
|
#include <rapidjson/writer.h>
|
|
|
|
#include <array>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
namespace sdl3cpp::services::impl {
|
|
|
|
JsonConfigWriterService::JsonConfigWriterService(std::shared_ptr<ILogger> logger)
|
|
: logger_(std::move(logger)) {
|
|
if (logger_) {
|
|
logger_->Trace("JsonConfigWriterService", "JsonConfigWriterService");
|
|
}
|
|
}
|
|
|
|
void JsonConfigWriterService::WriteConfig(const RuntimeConfig& config, const std::filesystem::path& configPath) {
|
|
if (logger_) {
|
|
logger_->Trace("JsonConfigWriterService", "WriteConfig",
|
|
"config.width=" + std::to_string(config.width) +
|
|
", config.height=" + std::to_string(config.height) +
|
|
", config.scriptPath=" + config.scriptPath.string() +
|
|
", config.luaDebug=" + std::string(config.luaDebug ? "true" : "false") +
|
|
", config.windowTitle=" + config.windowTitle +
|
|
", configPath=" + configPath.string(),
|
|
"Entering");
|
|
}
|
|
|
|
rapidjson::Document document;
|
|
document.SetObject();
|
|
auto& allocator = document.GetAllocator();
|
|
|
|
auto addStringMember = [&](rapidjson::Value& target, const char* name, const std::string& value) {
|
|
rapidjson::Value nameValue(name, allocator);
|
|
rapidjson::Value stringValue(value.c_str(), allocator);
|
|
target.AddMember(nameValue, stringValue, allocator);
|
|
};
|
|
|
|
document.AddMember("schema_version", 2, allocator);
|
|
|
|
rapidjson::Value scriptsObject(rapidjson::kObjectType);
|
|
addStringMember(scriptsObject, "entry", config.scriptPath.string());
|
|
scriptsObject.AddMember("lua_debug", config.luaDebug, allocator);
|
|
document.AddMember("scripts", scriptsObject, allocator);
|
|
|
|
rapidjson::Value windowObject(rapidjson::kObjectType);
|
|
addStringMember(windowObject, "title", config.windowTitle);
|
|
rapidjson::Value sizeObject(rapidjson::kObjectType);
|
|
sizeObject.AddMember("width", config.width, allocator);
|
|
sizeObject.AddMember("height", config.height, allocator);
|
|
windowObject.AddMember("size", sizeObject, allocator);
|
|
|
|
std::filesystem::path scriptsDir = config.scriptPath.parent_path();
|
|
|
|
rapidjson::Value mouseGrabObject(rapidjson::kObjectType);
|
|
mouseGrabObject.AddMember("enabled", config.mouseGrab.enabled, allocator);
|
|
mouseGrabObject.AddMember("grab_on_click", config.mouseGrab.grabOnClick, allocator);
|
|
mouseGrabObject.AddMember("release_on_escape", config.mouseGrab.releaseOnEscape, allocator);
|
|
mouseGrabObject.AddMember("start_grabbed", config.mouseGrab.startGrabbed, allocator);
|
|
mouseGrabObject.AddMember("hide_cursor", config.mouseGrab.hideCursor, allocator);
|
|
mouseGrabObject.AddMember("relative_mode", config.mouseGrab.relativeMode, allocator);
|
|
mouseGrabObject.AddMember("grab_mouse_button",
|
|
rapidjson::Value(config.mouseGrab.grabMouseButton.c_str(), allocator),
|
|
allocator);
|
|
mouseGrabObject.AddMember("release_key",
|
|
rapidjson::Value(config.mouseGrab.releaseKey.c_str(), allocator),
|
|
allocator);
|
|
windowObject.AddMember("mouse_grab", mouseGrabObject, allocator);
|
|
document.AddMember("window", windowObject, allocator);
|
|
|
|
rapidjson::Value bindingsObject(rapidjson::kObjectType);
|
|
auto addBindingMember = [&](const char* name, const std::string& value) {
|
|
rapidjson::Value nameValue(name, allocator);
|
|
rapidjson::Value stringValue(value.c_str(), allocator);
|
|
bindingsObject.AddMember(nameValue, stringValue, allocator);
|
|
};
|
|
struct BindingSpec {
|
|
const char* name;
|
|
std::string InputBindings::* member;
|
|
};
|
|
const std::array<BindingSpec, 18> bindingSpecs = {{
|
|
{"move_forward", &InputBindings::moveForwardKey},
|
|
{"move_back", &InputBindings::moveBackKey},
|
|
{"move_left", &InputBindings::moveLeftKey},
|
|
{"move_right", &InputBindings::moveRightKey},
|
|
{"fly_up", &InputBindings::flyUpKey},
|
|
{"fly_down", &InputBindings::flyDownKey},
|
|
{"jump", &InputBindings::jumpKey},
|
|
{"noclip_toggle", &InputBindings::noclipToggleKey},
|
|
{"music_toggle", &InputBindings::musicToggleKey},
|
|
{"music_toggle_gamepad", &InputBindings::musicToggleGamepadButton},
|
|
{"gamepad_move_x_axis", &InputBindings::gamepadMoveXAxis},
|
|
{"gamepad_move_y_axis", &InputBindings::gamepadMoveYAxis},
|
|
{"gamepad_look_x_axis", &InputBindings::gamepadLookXAxis},
|
|
{"gamepad_look_y_axis", &InputBindings::gamepadLookYAxis},
|
|
{"gamepad_dpad_up", &InputBindings::gamepadDpadUpButton},
|
|
{"gamepad_dpad_down", &InputBindings::gamepadDpadDownButton},
|
|
{"gamepad_dpad_left", &InputBindings::gamepadDpadLeftButton},
|
|
{"gamepad_dpad_right", &InputBindings::gamepadDpadRightButton},
|
|
}};
|
|
for (const auto& spec : bindingSpecs) {
|
|
addBindingMember(spec.name, config.inputBindings.*(spec.member));
|
|
}
|
|
|
|
auto addMappingObject = [&](const char* name,
|
|
const std::unordered_map<std::string, std::string>& mappings,
|
|
rapidjson::Value& target) {
|
|
rapidjson::Value mappingObject(rapidjson::kObjectType);
|
|
for (const auto& [key, value] : mappings) {
|
|
rapidjson::Value keyValue(key.c_str(), allocator);
|
|
rapidjson::Value stringValue(value.c_str(), allocator);
|
|
mappingObject.AddMember(keyValue, stringValue, allocator);
|
|
}
|
|
target.AddMember(rapidjson::Value(name, allocator), mappingObject, allocator);
|
|
};
|
|
|
|
addMappingObject("gamepad_button_actions", config.inputBindings.gamepadButtonActions, bindingsObject);
|
|
addMappingObject("gamepad_axis_actions", config.inputBindings.gamepadAxisActions, bindingsObject);
|
|
bindingsObject.AddMember("gamepad_axis_action_threshold",
|
|
config.inputBindings.gamepadAxisActionThreshold, allocator);
|
|
rapidjson::Value inputObject(rapidjson::kObjectType);
|
|
inputObject.AddMember("bindings", bindingsObject, allocator);
|
|
document.AddMember("input", inputObject, allocator);
|
|
|
|
std::filesystem::path projectRoot = scriptsDir.parent_path();
|
|
rapidjson::Value pathsObject(rapidjson::kObjectType);
|
|
if (!scriptsDir.empty()) {
|
|
addStringMember(pathsObject, "scripts", scriptsDir.string());
|
|
}
|
|
if (!projectRoot.empty()) {
|
|
addStringMember(pathsObject, "project_root", projectRoot.string());
|
|
addStringMember(pathsObject, "shaders", (projectRoot / "shaders").string());
|
|
} else {
|
|
addStringMember(pathsObject, "shaders", "shaders");
|
|
}
|
|
document.AddMember("paths", pathsObject, allocator);
|
|
|
|
rapidjson::Value bgfxObject(rapidjson::kObjectType);
|
|
bgfxObject.AddMember("renderer",
|
|
rapidjson::Value(config.bgfx.renderer.c_str(), allocator),
|
|
allocator);
|
|
rapidjson::Value materialObject(rapidjson::kObjectType);
|
|
materialObject.AddMember("enabled", config.materialX.enabled, allocator);
|
|
materialObject.AddMember("document",
|
|
rapidjson::Value(config.materialX.documentPath.string().c_str(), allocator),
|
|
allocator);
|
|
materialObject.AddMember("shader_key",
|
|
rapidjson::Value(config.materialX.shaderKey.c_str(), allocator),
|
|
allocator);
|
|
materialObject.AddMember("material",
|
|
rapidjson::Value(config.materialX.materialName.c_str(), allocator),
|
|
allocator);
|
|
materialObject.AddMember("library_path",
|
|
rapidjson::Value(config.materialX.libraryPath.string().c_str(), allocator),
|
|
allocator);
|
|
rapidjson::Value libraryFolders(rapidjson::kArrayType);
|
|
for (const auto& folder : config.materialX.libraryFolders) {
|
|
libraryFolders.PushBack(rapidjson::Value(folder.c_str(), allocator), allocator);
|
|
}
|
|
materialObject.AddMember("library_folders", libraryFolders, allocator);
|
|
materialObject.AddMember("use_constant_color", config.materialX.useConstantColor, allocator);
|
|
rapidjson::Value constantColor(rapidjson::kArrayType);
|
|
constantColor.PushBack(config.materialX.constantColor[0], allocator);
|
|
constantColor.PushBack(config.materialX.constantColor[1], allocator);
|
|
constantColor.PushBack(config.materialX.constantColor[2], allocator);
|
|
materialObject.AddMember("constant_color", constantColor, allocator);
|
|
|
|
if (!config.materialXMaterials.empty()) {
|
|
rapidjson::Value materialsArray(rapidjson::kArrayType);
|
|
for (const auto& material : config.materialXMaterials) {
|
|
rapidjson::Value entry(rapidjson::kObjectType);
|
|
entry.AddMember("enabled", material.enabled, allocator);
|
|
entry.AddMember("document",
|
|
rapidjson::Value(material.documentPath.string().c_str(), allocator),
|
|
allocator);
|
|
entry.AddMember("shader_key",
|
|
rapidjson::Value(material.shaderKey.c_str(), allocator),
|
|
allocator);
|
|
entry.AddMember("material",
|
|
rapidjson::Value(material.materialName.c_str(), allocator),
|
|
allocator);
|
|
entry.AddMember("use_constant_color", material.useConstantColor, allocator);
|
|
rapidjson::Value materialColor(rapidjson::kArrayType);
|
|
materialColor.PushBack(material.constantColor[0], allocator);
|
|
materialColor.PushBack(material.constantColor[1], allocator);
|
|
materialColor.PushBack(material.constantColor[2], allocator);
|
|
entry.AddMember("constant_color", materialColor, allocator);
|
|
materialsArray.PushBack(entry, allocator);
|
|
}
|
|
materialObject.AddMember("materials", materialsArray, allocator);
|
|
}
|
|
|
|
rapidjson::Value atmosphericsObject(rapidjson::kObjectType);
|
|
atmosphericsObject.AddMember("ambient_strength", config.atmospherics.ambientStrength, allocator);
|
|
atmosphericsObject.AddMember("fog_density", config.atmospherics.fogDensity, allocator);
|
|
rapidjson::Value fogColor(rapidjson::kArrayType);
|
|
fogColor.PushBack(config.atmospherics.fogColor[0], allocator);
|
|
fogColor.PushBack(config.atmospherics.fogColor[1], allocator);
|
|
fogColor.PushBack(config.atmospherics.fogColor[2], allocator);
|
|
atmosphericsObject.AddMember("fog_color", fogColor, allocator);
|
|
rapidjson::Value skyColor(rapidjson::kArrayType);
|
|
skyColor.PushBack(config.atmospherics.skyColor[0], allocator);
|
|
skyColor.PushBack(config.atmospherics.skyColor[1], allocator);
|
|
skyColor.PushBack(config.atmospherics.skyColor[2], allocator);
|
|
atmosphericsObject.AddMember("sky_color", skyColor, allocator);
|
|
atmosphericsObject.AddMember("gamma", config.atmospherics.gamma, allocator);
|
|
atmosphericsObject.AddMember("exposure", config.atmospherics.exposure, allocator);
|
|
atmosphericsObject.AddMember("enable_tone_mapping", config.atmospherics.enableToneMapping, allocator);
|
|
atmosphericsObject.AddMember("enable_shadows", config.atmospherics.enableShadows, allocator);
|
|
atmosphericsObject.AddMember("enable_ssgi", config.atmospherics.enableSSGI, allocator);
|
|
atmosphericsObject.AddMember("enable_volumetric_lighting", config.atmospherics.enableVolumetricLighting, allocator);
|
|
atmosphericsObject.AddMember("pbr_roughness", config.atmospherics.pbrRoughness, allocator);
|
|
atmosphericsObject.AddMember("pbr_metallic", config.atmospherics.pbrMetallic, allocator);
|
|
|
|
rapidjson::Value renderingObject(rapidjson::kObjectType);
|
|
renderingObject.AddMember("bgfx", bgfxObject, allocator);
|
|
renderingObject.AddMember("materialx", materialObject, allocator);
|
|
renderingObject.AddMember("atmospherics", atmosphericsObject, allocator);
|
|
document.AddMember("rendering", renderingObject, allocator);
|
|
|
|
rapidjson::Value guiObject(rapidjson::kObjectType);
|
|
rapidjson::Value fontObject(rapidjson::kObjectType);
|
|
fontObject.AddMember("use_freetype", config.guiFont.useFreeType, allocator);
|
|
fontObject.AddMember("font_path",
|
|
rapidjson::Value(config.guiFont.fontPath.string().c_str(), allocator),
|
|
allocator);
|
|
fontObject.AddMember("font_size", config.guiFont.fontSize, allocator);
|
|
guiObject.AddMember("font", fontObject, allocator);
|
|
guiObject.AddMember("opacity", config.guiOpacity, allocator);
|
|
document.AddMember("gui", guiObject, allocator);
|
|
|
|
if (!configPath.empty()) {
|
|
addStringMember(document, "config_file", configPath.string());
|
|
}
|
|
|
|
rapidjson::StringBuffer buffer;
|
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
|
document.Accept(writer);
|
|
|
|
auto parentDir = configPath.parent_path();
|
|
if (!parentDir.empty()) {
|
|
std::filesystem::create_directories(parentDir);
|
|
}
|
|
|
|
std::ofstream outFile(configPath);
|
|
if (!outFile) {
|
|
throw std::runtime_error("Failed to open config output file: " + configPath.string());
|
|
}
|
|
outFile << buffer.GetString();
|
|
|
|
if (logger_) {
|
|
logger_->Info("JsonConfigWriterService: Wrote runtime config to " + configPath.string());
|
|
logger_->Trace("JsonConfigWriterService", "WriteConfig", "", "Exiting");
|
|
}
|
|
}
|
|
|
|
} // namespace sdl3cpp::services::impl
|