refactor(maps): pyramid.yaml per piràmide amb merge a sala

This commit is contained in:
JailDesigner committed 2026-05-13 22:38:42 +02:00
1 parent 5f206e03c8
commit 125cdd0c74
45 files changed
+331 -1085

No files matched your search

+2 -7
View File
@@ -6,6 +6,7 @@
#include "core/resources/resource_helper.hpp"
#include "game/entities/entity.hpp"
#include "game/entities/entity_factory.hpp"
#include "game/map/room_yaml.hpp"
#include "utils/defaults.hpp"
namespace EntityLoader {
@@ -44,13 +45,7 @@ namespace EntityLoader {
}
auto readSpawns(const std::string& level_yaml_path) -> std::vector<fkyaml::node> {
auto bytes = Resource::Helper::loadFile(level_yaml_path);
if (bytes.empty()) {
throw std::runtime_error("EntityLoader: no s'ha pogut obrir " + level_yaml_path);
}
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
fkyaml::node root = fkyaml::node::deserialize(begin, end);
fkyaml::node root = RoomYaml::loadMerged(level_yaml_path);
std::vector<fkyaml::node> spawns;
if (!root.contains("entities")) { return spawns; }
const auto& list = root["entities"];
+2 -8
View File
@@ -5,8 +5,8 @@
#include <stdexcept>
#include <unordered_map>
#include "core/resources/resource_helper.hpp"
#include "external/fkyaml_node.hpp"
#include "game/map/room_yaml.hpp"
#include "utils/defaults.hpp"
#include "utils/log.hpp"
@@ -157,13 +157,7 @@ namespace Map {
}
void loadFrom(const std::string& yaml_path) {
auto bytes = Resource::Helper::loadFile(yaml_path);
if (bytes.empty()) {
throw std::runtime_error("Map: no s'ha pogut obrir " + yaml_path);
}
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
auto yaml = fkyaml::node::deserialize(begin, end);
auto yaml = RoomYaml::loadMerged(yaml_path);
if (!yaml.contains("geometry")) {
throw std::runtime_error("Map: manca bloc `geometry:` a " + yaml_path);
}
+66
View File
@@ -0,0 +1,66 @@
#include "game/map/room_yaml.hpp"
#include <stdexcept>
#include "core/resources/resource_helper.hpp"
namespace RoomYaml {
namespace {
// Fusiona `overlay` damunt `base` in-place. Recursió només per a
// mapes; per a la resta (escalars, sequences) la `overlay` substitueix
// l'entrada de `base`. Manté l'ordre de claus de `base` per a les
// que ja hi eren; les noves s'afegeixen al final.
void deepMerge(fkyaml::node& base, const fkyaml::node& overlay) {
if (!overlay.is_mapping()) { return; }
for (const auto& kv : overlay.as_map()) {
const auto KEY = kv.first.get_value<std::string>();
const auto& val = kv.second;
if (base.contains(KEY) && base[KEY].is_mapping() && val.is_mapping()) {
deepMerge(base[KEY], val);
} else {
base[KEY] = val;
}
}
}
auto deserializeFile(const std::string& path) -> fkyaml::node {
auto bytes = Resource::Helper::loadFile(path);
if (bytes.empty()) {
throw std::runtime_error("RoomYaml: no s'ha pogut obrir " + path);
}
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
return fkyaml::node::deserialize(begin, end);
}
// Retorna el directori del path (sense barra final). Si no hi ha
// separador, retorna cadena buida.
auto dirOf(const std::string& path) -> std::string {
const auto POS = path.find_last_of('/');
if (POS == std::string::npos) { return ""; }
return path.substr(0, POS);
}
} // namespace
auto loadMerged(const std::string& room_yaml_path) -> fkyaml::node {
const auto DIR = dirOf(room_yaml_path);
const auto PYRAMID_PATH = DIR.empty() ? std::string{"pyramid.yaml"} : (DIR + "/pyramid.yaml");
// El pyramid.yaml és opcional: si Resource::Helper::loadFile el
// troba (disc o pack), el fem servir com a base; si no, només
// retornem el YAML de sala tal qual.
auto pyramid_bytes = Resource::Helper::loadFile(PYRAMID_PATH);
auto room = deserializeFile(room_yaml_path);
if (pyramid_bytes.empty()) { return room; }
const auto* begin = reinterpret_cast<const char*>(pyramid_bytes.data());
const auto* end = begin + pyramid_bytes.size();
auto merged = fkyaml::node::deserialize(begin, end);
deepMerge(merged, room);
return merged;
}
} // namespace RoomYaml
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <string>
#include "external/fkyaml_node.hpp"
// Carregador de YAMLs de sala amb fusió per piràmide. Cada piràmide pot
// tenir un `pyramid.yaml` germà al directori de sala que aporta camps
// compartits (tileset, lighting, push_factor, paint_tiles...); el YAML
// de sala només declara el que canvia (data, entities, geometry, room).
//
// Regles de fusió:
// - mapes: fusió recursiva, claus de la sala guanyen
// - sequences i escalars: la sala substitueix sencer
//
// Si no hi ha `pyramid.yaml` al directori, retorna només el YAML de sala
// sense modificacions — així rutes externes (tests, mapes solts) segueixen
// funcionant igual.
namespace RoomYaml {
auto loadMerged(const std::string& room_yaml_path) -> fkyaml::node;
} // namespace RoomYaml
+2 -8
View File
@@ -9,8 +9,8 @@
#include "core/rendering/screen.hpp"
#include "core/rendering/surface.hpp"
#include "core/resources/resource_cache.hpp"
#include "core/resources/resource_helper.hpp"
#include "external/fkyaml_node.hpp"
#include "game/map/room_yaml.hpp"
#include "utils/log.hpp"
#ifdef _DEBUG
@@ -41,13 +41,7 @@ namespace {
} // namespace
Tilemap::Tilemap(const std::string& yaml_path) {
auto bytes = Resource::Helper::loadFile(yaml_path);
if (bytes.empty()) {
throw std::runtime_error("Tilemap: no s'ha pogut obrir " + yaml_path);
}
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
auto yaml = fkyaml::node::deserialize(begin, end);
auto yaml = RoomYaml::loadMerged(yaml_path);
tileset_path_ = yaml["tileset"].get_value<std::string>();
tile_size_ = yaml["tile_size"].get_value<int>();
+3 -10
View File
@@ -38,6 +38,7 @@
#include "game/gameplay_config.hpp"
#include "game/levels/level_manager.hpp"
#include "game/map/map.hpp"
#include "game/map/room_yaml.hpp"
#include "game/options.hpp"
#include "game/scenes/scene_flow.hpp"
#include "game/scenes/start_input.hpp"
@@ -65,21 +66,13 @@ namespace {
// pinta amb l'índex declarat al mapa, i un mapa sense aquests camps
// simplement no deixa rastre visual.
auto readOptionalInt(const std::string& yaml_path, const std::string& key, int fallback = -1) -> int {
auto bytes = Resource::Helper::loadFile(yaml_path);
if (bytes.empty()) { return fallback; }
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
auto yaml = fkyaml::node::deserialize(begin, end);
auto yaml = RoomYaml::loadMerged(yaml_path);
if (!yaml.contains(key)) { return fallback; }
return yaml[key].get_value<int>();
}
auto readOptionalFloat(const std::string& yaml_path, const std::string& key, float fallback) -> float {
auto bytes = Resource::Helper::loadFile(yaml_path);
if (bytes.empty()) { return fallback; }
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
auto yaml = fkyaml::node::deserialize(begin, end);
auto yaml = RoomYaml::loadMerged(yaml_path);
if (!yaml.contains(key)) { return fallback; }
return yaml[key].get_value<float>();
}