#pragma once #include #include #include #include #include #include #include #include // Forward: els events poden dur un punter a `Entity` (p. ex. quin sarcòfag // s'ha obert). No cal incloure el header complet aquí. class Entity; // Event pub/sub minimalista. Hi ha un únic `EventBus` per mundus (propietat // de l'`EntityManager`); les entitats que el necessiten en reben un punter // via `Entity::setEventBus`. Aquest sistema cobreix les necessitats // actuals (sarcophagus_opened, level_complete, player_hit, on_tile_entered) // sense portar-hi senyalització més pesada. // // Decisió: `std::variant` per al payload — evita any/void* i facilita // consumir events tipats amb `std::get_if`. Si apareixen més tipus de // payload, s'amplia aquí sense tocar cridants existents. // Tile (col, row) — payload de `on_tile_entered`. No és un `pair` // per evitar alias ambigus al variant (dos ints sense nom). struct TilePos { int col{0}; int row{0}; }; struct Event { std::string name; using Payload = std::variant; Payload payload; }; class EventBus { public: using Handler = std::function; using SubId = std::size_t; EventBus() = default; EventBus(const EventBus&) = delete; EventBus(EventBus&&) = delete; auto operator=(const EventBus&) -> EventBus& = delete; auto operator=(EventBus&&) -> EventBus& = delete; ~EventBus() = default; // Retorna un identificador únic per poder-se donar de baixa amb // `unsubscribe`. Els identificadors s'assignen globalment i no es // reutilitzen fins a overflow (acceptable per a la vida d'un nivell). auto subscribe(const std::string& name, Handler handler) -> SubId; void unsubscribe(SubId id); // Publica a tots els subscriptors registrats per al nom. Si no n'hi ha // cap, no fa res. void publish(const Event& event); // Forma ergonòmica: construeix un Event amb nom + payload opcional. void publish(const std::string& name) { publish(Event{.name = name, .payload = std::monostate{}}); } void publish(const std::string& name, Entity* entity) { publish(Event{.name = name, .payload = entity}); } void publish(const std::string& name, int value) { publish(Event{.name = name, .payload = value}); } void publish(const std::string& name, TilePos tile) { publish(Event{.name = name, .payload = tile}); } private: struct Subscription { SubId id; Handler handler; }; std::unordered_map> subs_; std::uint64_t next_id_{1}; };