encoding="utf-8" is not supported before Python 3.10.
[0ad.git] / source / network / FSM.cpp
blob5d4c49bd139a15b831e4f7d30199bf5a2de6ab78
1 /* Copyright (C) 2023 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
19 #include "FSM.h"
22 CFsmEvent::CFsmEvent(unsigned int type)
24 m_Type = type;
25 m_Param = nullptr;
28 CFsmEvent::~CFsmEvent()
30 m_Param = nullptr;
33 void CFsmEvent::SetParamRef(void* pParam)
35 m_Param = pParam;
38 CFsmTransition::CFsmTransition(unsigned int state)
40 m_CurrState = state;
43 CFsmTransition::~CFsmTransition()
45 m_Actions.clear();
46 m_Conditions.clear();
49 void CFsmTransition::RegisterAction(void* pAction, void* pContext)
51 CallbackFunction callback;
53 // Add action at the end of actions list
54 callback.pFunction = pAction;
55 callback.pContext = pContext;
57 m_Actions.push_back(callback);
60 void CFsmTransition::RegisterCondition(void* pCondition, void* pContext)
62 CallbackFunction callback;
64 // Add condition at the end of conditions list
65 callback.pFunction = pCondition;
66 callback.pContext = pContext;
68 m_Conditions.push_back(callback);
71 void CFsmTransition::SetEvent(CFsmEvent* pEvent)
73 m_Event = pEvent;
76 void CFsmTransition::SetNextState(unsigned int nextState)
78 m_NextState = nextState;
81 bool CFsmTransition::ApplyConditions() const
83 bool eval = true;
85 CallbackList::const_iterator it = m_Conditions.begin();
86 for (; it != m_Conditions.end(); ++it)
88 if (it->pFunction)
90 // Evaluate condition
91 Condition* condition = reinterpret_cast<Condition*>(it->pFunction);
92 eval &= condition(it->pContext);
96 return eval;
99 bool CFsmTransition::RunActions() const
101 bool result = true;
103 CallbackList::const_iterator it = m_Actions.begin();
104 for (; it != m_Actions.end(); ++it)
106 if (it->pFunction)
108 // Run action
109 Action* action = reinterpret_cast<Action*>(it->pFunction);
110 result &= action(it->pContext, m_Event);
114 return result;
117 CFsm::CFsm()
119 m_Done = false;
120 m_FirstState = FSM_INVALID_STATE;
121 m_CurrState = FSM_INVALID_STATE;
122 m_NextState = FSM_INVALID_STATE;
125 CFsm::~CFsm()
127 Shutdown();
130 void CFsm::Setup()
132 // Does nothing by default
135 void CFsm::Shutdown()
137 // Release transitions
138 TransitionList::iterator itTransition = m_Transitions.begin();
139 for (; itTransition < m_Transitions.end(); ++itTransition)
140 delete *itTransition;
142 // Release events
143 EventMap::iterator itEvent = m_Events.begin();
144 for (; itEvent != m_Events.end(); ++itEvent)
145 delete itEvent->second;
147 m_States.clear();
148 m_Events.clear();
149 m_Transitions.clear();
151 m_Done = false;
152 m_FirstState = FSM_INVALID_STATE;
153 m_CurrState = FSM_INVALID_STATE;
154 m_NextState = FSM_INVALID_STATE;
157 void CFsm::AddState(unsigned int state)
159 m_States.insert(state);
162 CFsmEvent* CFsm::AddEvent(unsigned int eventType)
164 CFsmEvent* pEvent = nullptr;
166 // Lookup event by type
167 EventMap::iterator it = m_Events.find(eventType);
168 if (it != m_Events.end())
170 pEvent = it->second;
172 else
174 pEvent = new CFsmEvent(eventType);
176 // Store new event into internal map
177 m_Events[eventType] = pEvent;
180 return pEvent;
183 CFsmTransition* CFsm::AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState )
185 // Make sure we store the current state
186 AddState(state);
188 // Make sure we store the next state
189 AddState(nextState);
191 // Make sure we store the event
192 CFsmEvent* pEvent = AddEvent(eventType);
193 if (!pEvent)
194 return nullptr;
196 // Create new transition
197 CFsmTransition* pNewTransition = new CFsmTransition(state);
199 // Setup new transition
200 pNewTransition->SetEvent(pEvent);
201 pNewTransition->SetNextState(nextState);
203 // Store new transition
204 m_Transitions.push_back(pNewTransition);
206 return pNewTransition;
209 CFsmTransition* CFsm::AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState,
210 void* pAction, void* pContext)
212 CFsmTransition* pTransition = AddTransition(state, eventType, nextState);
213 if (!pTransition)
214 return nullptr;
216 // If action specified, register it
217 if (pAction)
218 pTransition->RegisterAction(pAction, pContext);
220 return pTransition;
223 CFsmTransition* CFsm::GetTransition(unsigned int state, unsigned int eventType) const
225 if (!IsValidState(state))
226 return nullptr;
228 if (!IsValidEvent(eventType))
229 return nullptr;
231 TransitionList::const_iterator it = m_Transitions.begin();
232 for (; it != m_Transitions.end(); ++it)
234 CFsmTransition* pCurrTransition = *it;
235 if (!pCurrTransition)
236 continue;
238 CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
239 if (!pCurrEvent)
240 continue;
242 // Is it our transition?
243 if (pCurrTransition->GetCurrState() == state && pCurrEvent->GetType() == eventType)
244 return pCurrTransition;
247 // No transition found
248 return nullptr;
251 void CFsm::SetFirstState(unsigned int firstState)
253 m_FirstState = firstState;
256 void CFsm::SetCurrState(unsigned int state)
258 m_CurrState = state;
261 bool CFsm::IsFirstTime() const
263 return (m_CurrState == FSM_INVALID_STATE);
266 bool CFsm::Update(unsigned int eventType, void* pEventParam)
268 if (!IsValidEvent(eventType))
269 return false;
271 if (IsFirstTime())
272 m_CurrState = m_FirstState;
274 // Lookup transition
275 CFsmTransition* pTransition = GetTransition(m_CurrState, eventType);
276 if (!pTransition)
277 return false;
279 // Setup event parameter
280 EventMap::iterator it = m_Events.find(eventType);
281 if (it != m_Events.end())
283 CFsmEvent* pEvent = it->second;
284 if (pEvent)
285 pEvent->SetParamRef(pEventParam);
288 // Valid transition?
289 if (!pTransition->ApplyConditions())
290 return false;
292 // Save the default state transition (actions might call SetNextState
293 // to override this)
294 SetNextState(pTransition->GetNextState());
296 if (!pTransition->RunActions())
297 return false;
299 SetCurrState(GetNextState());
301 // Reset the next state since it's no longer valid
302 SetNextState(FSM_INVALID_STATE);
304 return true;
307 bool CFsm::IsDone() const
309 // By default the internal flag m_Done is tested
310 return m_Done;
313 bool CFsm::IsValidState(unsigned int state) const
315 StateSet::const_iterator it = m_States.find(state);
316 if (it == m_States.end())
317 return false;
319 return true;
322 bool CFsm::IsValidEvent(unsigned int eventType) const
324 EventMap::const_iterator it = m_Events.find(eventType);
325 if (it == m_Events.end())
326 return false;
328 return true;