Line data Source code
1 : /* Copyright (C) 2023 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 : #include "precompiled.h"
19 : #include "FSM.h"
20 :
21 :
22 0 : CFsmEvent::CFsmEvent(unsigned int type)
23 : {
24 0 : m_Type = type;
25 0 : m_Param = nullptr;
26 0 : }
27 :
28 0 : CFsmEvent::~CFsmEvent()
29 : {
30 0 : m_Param = nullptr;
31 0 : }
32 :
33 0 : void CFsmEvent::SetParamRef(void* pParam)
34 : {
35 0 : m_Param = pParam;
36 0 : }
37 :
38 0 : CFsmTransition::CFsmTransition(unsigned int state)
39 : {
40 0 : m_CurrState = state;
41 0 : }
42 :
43 0 : CFsmTransition::~CFsmTransition()
44 : {
45 0 : m_Actions.clear();
46 0 : m_Conditions.clear();
47 0 : }
48 :
49 0 : void CFsmTransition::RegisterAction(void* pAction, void* pContext)
50 : {
51 : CallbackFunction callback;
52 :
53 : // Add action at the end of actions list
54 0 : callback.pFunction = pAction;
55 0 : callback.pContext = pContext;
56 :
57 0 : m_Actions.push_back(callback);
58 0 : }
59 :
60 0 : void CFsmTransition::RegisterCondition(void* pCondition, void* pContext)
61 : {
62 : CallbackFunction callback;
63 :
64 : // Add condition at the end of conditions list
65 0 : callback.pFunction = pCondition;
66 0 : callback.pContext = pContext;
67 :
68 0 : m_Conditions.push_back(callback);
69 0 : }
70 :
71 0 : void CFsmTransition::SetEvent(CFsmEvent* pEvent)
72 : {
73 0 : m_Event = pEvent;
74 0 : }
75 :
76 0 : void CFsmTransition::SetNextState(unsigned int nextState)
77 : {
78 0 : m_NextState = nextState;
79 0 : }
80 :
81 0 : bool CFsmTransition::ApplyConditions() const
82 : {
83 0 : bool eval = true;
84 :
85 0 : CallbackList::const_iterator it = m_Conditions.begin();
86 0 : for (; it != m_Conditions.end(); ++it)
87 : {
88 0 : if (it->pFunction)
89 : {
90 : // Evaluate condition
91 0 : Condition* condition = reinterpret_cast<Condition*>(it->pFunction);
92 0 : eval &= condition(it->pContext);
93 : }
94 : }
95 :
96 0 : return eval;
97 : }
98 :
99 0 : bool CFsmTransition::RunActions() const
100 : {
101 0 : bool result = true;
102 :
103 0 : CallbackList::const_iterator it = m_Actions.begin();
104 0 : for (; it != m_Actions.end(); ++it)
105 : {
106 0 : if (it->pFunction)
107 : {
108 : // Run action
109 0 : Action* action = reinterpret_cast<Action*>(it->pFunction);
110 0 : result &= action(it->pContext, m_Event);
111 : }
112 : }
113 :
114 0 : return result;
115 : }
116 :
117 0 : CFsm::CFsm()
118 : {
119 0 : m_Done = false;
120 0 : m_FirstState = FSM_INVALID_STATE;
121 0 : m_CurrState = FSM_INVALID_STATE;
122 0 : m_NextState = FSM_INVALID_STATE;
123 0 : }
124 :
125 0 : CFsm::~CFsm()
126 : {
127 0 : Shutdown();
128 0 : }
129 :
130 0 : void CFsm::Setup()
131 : {
132 : // Does nothing by default
133 0 : }
134 :
135 0 : void CFsm::Shutdown()
136 : {
137 : // Release transitions
138 0 : TransitionList::iterator itTransition = m_Transitions.begin();
139 0 : for (; itTransition < m_Transitions.end(); ++itTransition)
140 0 : delete *itTransition;
141 :
142 : // Release events
143 0 : EventMap::iterator itEvent = m_Events.begin();
144 0 : for (; itEvent != m_Events.end(); ++itEvent)
145 0 : delete itEvent->second;
146 :
147 0 : m_States.clear();
148 0 : m_Events.clear();
149 0 : m_Transitions.clear();
150 :
151 0 : m_Done = false;
152 0 : m_FirstState = FSM_INVALID_STATE;
153 0 : m_CurrState = FSM_INVALID_STATE;
154 0 : m_NextState = FSM_INVALID_STATE;
155 0 : }
156 :
157 0 : void CFsm::AddState(unsigned int state)
158 : {
159 0 : m_States.insert(state);
160 0 : }
161 :
162 0 : CFsmEvent* CFsm::AddEvent(unsigned int eventType)
163 : {
164 0 : CFsmEvent* pEvent = nullptr;
165 :
166 : // Lookup event by type
167 0 : EventMap::iterator it = m_Events.find(eventType);
168 0 : if (it != m_Events.end())
169 : {
170 0 : pEvent = it->second;
171 : }
172 : else
173 : {
174 0 : pEvent = new CFsmEvent(eventType);
175 :
176 : // Store new event into internal map
177 0 : m_Events[eventType] = pEvent;
178 : }
179 :
180 0 : return pEvent;
181 : }
182 :
183 0 : CFsmTransition* CFsm::AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState )
184 : {
185 : // Make sure we store the current state
186 0 : AddState(state);
187 :
188 : // Make sure we store the next state
189 0 : AddState(nextState);
190 :
191 : // Make sure we store the event
192 0 : CFsmEvent* pEvent = AddEvent(eventType);
193 0 : if (!pEvent)
194 0 : return nullptr;
195 :
196 : // Create new transition
197 0 : CFsmTransition* pNewTransition = new CFsmTransition(state);
198 :
199 : // Setup new transition
200 0 : pNewTransition->SetEvent(pEvent);
201 0 : pNewTransition->SetNextState(nextState);
202 :
203 : // Store new transition
204 0 : m_Transitions.push_back(pNewTransition);
205 :
206 0 : return pNewTransition;
207 : }
208 :
209 0 : CFsmTransition* CFsm::AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState,
210 : void* pAction, void* pContext)
211 : {
212 0 : CFsmTransition* pTransition = AddTransition(state, eventType, nextState);
213 0 : if (!pTransition)
214 0 : return nullptr;
215 :
216 : // If action specified, register it
217 0 : if (pAction)
218 0 : pTransition->RegisterAction(pAction, pContext);
219 :
220 0 : return pTransition;
221 : }
222 :
223 0 : CFsmTransition* CFsm::GetTransition(unsigned int state, unsigned int eventType) const
224 : {
225 0 : if (!IsValidState(state))
226 0 : return nullptr;
227 :
228 0 : if (!IsValidEvent(eventType))
229 0 : return nullptr;
230 :
231 0 : TransitionList::const_iterator it = m_Transitions.begin();
232 0 : for (; it != m_Transitions.end(); ++it)
233 : {
234 0 : CFsmTransition* pCurrTransition = *it;
235 0 : if (!pCurrTransition)
236 0 : continue;
237 :
238 0 : CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
239 0 : if (!pCurrEvent)
240 0 : continue;
241 :
242 : // Is it our transition?
243 0 : if (pCurrTransition->GetCurrState() == state && pCurrEvent->GetType() == eventType)
244 0 : return pCurrTransition;
245 : }
246 :
247 : // No transition found
248 0 : return nullptr;
249 : }
250 :
251 0 : void CFsm::SetFirstState(unsigned int firstState)
252 : {
253 0 : m_FirstState = firstState;
254 0 : }
255 :
256 0 : void CFsm::SetCurrState(unsigned int state)
257 : {
258 0 : m_CurrState = state;
259 0 : }
260 :
261 0 : bool CFsm::IsFirstTime() const
262 : {
263 0 : return (m_CurrState == FSM_INVALID_STATE);
264 : }
265 :
266 0 : bool CFsm::Update(unsigned int eventType, void* pEventParam)
267 : {
268 0 : if (!IsValidEvent(eventType))
269 0 : return false;
270 :
271 0 : if (IsFirstTime())
272 0 : m_CurrState = m_FirstState;
273 :
274 : // Lookup transition
275 0 : CFsmTransition* pTransition = GetTransition(m_CurrState, eventType);
276 0 : if (!pTransition)
277 0 : return false;
278 :
279 : // Setup event parameter
280 0 : EventMap::iterator it = m_Events.find(eventType);
281 0 : if (it != m_Events.end())
282 : {
283 0 : CFsmEvent* pEvent = it->second;
284 0 : if (pEvent)
285 0 : pEvent->SetParamRef(pEventParam);
286 : }
287 :
288 : // Valid transition?
289 0 : if (!pTransition->ApplyConditions())
290 0 : return false;
291 :
292 : // Save the default state transition (actions might call SetNextState
293 : // to override this)
294 0 : SetNextState(pTransition->GetNextState());
295 :
296 0 : if (!pTransition->RunActions())
297 0 : return false;
298 :
299 0 : SetCurrState(GetNextState());
300 :
301 : // Reset the next state since it's no longer valid
302 0 : SetNextState(FSM_INVALID_STATE);
303 :
304 0 : return true;
305 : }
306 :
307 0 : bool CFsm::IsDone() const
308 : {
309 : // By default the internal flag m_Done is tested
310 0 : return m_Done;
311 : }
312 :
313 0 : bool CFsm::IsValidState(unsigned int state) const
314 : {
315 0 : StateSet::const_iterator it = m_States.find(state);
316 0 : if (it == m_States.end())
317 0 : return false;
318 :
319 0 : return true;
320 : }
321 :
322 0 : bool CFsm::IsValidEvent(unsigned int eventType) const
323 : {
324 0 : EventMap::const_iterator it = m_Events.find(eventType);
325 0 : if (it == m_Events.end())
326 0 : return false;
327 :
328 0 : return true;
329 : }
|