C++ 20
FSM library with lua
binding.
// `StateEx` inherits from `State` and runs in the same frame as `State`.
auto ex_hello = new StateEx();
LDJ::FsmAction<State> action_default(state_default, {});
LDJ::FsmAction<State> action_hello(state_hello, {ex_hello});
LDJ::FsmAction<State> action_wow(state_wow, {});
LDJ::FsmAction<State> action_pow(state_pow, {});
LDJ::FsmAction<State> action_combo1(state_wow, {}, [] { return LDJ::Completed; });
LDJ::FsmAction<State> action_combo2(state_pow, {}, [] { return LDJ::Completed; });
fsm = new LDJ::Fsm<Self, State>(this);
auto tr1 = fsm->NewTransition("tr1");
auto tr2 = fsm->NewTransition("tr2");
fsm
->BindDefault(tr1, action_default) // `action_default` automatically bound as "default"
->Bind("hello", action_hello)
->Bind("wow", action_wow)
->Bind("pow", action_pow)
->Bind("combo", {action_combo1, action_combo2});
tr1
->When("default", [] { return "hello"; })
->When("combo", [] { return "hello"; })
->When("hello", [=] { return tr2; });
tr2
->When("hello", [] { return random_range(0, 1) ? "wow" : "pow"; })
->When({"wow", "pow"}, [=] { return tr1->DoAction("combo"); });
local action_default = Action(State.default, {}, nil)
local action_hello = Action(State.hello, { State.ex_hello }, nil)
local action_wow = Action(State.wow, {}, nil)
local action_pow = Action(State.pow, {}, nil)
local action_combo1 = Action(State.wow, {}, function()
return Duration(1.5)
end)
local action_combo2 = Action(State.pow, {}, function()
return Status.Completed
end)
local fsm = Fsm
local this = This
print(this.name)
local tr1 = fsm:new_transition('tr1')
local tr2 = fsm:new_transition('tr2')
fsm
:bind_default(tr1, action_default)
:bind('hello', action_hello)
:bind('wow', action_wow)
:bind('pow', action_pow)
:bind('combo', { action_combo1, action_combo2 })
tr1
:when('default', function()
return 'hello'
end)
:when('combo', function()
if math.random(3) == 1 then return fsm:skip_current(fsm:reenter('combo')) end
if math.random(3) == 1 then return fsm:skip_current('hello') end
return 'hello'
end)
:when('hello', function()
return tr2
end)
tr2
:when('hello', function()
return 'wow'
end)
:when('wow', function()
return tr1:do_action('combo')
end)
auto c = new Character();
c->fsm = LDJ::prepare_fsm_lua_instance<CharacterBase, StateBase, Character, State>(Character::lua, this);
// ^^^ --> sol::state
c->fsm->print_log = true;
Character::lua["State"]["ex_hello"] = Character::ex_hello;
Character::lua["State"]["default"] = Character::state_default;
Character::lua["State"]["hello"] = Character::state_hello;
Character::lua["State"]["wow"] = Character::state_wow;
Character::lua["State"]["pow"] = Character::state_pow;
LDJ::execute_fsm_lua(Character::lua, "lua/character.lua");
LDJ::FsmLogger::fn_logger = [](std::string Msg, std::string Prefix)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *FString(UTF8_TO_TCHAR((Prefix + Msg).c_str())));
};
LDJ::FsmAssert::fn_assert = [](const bool bExpr, const std::string Msg)
{
checkf(bExpr, FString(UTF8_TO_TCHAR(Msg.c_str())));
};