This commit is contained in:
FlightControl 2016-12-15 09:50:21 +01:00
parent 63e46ad029
commit 51d8e2b7d8
7 changed files with 263 additions and 24 deletions

View File

@ -74,8 +74,9 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local EventGroup = GROUP:Find( EventData.IniDCSGroup )
if EventGroup and self:HasGroup( EventGroup ) then
local MenuReporting = MENU_GROUP:New( EventGroup, "Reporting", self.CommandCenterMenu )
local MenuMissions = MENU_GROUP_COMMAND:New( EventGroup, "Missions", MenuReporting, self.ReportMissions, self, EventGroup )
self:ReportMissions( EventGroup )
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Summary Report", MenuReporting, self.ReportSummary, self, EventGroup )
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Details Report", MenuReporting, self.ReportDetails, self, EventGroup )
self:ReportSummary( EventGroup )
end
end
)
@ -91,7 +92,9 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
function( self, EventData )
local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION
Mission:AddUnit( PlayerUnit )
Mission:ReportDetails()
end
end
)
@ -109,7 +112,20 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
end
end
)
-- Handle when a player leaves a slot and goes back to spectators ...
-- The PlayerUnit will be UnAssigned from the Task.
-- When there is no Unit left running the Task, the Task goes into Abort...
self:EventOnCrash(
--- @param #TASK_BASE self
-- @param Core.Event#EVENTDATA EventData
function( self, EventData )
local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do
Mission:CrashUnit( PlayerUnit )
end
end
)
return self
end
@ -208,16 +224,18 @@ function COMMANDCENTER:MessageToCoalition( Message )
self:GetPositionable():MessageToBlue( Message , 20, CCCoalition )
end
--- Report the status of all MISSIONs to a GROUP.
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
-- @param #COMMANDCENTER self
function COMMANDCENTER:ReportMissions( ReportGroup )
function COMMANDCENTER:ReportSummary( ReportGroup )
self:E( ReportGroup )
local Report = REPORT:New()
for MissionID, Mission in pairs( self.Missions ) do
local Mission = Mission -- Tasking.Mission#MISSION
Report:Add( " - " .. Mission:ReportStatus() )
Report:Add( " - " .. Mission:ReportOverview() )
end
self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup )
@ -225,18 +243,18 @@ function COMMANDCENTER:ReportMissions( ReportGroup )
end
--- Report the status of a Task to a Group.
-- Report the details of a Mission, listing the Mission, and all the Task details.
-- @param #COMMANDCENTER self
function COMMANDCENTER:ReportTaskStatus( ReportGroup, Task )
function COMMANDCENTER:ReportDetails( ReportGroup, Task )
self:E( ReportGroup )
local Report = REPORT:New()
for MissionID, Mission in pairs( self.Missions ) do
local Mission = Mission -- Tasking.Mission#MISSION
Report:Add( " - " .. Mission:ReportStatus() )
Report:Add( " - " .. Mission:ReportDetails() )
end
self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup )
end

View File

@ -46,7 +46,8 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
self:AddTransition( "Idle", "Start", "Ongoing" )
self:AddTransition( "Ongoing", "Stop", "Idle" )
self:AddTransition( "Ongoing", "Finish", "Finished" )
self:AddTransition( "Ongoing", "Complete", "Completed" )
self:AddTransition( "*", "Fail", "Failed" )
self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } )
@ -60,12 +61,35 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
self.Tasks = {}
-- Build the Fsm for the mission.
return self
end
--- FSM function for a MISSION
-- @param #MISSION self
-- @param #string Event
-- @param #string From
-- @param #string To
function MISSION:onbeforeComplete( Event, From, To )
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK_BASE
if not Task:IsStateSuccess() and not Task:IsStateFailed() and not Task:IsStateAborted() and not Task:IsStateCancelled() then
return false -- Mission cannot be completed. Other Tasks are still active.
end
end
return true -- Allow Mission completion.
end
--- FSM function for a MISSION
-- @param #MISSION self
-- @param #string Event
-- @param #string From
-- @param #string To
function MISSION:onenterCompleted( Event, From, To )
self:GetCommandCenter():MessageToCoalition( "Mission " .. self:GetName() .. " has been completed! Good job guys!" )
end
--- Gets the mission name.
-- @param #MISSION self
-- @return #MISSION self
@ -114,6 +138,28 @@ function MISSION:AbortUnit( PlayerUnit )
return PlayerUnitRemoved
end
--- Handles a crash of a PlayerUnit from the Mission.
-- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned.
-- If the Unit was not part of a Task in the Mission, false is returned.
-- If the Unit is part of a Task in the Mission, true is returned.
-- @param #MISSION self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player crashing.
-- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:CrashUnit( PlayerUnit )
self:F( { PlayerUnit = PlayerUnit } )
local PlayerUnitRemoved = false
for TaskID, Task in pairs( self:GetTasks() ) do
if Task:CrashUnit( PlayerUnit ) then
PlayerUnitRemoved = true
end
end
return PlayerUnitRemoved
end
--- Add a scoring to the mission.
-- @param #MISSION self
-- @return #MISSION self
@ -371,10 +417,12 @@ function MISSION:HasGroup( TaskGroup )
return Has
end
--- Create a summary report of the mission (one line).
--- Create a summary report of the Mission (one line).
-- @param #MISSION self
-- @return #string
function MISSION:ReportStatus()
function MISSION:ReportSummary()
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetName()
@ -392,7 +440,59 @@ function MISSION:ReportStatus()
end
end
return "Mission " .. Name .. " - " .. Status .. " - " .. TasksRemaining .. " tasks remaining."
Report:Add( "Mission " .. Name .. " - " .. Status .. " - " .. TasksRemaining .. " tasks remaining." )
return Report:Text()
end
--- Create a overview report of the Mission (multiple lines).
-- @param #MISSION self
-- @return #string
function MISSION:ReportOverview()
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetName()
-- Determine the status of the mission.
local Status = self:GetState()
Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" )
-- Determine how many tasks are remaining.
local TasksRemaining = 0
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK_BASE
Report:Add( "- " .. Task:ReportSummary() )
end
return Report:Text()
end
--- Create a detailed report of the Mission, listing all the details of the Task.
-- @param #MISSION self
-- @return #string
function MISSION:ReportDetails()
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetName()
-- Determine the status of the mission.
local Status = self:GetState()
Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" )
-- Determine how many tasks are remaining.
local TasksRemaining = 0
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK_BASE
Report:Add( Task:ReportDetails() )
end
return Report:Text()
end
--- Report the status of all MISSIONs to all active Clients.

View File

@ -215,7 +215,7 @@ end
--- Get the Task FSM Process Template
-- @param #TASK_BASE self
-- @return Fsm.Fsm#FSM_PROCESS
function TASK_BASE:GetFsmTemplate()
function TASK_BASE:GetUnitProcess()
return self.FsmTemplate
end
@ -223,7 +223,7 @@ end
--- Sets the Task FSM Process Template
-- @param #TASK_BASE self
-- @param Fsm.Fsm#FSM_PROCESS
function TASK_BASE:SetFsmTemplate( FsmTemplate )
function TASK_BASE:SetUnitProcess( FsmTemplate )
self.FsmTemplate = FsmTemplate
end
@ -405,7 +405,7 @@ end
function TASK_BASE:AssignToUnit( TaskUnit )
self:F( TaskUnit:GetName() )
local FsmTemplate = self:GetFsmTemplate()
local FsmTemplate = self:GetUnitProcess()
-- Assign a new FsmUnit to TaskUnit.
local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Fsm.Fsm#FSM_PROCESS
@ -869,6 +869,7 @@ function TASK_BASE:onenterAssigned( Event, From, To )
self:E("Task Assigned")
self:MessageToGroups( "Task " .. self:GetName() .. " has been assigned!" )
self:GetMission():__Start()
end
@ -883,6 +884,9 @@ function TASK_BASE:onenterSuccess( Event, From, To )
self:MessageToGroups( "Task " .. self:GetName() .. " is successful! Good job!" )
self:UnAssignFromGroups()
self:GetMission():__Complete()
end
@ -934,3 +938,61 @@ function TASK_BASE:onstatechange( Event, From, To )
end
end
do -- Reporting
--- Create a summary report of the Task.
-- List the Task Name and Status
-- @param #TASK_BASE self
-- @return #string
function TASK_BASE:ReportSummary()
local Report = REPORT:New()
-- List the name of the Task.
local Name = self:GetName()
-- Determine the status of the Task.
local State = self:GetState()
Report:Add( "Task " .. Name .. " - State '" .. State )
return Report:Text()
end
--- Create a detailed report of the Task.
-- List the Task Status, and the Players assigned to the Task.
-- @param #TASK_BASE self
-- @return #string
function TASK_BASE:ReportDetails()
local Report = REPORT:New()
-- List the name of the Task.
local Name = self:GetName()
-- Determine the status of the Task.
local State = self:GetState()
-- Loop each Unit active in the Task, and find Player Names.
local PlayerNames = {}
for PlayerGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do
local Player = PlayerGroup -- Wrapper.Group#GROUP
for PlayerUnitID, PlayerUnit in pairs( PlayerGroup:GetUnits() ) do
local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT
if PlayerUnit and PlayerUnit:IsAlive() then
local PlayerName = PlayerUnit:GetPlayerName()
PlayerNames[#PlayerNames+1] = PlayerName
end
end
PlayerNameText = table.concat( PlayerNames, ", " )
Report:Add( "Task " .. Name .. " - State '" .. State .. "' - Players " .. PlayerNameText )
end
return Report:Text()
end
end -- Reporting

View File

@ -45,7 +45,7 @@ do -- TASK_A2G
self.TargetZone = TargetZone
self.FACUnit = FACUnit
local Fsm = self:GetFsmTemplate()
local Fsm = self:GetUnitProcess()
Fsm:AddProcess( "Planned", "Accept", FSM_ASSIGN_ACCEPT:New( "Attack the Area" ), { Assigned = "Route", Rejected = "Eject" } )
Fsm:AddProcess( "Assigned", "Route", FSM_ROUTE_ZONE:New( self.TargetZone ), { Arrived = "Update" } )

View File

@ -45,7 +45,7 @@ do -- TASK_SEAD
self.TargetSetUnit = TargetSetUnit
self.TargetZone = TargetZone
local Fsm = self:GetFsmTemplate()
local Fsm = self:GetUnitProcess()
Fsm:AddProcess( "Planned", "Accept", FSM_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "Route", Rejected = "Eject" } )
Fsm:AddProcess( "Assigned", "Route", FSM_ROUTE_ZONE:New( self.TargetZone ), { Arrived = "Update" } )

View File

@ -1,4 +1,12 @@
--- Task Modelling - SEAD
--
-- ===
--
-- Author: FlightControl
-- Date Created: 15 Dec 2016
--
-- # Situation
--
-- This test mission is a test bed for the TASKING framework.
-- It creates an head quarters (HQ), which contains one mission with one task to be accomplished.
-- When the pilot joins the plane, it will need to accept the task using the HQ menu.
@ -7,6 +15,56 @@
-- A smoking system is available that the pilot can use the acquire targets.
-- Once all targets are elimitated, the task is finished, and the mission is set to complete.
-- If the pilot crashes during flying, the task will fail, and the mission is set to failed.
--
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- # Test cases:
--
-- There should only be one Task listed under Others Menu -> HQ -> SEAD Targets -> SEAD. This is the TaskSEAD2, that is copied from TaskSEAD.
-- TaskSEAD is removed from the mission once TaskSEAD2 is created.
--
-- ## Run this mission in DCS Single Player:
--
-- * Once started, a slot.
-- * When in the plane, join the SEAD task through the Others Menu -> HQ -> SEAD Targets -> SEAD -> SEAD Radars Vector 2.
-- * When flying, watch the messages appear. It should say that you've been assigned to the task, and that you need to route your plane to a coordinate.
-- * Exit your plane by pressing ESC, and go back to the spectators. When in single player mode, just click on Back, and then click Spectators.
-- * Immediately rejoin a Slot, select an other plane.
-- * When in the plane, you should now not be able to join the Task. No menu options are given. That is because the Task is "Aborted".
-- * However, the aborted task is replanned within 30 seconds. As such, go back to spectators, and after 30 seconds, rejoin a slot in a plane.
-- * When in the plane, you should not be able to join the Task through the Others Menu -> HQ -> SEAD Targets -> SEAD -> SEAD Radars Vector 2.
-- * Once accepted, watch the messages appear. Route to the attach zone, following the coordinates.
-- * Once at the attack zone, you'll see a message how many targets are left to be destroyed. Attack the radar emitting SAM with a kh-25.
-- * When you HIT the SAM, you'll see a scoring message appear. One point is granted.
-- * Maybe you've fired two missiles, so, you'll see another HIT maybe on the SAM, again granting a point.
-- * When the SAM is DEAD (it may take a while), you'll see a scoring message that 10 points have been granted.
-- * You'll see a scoring message appear that grants 25 points because you've hit a target of the Task. (This was programmed below).
-- * You'll see a scoring message appear that grants 250 points because all Task targets have been elimitated. (This was also programmed below).
-- * You'll see a message appear that you have Task success. The Task will be flagged as 'Success', and cannot be joined anymore.
-- * You'll see a message appear that the Mission "SEAD Targets" has been "Completed".
--
-- ## Run this mission in DCS Multiple Player, with one player:
--
-- * Retry the above scenario, but now running this scenario on a multi player server, while connecting with one player to the mission. Watch the consistency of the messages.
--
-- ## Run this mission in DCS Multiple Player, with two to three players simultaneously:
--
-- * Retry the above scenario running this scenario on a multi player server, while connecting with two or three players to the mission. Watch the consistency of the messages.
-- * When the first player has accepted the Task, the 2nd and 3rd player joining the Task, will be automatically assigned to the Task.
--
-- ## Others things to watch out for:
--
-- * When flying to the attack zone, a message should appear every 30 seconds with the coordinates.
-- * When in the attack zone, a message should appear every 30 seconds how many targes are left within the task.
-- * When a player aborts the task, a message is displayed of the player aborting, but only to the group assigned to execute the task.
-- * When a player joins the task, a message is displayed of the player joining, but only to the group assigned to execute the task.
-- * When a player crashes into the ground, a message is displayed of that event.
-- * In multi player, when the Task was assigned to the group, but all players in that group aborted the Task, the Task should become Aborted. It will be replanned in 30 seconds.
--
-- # Status: TESTING - 15 Dec 2016
-- Create the HQ object.
local HQ = COMMANDCENTER:New( GROUP:FindByName( "HQ" ) )
@ -64,7 +122,7 @@ local SEADTask = TASK_BASE:New( Mission, SEADSet, "SEAD Radars Vector 1", "SEAD"
-- The reason why this is done, is that each unit as a role within the Task, and can have different status.
-- Therefore, the FsmSEAD is a TEMPLATE PROCESS of the TASK, and must be designed as a UNIT with a player is executing that PROCESS.
local SEADProcess = SEADTask:GetFsmTemplate()
local SEADProcess = SEADTask:GetUnitProcess()
-- Adding a new sub-process to the Task Template.
-- At first, the task needs to be accepted by a pilot.
@ -115,15 +173,16 @@ end
-- we check if the SEADTask has still AlivePlayers assigned to the Task.
-- If not, the Task will Abort.
-- And it will be Replanned within 30 seconds.
function SEADTask:OnAfterPlayerAborted( PlayerUnit, PlayerName )
function SEADTask:OnAfterPlayerCrashed( PlayerUnit, PlayerName )
if not SEADTask:HasAliveUnits() then
SEADTask:__Abort()
SEADTask:__Replan( 30 )
end
end
local TaskSEAD2 = TASK_BASE:New( Mission, SEADSet, "SEAD Radars Vector 2", "SEAD" ) -- Tasking.Task#TASK_BASE
TaskSEAD2:SetFsmTemplate( SEADTask:GetFsmTemplate():Copy() )
TaskSEAD2:SetUnitProcess( SEADTask:GetUnitProcess():Copy() )
Mission:AddTask( TaskSEAD2 )
Mission:RemoveTask(SEADTask)