Director encadena LOGO → TITLE → INTRO → GAME amb factories injectades al ctor de cada placeholder (sense que cap escena conegui el tipus de la següent). L'escena d'arrencada surt de `debug.yaml` en debug build i és sempre LOGO en release. Comportament: - Release: `debug.yaml` s'ignora; arranca sempre a LOGO. - Debug: es llig `debug.yaml`. Si no existeix, es crea automàticament amb `start_scene: GAME` per no arrossegar 15 s de placeholders al dia a dia de gameplay. Valor invàlid o YAML corrupte → warning + GAME, però el fitxer no es reescriu (respectem l'edició manual). `debug.yaml` viu a `$XDG_CONFIG_HOME/jailgames/aee_2026/`, al costat de `config.yaml`, i queda fora del repo (ajust per màquina de dev).
99 lines
3.4 KiB
C++
99 lines
3.4 KiB
C++
#include "game/debug_config.hpp"
|
|
|
|
#include <exception>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "external/fkyaml_node.hpp"
|
|
|
|
namespace DebugConfig {
|
|
|
|
namespace {
|
|
|
|
auto readFile(const std::string& path) -> std::string {
|
|
std::ifstream file(path);
|
|
if (!file) { return {}; }
|
|
std::stringstream buffer;
|
|
buffer << file.rdbuf();
|
|
return buffer.str();
|
|
}
|
|
|
|
auto fromName(const std::string& name) -> StartScene {
|
|
if (name == "LOGO") { return StartScene::LOGO; }
|
|
if (name == "TITLE") { return StartScene::TITLE; }
|
|
if (name == "INTRO") { return StartScene::INTRO; }
|
|
if (name == "GAME") { return StartScene::GAME; }
|
|
return StartScene::GAME;
|
|
}
|
|
|
|
auto isKnown(const std::string& name) -> bool {
|
|
return name == "LOGO" || name == "TITLE" || name == "INTRO" || name == "GAME";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
auto parseStartScene(const std::string& yaml_content) -> StartScene {
|
|
if (yaml_content.empty()) { return StartScene::GAME; }
|
|
try {
|
|
auto yaml = fkyaml::node::deserialize(yaml_content);
|
|
if (!yaml.contains("start_scene")) { return StartScene::GAME; }
|
|
const auto RAW = yaml["start_scene"].get_value<std::string>();
|
|
if (!isKnown(RAW)) {
|
|
std::cerr << "debug.yaml: start_scene \"" << RAW << "\" invàlid, arrancant a GAME\n";
|
|
return StartScene::GAME;
|
|
}
|
|
return fromName(RAW);
|
|
} catch (const std::exception& e) {
|
|
std::cerr << "debug.yaml: error parsejant: " << e.what() << " — arrancant a GAME\n";
|
|
return StartScene::GAME;
|
|
}
|
|
}
|
|
|
|
auto resolveStartScene(const std::string& file_path) -> StartScene {
|
|
std::error_code error;
|
|
if (!std::filesystem::exists(file_path, error)) {
|
|
// Silenciós: la no-existència és el cas per defecte en una màquina
|
|
// neta, no un error. L'usuari crea el fitxer quan el necessita.
|
|
return StartScene::GAME;
|
|
}
|
|
const auto CONTENT = readFile(file_path);
|
|
if (CONTENT.empty()) {
|
|
std::cerr << "debug.yaml: fitxer buit a " << file_path << ", arrancant a GAME\n";
|
|
return StartScene::GAME;
|
|
}
|
|
return parseStartScene(CONTENT);
|
|
}
|
|
|
|
auto toString(StartScene scene) -> const char* {
|
|
switch (scene) {
|
|
case StartScene::LOGO:
|
|
return "LOGO";
|
|
case StartScene::TITLE:
|
|
return "TITLE";
|
|
case StartScene::INTRO:
|
|
return "INTRO";
|
|
case StartScene::GAME:
|
|
return "GAME";
|
|
}
|
|
return "GAME";
|
|
}
|
|
|
|
void createDefaultIfMissing(const std::string& file_path) {
|
|
std::error_code error;
|
|
if (std::filesystem::exists(file_path, error)) { return; }
|
|
std::ofstream file(file_path);
|
|
if (!file) {
|
|
std::cerr << "debug.yaml: no s'ha pogut crear " << file_path << '\n';
|
|
return;
|
|
}
|
|
file << "# debug.yaml — ajust personal de dev (no versionat).\n";
|
|
file << "# Valors vàlids: LOGO, TITLE, INTRO, GAME.\n";
|
|
file << "start_scene: GAME\n";
|
|
std::cout << "debug.yaml: creat a " << file_path << " amb start_scene=GAME\n";
|
|
}
|
|
|
|
} // namespace DebugConfig
|