Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
FSM.h
Go to the documentation of this file.
1/* Copyright (C) 2024 Wildfire Games.
2 * This file is part of 0 A.D.
3 *
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef FSM_H
19#define FSM_H
20
21#include <limits>
22#include <unordered_map>
23
24
25constexpr unsigned int FSM_INVALID_STATE{std::numeric_limits<unsigned int>::max()};
26
27/**
28 * Represents a signal in the state machine that a change has occurred.
29 * The CFsmEvent objects are under the control of CFsm so
30 * they are created and deleted via CFsm.
31 */
33{
34public:
35 CFsmEvent(unsigned int type, void* pParam) :
36 m_Type{type},
37 m_Param{pParam}
38 {}
39
40 unsigned int GetType() const
41 {
42 return m_Type;
43 }
44
46 {
47 return m_Param;
48 }
49
50private:
51 unsigned int m_Type; // Event type
52 void* m_Param; // Event paramater
53};
54
55/**
56 * Manages states, events, actions and transitions
57 * between states. It provides an interface for advertising
58 * events and track the current state. The implementation is
59 * a Mealy state machine, so the system respond to events
60 * and execute some action.
61 *
62 * A Mealy state machine has behaviour associated with state
63 * transitions; Mealy machines are event driven where an
64 * event triggers a state transition.
65 */
66template <typename Context>
67class CFsm
68{
69 using Action = bool(Context* pContext, CFsmEvent* pEvent);
70
72 {
73 Action* pFunction{nullptr};
74 Context* pContext{nullptr};
75
76 bool operator()(CFsmEvent& event) const
77 {
78 return !pFunction || pFunction(pContext, &event);
79 }
80 };
81public:
82 /**
83 * Adds a new transistion to the state machine.
84 */
85 void AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState,
86 Action* pAction = nullptr, Context* pContext = nullptr)
87 {
88 m_Transitions.insert({TransitionKey{state, eventType},
89 Transition{{pAction, pContext}, nextState}});
90 }
91
92 /**
93 * Sets the initial state for FSM.
94 */
95 void SetFirstState(unsigned int firstState)
96 {
97 m_FirstState = firstState;
98 }
99
100 /**
101 * Sets the current state and update the last state to the current state.
102 */
103 void SetCurrState(unsigned int state)
104 {
106 }
107 unsigned int GetCurrState() const
108 {
109 return m_CurrState;
110 }
111
112 void SetNextState(unsigned int nextState)
113 {
114 m_NextState = nextState;
115 }
116
117 unsigned int GetNextState() const
118 {
119 return m_NextState;
120 }
121
122 /**
123 * Updates the FSM and retrieves next state.
124 * @return whether the state was changed.
125 */
126 bool Update(unsigned int eventType, void* pEventData)
127 {
128 if (IsFirstTime())
130
131 // Lookup transition
132 auto transitionIterator = m_Transitions.find({m_CurrState, eventType});
133 if (transitionIterator == m_Transitions.end())
134 return false;
135
136 CFsmEvent event{eventType, pEventData};
137
138 // Save the default state transition (actions might call SetNextState
139 // to override this)
140 SetNextState(transitionIterator->second.nextState);
141
142 if (!transitionIterator->second.action(event))
143 return false;
144
146
147 // Reset the next state since it's no longer valid
149
150 return true;
151 }
152
153 /**
154 * Tests whether the state machine has finished its work.
155 */
156 bool IsDone() const
157 {
158 return m_Done;
159 }
160
161private:
163 {
164 using UnderlyingType = unsigned int;
167
168 struct Hash
169 {
170 size_t operator()(const TransitionKey& key) const noexcept
171 {
172 constexpr size_t count{std::numeric_limits<size_t>::digits / 2};
173 const size_t wideState{static_cast<size_t>(key.state)};
174 const size_t rotatedState{(wideState << count) | (wideState >> count)};
175 return static_cast<size_t>(key.eventType) ^ rotatedState;
176 }
177 };
178
179 friend bool operator==(const TransitionKey& lhs, const TransitionKey& rhs) noexcept
180 {
181 return lhs.state == rhs.state && lhs.eventType == rhs.eventType;
182 }
183 };
184
186 {
188 unsigned int nextState;
189 };
190
191 using TransitionMap = std::unordered_map<TransitionKey, const Transition,
192 typename TransitionKey::Hash>;
193
194 /**
195 * Verifies whether state machine has already been updated.
196 */
197 bool IsFirstTime() const
198 {
200 }
201
202 bool m_Done{false};
207};
208
209#endif // FSM_H
constexpr unsigned int FSM_INVALID_STATE
Definition: FSM.h:25
static enum @29 state
Represents a signal in the state machine that a change has occurred.
Definition: FSM.h:33
void * m_Param
Definition: FSM.h:52
unsigned int m_Type
Definition: FSM.h:51
unsigned int GetType() const
Definition: FSM.h:40
void * GetParamRef()
Definition: FSM.h:45
CFsmEvent(unsigned int type, void *pParam)
Definition: FSM.h:35
Manages states, events, actions and transitions between states.
Definition: FSM.h:68
unsigned int m_FirstState
Definition: FSM.h:203
void SetCurrState(unsigned int state)
Sets the current state and update the last state to the current state.
Definition: FSM.h:103
bool IsFirstTime() const
Verifies whether state machine has already been updated.
Definition: FSM.h:197
TransitionMap m_Transitions
Definition: FSM.h:206
void SetFirstState(unsigned int firstState)
Sets the initial state for FSM.
Definition: FSM.h:95
unsigned int GetCurrState() const
Definition: FSM.h:107
unsigned int GetNextState() const
Definition: FSM.h:117
void AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState, Action *pAction=nullptr, Context *pContext=nullptr)
Adds a new transistion to the state machine.
Definition: FSM.h:85
bool IsDone() const
Tests whether the state machine has finished its work.
Definition: FSM.h:156
void SetNextState(unsigned int nextState)
Definition: FSM.h:112
unsigned int m_NextState
Definition: FSM.h:205
std::unordered_map< TransitionKey, const Transition, typename TransitionKey::Hash > TransitionMap
Definition: FSM.h:192
bool(Context *pContext, CFsmEvent *pEvent) Action
Definition: FSM.h:69
bool Update(unsigned int eventType, void *pEventData)
Updates the FSM and retrieves next state.
Definition: FSM.h:126
bool m_Done
Definition: FSM.h:202
unsigned int m_CurrState
Definition: FSM.h:204
Definition: FSM.h:72
Action * pFunction
Definition: FSM.h:73
bool operator()(CFsmEvent &event) const
Definition: FSM.h:76
Context * pContext
Definition: FSM.h:74
Definition: FSM.h:169
size_t operator()(const TransitionKey &key) const noexcept
Definition: FSM.h:170
Definition: FSM.h:163
UnderlyingType eventType
Definition: FSM.h:166
friend bool operator==(const TransitionKey &lhs, const TransitionKey &rhs) noexcept
Definition: FSM.h:179
unsigned int UnderlyingType
Definition: FSM.h:164
UnderlyingType state
Definition: FSM.h:165
Definition: FSM.h:186
CallbackFunction action
Definition: FSM.h:187
unsigned int nextState
Definition: FSM.h:188
pthread_key_t key
Definition: wpthread.cpp:140