feat(entities): andamiatge del sistema d'entitats (classes, factory, bus, YAML, placeholders, smoke tests)
This commit is contained in:
1 parent
984cc820c0
commit
96b71b0f65
48 files changed
+1957
No files matched your search
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "external/fkyaml_node.hpp"
|
||||
|
||||
class Entity;
|
||||
|
||||
// Factory amb registre obert a extensió: cada `concrete/*.cpp` declara un
|
||||
// registrador estàtic amb `REGISTER_ENTITY(name, Class)` que s'executa
|
||||
// abans de `main`. Afegir un tipus nou d'entitat = nova classe + nova
|
||||
// crida `REGISTER_ENTITY`, sense tocar el factory.
|
||||
//
|
||||
// El `Creator` rep el `fkyaml::node` de la plantilla de l'entitat (no el
|
||||
// spawn). És el constructor de la classe concreta qui extreu els camps
|
||||
// que li interessin (sprite.path, animations, stats, etc.).
|
||||
class EntityFactory {
|
||||
public:
|
||||
using Creator = std::function<std::unique_ptr<Entity>(const fkyaml::node&)>;
|
||||
|
||||
static auto instance() -> EntityFactory&;
|
||||
|
||||
// Idempotent per nom: si s'invoca dues vegades amb el mateix nom,
|
||||
// la segona sobreescriu (útil en tests que re-registren; no és
|
||||
// especialment defensiu perquè els registradors són d'execució única).
|
||||
void registerCreator(const std::string& name, Creator creator);
|
||||
|
||||
// Retorna nullptr si el nom no té registrada cap creator.
|
||||
[[nodiscard]] auto create(const std::string& name, const fkyaml::node& yaml) const
|
||||
-> std::unique_ptr<Entity>;
|
||||
|
||||
// Diagnòstic: llista de noms registrats (per ordre d'inserció no
|
||||
// garantit). Útil al smoke per comprovar que tots els concrets
|
||||
// s'han auto-registrat.
|
||||
[[nodiscard]] auto registeredNames() const -> std::vector<std::string>;
|
||||
|
||||
private:
|
||||
EntityFactory() = default;
|
||||
std::unordered_map<std::string, Creator> creators_;
|
||||
};
|
||||
|
||||
// La macro genera un objecte anònim dins un namespace anònim: el seu
|
||||
// constructor s'executa abans de `main` i registra la factory. El nom del
|
||||
// símbol és únic per `CLASS` perquè el preprocessor el concatena; així
|
||||
// dues entitats diferents no xoquen.
|
||||
//
|
||||
// IMPORTANT: perquè el registrador es cridi, el `.cpp` que el conté ha
|
||||
// d'estar enllaçat directament a l'executable (no dins una STATIC lib
|
||||
// sense `--whole-archive`). Tots els `concrete/*.cpp` entren a APP_SOURCES.
|
||||
#define REGISTER_ENTITY(NAME, CLASS) \
|
||||
namespace { \
|
||||
struct CLASS##_Registrar { \
|
||||
CLASS##_Registrar() { \
|
||||
EntityFactory::instance().registerCreator( \
|
||||
NAME, \
|
||||
[](const fkyaml::node& yaml) -> std::unique_ptr<Entity> { \
|
||||
return std::make_unique<CLASS>(yaml); \
|
||||
}); \
|
||||
} \
|
||||
}; \
|
||||
const CLASS##_Registrar g_##CLASS##_registrar; /* NOLINT(cert-err58-cpp) */ \
|
||||
}
|
||||
Reference in new issue
Block a user