From e742b8772d00bb1c6a992ff7b454c1039199f7ed Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Mon, 23 Mar 2026 12:47:16 -0400 Subject: [PATCH] Refactored the FSM so that it uses a generic registry of systems to do what it needs. --- src/game/registry.hpp | 82 +++++++++++++++++++++++++++++ src/game/systems.cpp | 24 +++++++-- src/game/systems.hpp | 8 ++- src/gui/fsm.cpp | 29 +++------- src/gui/fsm.hpp | 4 +- src/main.cpp | 2 + tests/systems.cpp | 119 +++++++++++------------------------------- 7 files changed, 150 insertions(+), 118 deletions(-) create mode 100644 src/game/registry.hpp diff --git a/src/game/registry.hpp b/src/game/registry.hpp new file mode 100644 index 0000000..cf5b8ee --- /dev/null +++ b/src/game/registry.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include "game/components.hpp" + +namespace System { + using MovingFunc = std::function; + using CombatFunc = std::function; + using RenderFunc = std::function; + using UpdateFunc = std::function; + using UseItemFunc = std::function; + using PickupFunc = std::function; + + struct Registry { + std::vector $moving; + std::vector $combat; + std::vector $render; + std::vector $update; + std::vector $use_item; + std::vector $pickup; + + void addMoving(MovingFunc action) { + $moving.emplace_back(action); + } + + void addCombat(CombatFunc action) { + $combat.emplace_back(action); + } + + void addRender(RenderFunc action) { + $render.emplace_back(action); + } + + void addUpdate(UpdateFunc action) { + $update.emplace_back(action); + } + + void addUseItem(UseItemFunc action) { + $use_item.emplace_back(action); + } + + void addPickup(PickupFunc action) { + $pickup.emplace_back(action); + } + + void runMoving(components::Position move_to) { + for(auto func : $moving) { + func(move_to); + } + } + + void runCombat(int attack_id) { + for(auto func : $combat) { + func(attack_id); + } + } + + void runRender() { + for(auto func : $render) { + func(); + } + } + + void runUpdate() { + for(auto func : $update) { + func(); + } + } + + void runUseItem(const std::string& slot_name) { + for(auto func : $use_item) { + func(slot_name); + } + } + + void runPickup() { + for(auto func : $pickup) { + func(); + } + } + }; +} diff --git a/src/game/systems.cpp b/src/game/systems.cpp index d01fb93..0dffdc1 100644 --- a/src/game/systems.cpp +++ b/src/game/systems.cpp @@ -474,14 +474,14 @@ bool System::inventory_occupied(Entity container_id, const std::string& name) { return inventory.has(name); } -bool System::use_item(const string& slot_name) { +void System::use_item(const string& slot_name) { auto& level = GameDB::current_level(); auto& world = *level.world; auto& inventory = world.get(level.player); auto& player_combat = world.get(level.player); - if(player_combat.hp >= player_combat.max_hp) return false; - if(!inventory.has(slot_name)) return false; + if(player_combat.hp >= player_combat.max_hp) return; + if(!inventory.has(slot_name)) return; auto what = inventory.get(slot_name); @@ -498,10 +498,8 @@ bool System::use_item(const string& slot_name) { player_combat.hp)); world.remove(what); - return true; } else { dbc::log($F("no usable item at {}", what)); - return false; } } @@ -541,3 +539,19 @@ void System::clear_attack() { void System::spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy) { } + + +void System::init(Registry& reg) { + reg.addRender(System::clear_attack); + reg.addUseItem(System::use_item); + reg.addMoving(System::move_player); + reg.addCombat(System::combat); + reg.addPickup(System::pickup); + reg.addUpdate(System::generate_paths); + reg.addUpdate(System::enemy_ai_initialize); + reg.addUpdate(System::enemy_pathing); + reg.addUpdate(System::motion); + reg.addUpdate(System::collision); + reg.addUpdate(System::lighting); + reg.addUpdate(System::death); +} diff --git a/src/game/systems.hpp b/src/game/systems.hpp index b1edd4e..38f29e0 100644 --- a/src/game/systems.hpp +++ b/src/game/systems.hpp @@ -5,8 +5,10 @@ #include "algos/spatialmap.hpp" #include "game/level.hpp" #include "events.hpp" +#include "game/registry.hpp" namespace System { + using namespace components; using namespace DinkyECS; using std::string, matrix::Matrix; @@ -32,15 +34,15 @@ namespace System { void pickup(); + // BUG: these might need to go somewhere else.... bool place_in_container(Entity cont_id, const string& name, Entity world_entity); - void remove_from_container(Entity cont_id, const std::string& name); void remove_from_world(Entity entity); void inventory_swap(Entity container_id, const std::string& a_name, const std::string &b_name); bool inventory_occupied(Entity container_id, const std::string& name); void set_position(DinkyECS::World& world, SpatialMap& collision, Entity entity, Position pos); - bool use_item(const std::string& slot_name); + void use_item(const std::string& slot_name); game::Event shortest_rotate(Point player_at, Point aiming_at, Point turning_to); @@ -67,4 +69,6 @@ namespace System { void clear_attack(); void spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy); + + void init(Registry& reg); } diff --git a/src/gui/fsm.cpp b/src/gui/fsm.cpp index 8a7686a..9062526 100644 --- a/src/gui/fsm.cpp +++ b/src/gui/fsm.cpp @@ -58,7 +58,7 @@ namespace gui { void FSM::MOVING(Event ) { // this should be an optional that returns a point if(auto move_to = $main_ui.play_move()) { - System::move_player(*move_to); + $systems.runMoving(*move_to); run_systems(); $main_ui.dirty(); state(State::IDLE); @@ -70,7 +70,7 @@ namespace gui { switch(ev) { case TICK: { dbc::log("!!!!!! FIX System::combat(0) doesn't use any weapons, only first"); - System::combat(0); + $systems.runCombat(0); run_systems(); state(State::IN_COMBAT); } break; @@ -79,7 +79,7 @@ namespace gui { break; case ATTACK: { int attack_id = std::any_cast(data); - System::combat(attack_id); + $systems.runCombat(attack_id); run_systems(); } break; default: @@ -174,10 +174,8 @@ namespace gui { case USE_ITEM: { auto gui_id = std::any_cast(data); auto& slot_name = $status_ui.$gui.name_for(gui_id); - - if(System::use_item(slot_name)) { - $status_ui.update(); - } + $systems.runUseItem(slot_name); + $status_ui.update(); } break; case MOUSE_CLICK: mouse_action(guecs::NO_MODS); @@ -186,7 +184,7 @@ namespace gui { mouse_action({1 << guecs::ModBit::hover}); } break; case AIM_CLICK: - System::pickup(); + $systems.runPickup(); break; default: break; // ignore everything else @@ -312,9 +310,6 @@ namespace gui { $debug_ui.debug(); shaders::reload(); break; - case KEY::O: - autowalking = true; - break; case KEY::L: // This will go away as soon as containers work $loot_ui.set_target($loot_ui.$temp_loot); @@ -360,10 +355,8 @@ namespace gui { } void FSM::render() { - $window.clear(); - // this clears any attack animations, like fire - System::clear_attack(); + $systems.runRender(); // BUG: this is the render for this class, and where I add an update draw_gui(); @@ -371,13 +364,7 @@ namespace gui { } void FSM::run_systems() { - System::generate_paths(); - System::enemy_ai_initialize(); - System::enemy_pathing(); - System::motion(); - System::collision(); - System::lighting(); - System::death(); + $systems.runUpdate(); } bool FSM::active() { diff --git a/src/gui/fsm.hpp b/src/gui/fsm.hpp index 0610626..36aed03 100644 --- a/src/gui/fsm.hpp +++ b/src/gui/fsm.hpp @@ -1,6 +1,7 @@ #pragma once #include "constants.hpp" +#include "game/registry.hpp" #include "algos/simplefsm.hpp" #include "gui/debug_ui.hpp" #include "gui/main_ui.hpp" @@ -35,12 +36,11 @@ namespace gui { LootUI $loot_ui; gui::routing::Router $router; DNDLoot $dnd_loot; + System::Registry $systems; FSM(); void event(game::Event ev, std::any data={}); - void autowalk(); - void start_autowalk(double rot_speed); void START(game::Event ev); void MOVING(game::Event ev); diff --git a/src/main.cpp b/src/main.cpp index a889731..28a5f35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "gui/backend.hpp" #include "game/level.hpp" #include "graphics/camera.hpp" +#include "game/systems.hpp" int main(int argc, char* argv[]) { try { @@ -21,6 +22,7 @@ int main(int argc, char* argv[]) { sound::mute(true); gui::FSM main; + System::init(main.$systems); main.event(game::Event::START); sound::play("ambient_1", true); diff --git a/tests/systems.cpp b/tests/systems.cpp index 55c7308..4272a9d 100644 --- a/tests/systems.cpp +++ b/tests/systems.cpp @@ -3,7 +3,9 @@ #include "game/systems.hpp" #include #include +#include "game/registry.hpp" +using components::Position; TEST_CASE("figure out best rotation direction", "[systems-rotate]") { Matrix map = matrix::make(3, 3); @@ -35,104 +37,45 @@ TEST_CASE("figure out best rotation direction", "[systems-rotate]") { } } -using MovingFunc = std::function; -using CombatFunc = std::function; -using RenderFunc = std::function; -using UpdateFunc = std::function; -using UseFunc = std::function; -using PickupFunc = std::function; -struct Engine { - std::vector $moving; - std::vector $combat; - std::vector $render; - std::vector $update; - std::vector $use; - std::vector $pickup; - - void addMoving(MovingFunc action) { - $moving.emplace_back(action); - } - - void addCombat(CombatFunc action) { - $combat.emplace_back(action); - } - - void addRender(RenderFunc action) { - $render.emplace_back(action); - } - - void addUpdate(UpdateFunc action) { - $update.emplace_back(action); - } - - void addUse(UseFunc action) { - $use.emplace_back(action); - } - - void addPickup(PickupFunc action) { - $pickup.emplace_back(action); - } - - void runMoving() { - for(auto func : $moving) { - func(); - } - } - - void runCombat(bool attr) { - for(auto func : $combat) { - func(attr); - } - } - - void runRender() { - for(auto func : $render) { - func(); - } - } - - void runUpdate() { - for(auto func : $update) { - func(); - } - } - - void runUse() { - for(auto func : $use) { - func(); - } - } - - void runPickup() { - for(auto func : $pickup) { - func(); - } - } -}; - -void test_system_1() { - fmt::println("TEST 1"); +void test_moving(Position& move_to) { + fmt::println("MOVING: {},{}", move_to.location.x, move_to.location.y); } -void test_combat(bool what) { - fmt::println("TEST 2: {}", what); +void test_combat(int attack_id) { + fmt::println("ATTACK: {}", attack_id); +} + +void test_render() { + fmt::println("RENDER"); +} + +void test_update() { + fmt::println("UPDATE"); +} + +void test_use_item(const std::string& slot_name) { + fmt::println("USE ITEM {}", slot_name); +} + +void test_pickup() { + fmt::println("PICKUP"); } TEST_CASE("new system running engine thing", "[systems-engine]") { - Engine systems; + System::Registry systems; - systems.addMoving(test_system_1); + systems.addMoving(test_moving); systems.addCombat(test_combat); - systems.addRender(test_system_1); - systems.addUpdate(test_system_1); - systems.addUse(test_system_1); - systems.addPickup(test_system_1); + systems.addRender(test_render); + systems.addUpdate(test_update); + systems.addUseItem(test_use_item); + systems.addPickup(test_pickup); - systems.runCombat(false); - systems.runMoving(); + systems.runCombat(1); + systems.runMoving({1,1}); systems.runRender(); systems.runUpdate(); - systems.runUse(); + systems.runUseItem("hand_l"); systems.runPickup(); }