Changeset View
Standalone View
source/network/Fsm.cpp
- This file was added.
/* Copyright (C) 2017 Wildfire Games. | |||||
* This file is part of 0 A.D. | |||||
* | |||||
* 0 A.D. is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* 0 A.D. is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "precompiled.h" | |||||
#include "Fsm.h" | |||||
CFsmEvent::CFsmEvent(u32 type, const CNetMessageBuffer* buffer) : | |||||
m_Buffer(buffer), | |||||
leper: At least some of the codebase has `\n\t: m_Foo(bar)`. | |||||
Not Done Inline ActionsIt is the questions which we prefer: looking in some of the simulation2 and the network files, there is no break before the :. echotangoecho: It is the questions which we prefer: looking in some of the simulation2 and the network files… | |||||
Not Done Inline ActionsI somewhat dislike having that thing trailing at the end of a long line like that, but if you prefer this, fine by me. leper: I somewhat dislike having that thing trailing at the end of a long line like that, but if you… | |||||
m_Type(type) | |||||
{ | |||||
} | |||||
u32 CFsmEvent::GetType() const | |||||
{ | |||||
return m_Type; | |||||
} | |||||
const CNetMessageBuffer& CFsmEvent::GetMessageBuffer() const | |||||
{ | |||||
ENSURE(m_Buffer); | |||||
return *m_Buffer; | |||||
} | |||||
void CFsmEvent::SetMessage(const CNetMessageBuffer& buffer) | |||||
{ | |||||
m_Buffer = &buffer; | |||||
} | |||||
Done Inline ActionsI do hope that we do take quite some care (as in fail-safe or rather fail-early-and-loud checks) that the lifetime of that buffer actually is longer than that of the event. leper: I do hope that we do take quite some care (as in fail-safe or rather fail-early-and-loud… | |||||
Not Done Inline ActionsThe buffer is only used from inside the update function where it is used to execute all handlers, and they probably shouldn't depend on the buffer living any longer than for the execution of the function. echotangoecho: The buffer is only used from inside the update function where it is used to execute all… | |||||
Done Inline ActionsActually this whole implementation is that short (and mostly trivial) that it could just be done in the header, but I guess that is just personal preference. leper: Actually this whole implementation is that short (and mostly trivial) that it could just be… | |||||
CFsmTransition::CFsmTransition(u32 state, u32 eventType, u32 nextState, StoredAction action) : | |||||
m_CurrState(state), | |||||
m_EventType(eventType), | |||||
m_NextState(nextState), | |||||
m_Action(action) | |||||
{ | |||||
} | |||||
u32 CFsmTransition::GetCurrState() const | |||||
{ | |||||
return m_CurrState; | |||||
} | |||||
u32 CFsmTransition::GetEventType() const | |||||
{ | |||||
return m_EventType; | |||||
} | |||||
u32 CFsmTransition::GetNextState() const | |||||
{ | |||||
return m_NextState; | |||||
} | |||||
Done Inline ActionsThese sound just like header defs, but well. leper: These sound just like header defs, but well. | |||||
Done Inline ActionsThat was what that one emplace_back comment below referred to IIRC. leper: That was what that one `emplace_back` comment below referred to IIRC. | |||||
bool CFsmTransition::RunAction(CFsmEvent* event) const | |||||
{ | |||||
bool result = true; | |||||
if (m_Action.m_Function) | |||||
result &= m_Action.m_Function(m_Action.m_Context, event); | |||||
Done Inline ActionsUnless we expect this to handle multiple actions (which would make me question the function name), why not just result = ...? Or even return !m_Action.m_Function || m_Action.m_Function(...)? (The latter might be golfing, but the &= seems pointless. leper: Unless we expect this to handle multiple actions (which would make me question the function… | |||||
return result; | |||||
} | |||||
CFsm::CFsm(u32 firstState) : | |||||
m_FirstState(firstState), | |||||
m_CurrState(firstState), | |||||
m_NextState(INVALID_STATE) | |||||
{ | |||||
} | |||||
void CFsm::AddTransition(u32 state, u32 eventType, u32 nextState) | |||||
{ | |||||
AddState(state); | |||||
AddEvent(eventType); | |||||
AddState(nextState); | |||||
m_Transitions.push_back(CFsmTransition(state, eventType, nextState, StoredAction{nullptr, nullptr})); | |||||
} | |||||
Done Inline ActionsCould use emplace, given that we are really just calling the ctor and passing that to push_back. leper: Could use emplace, given that we are really just calling the ctor and passing that to push_back. | |||||
void CFsm::AddTransition(u32 state, u32 eventType, u32 nextState, Action action, void* context ) | |||||
{ | |||||
AddState(state); | |||||
AddEvent(eventType); | |||||
AddState(nextState); | |||||
m_Transitions.push_back(CFsmTransition(state, eventType, nextState, StoredAction{action, context})); | |||||
} | |||||
void CFsm::SetCurrState(u32 state) | |||||
{ | |||||
m_CurrState = state; | |||||
} | |||||
u32 CFsm::GetCurrState() const | |||||
{ | |||||
return m_CurrState; | |||||
} | |||||
void CFsm::SetNextState(u32 nextState) | |||||
{ | |||||
m_NextState = nextState; | |||||
} | |||||
Done Inline ActionsGuess what ;-) leper: Guess what ;-) | |||||
bool CFsm::Update(u32 type, const CNetMessageBuffer* message) | |||||
{ | |||||
const CFsmTransition* transition = GetTransition(m_CurrState, type); | |||||
if (!transition) | |||||
return false; | |||||
// Save the default state transition (actions might call SetNextState to override this) | |||||
SetNextState(transition->GetNextState()); | |||||
CFsmEvent event(type, message); | |||||
if (!transition->RunAction(&event)) | |||||
return false; | |||||
m_CurrState = m_NextState; | |||||
SetNextState(INVALID_STATE); | |||||
return true; | |||||
} | |||||
const CFsmTransition* CFsm::GetTransition(u32 state, u32 eventType) const | |||||
{ | |||||
if (!IsValidState(state) || !IsValidEvent(eventType)) | |||||
return nullptr; | |||||
TransitionList::const_iterator it = std::find_if(m_Transitions.begin(), m_Transitions.end(), [state, eventType](const CFsmTransition& transition) { | |||||
return transition.GetCurrState() == state && transition.GetEventType() == eventType; | |||||
}); | |||||
if (it == m_Transitions.end()) | |||||
return nullptr; | |||||
return &(*it); | |||||
} | |||||
void CFsm::AddState(u32 state) | |||||
{ | |||||
m_States.insert(state); | |||||
} | |||||
void CFsm::AddEvent(u32 eventType) | |||||
{ | |||||
m_Events.insert(eventType); | |||||
} | |||||
bool CFsm::IsValidState(u32 state) const | |||||
{ | |||||
return m_States.find(state) != m_States.end(); | |||||
} | |||||
bool CFsm::IsValidEvent(u32 eventType) const | |||||
{ | |||||
return m_Events.find(eventType) != m_Events.end(); | |||||
} | |||||
Done Inline ActionsYeah, well. leper: Yeah, well. |
At least some of the codebase has \n\t: m_Foo(bar).