diff --git a/docs/audit-game.md b/docs/audit-game.md index ca4f131..e3e5146 100644 --- a/docs/audit-game.md +++ b/docs/audit-game.md @@ -33,7 +33,7 @@ Els IDs es mantenen estables una vegada assignats. Cada entrada apunta al fitxer | DUP-01 | `options.cpp:152-335,443-547` | PostFX i CrtPi tenen `default*Presets/parse*Preset/write*Preset/load*FromFile/save*ToFile/set*File` duplicats | Importante | DONE | Afegits `loadPresetsFromFile` i `savePresetsToFile` a l'anonymous namespace; els 4 entry-points passen a ser one-liners que injecten parse/write/defaults per tipus. Els fitxers `postfx.yaml`/`crtpi.yaml` regenerats són idèntics a l'anterior. `std::cerr` manté el comportament — INCONS-02 el corregirà | | DUP-02 | `player.cpp:100-140` | `snapToHorizontalLane` i `snapToVerticalLane` són el mateix algorisme amb eixos permutats | Importante | DONE | `snapToLane(dt, base, pitch, max_idx, get_pos, set_pos)` pren member-fn pointers; els dos wrappers deleguen només amb `Map::pitch_*`/`grid_*` distints | | DUP-03 | `options.cpp:14-62` | Tres parelles `enumToString`/`enumFromString` amb la mateixa forma | Menor | DONE | Tres `constexpr std::array, N>` + helpers `enumToString`/`enumFromString` plantilla. La primera entrada és el fallback (documentat). També elimina HC-07 | -| DUP-04 | `options.cpp:79-149` | Cada `parse*` repeteix `if (node.contains) { ... get_value }` | Menor | PENDING | Helper `readField(node, key, dst)` | +| DUP-04 | `options.cpp:79-149` | Cada `parse*` repeteix `if (node.contains) { ... get_value }` | Menor | DONE | Afegit `readField(node, key, dst)` plantilla a l'anonymous namespace. Aplicat a les 7 funcions `parse*` + `parsePostFXPreset`/`parseCrtPiPreset` | | DUP-05 | `player.cpp:81-88` | Càlcul `MIN_/MAX_` + `clamp` per eix és la mateixa fórmula que el snap | Menor | PENDING | Fold en helper | ## 2. Hardcoding diff --git a/source/game/options.cpp b/source/game/options.cpp index 6a1b9a7..0934a5e 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -68,6 +68,14 @@ namespace { return file.good(); } + // Helper trivial per a llegir un camp optional del YAML: si existeix, + // sobreescriu `dst`; si no, el deixa com estava (valor per defecte). + // Centralitza el patró `if (node.contains("x")) { x = node["x"].get_value(); }`. + template + void readField(const fkyaml::node& node, const char* key, T& dst) { + if (node.contains(key)) { dst = node[key].get_value(); } + } + // Còpia `` a `.bak` per protegir ediciones manuals de // l'usuari quan estem a punt de reescriure el fitxer amb defaults per // error de parseig o canvi de versió. Si el fitxer no existeix (primera @@ -85,36 +93,30 @@ namespace { void parseWindow(const fkyaml::node& yaml) { if (!yaml.contains("window")) { return; } const auto& node = yaml["window"]; - if (node.contains("zoom")) { Options::window.zoom = node["zoom"].get_value(); } - if (node.contains("fullscreen")) { Options::window.fullscreen = node["fullscreen"].get_value(); } + readField(node, "zoom", Options::window.zoom); + readField(node, "fullscreen", Options::window.fullscreen); } void parseGpu(const fkyaml::node& video_node) { if (!video_node.contains("gpu")) { return; } const auto& node = video_node["gpu"]; - if (node.contains("acceleration")) { Options::video.gpu.acceleration = node["acceleration"].get_value(); } - if (node.contains("preferred_driver")) { Options::video.gpu.preferred_driver = node["preferred_driver"].get_value(); } + readField(node, "acceleration", Options::video.gpu.acceleration); + readField(node, "preferred_driver", Options::video.gpu.preferred_driver); } void parseShader(const fkyaml::node& video_node) { if (!video_node.contains("shader")) { return; } const auto& node = video_node["shader"]; - if (node.contains("enabled")) { Options::video.shader.enabled = node["enabled"].get_value(); } - if (node.contains("current_shader")) { - Options::video.shader.current_shader = node["current_shader"].get_value(); - } - if (node.contains("current_postfx_preset")) { - Options::video.shader.current_postfx_preset = node["current_postfx_preset"].get_value(); - } - if (node.contains("current_crtpi_preset")) { - Options::video.shader.current_crtpi_preset = node["current_crtpi_preset"].get_value(); - } + readField(node, "enabled", Options::video.shader.enabled); + readField(node, "current_shader", Options::video.shader.current_shader); + readField(node, "current_postfx_preset", Options::video.shader.current_postfx_preset); + readField(node, "current_crtpi_preset", Options::video.shader.current_crtpi_preset); } void parseVideo(const fkyaml::node& yaml) { if (!yaml.contains("video")) { return; } const auto& node = yaml["video"]; - if (node.contains("vsync")) { Options::video.vsync = node["vsync"].get_value(); } + readField(node, "vsync", Options::video.vsync); if (node.contains("scaling_mode")) { Options::video.scaling_mode = enumFromString(SCALING_MODE_NAMES, node["scaling_mode"].get_value()); } @@ -124,9 +126,7 @@ namespace { if (node.contains("render_info_position")) { Options::video.render_info_position = enumFromString(RENDER_INFO_POSITION_NAMES, node["render_info_position"].get_value()); } - if (node.contains("render_info_show_time")) { - Options::video.render_info_show_time = node["render_info_show_time"].get_value(); - } + readField(node, "render_info_show_time", Options::video.render_info_show_time); parseGpu(node); parseShader(node); } @@ -134,22 +134,22 @@ namespace { void parseMusic(const fkyaml::node& audio_node) { if (!audio_node.contains("music")) { return; } const auto& node = audio_node["music"]; - if (node.contains("enabled")) { Options::audio.music.enabled = node["enabled"].get_value(); } - if (node.contains("volume")) { Options::audio.music.volume = node["volume"].get_value(); } + readField(node, "enabled", Options::audio.music.enabled); + readField(node, "volume", Options::audio.music.volume); } void parseSound(const fkyaml::node& audio_node) { if (!audio_node.contains("sound")) { return; } const auto& node = audio_node["sound"]; - if (node.contains("enabled")) { Options::audio.sound.enabled = node["enabled"].get_value(); } - if (node.contains("volume")) { Options::audio.sound.volume = node["volume"].get_value(); } + readField(node, "enabled", Options::audio.sound.enabled); + readField(node, "volume", Options::audio.sound.volume); } void parseAudio(const fkyaml::node& yaml) { if (!yaml.contains("audio")) { return; } const auto& node = yaml["audio"]; - if (node.contains("enabled")) { Options::audio.enabled = node["enabled"].get_value(); } - if (node.contains("volume")) { Options::audio.volume = node["volume"].get_value(); } + readField(node, "enabled", Options::audio.enabled); + readField(node, "volume", Options::audio.volume); parseMusic(node); parseSound(node); } @@ -215,15 +215,15 @@ namespace { } void parsePostFXPreset(const fkyaml::node& node, Options::PostFXPreset& preset) { - if (node.contains("name")) { preset.name = node["name"].get_value(); } - if (node.contains("vignette")) { preset.vignette = node["vignette"].get_value(); } - if (node.contains("scanlines")) { preset.scanlines = node["scanlines"].get_value(); } - if (node.contains("chroma")) { preset.chroma = node["chroma"].get_value(); } - if (node.contains("mask")) { preset.mask = node["mask"].get_value(); } - if (node.contains("gamma")) { preset.gamma = node["gamma"].get_value(); } - if (node.contains("curvature")) { preset.curvature = node["curvature"].get_value(); } - if (node.contains("bleeding")) { preset.bleeding = node["bleeding"].get_value(); } - if (node.contains("flicker")) { preset.flicker = node["flicker"].get_value(); } + readField(node, "name", preset.name); + readField(node, "vignette", preset.vignette); + readField(node, "scanlines", preset.scanlines); + readField(node, "chroma", preset.chroma); + readField(node, "mask", preset.mask); + readField(node, "gamma", preset.gamma); + readField(node, "curvature", preset.curvature); + readField(node, "bleeding", preset.bleeding); + readField(node, "flicker", preset.flicker); } void writePostFXPreset(std::ostringstream& out, const Options::PostFXPreset& preset) { @@ -305,21 +305,21 @@ namespace { } void parseCrtPiPreset(const fkyaml::node& node, Options::CrtPiPreset& preset) { - if (node.contains("name")) { preset.name = node["name"].get_value(); } - if (node.contains("scanline_weight")) { preset.scanline_weight = node["scanline_weight"].get_value(); } - if (node.contains("scanline_gap_brightness")) { preset.scanline_gap_brightness = node["scanline_gap_brightness"].get_value(); } - if (node.contains("bloom_factor")) { preset.bloom_factor = node["bloom_factor"].get_value(); } - if (node.contains("input_gamma")) { preset.input_gamma = node["input_gamma"].get_value(); } - if (node.contains("output_gamma")) { preset.output_gamma = node["output_gamma"].get_value(); } - if (node.contains("mask_brightness")) { preset.mask_brightness = node["mask_brightness"].get_value(); } - if (node.contains("curvature_x")) { preset.curvature_x = node["curvature_x"].get_value(); } - if (node.contains("curvature_y")) { preset.curvature_y = node["curvature_y"].get_value(); } - if (node.contains("mask_type")) { preset.mask_type = node["mask_type"].get_value(); } - if (node.contains("enable_scanlines")) { preset.enable_scanlines = node["enable_scanlines"].get_value(); } - if (node.contains("enable_multisample")) { preset.enable_multisample = node["enable_multisample"].get_value(); } - if (node.contains("enable_gamma")) { preset.enable_gamma = node["enable_gamma"].get_value(); } - if (node.contains("enable_curvature")) { preset.enable_curvature = node["enable_curvature"].get_value(); } - if (node.contains("enable_sharper")) { preset.enable_sharper = node["enable_sharper"].get_value(); } + readField(node, "name", preset.name); + readField(node, "scanline_weight", preset.scanline_weight); + readField(node, "scanline_gap_brightness", preset.scanline_gap_brightness); + readField(node, "bloom_factor", preset.bloom_factor); + readField(node, "input_gamma", preset.input_gamma); + readField(node, "output_gamma", preset.output_gamma); + readField(node, "mask_brightness", preset.mask_brightness); + readField(node, "curvature_x", preset.curvature_x); + readField(node, "curvature_y", preset.curvature_y); + readField(node, "mask_type", preset.mask_type); + readField(node, "enable_scanlines", preset.enable_scanlines); + readField(node, "enable_multisample", preset.enable_multisample); + readField(node, "enable_gamma", preset.enable_gamma); + readField(node, "enable_curvature", preset.enable_curvature); + readField(node, "enable_sharper", preset.enable_sharper); } void writeCrtPiPreset(std::ostringstream& out, const Options::CrtPiPreset& preset) {