Giter Site home page Giter Site logo

andrew-gresyk / hfsm2 Goto Github PK

View Code? Open in Web Editor NEW
436.0 15.0 56.0 2.31 MB

High-Performance Hierarchical Finite State Machine Framework

Home Page: https://hfsm.dev

License: MIT License

CMake 0.25% C++ 99.20% Python 0.11% SCSS 0.02% Batchfile 0.01% Lua 0.42%
hfsm fsm fsm-library state-machine cpp cpp11 modern-cpp template-metaprogramming header-only mit-license

hfsm2's Introduction

License: MIT GitHub Release Date
CII Best Practices
GCC, Clang ARM GCC MS VS
Gitter Discord Twitter Follow


HFSM2

High-Performance Hierarchical Finite State Machine

Header-only heriarchical FSM framework in C++11, with fully statically-defined structure (no dynamic allocations), built with variadic templates.


Compiler Support

  • Visual Studio: 2015, 2017, 2019, 2022
  • GCC: 5, 6, 7, 8, 9, 10, 11, 12
  • ARM GCC: 9
  • Clang: 3.9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
  • AppleClang: 12, 13, 13

(Currently CI-tested toolchains in bold)


Quick Start


See Also


Documentation


Feature Highlights

  • Permissive MIT License
  • Written in widely-supported modern(ish) C++11
  • Header-only
  • Convenient, minimal boilerplate
  • Fully static, no dynamic allocations
  • Uses inline-friendly compile-time polymorphism, no virtual methods are used
  • Type-safe transitions: FSM.changeTo<TargetState>() with optional payloads
  • Flexible configuration using HFSM2_ENABLE_* macros
  • Scalable, supports robust state re-use via state injections
  • Hierarchical, with a selection of composite (sub-machine) and orthogonal regions
  • Gamedev-friendly, supports explicit State::update()
  • Also supports traditional event-based workflow with State::react()
  • Inspect anything: previous and current transitions, state activation status, and more!
  • Game AI-friendly with dynamic planning support
  • Utility theory support (max score and ranked weighted random)
  • Serializable, with activity and transition history support
  • Debug-assisted, includes automatic structure and activity visualization API with #define HFSM_ENABLE_STRUCTURE_REPORT
  • Built-in logging support

3rd Party Libraries

  • doctest unit testing framework
  • XoShiRo pseuto-random number generators

Get In Touch


Special Thanks

hfsm2's People

Contributors

alexandrosk0 avatar andrew-gresyk avatar dependabot[bot] avatar dibsonmuad avatar donmathi avatar lbakman avatar mrcmry avatar schoppenglas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hfsm2's Issues

Warning: extra ';' [-Wpedantic]

Hi Andrew

Since I have changed to c++17 I get a warning: extra ';' [-Wpedantic], on several line in the machine.hpp code:
Example:

line 215:  HFSM_IF_DEBUG(struct None{});
                                       ^
line 1097: HFSM_IF_ASERT(void verifyStructure(const Index occupied = INVALID) const);
                                                                                    ^

I simply declare

_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
#include <hfsm2/machine.hpp>
_Pragma("GCC diagnostic pop")

to remove the warnings

Hitting the CAPACITY roof

Hi Andrew

Next quest for you. My state machine has become so large that it complains about (line 1013)
static_assert(UNIT+(WIDTH+7)/(sizeof(Unit)*8)<=CAPACITY,"");

How do I change the CAPACITY limit?

Any example about "Hierarchical" ?

  1. Is there any example about how to show a multi-layered fsm (layer number >= 3) ?
  2. Any thread-safe feature with the newest version 2.5.0?

Orthogonal Regions with Composite

Hi Andrew

I'm having some problems with creating orthogonal regions with composite parts.
I have something like this:

struct SomeEvent{};
HFSM=Machine::Root<A,
    B,
    Machine::Orthogonal<C,
        Machine::Composite<D,
            E,F,G,Machine::Composite<H,I,J>
        >,
        Machine::Composite<K,
            L,
            Machine::Composite<M,N,O>,
            Machine::Composite<P,Q,R>,
            Machine::Composite<S,T,U>,
            V
        >
    >,
    W
>;

The structure compiles fine, but when I add changeTo to state E, then it complains

state E : HFSM::State
{
    void react(const SomeEvent&, FullControl& control)
    {
        control.changeTo<F>();
    }
    using HFSM::State::react;
}

Macro conflict between sys/ioctl.h and hfsm2/machine.hpp

I discovered today that there appears to be a conflict between HFSM2 and the Linux libc sys/ioctl.h header that causes a bizarre cascade of template errors and syntax errors.

The conflict occurs when including sys/ioctl.h before hfsm2/machine.hpp, due to HFSM2's use of the symbol NCC in various template arguments in machine.hpp:
https://github.com/andrew-gresyk/HFSM2/blob/master/include/hfsm2/machine.hpp#L3562

NCC is defined as an integer literal in <bits/ioctl-types.h> which gets included by <sys/ioctl.h>:
https://github.com/raspberrypi/tools/blob/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/usr/include/arm-linux-gnueabihf/bits/ioctl-types.h#L36

After renaming NCC to _NCC in HFSM2, I can confirm that the errors are resolved.

It's a bit unfortunate that the ioctl.h header causes this macro pollution. I'm not sure if there is any better fix than renaming the template argument in HFSM2 or maybe #undef'ing the symbol...

Conflict with ioctl-types.h

Hi Andrew

I found a conflict between your hfsm2.hpp file and ioctl-types.h file
The ioctl-types.h file defines a value for NCC to be 8, and this course your file to make compile errors.
Could you rename your NCC template variable?

#define NCC 8
struct termio
  {
    unsigned short int c_iflag;		/* input mode flags */
    unsigned short int c_oflag;		/* output mode flags */
    unsigned short int c_cflag;		/* control mode flags */
    unsigned short int c_lflag;		/* local mode flags */
    unsigned char c_line;		/* line discipline */
    unsigned char c_cc[NCC];		/* control characters */
};

HFSM2 as parameter in function?

Hi Andrew

Thanks for your help last time.
Here comes my next question.
Is it possible to give a hfsm as an parameter in a function?
Could be as a pointer, a reference (or something else, if that is the way to go).

Best regards
Kjeld

The logger can freeze due to unknown methods

The following snippet is missing CONSTRUCT and DESTRUCT. In which case it returns nullptr. Yet, these functions seem to be called when we implement enter and exit functions.

methodName(const Method method) {
switch (method) {
case Method::RANK: return "rank";
case Method::UTILITY: return "utility";
case Method::ENTRY_GUARD: return "entryGuard";
case Method::ENTER: return "enter";
case Method::REENTER: return "reenter";
case Method::UPDATE: return "update";
case Method::REACT: return "react";
case Method::EXIT_GUARD: return "exitGuard";
case Method::EXIT: return "exit";
case Method::PLAN_SUCCEEDED: return "planSucceeded";
case Method::PLAN_FAILED: return "planFailed";
default:
HFSM_BREAK();
return nullptr;
}
}

This causes the proposed "recordMethod" logger to be stuck:

  void recordMethod(Context& /*context*/, const StateID origin, const Method method) override {
    std::cout << stateName(origin) << "::" << hfsm2::methodName(method) << "()" << std::endl;
  }

Adding the two fixes the freeze and we have the following output:

Idle -> DoAction
DoAction::contruct()
DoAction::enter()
HeadState::update()
HeadState -> Idle
DoAction::update()
DoAction -> Idle
DoAction::exit()
DoAction::destruct()
HeadState::update()

This function should not return nullptr but instead '\0' or unknownMethod to prevent unsafe operations.

Looped plan

Hi, I want to create state machine with looped plan. I took Wiki.Plans.Traffic Light test as a starting point and added

fsm.update();
REQUIRE(fsm.isActive<Yellow>());

at the end. After update state machine is still in Red state. Is this a bug or I have to somehow "restart" the plan?

Broken links in doc

The minimal example and extended tutorial links on the webpage are broken

Can't get Context from Control in Utility function

I have tried to get a variable from the current Context to modify the Utility function. this doesn't seem to work for me. leaving the Control signature const results in the following error in intellisense:

C++ the object has type qualifiers that are not compatible with the member function object type is: const hfsm2::detail::ControlT<hfsm2::detail::ArgsT<Context, hfsm2::detail::G_<(hfsm2::FeatureTag)'\001', Context, int8_t, float, hfsm2::RandomT<float>, (hfsm2::Long)4U, void>, hfsm2::detail::Merge<hfsm2::detail::ITL_<void>, hfsm2::detail::Merge<hfsm2::detail::Merge<hfsm2::detail::ITL_<Red>, hfsm2::detail::Merge<hfsm2::detail::ITL_<Yellow>, hfsm2::detail::ITL_<Green>>>, hfsm2::detail::ITL_<Off>>>, hfsm2::detail::Merge<hfsm2::detail::ITL_<void>, hfsm2::detail::Merge<hfsm2::detail::ITL_<Red>, hfsm2::detail::Merge<hfsm2::detail::ITL_<>, hfsm2::detail::ITL_<>>>>, (hfsm2::Long)2U, (hfsm2::Long)0U, (hfsm2::Long)0U, (hfsm2::Long)6U, (hfsm2::Long)4U, void>>

Removing the cosnt gets rid of the error, but causes compilation to fail.

I made a minimal example to test the error, and it still seems to happen.

#define HFSM2_ENABLE_UTILITY_THEORY
#include <hfsm2/machine.hpp>
#include <iostream>

struct Context {
	uint8_t cycleCount = 0;
};

using M = hfsm2::MachineT<hfsm2::Config::ContextT<Context>>;

#define S(s) struct s
using FSM = M::PeerRoot<
	M::Utilitarian<S(Red),
	S(Yellow),
	S(Green)
	>,
	S(Off)
>;
#undef S

struct On
	: FSM::State {
	void enter(Control& control) {
		control.context().cycleCount = 0;
		std::cout << "On" << std::endl;
	}};

struct Red
	: FSM::State {
	void enter(Control& control) {
		++control.context().cycleCount;
		std::cout << "  Red" << std::endl;
	}

	void update(FullControl& control) {
		if (control.context().cycleCount > 3)
			control.changeTo<Off>();
		else
			control.changeTo<Green>();
	}};

struct Yellow
	: FSM::State {
	void enter(Control&) { std::cout << "    Yellow ^" << std::endl; }
	void update(FullControl& control) { control.changeTo<Red>(); }
	///
	Utility utility(const Control& control) { return 0.5f + control.context().cycleCount; }
	///
};

struct Green
	: FSM::State {
	void enter(Control&) { std::cout << "      Green" << std::endl; }
	void update(FullControl& control) { control.changeTo<Yellow>(); }
};

struct Off
	: FSM::State {
	void enter(Control&) { std::cout << "Off" << std::endl; }
};

int main() {
	Context context;
	FSM::Instance machine{ context };

	while (machine.isActive<Off>() == false)
		machine.update();

	return 0;
}

Multiple copies of same HFSM2 machine

Hi Andrew

Do you have some examples on how to make mulitple copies of the same HFSM2 machine?
Creating an object containing an HFSM2, and the creating multiple instances of that obejct

Best regards
Kjeld

State members?

This might be a dumb question, but when a state function is called (enter(), update(), etc), is it an instance, with viable member data, or must I call Instance::access() to get access to the current state?

I thought at first that it is an instance, but reading through the source of machine.hpp, it calls Head::enter(), where Head is a type, so I don't see any instance being passed through.

By the way, I love this library. I looked at the Boost state machine documentation, and couldn't make heads or tails of it reading over for an hour, while I was able to go from zero to skeleton with HFSM2 in less than that time.

For others, I'm using this in an embedded system (RPi Pico, hierarchical states) and it compiles down to a nice size. I've thus far just tested it in a simulated environment with FreeRTOS (POSIX target), while I work out the rest of the development, but always also compile for my target system as well.

Using in embedded systems

I'd like use HFSM2 in firmware for stm32, compiler is GNU ARM Embedded Toolchain (gcc 10.2 or 9.3.1). The problem is that both RTOSes and bare metal usually don't support stdlib and POSIX. Can I use the library as it is or some efforts to port are needed?

Compile error in B_<TFirst>::stateId()

The following, in clang

MyState : FSM::State
{
	void update(FullControl& control)
	{
		hfsm2::StateID OtherStateID = stateId<MyOtherState>();

		// do some stuff
	}
}

Gives this error (in machine.hpp~4395):

error : template name refers to non-type template 'index'
1>          static constexpr StateID  stateId()                             { return                        typename TFirst::StateList ::template index<T>();       }

I believe the compiler is treating the typename keyword as though it applies to the whole function call expression (TFirst::StateList:: template index<T>()) instead of just TFirst::StateList.

I tried to disambiguate this inline by finding the right incantation of typename/template keywords, but it proved beyond my capabilities.

This fixed the error:

	using StateList = typename TFirst::StateList;

	template <typename T>
	static constexpr StateID  stateId()				{ return			StateList ::template index<T>();	}

Reacting to events deeply

Hi, I have a scenario where I am transitioning into a state (FHaveTarget) because of a parent state's react() function. In FHaveTarget::entryGuard(), I want to set the initial substate of FHaveTarget based on the parameters from that event.

Is there a way for the parent to pass those parameters into the entryGuard() of the state? Here follows the simplest version of this I've got.

The two ways I can think around this are to add parameters to a shared context object, or to flatten the hierarchy, neither of which are satisfactory.

How should I do this in HFSM2?

using M = hfsm2::Machine
using FSM =
	M::Root
	<
		struct FRoot,
		struct FNoTarget,
		M::Composite
		<
			struct FHaveTarget,
			struct FTargetInRange,
			struct FTargetOutOfRange
		>
	>;

struct FUpdateTargetEvent
{
	AActor* Target;
	bool    bTargetOutOfRange;
};

struct FRoot : FSM::State
{
	void react(FUpdateTargetEvent const& Event, FullControl& Control)
	{
		if (Event.Target)
		{
			Control.changeTo<FHaveTarget>();
		}
		else
		{
			Control.changeTo<FNoTarget>();
		}
	}
};

struct FNoTarget : FSM::State
{
};

struct FHaveTarget : FSM::State
{
	void entryGuard(FullControl& control)
	{
		// HERE is where I don't have the data I want: Event
		if (Event.bTargetOutOfRange)
		{
			Control.changeTo<FTargetOutOfRange>();
		}
		else
		{
			Control.changeTo<FTargetInRange>();
		}
	}

	void enter(Control& control) { /* set FireTarget (somehow) and set some state on it */ }
	void exit(Control& control)  { /* unset that state */ }

private:
	AActor* FireTarget = nullptr;
};

struct FTargetInRange : FSM::State
{
	void enter(Control& control) { /* set some additional state on target */ }
	void exit(Control& control) { /* unset that state */ }
};

struct FTargetOutOfRange : FSM::State
{
};

Examples for HFSM2

Thank you for this promising contribution, @andrew-gresyk! I like very much little header-only gems like this library! :-D

I am a absolute newbie in Hierarchical Finite State Machines. :-) My interests are robotics and games too.

However i am interested in knowing more about it. I would like to familiarize myself with some kind of (graphical?) representation of HFSM. Any suggestion? Any recommended reading?

I miss a series of examples that serve to show/explain the library and, incidentally, to test it. :-)

Cheers!

DJuego

Trouble with HFSM2 master version in MSVC2019 16.6.5

When i try to compile the next code (https://doc.hfsm.dev/quick-tutorial):

#include <HFSM2/include/hfsm2/machine.hpp>

struct Context {
    bool powerOn;
};

using M = hfsm2::MachineT<Context>;
//using M = hfsm2::MachineT<hfsm2::Config::ContextT<Context>>;
#define S(s) struct s

using FSM = M::PeerRoot<
    S(Off),                                // initial top-level state
    M::Composite<S(On),                    // sub-machine region with a head state (On) and and 3 sub-states
    S(Red),                            // initial sub-state of the region
    S(Yellow),
    S(Green)
    >,
    S(Done)
>;

#undef S

struct Event {};

struct Off
    : FSM::State
{
    void entryGuard(FullControl& control) {            // called before state activation, use to re-route transitions
        if (control.context().powerOn)                 // access shared data
            control.changeTo<On>();                    // initiate a transition into 'On' region
    }
};

struct On
    : FSM::State
{
    void enter(PlanControl& control) {                 // called on state activation
        auto plan = control.plan();                    // access the plan for the region

        plan.append<Red, Yellow>();                    // sequence plan steps, executed when the previous state succeeds
        plan.append<Yellow, Green>();
        plan.append<Green, Yellow>();
        plan.append<Yellow, Red>();
    }

    void exit(PlanControl& /*control*/) {}             // called on state deactivation

    void planSucceeded(FullControl& control) {         // called on the successful completion of all plan steps
        control.changeTo<Done>();
    }

    void planFailed(FullControl& /*control*/) {}       // called if any of the plan steps fails
};

struct Red
    : FSM::State
{
    void update(FullControl& control) {                // called on periodic state machine updates
        control.succeed();                             // notify successful completion of the plan step
    }                                                  // plan will advance to the 'Yellow' state
};

struct Yellow
    : FSM::State
{
    void update(FullControl& control) {
        control.succeed();                             // plan will advance to the 'Green' state on the first entry
                                                       // and 'Red' state on the second one
    }
};

struct Green
    : FSM::State
{
    void react(const Event&, FullControl& control) {   // called on external events
        control.succeed();                             // advance to the next plan step
    }
};

struct Done
    : FSM::State
{};


int main() {

    Context context;
    context.powerOn = true;

    FSM fsm{ context };
    assert(fsm.isActive<On>());                        // activated by Off::entryGuard()
    assert(fsm.isActive<Red>());                       // On's initial sub-state


    fsm.update();
    assert(fsm.isActive<Yellow>());                    // 1st setp of On's plan

    fsm.update();
    assert(fsm.isActive<Green>());                     // 2nd setp of On's plan

    fsm.react(Event{});
    assert(fsm.isActive<Yellow>());                    // 3rd setp of On's plan

    fsm.update();
    assert(fsm.isActive<Red>());                       // 4th setp of On's plan

    fsm.update();
    assert(fsm.isActive<Done>());                      // activated by On::planSucceeded()

    return 0;
}

I get:

1>------ Build started: Project: prueba_hfsm2_msvc2019, Configuration: Debug x64 ------
1>main.cpp
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11821,16): error C2027: use of undefined type 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11248): message : see declaration of 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11821,1): error C2061: syntax error: identifier 'PeerRoot'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11823,8): error C2027: use of undefined type 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11248): message : see declaration of 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11827,5): error C2059: syntax error: '>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11837,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11837,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11838,32): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11839,13): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11840,13): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11840,30): error C2065: 'On': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11840,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11846,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11846,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11847,27): error C2061: syntax error: identifier 'PlanControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11856,26): error C2061: syntax error: identifier 'PlanControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11858,35): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11862,32): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11848,21): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11850,1): error C3536: 'plan': cannot be used before it is initialized
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11850,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11851,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11852,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11853,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11859,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11859,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11867,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11867,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11868,28): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11869,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11875,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11875,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11876,28): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11877,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11884,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11884,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11885,41): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11886,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11892,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11892,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11900,5): error C2065: 'FSM': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11900,9): error C2146: syntax error: missing ';' before identifier 'fsm'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11900,9): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11901,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11901,29): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11902,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11902,30): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11905,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11906,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11906,33): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11908,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11909,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11909,32): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11911,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11912,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11912,33): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11914,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11915,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11915,30): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11917,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11918,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11918,31): error C2059: syntax error: ')'
1>Done building project "prueba_hfsm2_msvc2019.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

DJuego

Retract

Thank you for your brilliant work.
Your "react" pattern works by calling every active state from the outside and in.
Could you also add a "retract" pattern, that would be call the way back?
I had some issue, where I had to have the inner react have higher priority than some further out,
So therefor I ask for the update.

Fetching payload contents

Hi!
I'm looking to leverage payloads for "messaging" on state switch - both documentation and tests exist for payloads but they don't describe how to actually fetch them.

This was my attempt:

void StateActivating::enter(PlanControl& aControl)
{
    auto currentRequest = aControl.requests().begin();

    if (currentRequest != aControl.requests().end() && currentRequest->payloadSet)
    {
        const auto& stateChangePayload = currentRequest->payload();
	// intended entry processing
    }
    else
    {
        // failsafe entry processing
    }
}

However currentRequest != aControl.requests().end() always evaluates to false, curiously enough payloadSet is true.

Test code that invokes entry looks like this:
fsmInstance.immediateChangeWith<StateActivating>(entryPayload);

Perhaps immediateChangeWith immediately clears the request? If so, how to retrieve the payload then?

Usage within ecs systems like entt

Thank you very much for the library, it is one of the most robust libraries I found in Github. I am thinking of employing it within entt ecs framework. Do you have any recommendations or experience? Do I store FSM::Instance (FSM is M::Root or M::PeerRoot) as a component in the ecs system? Is the size of the FSM::Instance always constant regardless of the state selected if the plan did not change (ie it has the size of the largest state?)

Thanks

State machine stuck in update method

Hi, I have issue with state machine below. It's stuck in last update method, program never stops. If I uncomment call to update before Disable event, everything works as expected. I'm not sure if I'm using the library incorrectly or if it's a bug.

#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

#define HFSM2_ENABLE_PLANS
#include <hfsm2/machine.hpp>

using M = hfsm2::Machine;

using FSM = M::PeerRoot<struct Disabled,
                M::Composite<struct Enabled,
                    M::Composite<struct Active,
                        struct A,
                        struct B,
                        struct C,
                        struct D
                    >,
                    struct Idle
                >
            >;

// Events
struct Enable {};
struct Disable {};

struct Disabled : FSM::State
{
    void update(FullControl& control) noexcept
    {
        control.changeTo<Enabled>();
    }

    void react(const Enable&, FullControl& control) noexcept
    {
        control.changeTo<Enabled>();
    }

    using FSM::State::react;
};

struct Enabled : FSM::State
{
    void react(const Disable&, FullControl& control) noexcept
    {
        control.changeTo<Disabled>();
    }

    using FSM::State::react;
};

struct Active : FSM::State
{
    void planSucceeded(FullControl& control)
    {
        control.changeTo<Idle>();
    }
};

struct Idle : FSM::State
{
    void update(FullControl& control) noexcept
    {
        control.changeTo<Active>();
    }
};

struct A : FSM::State
{
    void enter(PlanControl& control) noexcept
    {
        auto plan = control.plan();

        plan.change<A, B>();
        plan.change<B, C>();
        plan.change<C, D>();
    }

    void update(FullControl& control) noexcept { control.succeed(); }
};

struct B : FSM::State
{
    void update(FullControl& control) noexcept { control.succeed(); }
};

struct C : FSM::State
{
    void update(FullControl& control) noexcept { control.succeed(); }
};

struct D : FSM::State
{
    void update(FullControl& control) noexcept { control.succeed(); }
};

TEST_CASE("test")
{
    FSM::Instance fsm;

    REQUIRE(fsm.isActive<Disabled>());

    fsm.update();
    REQUIRE(fsm.isActive<Enabled>());
    REQUIRE(fsm.isActive<Active>());
    REQUIRE(fsm.isActive<A>());

    fsm.update();
    REQUIRE(fsm.isActive<B>());

    fsm.update();
    REQUIRE(fsm.isActive<C>());

    fsm.update();
    REQUIRE(fsm.isActive<D>());

    fsm.update();
    REQUIRE(fsm.isActive<Idle>());

    fsm.update();
    REQUIRE(fsm.isActive<A>());

    fsm.update();
    REQUIRE(fsm.isActive<B>());

    // uncomment to make test pass
    // fsm.update();
    // REQUIRE(fsm.isActive<C>());

    fsm.react(Disable{});
    REQUIRE(fsm.isActive<Disabled>());

    fsm.react(Enable{});
    REQUIRE(fsm.isActive<Enabled>());
    REQUIRE(fsm.isActive<Active>());
    REQUIRE(fsm.isActive<A>());

    fsm.update();
    REQUIRE(fsm.isActive<B>());
}

Structural difference?

Hi Andrew

Is there an structural difference between
M::Root<THead, TStates>
and
M::PeerRoot<M::Composite<THead, TStates>>
and
M::PeerRoot<THead,M::CompositePeers<TStates>>

Does all 3 implementation give the same?
Which is better?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.