From ae1aeac6cebfca3698a09e70fb2ae0632536aebf Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 2 Jul 2016 09:06:29 +0200 Subject: [PATCH] DONE! Prototype of hierarchical state machine is works!!! --- Moose Development/Moose/StateMachine.lua | 36 ++++++++++++++---- Moose Development/Moose/TaskClientMenu.lua | 2 +- .../Moose_Test_TASK_SEAD.lua | 8 ++-- .../Moose_Test_TASK_SEAD.miz | Bin 20051 -> 20061 bytes 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/StateMachine.lua b/Moose Development/Moose/StateMachine.lua index 32e6eab08..3f070308d 100644 --- a/Moose Development/Moose/StateMachine.lua +++ b/Moose Development/Moose/StateMachine.lua @@ -56,7 +56,7 @@ function STATEMACHINE:New( options ) end for name, endstate in pairs( options.endstates or {} ) do - self.endstates[name] = endstate + self.endstates[endstate] = endstate end return self @@ -64,11 +64,12 @@ end function STATEMACHINE:_submap( subs, sub, name ) - self:E( { subs = subs, sub = sub, name = name } ) + self:E( { sub = sub, name = name } ) subs[sub.onstateparent] = subs[sub.onstateparent] or {} subs[sub.onstateparent][sub.oneventparent] = subs[sub.onstateparent][sub.oneventparent] or {} subs[sub.onstateparent][sub.oneventparent].fsm = sub.fsm subs[sub.onstateparent][sub.oneventparent].event = sub.event + subs[sub.onstateparent][sub.oneventparent].returnevents = sub.returnevents -- these events need to be given to find the correct continue event ... if none given, the processing will stop. subs[sub.onstateparent][sub.oneventparent].name = name subs[sub.onstateparent][sub.oneventparent].fsmparent = self end @@ -83,8 +84,8 @@ end function STATEMACHINE:_create_transition(name) self:E( { name = name } ) return function(self, ...) - self:E(name) local can, to = self:can(name) + self:E( { name, can, to } ) if can then local from = self.current @@ -101,12 +102,12 @@ function STATEMACHINE:_create_transition(name) if fsm and fsm[event] then self:E( "calling sub: " .. event ) fsm.fsmparent = self - fsm.from = to + fsm.returnevents = self:_returnevents( to, name ) fsm[event]( fsm ) else local fsmparent, event = self:_isendstate( to ) - if fsmparent then + if fsmparent and event then fsmparent[event]( fsmparent ) else self:_call_handler(self["onenter" .. to] or self["on" .. to], params) @@ -130,13 +131,32 @@ function STATEMACHINE:_gosub( parentstate, parentevent ) end end -function STATEMACHINE:_isendstate( state ) - if self.fsmparent then - return self.fsmparent, +function STATEMACHINE:_returnevents( parentstate, parentevent ) + if self.subs[parentstate] and self.subs[parentstate][parentevent] then + self:E(self.subs[parentstate][parentevent].returnevents) + return self.subs[parentstate][parentevent].returnevents else return nil end +end +function STATEMACHINE:_isendstate( state ) + local fsmparent = self.fsmparent + if fsmparent and self.endstates[state] then + self:E( { state = state, endstates = self.endstates, endstate = self.endstates[state] } ) + local returnevent = nil + local fromstate = fsmparent.current + for _, eventname in pairs( self.returnevents ) do + local event = fsmparent.events[eventname] + self:E( event ) + local to = event and event.map[fromstate] or event.map['*'] + if to then + return fsmparent, eventname + end + end + end + + return nil end function STATEMACHINE:_add_to_map(map, event) diff --git a/Moose Development/Moose/TaskClientMenu.lua b/Moose Development/Moose/TaskClientMenu.lua index a99e119ee..5c3c372c1 100644 --- a/Moose Development/Moose/TaskClientMenu.lua +++ b/Moose Development/Moose/TaskClientMenu.lua @@ -35,7 +35,7 @@ function TASK2_CLIENT_MENU:New( Client, Mission, MenuText ) onMenu = self.OnMenu, onAssign = self.OnAssign, }, - finals = { + endstates = { 'Assigned' }, } ) diff --git a/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.lua b/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.lua index c875314a9..4c3d407e6 100644 --- a/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.lua +++ b/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.lua @@ -18,15 +18,15 @@ local Task_Sead = STATEMACHINE:New( { initial = 'None', events = { { name = 'Start', from = 'None', to = 'Unassigned' }, - { name = 'Assign', from = 'Unassigned', to = 'Assigned' }, + { name = 'Next', from = 'Unassigned', to = 'Assigned' }, -- { name = 'Route', from = 'Assigned', to = 'Arrived' }, - { name = 'Sead', from = 'Assigned', to = 'Seading' }, + { name = 'Next', from = 'Assigned', to = 'Seading' }, { name = 'Destroyed', from = 'Destroy', to = 'Success' }, }, subs = { - Menu = { onstateparent = 'Unassigned', oneventparent = 'Start', fsm = Task_Menu.Fsm, event = 'Menu' }, + Menu = { onstateparent = 'Unassigned', oneventparent = 'Start', fsm = Task_Menu.Fsm, event = 'Menu', returnevents = { 'Next' } }, --Assigned = { onstateparent = 'Assigned', oneventparent = 'Assign', fsm = Task_Route.Fsm, event = 'Route' }, - Sead = { onstateparent = 'Assigned', oneventparent = 'Assign', fsm = Task_Client_Sead.Fsm, event = 'Await' } + Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = Task_Client_Sead.Fsm, event = 'Await', returnevents = { 'Next' } } } } ) diff --git a/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.miz b/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.miz index d61404df08515b7f8814e45cf9d8e9a0027ab6d5..ceb51bf0cfb30f1310ea33cb5bc899b58e7a75ce 100644 GIT binary patch delta 5206 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 Q0eq7%P8|j!O8@`>07erX@c;k- delta 5234 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