#include "game/map/map_writer.hpp" #ifdef _DEBUG #include #include #include #include #include #include namespace MapWriter { namespace { // Cerca la línia que comença per `:` a columna 0 (top-level) // o, si `min_indent>0`, a una indentació mínima donada — això ens // permet trobar tant `geometry:` com una clau interna del bloc. auto findKeyLine(const std::string& content, const std::string& key, std::size_t start_pos, std::size_t min_indent) -> std::size_t { const std::string PREFIX = key + ":"; std::size_t pos = start_pos; while (pos < content.size()) { // Compta la indentació de la línia actual. std::size_t indent = 0; while (pos + indent < content.size() && (content[pos + indent] == ' ' || content[pos + indent] == '\t')) { ++indent; } const bool INDENT_OK = (min_indent == 0) ? (indent == 0) : (indent >= min_indent); if (INDENT_OK && pos + indent + PREFIX.size() <= content.size() && content.compare(pos + indent, PREFIX.size(), PREFIX) == 0) { const std::size_t AFTER = pos + indent + PREFIX.size(); if (AFTER >= content.size() || content[AFTER] == '\n' || content[AFTER] == '\r' || content[AFTER] == ' ' || content[AFTER] == '\t' || content[AFTER] == '#') { return pos + indent; } } const auto NL = content.find('\n', pos); if (NL == std::string::npos) { break; } pos = NL + 1; // Si la línia actual és de columna 0 i no és la que busquem, // i estem dins d'un bloc indentat, sortim (no és part del bloc). if (min_indent > 0 && indent == 0 && content.compare(pos - 1, 1, "\n") == 0) { // No usem aquest break agressiu perquè línies en blanc // (indent=0) no han de tallar la cerca dins del bloc. // Tractades implícitament pel control superior. } } return std::string::npos; } auto atomicWrite(const std::string& path, const std::string& content) -> bool { const auto TMP_PATH = path + ".tmp"; { std::ofstream out(TMP_PATH, std::ios::binary | std::ios::trunc); if (!out) { return false; } out.write(content.data(), static_cast(content.size())); out.close(); if (!out) { std::error_code ec; std::filesystem::remove(TMP_PATH, ec); return false; } } std::error_code ec; std::filesystem::rename(TMP_PATH, path, ec); if (ec) { std::filesystem::remove(TMP_PATH, ec); return false; } return true; } } // namespace auto saveDoorCol(const std::string& path, int door_col) -> bool { std::ifstream in(path, std::ios::binary); if (!in) { return false; } std::ostringstream ss; ss << in.rdbuf(); const std::string CONTENT = ss.str(); in.close(); // 1) Localitza el bloc `geometry:` a columna 0. const auto GEO_POS = findKeyLine(CONTENT, "geometry", 0, 0); if (GEO_POS == std::string::npos) { return false; } const auto GEO_LINE_END = CONTENT.find('\n', GEO_POS); if (GEO_LINE_END == std::string::npos) { return false; } const std::size_t BLOCK_START = GEO_LINE_END + 1; // 2) Dins del bloc, busca `door_col:` indentada (>=1 espai/tab). const auto KEY_POS = findKeyLine(CONTENT, "door_col", BLOCK_START, 1); const std::string NEW_LINE = " door_col: " + std::to_string(door_col); if (KEY_POS != std::string::npos) { // Substitueix la línia sencera (manté indentació original // recalculant el start de la línia). std::size_t line_start = KEY_POS; while (line_start > 0 && CONTENT[line_start - 1] != '\n') { --line_start; } const auto LINE_END = CONTENT.find('\n', KEY_POS); const auto END = (LINE_END == std::string::npos) ? CONTENT.size() : LINE_END; const std::string NEW_CONTENT = CONTENT.substr(0, line_start) + NEW_LINE + CONTENT.substr(END); return atomicWrite(path, NEW_CONTENT); } // Si manca, l'afegim al final del bloc geometry (just abans // de la primera línia top-level que segueix). Trobem la fi // del bloc avançant mentre les línies són indentades o buides. std::size_t pos = BLOCK_START; while (pos < CONTENT.size()) { const char C = CONTENT[pos]; const bool INDENTED = (C == ' ' || C == '\t'); const bool BLANK = (C == '\n' || C == '\r'); if (!INDENTED && !BLANK) { break; } const auto NL = CONTENT.find('\n', pos); pos = (NL == std::string::npos) ? CONTENT.size() : NL + 1; } const std::string NEW_CONTENT = CONTENT.substr(0, pos) + NEW_LINE + "\n" + CONTENT.substr(pos); return atomicWrite(path, NEW_CONTENT); } } // namespace MapWriter #endif // _DEBUG