The whole project
This commit is contained in:
commit
7a305babb4
110
include/state-machine_pool.hpp
Normal file
110
include/state-machine_pool.hpp
Normal file
@ -0,0 +1,110 @@
|
||||
#ifndef STATEMACHINE_POOL_HPP
|
||||
#define STATEMACHINE_POOL_HPP
|
||||
|
||||
#include <state_machine.hpp>
|
||||
|
||||
template<typename StateOwnerType>
|
||||
class StateMachinePool {
|
||||
public:
|
||||
void RegisterEntity(const std::string &id, StateOwnerType &entity) {
|
||||
machines[id] = std::make_unique<StateMachine<StateOwnerType>>(entity, factory);
|
||||
}
|
||||
|
||||
void UnregisterEntity(const std::string &id) {
|
||||
machines.erase(id);
|
||||
}
|
||||
|
||||
void UpdateAll() {
|
||||
for (const auto &[id, machine] : machines)
|
||||
machine->Update();
|
||||
}
|
||||
|
||||
void ChangeState(const std::string &id, const std::string &stateId) {
|
||||
auto it = machines.find(id);
|
||||
|
||||
if (it != machines.end())
|
||||
it->second->ChangeState(stateId);
|
||||
}
|
||||
|
||||
void RevertState(const std::string &id) {
|
||||
auto it = machines.find(id);
|
||||
|
||||
if (it != machines.end())
|
||||
it->second->RevertState();
|
||||
}
|
||||
|
||||
void RegisterState(const std::string &id, std::shared_ptr<State<StateOwnerType>> state) {
|
||||
factory.RegisterState(id, state);
|
||||
}
|
||||
|
||||
StateMachine<StateOwnerType> *GetMachine(const std::string &id) {
|
||||
auto it = machines.find(id);
|
||||
|
||||
return it != machines.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
json Serialize() const {
|
||||
json j;
|
||||
|
||||
for (const auto &[id, machine] : machines) {
|
||||
j["machines"][id] = {
|
||||
{"current", machine->GetCurrentStateId()},
|
||||
{"history", machine->GetHistory()}
|
||||
};
|
||||
}
|
||||
|
||||
j["settings"] = {
|
||||
{"auto_transitions", auto_transition ? "true" : "false"},
|
||||
{"strict_transitions", strict_transition ? "true" : "false"}
|
||||
};
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
void Deserialize(const json &j, std::function<StateOwnerType &(const std::string&)> getEntity) {
|
||||
SetStrictTransitions(j.value("strict_transitions", false));
|
||||
SetAutoTransitions(j.value("auto_transitions", false));
|
||||
|
||||
const json &machines_json = j["machines"];
|
||||
|
||||
for (auto it = machines_json.begin(); it != machines_json.end(); ++it) {
|
||||
std::string id = it.key();
|
||||
const json &entry = it.value();
|
||||
|
||||
std::string current = entry.value("current", "null");
|
||||
std::vector<std::string> history = entry.value("history", std::vector<std::string>{});
|
||||
|
||||
StateOwnerType& entity = getEntity(id);
|
||||
RegisterEntity(id, entity);
|
||||
|
||||
auto *machine = GetMachine(id);
|
||||
|
||||
if (machine) {
|
||||
machine->SetHistory(history);
|
||||
machine->SetState(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetStrictTransitions(bool enabled) {
|
||||
strict_transition = enabled;
|
||||
|
||||
for (auto &[_, machine] : machines)
|
||||
machine->SetStrictTransitions(enabled);
|
||||
}
|
||||
|
||||
void SetAutoTransitions(bool enabled) {
|
||||
auto_transition = enabled;
|
||||
|
||||
for (const auto &[_, machine] : machines)
|
||||
machine->SetAutoTransitions(enabled);
|
||||
}
|
||||
|
||||
private:
|
||||
StateFactory<StateOwnerType> factory;
|
||||
std::unordered_map<std::string, std::unique_ptr<StateMachine<StateOwnerType>>> machines;
|
||||
bool auto_transition = false;
|
||||
bool strict_transition = false;
|
||||
};
|
||||
|
||||
#endif // STATEMACHINE_POOL_HPP
|
||||
52
include/state.hpp
Normal file
52
include/state.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef STATE_HPP
|
||||
#define STATE_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
template <typename Type>
|
||||
struct Transition {
|
||||
const std::string target_state;
|
||||
const std::function<bool (const Type&)> condition;
|
||||
};
|
||||
|
||||
template <typename OwnerType>
|
||||
class State {
|
||||
public:
|
||||
virtual ~State() = default;
|
||||
|
||||
virtual void OnEnter(OwnerType &owner) = 0;
|
||||
virtual void OnUpdate(OwnerType &owner) = 0;
|
||||
virtual void OnExit(OwnerType &owner) = 0;
|
||||
|
||||
virtual void AddTransition(const std::string &to,
|
||||
std::function<bool (const OwnerType&)> condition) = 0;
|
||||
virtual std::vector<Transition<OwnerType>> GetTransitions() = 0;
|
||||
|
||||
virtual std::string Id() const = 0;
|
||||
};
|
||||
|
||||
template <typename OwnerType>
|
||||
class AState : public State<OwnerType> {
|
||||
public:
|
||||
AState(const std::string &id) : entity_id(id) {};
|
||||
|
||||
void AddTransition(const std::string &to,
|
||||
std::function<bool (const OwnerType&)> condition) override {
|
||||
transitions.push_back({ to, condition });
|
||||
}
|
||||
std::vector<Transition<OwnerType>> GetTransitions() override {
|
||||
return transitions;
|
||||
}
|
||||
|
||||
std::string Id() const override {
|
||||
return entity_id;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Transition<OwnerType>> transitions;
|
||||
std::string entity_id;
|
||||
};
|
||||
|
||||
#endif // STATE_HPP
|
||||
33
include/state_factory.hpp
Normal file
33
include/state_factory.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef STATE_FACTORY_HPP
|
||||
#define STATE_FACTORY_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <state.hpp>
|
||||
|
||||
|
||||
template <typename OwnerType>
|
||||
class StateFactory {
|
||||
using SharedState = std::shared_ptr<State<OwnerType>>;
|
||||
|
||||
public:
|
||||
void RegisterState(const std::string &id, SharedState state) {
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
states[id] = std::move(state);
|
||||
}
|
||||
|
||||
SharedState Get(const std::string &id) const {
|
||||
auto it = states.find(id);
|
||||
return it != states.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, SharedState> All() const {
|
||||
return states;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, SharedState> states;
|
||||
};
|
||||
|
||||
#endif // STATE_FACTORY_HPP
|
||||
123
include/state_machine.hpp
Normal file
123
include/state_machine.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef STATE_MACHINE_HPP
|
||||
#define STATE_MACHINE_HPP
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <vector>
|
||||
#include <state_factory.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
template<typename T>
|
||||
class StateMachine {
|
||||
using SharedState = std::shared_ptr<State<T>>;
|
||||
|
||||
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
|
||||
70
include/state_system.hpp
Normal file
70
include/state_system.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef STATE_SYSTEM_HPP
|
||||
#define STATE_SYSTEM_HPP
|
||||
|
||||
#include <state_machine.hpp>
|
||||
#include <state-machine_pool.hpp>
|
||||
|
||||
class StateSystem {
|
||||
public:
|
||||
template <typename T>
|
||||
void RegisterEntity(const std::string &id, T &object) {
|
||||
GetPool<T>().RegisterEntity(id, object);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UnregisterEntity(const std::string &id) {
|
||||
GetPool<T>().UnregisterEntity(id);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UpdateAll() {
|
||||
GetPool<T>().UpdateAll();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ChangeState(const std::string &id, const std::string &stateId) {
|
||||
GetPool<T>().ChangeState(id, stateId);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RevertState(const std::string &id) {
|
||||
GetPool<T>().RevertState(id);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RegisterState(const std::string &id, std::shared_ptr<State<T>> state) {
|
||||
if (state)
|
||||
GetPool<T>().RegisterState(id, std::move(state));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
json Serialize() const {
|
||||
StateMachinePool<T> &pool = GetPool<T>();
|
||||
return pool.Serialize();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Deserialize(const json& j, std::function<T &(const std::string&)> getEntity) {
|
||||
GetPool<T>().Deserialize(j, getEntity);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SetStrictTransitions(bool enabled) {
|
||||
GetPool<T>().SetStrictTransitions(enabled);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SetAutoTransitions(bool enabled) {
|
||||
GetPool<T>().SetAutoTransitions(enabled);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
StateMachinePool<T> &GetPool() const {
|
||||
static StateMachinePool<T> pool;
|
||||
return pool;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // STATE_SYSTEM_HPP
|
||||
Loading…
x
Reference in New Issue
Block a user