feat(editor): mou la porta i persisteix geometry.door_col
This commit is contained in:
1 parent
a254fdd669
commit
c003e6665e
8 files changed
+214
-20
No files matched your search
@@ -0,0 +1,123 @@
|
||||
#include "game/map/map_writer.hpp"
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
namespace MapWriter {
|
||||
|
||||
namespace {
|
||||
|
||||
// Cerca la línia que comença per `<key>:` 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<std::streamsize>(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
|
||||
Reference in new issue
Block a user