The whole project

This commit is contained in:
Erris 2025-04-18 21:31:17 +02:00
commit 7a305babb4
6 changed files with 388 additions and 0 deletions

0
README.md Normal file
View File

View 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
View 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
View 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
View 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
View 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