Got tasking working again now, with the NEW API set!!!

This is really, really great!
Now document all, and optimize the code.
And start video making.
And re-test the test mission, all...

And PUBLISH!!!
This commit is contained in:
FlightControl 2016-11-22 12:46:28 +01:00
parent 2f4eb39156
commit 4816cd2c57
7 changed files with 185 additions and 153 deletions

View File

@ -41,6 +41,7 @@ function STATEMACHINE:New( options )
--self.__index = self
self.options = options
self.options.subs = self.options.subs or {}
self.current = options.initial or 'none'
self.events = {}
self.subs = {}
@ -96,6 +97,8 @@ function STATEMACHINE:AddProcess( From, Event, Process, ReturnEvents )
sub.fsm = Process
sub.event = "Start"
sub.ReturnEvents = ReturnEvents
self.options.subs[Event] = sub
self:_submap( self.subs, sub, nil )
@ -145,26 +148,27 @@ end
function STATEMACHINE:_call_handler(handler, params)
if handler then
return handler( self, unpack(params) )
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, unpack(params) )
end
end
function STATEMACHINE._handler( self, EventName, ... )
self:F( { EventName, ... } )
self:E( { EventName, ... } )
local can, to = self:can(EventName)
self:T( { EventName, can, to } )
local can, to = self:can( EventName )
self:E( { EventName, can, to } )
local ReturnValues = nil
if can then
local from = self.current
local params = { ..., EventName, from, to }
local params = { EventName, from, to, ... }
if self:_call_handler(self["onbefore" .. EventName], params) == false
or self:_call_handler(self["onleave" .. from], params) == false then
if self:_call_handler("onbefore" .. EventName, params) == false
or self:_call_handler("onleave" .. from, params) == false then
return false
end
@ -188,28 +192,28 @@ function STATEMACHINE._handler( self, EventName, ... )
local fsmparent, event = self:_isendstate( to )
if fsmparent and event then
self:F2( { "end state: ", fsmparent, event } )
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params)
self:_call_handler(self["onstatechange"], params)
self:_call_handler("onenter" .. to, params)
self:_call_handler("onafter" .. EventName, params)
self:_call_handler("onstatechange", params)
fsmparent[event]( fsmparent )
execute = false
end
if execute then
self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } )
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
self:_call_handler("onenter" .. to, params)
self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } )
if ( self:_call_handler(self["OnBefore" .. to], params ) ~= false ) then
if ( self:_call_handler("OnBefore" .. to, params ) ~= false ) then
self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } )
self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params)
self:_call_handler("onafter" .. EventName, params)
self:T3( { On = "OnAfter" .. to, callback = self["OnAfter" .. to] } )
ReturnValues = self:_call_handler(self["OnAfter" .. to], params )
ReturnValues = self:_call_handler("OnAfter" .. to, params )
end
self:_call_handler(self["onstatechange"], params)
self:_call_handler("onstatechange", params)
end
return ReturnValues
@ -233,8 +237,8 @@ end
function STATEMACHINE:_gosub( ParentFrom, ParentEvent )
local fsmtable = {}
self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom] } )
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom] } )
return self.subs[ParentFrom][ParentEvent]
else
return {}
@ -308,40 +312,6 @@ function STATEMACHINE:todot(filename)
end
--- STATEMACHINE_TASK class
-- @type STATEMACHINE_TASK
-- @field Task#TASK_BASE Task
-- @extends StateMachine#STATEMACHINE
STATEMACHINE_TASK = {
ClassName = "STATEMACHINE_TASK",
}
--- Creates a new STATEMACHINE_TASK object.
-- @param #STATEMACHINE_TASK self
-- @param #table FSMT
-- @param Task#TASK_BASE Task
-- @param Unit#UNIT TaskUnit
-- @return #STATEMACHINE_TASK
function STATEMACHINE_TASK:New( FSMT, Task, TaskUnit )
local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_PROCESS
self["onstatechange"] = Task.OnStateChange
self["onAssigned"] = Task.OnAssigned
self["onSuccess"] = Task.OnSuccess
self["onFailed"] = Task.OnFailed
self.Task = Task
self.TaskUnit = TaskUnit
return self
end
function STATEMACHINE_TASK:_call_handler( handler, params )
if handler then
return handler( self.Task, self.TaskUnit, unpack( params ) )
end
end
--- STATEMACHINE_CONTROLLABLE class
-- @type STATEMACHINE_CONTROLLABLE
@ -385,14 +355,16 @@ function STATEMACHINE_CONTROLLABLE:GetControllable()
end
function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params )
if handler then
return handler( self, self.Controllable, unpack( params ) )
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, self.Controllable, unpack( params ) )
end
end
--- STATEMACHINE_PROCESS class
-- @type STATEMACHINE_PROCESS
-- @field Process#PROCESS Process
-- @field Tasking.Task#TASK_BASE Task
-- @extends Core.StateMachine#STATEMACHINE_CONTROLLABLE
STATEMACHINE_PROCESS = {
ClassName = "STATEMACHINE_PROCESS",
@ -408,6 +380,92 @@ function STATEMACHINE_PROCESS:New( FSMT )
return self
end
--- Sets the task of the process.
-- @param #PROCESS self
-- @param Tasking.Task#TASK_BASE Task
-- @return #PROCESS
function STATEMACHINE_PROCESS:SetTask( Task )
self.Task = Task
return self
end
--- Gets the task of the process.
-- @param #PROCESS self
-- @return Task#TASK_BASE
function STATEMACHINE_PROCESS:GetTask()
return self.Task
end
--- Gets the mission of the process.
-- @param #PROCESS self
-- @return Mission#MISSION
function STATEMACHINE_PROCESS:GetMission()
return self.Task.Mission
end
--- Assign the process to a @{Unit} and activate the process.
-- @param #PROCESS self
-- @param Task.Tasking#TASK_BASE Task
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #PROCESS self
function STATEMACHINE_PROCESS:Assign( Task, ProcessUnit )
self:E( { Task, ProcessUnit } )
self:SetControllable( ProcessUnit )
self:SetTask( Task )
self.ProcessGroup = ProcessUnit:GetGroup()
--self:Activate()
return self
end
function STATEMACHINE_PROCESS:onenterAssigned( ProcessUnit )
self.Task:Assign()
end
function STATEMACHINE_PROCESS:onenterSuccess( ProcessUnit )
self.Task:Success()
end
--- STATEMACHINE_TASK class
-- @type STATEMACHINE_TASK
-- @field Task#TASK_BASE Task
-- @extends Core.StateMachine#STATEMACHINE
STATEMACHINE_TASK = {
ClassName = "STATEMACHINE_TASK",
}
--- Creates a new STATEMACHINE_TASK object.
-- @param #STATEMACHINE_TASK self
-- @param #table FSMT
-- @param Task#TASK_BASE Task
-- @param Unit#UNIT TaskUnit
-- @return #STATEMACHINE_TASK
function STATEMACHINE_TASK:New( FSMT )
local self = BASE:Inherit( self, STATEMACHINE_CONTROLLABLE:New( FSMT ) ) -- Core.StateMachine#STATEMACHINE_TASK
self["onstatechange"] = self.OnStateChange
return self
end
function STATEMACHINE_TASK:_call_handler( handler, params )
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, unpack( params ) )
end
end
do -- STATEMACHINE_SET
--- STATEMACHINE_SET class
@ -452,8 +510,9 @@ function STATEMACHINE_SET:Get()
end
function STATEMACHINE_SET:_call_handler( handler, params )
if handler then
return handler( self, self.Set, unpack( params ) )
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, self.Set, unpack( params ) )
end
end

View File

@ -19,7 +19,7 @@ PROCESS = {
-- @param Unit#UNIT ProcessUnit (Optional) If provided, it defines the UNIT for which the process is running.
-- @return #PROCESS
function PROCESS:New( FSMT, ProcessName, ProcessUnit )
local self = BASE:Inherit( self, STATEMACHINE_CONTROLLABLE:New( FSMT, ProcessUnit ) )
local self = BASE:Inherit( self, STATEMACHINE_PROCESS:New( FSMT, ProcessUnit ) )
self:F()
if ProcessUnit then
@ -41,63 +41,20 @@ function PROCESS:GetGroup()
return self.ProcessGroup
end
--- Sets the task of the process.
-- @param #PROCESS self
-- @param Tasking.Task#TASK_BASE ProcessTask
-- @return #PROCESS
function PROCESS:SetTask( ProcessTask )
self.ProcessTask = ProcessTask
return self
end
--- Gets the task of the process.
-- @param #PROCESS self
-- @return Task#TASK_BASE
function PROCESS:GetTask()
return self.ProcessTask
end
--- Gets the mission of the process.
-- @param #PROCESS self
-- @return Mission#MISSION
function PROCESS:GetMission()
return self.ProcessTask.Mission
end
--- Assign the process to a @{Unit} and activate the process.
-- @param #PROCESS self
-- @param Unit#UNIT ProcessUnit
-- @return #PROCESS self
function PROCESS:Assign( ProcessTask, ProcessUnit )
self:SetControllable( ProcessUnit )
self:SetTask( ProcessTask )
self.ProcessGroup = ProcessUnit:GetGroup()
--self:Activate()
return self
end
--- Adds a score for the PROCESS to be achieved.
-- @param #PROCESS self
-- @param Task#TASK_BASE Task The task for which the process needs to account score.
-- @param #string ProcessStatus is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #PROCESS self
function PROCESS:AddScore( Task, ProcessStatus, ScoreText, Score )
function PROCESS:AddScore( ProcessStatus, ScoreText, Score )
self:F2( { ProcessStatus, ScoreText, Score } )
self.Scores[ProcessStatus] = self.Scores[ProcessStatus] or {}
self.Scores[ProcessStatus].ScoreText = ScoreText
self.Scores[ProcessStatus].Score = Score
self.Scores[ProcessStatus].Task = Task
return self
end
@ -108,17 +65,18 @@ end
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS:OnStateChange( ProcessUnit, Event, From, To )
self:E( { self.ProcessName, Event, From, To, ProcessUnit.UnitName } )
function PROCESS:onstatechange( ProcessUnit, Event, From, To, Dummy )
self:E( { ProcessUnit, Event, From, To, Dummy } )
if self:IsTrace() then
MESSAGE:New( "Process " .. self.ProcessName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
end
self:E( self.Scores[To] )
-- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects...
if self.Scores[To] then
local Task = self.Scores[To].Task
local Task = self.Task
local Scoring = Task:GetScoring()
if Scoring then
Scoring:_AddMissionTaskScore( Task.Mission, ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score )

View File

@ -275,18 +275,20 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
local MissionName = Mission:GetName()
self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
local PlayerData = self.Players[PlayerName]
if not self.Players[PlayerName].Mission[MissionName] then
self.Players[PlayerName].Mission[MissionName] = {}
self.Players[PlayerName].Mission[MissionName].ScoreTask = 0
self.Players[PlayerName].Mission[MissionName].ScoreMission = 0
if not PlayerData.Mission[MissionName] then
PlayerData.Mission[MissionName] = {}
PlayerData.Mission[MissionName].ScoreTask = 0
PlayerData.Mission[MissionName].ScoreMission = 0
end
self:T( PlayerName )
self:T( self.Players[PlayerName].Mission[MissionName] )
self:T( PlayerData.Mission[MissionName] )
self.Players[PlayerName].Score = self.Players[PlayerName].Score + Score
self.Players[PlayerName].Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
PlayerData.Score = self.Players[PlayerName].Score + Score
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
Score .. " task score!",
@ -306,10 +308,12 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
local MissionName = Mission:GetName()
self:F( { Mission, Text, Score } )
self:E( { Mission, Text, Score } )
self:E( self.Players )
for PlayerName, PlayerData in pairs( self.Players ) do
self:E( PlayerData )
if PlayerData.Mission[MissionName] then
PlayerData.Score = PlayerData.Score + Score

View File

@ -96,10 +96,10 @@ do -- PROCESS_ACCOUNT
{ name = 'Report', from = '*', to = 'Report' },
{ name = 'Event', from = '*', to = 'Account' },
{ name = 'More', from = 'Account', to = 'Wait' },
{ name = 'NoMore', from = 'Account', to = 'Success' },
{ name = 'NoMore', from = 'Account', to = 'Accounted' },
{ name = 'Fail', from = '*', to = 'Failed' },
},
endstates = { 'Success', 'Failed' }
endstates = { 'Accounted', 'Failed' }
}
-- Inherits from BASE
@ -214,6 +214,7 @@ do -- PROCESS_ACCOUNT_DEADS
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT_DEADS:onenterReport( ProcessUnit, Event, From, To )
self:E( { ProcessUnit, Event, From, To } )
local TaskGroup = ProcessUnit:GetGroup()
MESSAGE:New( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup )
@ -226,7 +227,7 @@ do -- PROCESS_ACCOUNT_DEADS
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT_DEADS:onenterAccount( ProcessUnit, EventData, Event, From, To )
function PROCESS_ACCOUNT_DEADS:onenterAccount( ProcessUnit, Event, From, To, EventData )
self:T( { ProcessUnit, EventData, Event, From, To } )
self:T({self.Controllable})

View File

@ -77,7 +77,14 @@ TASK_BASE = {
-- @return #TASK_BASE self
function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType, TaskCategory )
local self = BASE:Inherit( self, BASE:New() )
local self = BASE:Inherit( self, STATEMACHINE_TASK:New( {} ) )
self:SetInitialState( "Planned" )
self:AddAction( "Planned", "Assign", "Assigned" )
self:AddAction( "Assigned", "Success", "Success" )
self:AddAction( "*", "Fail", "Failed" )
self:E( "New TASK " .. TaskName )
self.Processes = {}
@ -93,7 +100,8 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType, TaskCategor
self.TaskBriefing = "You are assigned to the task: " .. self.TaskName .. "."
self.FsmTemplate = self.FsmTemplate or STATEMACHINE_TASK:New( {}, self )
self.FsmTemplate = self.FsmTemplate or STATEMACHINE_PROCESS:New( {} )
self.FsmTemplate:SetTask( self )
return self
end
@ -158,9 +166,10 @@ function TASK_BASE:AssignToUnit( TaskUnit )
-- Assign each FsmSub in FsmUnit to the TaskUnit.
-- (This is not done during the copy).
for FsmSubID, FsmSub in ipairs( FsmUnit:GetSubs() ) do
self:E( { "Sub ID", FsmSub:GetClassNameAndID() } )
FsmSub:Assign( self, TaskUnit )
self:E(FsmUnit:GetSubs())
for FsmSubID, FsmSub in pairs( FsmUnit:GetSubs() ) do
self:E( { "Sub ID", FsmSub.fsm:GetClassNameAndID(), FsmSubID } )
FsmSub.fsm:Assign( self, TaskUnit )
end
@ -590,7 +599,7 @@ end
--- Gets the Scoring of the task
-- @param #TASK_BASE self
-- @return Scoring#SCORING Scoring
-- @return Functional.Scoring#SCORING Scoring
function TASK_BASE:GetScoring()
return self.Mission:GetScoring()
end
@ -766,7 +775,7 @@ end
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #TASK_BASE self
function TASK_BASE:AddScore( TaskStatus, ScoreText, Score )
function TASK_BASE:AddScoreTask( TaskStatus, ScoreText, Score )
self:F2( { TaskStatus, ScoreText, Score } )
self.Scores[TaskStatus] = self.Scores[TaskStatus] or {}
@ -775,26 +784,35 @@ function TASK_BASE:AddScore( TaskStatus, ScoreText, Score )
return self
end
--- Adds a score for the TASK to be achieved.
-- @param #TASK_BASE self
-- @param #string TaskStatus is the status of the TASK when the score needs to be given.
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #TASK_BASE self
function TASK_BASE:AddScoreProcess( Event, State, ScoreText, Score )
self:F2( { State, ScoreText, Score } )
self:E( self:GetFsmTemplate():GetSubs()[Event].fsm )
local Process = self:GetFsmTemplate():GetSubs()[Event].fsm
Process:AddScore( State, ScoreText, Score )
return self
end
--- StateMachine callback function for a TASK
-- @param #TASK_BASE self
-- @param Unit#UNIT TaskUnit
-- @param StateMachine#STATEMACHINE_TASK Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
function TASK_BASE:OnAssigned( TaskUnit, Fsm, Event, From, To )
function TASK_BASE:onenterAssigned( Fsm, Event, From, To )
self:E("Assigned")
local TaskGroup = TaskUnit:GetGroup()
TaskGroup:Message( self.TaskBriefing, 20 )
self:RemoveMenuForGroup( TaskGroup )
self:SetAssignedMenuForGroup( TaskGroup )
end
@ -806,19 +824,9 @@ end
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
function TASK_BASE:OnSuccess( TaskUnit, Fsm, Event, From, To )
function TASK_BASE:onenterSuccess( TaskUnit, Fsm, Event, From, To )
self:E("Success")
self:UnAssignFromGroups()
self:RemoveMenu()
local TaskGroup = TaskUnit:GetGroup()
self:StateSuccess()
-- The task has become successful, the event catchers can be cleaned.
self:EventRemoveAll()
end
--- StateMachine callback function for a TASK
@ -850,17 +858,18 @@ end
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
function TASK_BASE:OnStateChange( TaskUnit, Fsm, Event, From, To )
function TASK_BASE:onstatechange( Event, From, To )
if self:IsTrace() then
MESSAGE:New( "Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
end
self:T2( { Event, From, To } )
self:SetState( self, "State", To )
self:E( { Event, From, To, self:IsTrace() } )
self:E( self.Scores )
if self.Scores[To] then
local Scoring = self:GetScoring()
self:E( Scoring )
if Scoring then
Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score )
end

View File

@ -20,19 +20,20 @@ FsmSEAD:AddProcess( "Planned", "Accept", PROCESS_ASSIGN_ACCEPT:New( "SEAD t
FsmSEAD:AddProcess( "Assigned", "Route", PROCESS_ROUTE_ZONE:New( TargetZone, 3000 ), { Arrived = "Update" } )
FsmSEAD:AddAction ( "Rejected", "Eject", "Planned" )
FsmSEAD:AddAction ( "Arrived", "Update", "Updated" )
FsmSEAD:AddProcess( "Updated", "Account", PROCESS_ACCOUNT_DEADS:New( TargetSet, "SEAD" ), { Destroyed = "Success" } )
FsmSEAD:AddProcess( "Updated", "Account", PROCESS_ACCOUNT_DEADS:New( TargetSet, "SEAD" ), { Accounted = "Success" } )
FsmSEAD:AddProcess( "Updated", "Smoke", PROCESS_SMOKE_TARGETS_ZONE:New( TargetSet, TargetZone ) )
FsmSEAD:AddAction ( "Destroyed", "Success", "Success" )
FsmSEAD:AddAction ( "Accounted", "Success", "Success" )
FsmSEAD:AddAction ( "Failed", "Fail", "Failed" )
--TaskSEAD:AddScoreTask( "Success", "Destroyed all target radars", 250 )
--TaskSEAD:AddScoreTask( "Failed", "Failed to destroy all target radars", -100 )
--TaskSEAD:AddScoreProcess( "Account", "Account", "destroyed a radar", 25 )
--TaskSEAD:AddScoreProcess( "Smoke", "Failed", "failed to destroy a radar", -100 )
TaskSEAD:AddScoreTask( "Success", "Destroyed all target radars", 250 )
TaskSEAD:AddScoreTask( "Failed", "Failed to destroy all target radars", -100 )
TaskSEAD:AddScoreProcess( "Account", "Account", "destroyed a radar", 25 )
TaskSEAD:AddScoreProcess( "Account", "Fail", "failed to destroy a radar", -100 )
function FsmSEAD:onenterUpdated( TaskUnit )
TaskSEAD:Account()
TaskSEAD:Smoke()
self:E( { self } )
self:Account()
self:Smoke()
end
-- Needs to be checked, should not be necessary ...