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) | |||||
{ | |||||
} | |||||
CFsmTransition::CFsmTransition(u32 state, u32 eventType, u32 nextState, StoredAction action) : | |||||
m_CurrState(state), | |||||
m_EventType(eventType), | |||||
m_NextState(nextState), | |||||
m_Action(action) | |||||
{ | |||||
} | |||||
bool CFsmTransition::RunAction(const CFsmEvent* event) const | |||||
{ | |||||
if (m_Action.m_Function) | |||||
return m_Action.m_Function(m_Action.m_Context, *event); | |||||
return true; | |||||
} | |||||
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… | |||||
CFsm::CFsm(u32 firstState) : | |||||
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… | |||||
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.emplace_back(state, eventType, nextState, StoredAction{nullptr, nullptr}); | |||||
} | |||||
void CFsm::AddTransition(u32 state, u32 eventType, u32 nextState, Action action, void* context ) | |||||
{ | |||||
AddState(state); | |||||
AddEvent(eventType); | |||||
AddState(nextState); | |||||
m_Transitions.emplace_back(state, eventType, nextState, StoredAction{action, context}); | |||||
} | |||||
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 CFsm::Update(u32 type, const CNetMessageBuffer* message) | |||||
{ | |||||
const CFsmTransition* transition = GetTransition(m_CurrState, type); | |||||
if (!transition) | |||||
return false; | |||||
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… | |||||
// 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; | |||||
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. | |||||
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); | |||||
} | |||||
Done Inline ActionsGuess what ;-) leper: Guess what ;-) | |||||
Done Inline ActionsYeah, well. leper: Yeah, well. |
At least some of the codebase has \n\t: m_Foo(bar).