mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Progress hierarchical state machine
- sub fsm call is working - return from fsm to parent fsm is in progress
This commit is contained in:
parent
7b66589cca
commit
d668b0a0f7
@ -45,9 +45,10 @@ Include.File( "AIBalancer" )
|
||||
Include.File( "AirbasePolice" )
|
||||
Include.File( "Detection" )
|
||||
Include.File( "FAC" )
|
||||
Include.File( "Task2" )
|
||||
Include.File( "TaskSead" )
|
||||
Include.File( "StateMachine" )
|
||||
Include.File( "Task2" )
|
||||
Include.File( "TaskClientSead" )
|
||||
Include.File( "TaskClientMenu" )
|
||||
|
||||
-- The order of the declarations is important here. Don't touch it.
|
||||
|
||||
|
||||
@ -22,17 +22,23 @@ STATEMACHINE = {
|
||||
-- @return #STATEMACHINE
|
||||
function STATEMACHINE:New( options )
|
||||
|
||||
local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
|
||||
|
||||
--local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||
|
||||
assert(options.events)
|
||||
|
||||
local MT = {}
|
||||
setmetatable( self, MT )
|
||||
self.__index = self
|
||||
--local MT = {}
|
||||
--setmetatable( self, MT )
|
||||
--self.__index = self
|
||||
|
||||
self.options = options
|
||||
self.current = options.initial or 'none'
|
||||
self.events = {}
|
||||
self.subs = {}
|
||||
self.endstates = {}
|
||||
|
||||
for _, event in ipairs(options.events or {}) do
|
||||
local name = event.name
|
||||
@ -44,11 +50,30 @@ function STATEMACHINE:New( options )
|
||||
for name, callback in pairs(options.callbacks or {}) do
|
||||
self[name] = callback
|
||||
end
|
||||
|
||||
for name, sub in pairs( options.subs or {} ) do
|
||||
self:_submap( self.subs, sub, name )
|
||||
end
|
||||
|
||||
for name, endstate in pairs( options.endstates or {} ) do
|
||||
self.endstates[name] = endstate
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function STATEMACHINE:_submap( subs, sub, name )
|
||||
self:E( { subs = subs, 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].name = name
|
||||
subs[sub.onstateparent][sub.oneventparent].fsmparent = self
|
||||
end
|
||||
|
||||
|
||||
function STATEMACHINE:_call_handler(handler, params)
|
||||
if handler then
|
||||
return handler(unpack(params))
|
||||
@ -56,7 +81,9 @@ function STATEMACHINE:_call_handler(handler, params)
|
||||
end
|
||||
|
||||
function STATEMACHINE:_create_transition(name)
|
||||
self:E( { name = name } )
|
||||
return function(self, ...)
|
||||
self:E(name)
|
||||
local can, to = self:can(name)
|
||||
|
||||
if can then
|
||||
@ -69,11 +96,25 @@ function STATEMACHINE:_create_transition(name)
|
||||
end
|
||||
|
||||
self.current = to
|
||||
|
||||
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
|
||||
self:_call_handler(self["onafter" .. name] or self["on" .. name], params)
|
||||
self:_call_handler(self["onstatechange"], params)
|
||||
|
||||
|
||||
local fsm, event = self:_gosub( to, name )
|
||||
if fsm and fsm[event] then
|
||||
self:E( "calling sub: " .. event )
|
||||
fsm.fsmparent = self
|
||||
fsm.from = to
|
||||
fsm[event]( fsm )
|
||||
else
|
||||
|
||||
local fsmparent, event = self:_isendstate( to )
|
||||
if fsmparent then
|
||||
fsmparent[event]( fsmparent )
|
||||
else
|
||||
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
|
||||
self:_call_handler(self["onafter" .. name] or self["on" .. name], params)
|
||||
self:_call_handler(self["onstatechange"], params)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -81,6 +122,23 @@ function STATEMACHINE:_create_transition(name)
|
||||
end
|
||||
end
|
||||
|
||||
function STATEMACHINE:_gosub( parentstate, parentevent )
|
||||
if self.subs[parentstate] and self.subs[parentstate][parentevent] then
|
||||
return self.subs[parentstate][parentevent].fsm, self.subs[parentstate][parentevent].event
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function STATEMACHINE:_isendstate( state )
|
||||
if self.fsmparent then
|
||||
return self.fsmparent,
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function STATEMACHINE:_add_to_map(map, event)
|
||||
if type(event.from) == 'string' then
|
||||
map[event.from] = event.to
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
-- @field Scheduler#SCHEDULER TaskScheduler
|
||||
-- @field Client#CLIENT Client
|
||||
-- @field Mission#MISSION Mission
|
||||
-- @field StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @extends Base#BASE
|
||||
TASK2 = {
|
||||
ClassName = "TASK",
|
||||
|
||||
84
Moose Development/Moose/TaskClientMenu.lua
Normal file
84
Moose Development/Moose/TaskClientMenu.lua
Normal file
@ -0,0 +1,84 @@
|
||||
--- @module Task_Client_Menu
|
||||
|
||||
--- TASK2_CLIENT_MENU class
|
||||
-- @type TASK2_CLIENT_MENU
|
||||
-- @field Client#CLIENT Client
|
||||
-- @field Set#SET_UNIT TargetSet
|
||||
-- @field Menu#MENU_CLIENT_COMMAND MenuSEAD
|
||||
-- @extends Task2#TASK2
|
||||
TASK2_CLIENT_MENU = {
|
||||
ClassName = "TASK2_CLIENT_MENU",
|
||||
TargetSet = nil,
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new MENU handling machine.
|
||||
-- @param #TASK2_CLIENT_MENU self
|
||||
-- @param Client#CLIENT Client
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param #string MenuText The text of the menu item.
|
||||
-- @return #TASK2_CLIENT_MENU self
|
||||
function TASK2_CLIENT_MENU:New( Client, Mission, MenuText )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, TASK2:New( Client, Mission ) ) -- #TASK2_CLIENT_MENU
|
||||
|
||||
self.MenuText = MenuText
|
||||
|
||||
self.Fsm = STATEMACHINE_TASK:New( self, {
|
||||
initial = 'Unassigned',
|
||||
events = {
|
||||
{ name = 'Menu', from = 'Unassigned', to = 'AwaitingMenu' },
|
||||
{ name = 'Assign', from = 'AwaitingMenu', to = 'Assigned' },
|
||||
},
|
||||
callbacks = {
|
||||
onMenu = self.OnMenu,
|
||||
onAssign = self.OnAssign,
|
||||
},
|
||||
finals = {
|
||||
'Assigned'
|
||||
},
|
||||
} )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Task Events
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #TASK2_CLIENT_MENU self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function TASK2_CLIENT_MENU:OnMenu( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.Client.ClientName} )
|
||||
|
||||
self.Client:Message( "Press F10 for task menu", 15 )
|
||||
self.Menu = MENU_CLIENT:New( self.Client, self.Mission:GetName(), nil )
|
||||
self.MenuTask = MENU_CLIENT_COMMAND:New( self.Client, self.MenuText, self.Menu, self.MenuAssign, self )
|
||||
end
|
||||
|
||||
--- Menu function.
|
||||
-- @param #TASK2_CLIENT_MENU self
|
||||
function TASK2_CLIENT_MENU:MenuAssign()
|
||||
self:E( )
|
||||
|
||||
self.Client:Message( "Menu Assign", 15 )
|
||||
|
||||
self:NextEvent( self.Fsm.Assign )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #TASK2_CLIENT_MENU self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function TASK2_CLIENT_MENU:OnAssign( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.Client.ClientName} )
|
||||
|
||||
self.Client:Message( "Assign Task", 15 )
|
||||
self.MenuTask:Remove()
|
||||
end
|
||||
|
||||
@ -27,10 +27,8 @@ function TASK2_SEAD:New( Client, Mission, TargetSet )
|
||||
self.TargetSet = TargetSet
|
||||
|
||||
self.Fsm = STATEMACHINE_TASK:New( self, {
|
||||
initial = 'Start',
|
||||
initial = 'Assigned',
|
||||
events = {
|
||||
{ name = 'Menu', from = 'Start', to = 'Unassigned' },
|
||||
{ name = 'Assign', from = 'Unassigned', to = 'Assigned' },
|
||||
{ name = 'Await', from = 'Assigned', to = 'Waiting' },
|
||||
{ name = 'HitTarget', from = 'Waiting', to = 'Destroy' },
|
||||
{ name = 'MoreTargets', from = 'Destroy', to = 'Waiting' },
|
||||
@ -38,17 +36,13 @@ function TASK2_SEAD:New( Client, Mission, TargetSet )
|
||||
{ name = 'Killed', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Killed', from = 'Waiting', to = 'Failed' },
|
||||
{ name = 'Killed', from = 'Destroy', to = 'Failed' },
|
||||
{ name = 'Restart', from = 'Failed', to = 'Unassigned' }
|
||||
},
|
||||
callbacks = {
|
||||
onMenu = self.OnMenu,
|
||||
onAssign = self.OnAssign,
|
||||
onAwait = self.OnAwait,
|
||||
onHitTarget = self.OnHitTarget,
|
||||
onMoreTargets = self.OnMoreTargets,
|
||||
onDestroyed = self.OnDestroyed,
|
||||
onKilled = self.OnKilled,
|
||||
onRestart = self.OnRestart,
|
||||
}
|
||||
} )
|
||||
|
||||
@ -57,53 +51,11 @@ function TASK2_SEAD:New( Client, Mission, TargetSet )
|
||||
_EVENTDISPATCHER:OnDead( self.EventKilled, self )
|
||||
_EVENTDISPATCHER:OnCrash( self.EventKilled, self )
|
||||
|
||||
self:NextEvent( self.Fsm.Menu )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Task Events
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #TASK2_SEAD self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function TASK2_SEAD:OnMenu( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.Client.ClientName} )
|
||||
|
||||
self.Client:Message( "Menu", 15 )
|
||||
self.Menu = MENU_CLIENT:New( self.Client, self.Mission:GetName(), nil )
|
||||
self.MenuSEAD = MENU_CLIENT_COMMAND:New( self.Client, "SEAD", self.Menu, self.SEADAssign, self )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #TASK2_SEAD self
|
||||
function TASK2_SEAD:SEADAssign()
|
||||
self:E( )
|
||||
|
||||
self.Client:Message( "SEAD Menu Assign", 15 )
|
||||
|
||||
self:NextEvent( self.Fsm.Assign )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #TASK2_SEAD self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function TASK2_SEAD:OnAssign( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.Client.ClientName} )
|
||||
|
||||
self.Client:Message( "Assigned", 15 )
|
||||
self.MenuSEAD:Remove()
|
||||
self:NextEvent( Fsm.Await )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #TASK2_SEAD self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -7,9 +7,27 @@ Mission:AddScoring( Scoring )
|
||||
local Client = CLIENT:FindByName( "Test SEAD" )
|
||||
local TargetSet = SET_UNIT:New():FilterPrefixes( "US Hawk SR" ):FilterStart()
|
||||
|
||||
local Task_SEAD = TASK2_SEAD:New( Client, Mission, TargetSet )
|
||||
local Task_Menu = TASK2_CLIENT_MENU:New( Client, Mission, "SEAD" )
|
||||
--local Task_Route = TASK2_ROUTE:New( Client, Mission ) -- Zone is dynamically defined in state machine
|
||||
local Task_Client_Sead = TASK2_SEAD:New( Client, Mission, TargetSet )
|
||||
|
||||
Task_SEAD:AddScore( "Destroy", "Destroyed RADAR", 25 )
|
||||
Task_SEAD:AddScore( "Success", "Destroyed all radars!!!", 100 )
|
||||
Task_Client_Sead:AddScore( "Destroy", "Destroyed RADAR", 25 )
|
||||
Task_Client_Sead:AddScore( "Success", "Destroyed all radars!!!", 100 )
|
||||
|
||||
local Task_Sead = STATEMACHINE:New( {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Start', from = 'None', to = 'Unassigned' },
|
||||
{ name = 'Assign', from = 'Unassigned', to = 'Assigned' },
|
||||
-- { name = 'Route', from = 'Assigned', to = 'Arrived' },
|
||||
{ name = 'Sead', from = 'Assigned', to = 'Seading' },
|
||||
{ name = 'Destroyed', from = 'Destroy', to = 'Success' },
|
||||
},
|
||||
subs = {
|
||||
Menu = { onstateparent = 'Unassigned', oneventparent = 'Start', fsm = Task_Menu.Fsm, event = 'Menu' },
|
||||
--Assigned = { onstateparent = 'Assigned', oneventparent = 'Assign', fsm = Task_Route.Fsm, event = 'Route' },
|
||||
Sead = { onstateparent = 'Assigned', oneventparent = 'Assign', fsm = Task_Client_Sead.Fsm, event = 'Await' }
|
||||
}
|
||||
} )
|
||||
|
||||
Task_Sead:Start()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user