LCOV - code coverage report
Current view: top level - source/network - FSM.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 161 0.0 %
Date: 2023-01-19 00:18:29 Functions: 0 28 0.0 %

          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             : }

Generated by: LCOV version 1.13