Erris-State-System/include/state_machine.hpp

124 lines
3.3 KiB
C++

#ifndef STATE_MACHINE_HPP
#define STATE_MACHINE_HPP
#include <string>
#include <memory>
#include <vector>
#include <nlohmann/json.hpp>
#include "state_factory.hpp"
using json = nlohmann::json;
template<typename T>
class StateMachine {
public:
StateMachine(T &owner, const StateFactory<T> &factory) : owner(owner), factory(factory) {};
void ChangeState(const std::string &id) {
auto new_state = factory.Get(id);
if (!new_state)
return;
if (strict_transition && current_state) {
bool allowed = false;
for (const auto &transition : current_state->GetTransitions()) {
if (transition.target_state == id &&
(!transition.condition || transition.condition(owner))) {
allowed = true;
break;
}
}
if (!allowed)
return;
}
if (current_state) {
current_state->OnExit(owner);
history.push_back(current_state->Id());
}
current_state = std::move(new_state);
current_state->OnEnter(owner);
};
void SetState(const std::string &id) {
auto new_state = factory.Get(id);
if (!new_state)
return;
if (current_state)
current_state->OnExit(owner);
current_state = std::move(new_state);
current_state->OnEnter(owner);
}
void RevertState() {
if (history.empty())
return;
std::string last = history.back();
history.pop_back();
ChangeState(last);
}
void Update() {
if (!current_state)
return;
for (const auto &transition : current_state->GetTransitions())
if (auto_transition && transition.condition(owner)) {
ChangeState(transition.target_state);
return;
}
current_state->OnUpdate(owner);
}
const std::vector<std::string> &GetHistory() const {
return history;
}
void SetHistory(const std::vector<std::string> history) {
this->history = history;
}
void ReplayHistory() {
for (const std::string &stateId : history)
ChangeState(stateId);
}
const std::string GetCurrentStateId() const {
static const std::string nullState = "null";
return current_state ? current_state->Id() : nullState;
}
void SetStrictTransitions(bool enabled) {
this->strict_transition = enabled;
}
bool GetStrictTransitions() const {
return strict_transition;
}
void SetAutoTransitions(bool enabled) {
this->auto_transition = enabled;
}
bool GetAutoTransitions() const {
return auto_transition;
}
private:
T &owner;
const StateFactory<T> &factory;
std::shared_ptr<State<T>> current_state;
bool strict_transition = false;
bool auto_transition = false;
std::vector<std::string> history;
};
#endif // STATE_MACHINE_HPP