From 72c2bb533684165dc115da4d1f1c2df3d2fc53fe Mon Sep 17 00:00:00 2001 From: Thraix Date: Sun, 28 Jun 2026 20:41:40 +0200 Subject: [PATCH] Add StateMachine class --- CopiumEngine/src/copium/util/StateMachine.h | 84 +++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 CopiumEngine/src/copium/util/StateMachine.h diff --git a/CopiumEngine/src/copium/util/StateMachine.h b/CopiumEngine/src/copium/util/StateMachine.h new file mode 100644 index 0000000..34514fa --- /dev/null +++ b/CopiumEngine/src/copium/util/StateMachine.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +namespace copium +{ + template + class StateMachine + { + public: + StateMachine(State initialState) + : currentState{initialState}, + failOnInvalidTrigger{false} + { + } + + StateMachine(State initialState, bool failOnInvalidTrigger) + : currentState{initialState}, + failOnInvalidTrigger{failOnInvalidTrigger} + { + } + + void AddTransition(State from, State to, Trigger trigger) + { + auto& map = transitionMap[from]; + CP_ASSERT( + map.find(trigger) == map.end(), "Transition already exists for state {} using trigger {}", from, trigger); + + map[trigger] = to; + } + + void HandleTrigger(Trigger trigger) + { + auto& map = transitionMap[currentState]; + auto it = map.find(trigger); + if (it == map.end()) + { + CP_ASSERT(!failOnInvalidTrigger, "Trigger {} doesn't exist for state {}", trigger, currentState); + return; + } + + CP_DEBUG("Transitioning from state {} to state {} due to trigger {}", currentState, it->second, trigger); + RunTrigger(leaveTriggers); + currentState = it->second; + RunTrigger(enterTriggers); + } + + void AddEnterTrigger(State from, std::function func) + { + CP_ASSERT(enterTriggers.find(from) == enterTriggers.end(), "State {} already has an enter trigger", from); + enterTriggers[from] = func; + } + + void AddLeaveTrigger(State from, std::function func) + { + CP_ASSERT(leaveTriggers.find(from) == leaveTriggers.end(), "State {} already has a leave trigger", from); + leaveTriggers[from] = func; + } + + State GetCurrentState() const + { + return currentState; + } + + private: + State currentState; + bool failOnInvalidTrigger; + + std::map> transitionMap; + + std::map> enterTriggers; + std::map> leaveTriggers; + + void RunTrigger(const std::map>& triggers) + { + auto it = triggers.find(currentState); + if (it != triggers.end()) + { + it->second(); + } + } + }; +}