This commit is contained in:
Frank
2020-03-03 16:48:05 +01:00
parent 9ea52fce28
commit ae3d1f6b2a
5 changed files with 252 additions and 72 deletions
+2
View File
@@ -85,6 +85,8 @@ AIRWING.version="0.1.3"
-- TODO: Check if missions are accomplished. -- TODO: Check if missions are accomplished.
-- DONE: Payloads as resources. -- DONE: Payloads as resources.
-- TODO: Spawn in air or hot. -- TODO: Spawn in air or hot.
-- TODO: Define CAP zones.
-- TODO: Define TANKER zones for refuelling.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor -- Constructor
+9 -1
View File
@@ -54,6 +54,7 @@
-- @field Wrapper.Group#GROUP escortGroup The group to be escorted. -- @field Wrapper.Group#GROUP escortGroup The group to be escorted.
-- @field DCS#Vec3 escortVec3 The 3D offset vector from the escorted group to the escort group. -- @field DCS#Vec3 escortVec3 The 3D offset vector from the escorted group to the escort group.
-- --
-- @field Ops.AirWing#AIRWING airwing The assigned airwing.
-- @field #string squadname Name of the assigned Airwing squadron. -- @field #string squadname Name of the assigned Airwing squadron.
-- @field #table assets Airwing Assets assigned for this mission. -- @field #table assets Airwing Assets assigned for this mission.
-- @field #number nassets Number of required assets by the Airwing. -- @field #number nassets Number of required assets by the Airwing.
@@ -436,6 +437,13 @@ function AUFTRAG:SetWeaponType(WeaponType)
return self return self
end end
--- Check if mission is executing.
-- @param #AUFTRAG self
-- @return #boolean If true, mission is currently executing.
function AUFTRAG:IsExecuting()
return self.status==AUFTRAG.Status.EXECUTING
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions -- FSM Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -525,7 +533,7 @@ end
--- Get coordinate of target. First unit/group of the set is used. --- Get coordinate of target. First unit/group of the set is used.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Core.Point#COORDINATE The target coordinate or nil. -- @return Core.Point#COORDINATE The target coordinate or nil.
function AUFTRAG:GetTargetCoordinate() function AUFTRAG:GetTargetCoordinate()
if self.engageTargetGroupset then if self.engageTargetGroupset then
+5 -5
View File
@@ -3140,7 +3140,6 @@ function FLIGHTGROUP:onafterMissionStart(From, Event, To, Mission)
-- Set mission status. -- Set mission status.
Mission:Start() Mission:Start()
--Mission.status=AUFTRAG.Status.STARTED
-- Route flight to mission zone. -- Route flight to mission zone.
self:RouteToMission(Mission, 5) self:RouteToMission(Mission, 5)
@@ -3159,19 +3158,20 @@ function FLIGHTGROUP:onafterMissionExecute(From, Event, To, Mission)
self:I(self.lid..text) self:I(self.lid..text)
MESSAGE:New(text, 120, "DEBUG"):ToAllIf(true) MESSAGE:New(text, 120, "DEBUG"):ToAllIf(true)
-- Set mission status.
Mission:Execute() Mission:Execute()
--Mission.status=AUFTRAG.Status.EXECUTING
end end
--- On after "MissionCancel" event. Cancels the current mission. --- On after "MissionCancel" event. Cancels the mission.
-- @param #FLIGHTGROUP self -- @param #FLIGHTGROUP self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function FLIGHTGROUP:onafterMissionCancel(From, Event, To) -- @param Ops.Auftrag#AUFTRAG Mission The mission to be cancelled.
function FLIGHTGROUP:onafterMissionCancel(From, Event, To, Mission)
if self.currentmission then if Mission.auftragsnummer==self.currentmission then
-- Cancelling the mission is actually cancelling the current task. -- Cancelling the mission is actually cancelling the current task.
self:TaskCancel() self:TaskCancel()
+101 -30
View File
@@ -17,7 +17,9 @@
-- @field #boolean Debug Debug mode. Messages to all about status. -- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #table filter Category filters. -- @field #table filter Category filters.
-- @field #table DetectedItems Table of detected items. -- @field #table Contacts Table of detected items.
-- @field #table ContactsLost Table of lost detected items.
-- @field #table ContactsUnknown Table of new detected items.
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Be surprised! --- Be surprised!
@@ -32,13 +34,14 @@
-- --
-- @field #INTEL -- @field #INTEL
INTEL = { INTEL = {
ClassName = "INTEL", ClassName = "INTEL",
Debug = nil, Debug = nil,
lid = nil, lid = nil,
filter = nil, filter = nil,
detectionset = nil, detectionset = nil,
DetectedItems = {}, Contacts = {},
DetectedGroups = {}, ContactsLost = {},
ContactsUnknown = {},
} }
--- Detected item info. --- Detected item info.
@@ -56,7 +59,7 @@ INTEL = {
--- INTEL class version. --- INTEL class version.
-- @field #string version -- @field #string version
INTEL.version="0.0.1" INTEL.version="0.0.2"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list -- ToDo list
@@ -87,9 +90,6 @@ function INTEL:New(DetectionSet)
-- Start State. -- Start State.
self:SetStartState("Stopped") self:SetStartState("Stopped")
-- Init set of detected units.
self.detectedunits=SET_UNIT:New()
-- Add FSM transitions. -- Add FSM transitions.
-- From State --> Event --> To State -- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM. self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
@@ -97,12 +97,8 @@ function INTEL:New(DetectionSet)
self:AddTransition("*", "Detect", "*") -- INTEL status update self:AddTransition("*", "Detect", "*") -- INTEL status update
self:AddTransition("*", "DetectedUnit", "*") -- self:AddTransition("*", "NewContact", "*") --
self:AddTransition("*", "LostContact", "*") --
self:AddTransition("*", "DetectedGroups", "*") -- All groups that are currently detected.
self:AddTransition("*", "DetectedGroupsUnknown", "*") -- Newly detected groups, which were previously unknown.
self:AddTransition("*", "DetectedGroupsDead", "*") -- Previously detected groups that could not be detected any more.
self:AddTransition("*", "DetectedGroupsLost", "*") -- Previously detected groups that could not be detected any more.
------------------------ ------------------------
@@ -153,12 +149,21 @@ end
-- User functions -- User functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set livery. --- Set accept zones.
-- @param #INTEL self -- @param #INTEL self
-- @param #string liveryname Name of the livery. -- @param Core.Set#SET_ZONE AcceptZoneSet Set of accept zones
-- @return #INTEL self -- @return #INTEL self
function INTEL:SetLivery(liveryname) function INTEL:SetAcceptZones(AcceptZoneSet)
self.livery=liveryname self.acceptzoneset=AcceptZoneSet or SET_ZONE:New()
return self
end
--- Set accept zones.
-- @param #INTEL self
-- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set.
-- @return #INTEL self
function INTEL:AddAcceptZone(AcceptZone)
self.acceptzoneset=nil
end end
@@ -175,7 +180,7 @@ end
function INTEL:onafterStart(From, Event, To) function INTEL:onafterStart(From, Event, To)
-- Short info. -- Short info.
local text=string.format("Starting flight group %s.", self.groupname) local text=string.format("Starting INTEL v%s.", self.version)
self:I(self.sid..text) self:I(self.sid..text)
-- Start the status monitoring. -- Start the status monitoring.
@@ -197,8 +202,8 @@ function INTEL:onafterStatus(From, Event, To)
self:UpdateIntel() self:UpdateIntel()
-- Short info. -- Short info.
local text=string.format("Flight status %s [%d/%d]. Task=%d/%d. Waypoint=%d/%d. Detected=%d", fsmstate, #self.element, #self.element, self.taskcurrent, #self.taskqueue, self.currentwp or 0, #self.waypoints or 0, self.detectedunits:Count()) local text=string.format("Status=%s", fsmstate)
self:I(self.sid..text) self:I(self.lid..text)
self:__Status(-30) self:__Status(-30)
@@ -224,12 +229,22 @@ function INTEL:UpdateIntel()
end end
-- TODO: Filter units from accept/reject zones.
-- TODO: Filter unit types.
-- TODO: Filter detection methods?
self:CreateDetectedItems(DetectedSet)
--[[
-- Newly detected units. -- Newly detected units.
local detectednew=DetectedSet:GetSetComplement(self.detectedunits) local detectednew=DetectedSet:GetSetComplement(self.detectedunits)
-- Previously detected units which got lost. -- Previously detected units which got lost.
local detectedlost=self.detectedunits:GetSetComplement(DetectedSet) local detectedlost=self.detectedunits:GetSetComplement(DetectedSet)
]]
-- TODO: Loose units only if they remain undetected for a given time interval. We want to avoid fast oscillation between detected/lost states. Maybe 1-5 min would be a good time interval?! -- TODO: Loose units only if they remain undetected for a given time interval. We want to avoid fast oscillation between detected/lost states. Maybe 1-5 min would be a good time interval?!
-- TODO: Combine units to groups for all, new and lost. -- TODO: Combine units to groups for all, new and lost.
-- TODO: process detected set asynchroniously for better performance. -- TODO: process detected set asynchroniously for better performance.
@@ -259,34 +274,90 @@ function INTEL:CreateDetectedItems(detectedunitset)
for _,_group in pairs(detectedgroupset.Set) do for _,_group in pairs(detectedgroupset.Set) do
local group=_group --Wrapper.Group#GROUP local group=_group --Wrapper.Group#GROUP
local detecteditem=self:GetDetectedItemByName(group:GetName()) local groupname=group:GetName()
local detecteditem=self:GetContactByName(groupname)
if detecteditem then if detecteditem then
--- ---
-- Detected item already exists ==> Update data. -- Detected item already exists ==> Update data.
--- ---
detecteditem.Tdetected=timer.getAbsTime()
detecteditem.position=group:GetCoordinate()
else else
--- ---
-- Detected item does not exist in our list yet. -- Detected item does not exist in our list yet.
--- ---
local item={} --#INTEL.DetectedItem
item.groupname=groupname
item.Tdetected=timer.getAbsTime()
item.group=group
item.position=group:GetCoordinate()
item.typename=group:GetTypeName()
item.attribute=group:GetAttribute()
item.category=group:GetCategory()
item.categoryname=group:GetCategoryName()
self:AddContact(item)
end end
end end
-- Now check if there some groups could not be detected any more.
for i=#self.Contacts,1,-1 do
local item=self.Contacts[i] --#INTEL.DetectedItem
local group=detectedgroupset:FindGroup(item.groupname)
if not group then
--TODO: check if deltaT>Tforget. we dont want quick oszillations between detected and undetected states.
self:RemoveContact(item)
end
end
end end
--- Create detected items. --- Create detected items.
-- @param #INTEL self -- @param #INTEL self
-- @param #string name Name of the detected item. -- @param #string groupname Name of the contact group.
-- @return #INTEL.DetectedItem -- @return #INTEL.DetectedItem
function INTEL:GetDetectedItemByName(name) function INTEL:GetContactByName(groupname)
return self.DetectedItems[name] for i,_contact in pairs(self.Contacts) do
local contact=_contact --#INTEL.DetectedItem
if contact.groupname==groupname then
return contact
end
end
return nil
end
--- Remove a contact from our list.
-- @param #INTEL self
-- @param #INTEL.DetectedItem Contact The contact to be removed.
function INTEL:RemoveContact(Contact)
for i,_contact in pairs(self.Contacts) do
local contact=_contact --#INTEL.DetectedItem
if contact.groupname==Contact.groupname then
table.remove(self.Contacts, i)
end
end
end
--- Remove a contact from our list.
-- @param #INTEL self
-- @param #INTEL.DetectedItem Contact The contact to be removed.
function INTEL:AddContact(Contact)
table.insert(self.Contacts, Contact)
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+135 -36
View File
@@ -17,7 +17,8 @@
-- @field #boolean Debug Debug mode. Messages to all about status. -- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #table airwings Table of airwings. -- @field #table airwings Table of airwings.
-- @extends Core.Fsm#FSM -- @field #table missionqueue Mission queue.
-- @extends Ops.Intelligence#INTEL
--- Be surprised! --- Be surprised!
-- --
@@ -35,22 +36,21 @@ WINGCOMMANDER = {
Debug = nil, Debug = nil,
lid = nil, lid = nil,
airwings = {}, airwings = {},
missionqueue = {},
} }
--- Mission capability.
-- @type WINGCOMMANDER.Capability
-- @field #string missiontype Mission Type.
-- @field #number Ntot Total number of assets for this task.
-- @field #number Navail Number of available assets
-- @field #number Nonmission Number of assets currently on mission.
--- Mission resources. --- Mission resources.
-- @type WINGCOMMANDER.Recourses -- @type WINGCOMMANDER.Recourses
--
-- @field #string missiontype Mission Type. -- @field #string missiontype Mission Type.
-- @field #number Ntot Total number of assets for this task. -- @field #number Ntot Total number of assets for this task.
-- @field #number Navail Number of available assets -- @field #number Navail Number of available assets
-- @field #number Nonmission Number of assets currently on mission. -- @field #number Nonmission Number of assets currently on mission.
--- Contact details.
-- @type WINGCOMMANDER.Contact
-- @field Ops.Auftrag#AUFTRAG mission The assigned mission.
-- @extends Ops.Intelligence#INTEL.DetectedItem
--- WINGCOMMANDER class version. --- WINGCOMMANDER class version.
-- @field #string version -- @field #string version
@@ -84,9 +84,7 @@ function WINGCOMMANDER:New(AgentSet)
-- Add FSM transitions. -- Add FSM transitions.
-- From State --> Event --> To State -- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM. --self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Sitrep", "*") -- WINGCOMMANDER status update
------------------------ ------------------------
@@ -110,12 +108,12 @@ function WINGCOMMANDER:New(AgentSet)
-- @param #WINGCOMMANDER self -- @param #WINGCOMMANDER self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- Triggers the FSM event "FlightStatus". --- Triggers the FSM event "Status".
-- @function [parent=#WINGCOMMANDER] WingCommanderStatus -- @function [parent=#WINGCOMMANDER] Status
-- @param #WINGCOMMANDER self -- @param #WINGCOMMANDER self
--- Triggers the FSM event "SkipperStatus" after a delay. --- Triggers the FSM event "SkipperStatus" after a delay.
-- @function [parent=#WINGCOMMANDER] __WingCommanderStatus -- @function [parent=#WINGCOMMANDER] __Status
-- @param #WINGCOMMANDER self -- @param #WINGCOMMANDER self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
@@ -167,8 +165,10 @@ function WINGCOMMANDER:onafterStart(From, Event, To)
local text=string.format("Starting Wing Commander") local text=string.format("Starting Wing Commander")
self:I(self.lid..text) self:I(self.lid..text)
-- Start the status monitoring. -- Start parent INTEL.
self:__SitRep(-1) self:GetParent(self).onafterStart(self, From, Event, To)
end end
--- On after "Sitrep" event. --- On after "Sitrep" event.
@@ -177,18 +177,19 @@ end
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function WINGCOMMANDER:onafterSitrep(From, Event, To) function WINGCOMMANDER:onafterStatus(From, Event, To)
-- Start parent INTEL.
self:GetParent(self).onafterStatus(self, From, Event, To)
-- FSM state. -- FSM state.
local fsmstate=self:GetState() local fsmstate=self:GetState()
-- Short info. -- Short info.
local text=string.format("No activities") local text=string.format("No activities")
local capabilities=self:CheckResources() --local capabilities=self:CheckResources()
-- Number of assets total, on mission, available -- Number of assets total, on mission, available
-- Number of assets available of each mission type. -- Number of assets available of each mission type.
@@ -196,10 +197,25 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To)
self:I(self.lid..text) self:I(self.lid..text)
if DetectedGroupsUnknown then
for _,_group in pairs(DetectedGroupsUnknown) do -- Clean up missions where the contact was lost.
local group=_group --Wrapper.Group#GROUP for _,_contact in pairs(self.ContactsLost) do
local contact=_contact --#WINGCOMMANDER.Contact
if contact.mission and contact.mission.airwing then
-- Cancel this mission.
contact.mission.airwing:MissionCancel(contact.mission)
end
end
-- Create missions for all new contacts.
for _,_contact in pairs(self.ContactsUnknown) do
local contact=_contact --#WINGCOMMANDER.Contact
local group=contact.group --Wrapper.Group#GROUP
if group and group:IsAlive() then if group and group:IsAlive() then
@@ -207,14 +223,11 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To)
local attribute=group:GetAttribute() local attribute=group:GetAttribute()
local threatlevel=group:GetThreatLevel() local threatlevel=group:GetThreatLevel()
if category==Group.Category.AIRPLANE or category==Group.Category.HELICOPTER then local mission=nil --Ops.Auftrag#AUFTRAG
if capability.INTERCEPT.Navail>0 then if category==Group.Category.AIRPLANE or category==Group.Category.HELICOPTER then
--TODO: Something like get closest AIRWING or squadron? mission=AUFTRAG:NewINTERCEPT(group)
-- Launch even from multiple airwings? Currently Navail is like this.
end
elseif category==Group.Category.GROUND then elseif category==Group.Category.GROUND then
@@ -231,27 +244,113 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To)
end end
mission=AUFTRAG:NewBAI(group)
elseif category==Group.Category.SHIP then elseif category==Group.Category.SHIP then
--TODO: ANTISHIP --TODO: ANTISHIP
end end
-- Add mission to queue.
if mission then
table.insert(self.missionqueue, mission)
end
end end
end end
end -- Check mission queue and assign one PLANNED mission.
self:CheckMissionQueue()
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Resources -- Resources
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Check mission queue and assign ONE planned mission.
-- @param #WINGCOMMANDER self
function WINGCOMMANDER:CheckMissionQueue()
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
-- We look for PLANNED missions.
if mission.status==AUFTRAG.Status.PLANNED then
---
-- PLANNNED Mission
---
-- Table of airwings that can do the mission.
local airwings={}
-- Loop over all airwings.
for _,_airwing in pairs(self.airwings) do
local airwing=_airwing --Ops.AirWing#AIRWING
-- Check if airwing can do this mission.
local can,assets=airwing:CanMission(mission.type, mission.nassets)
-- Can it?
if can then
-- Get coordinate of the target.
local coord=mission:GetTargetCoordinate()
if coord then
-- Distance from airwing to target.
local dist=coord:Get2DDistance(airwing:GetCoordinate())
-- Add airwing to table of airwings that can.
table.insert(airwings, {airwing=airwing, dist=dist, targetcoord=coord})
end
end
end
-- Can anyone?
if #airwings>0 then
-- Sort table wrt distace
local function sortdist(a,b)
return a.dist<b.dist
end
table.sort(airwings, sortdist)
local airwing=airwings[1].airwing --Ops.AirWing#AIRWING
local targetcoord=airwings[1].targetcoord --Core.Point#COORDINATE
-- Get waypoint coordinate. This is where the mission is actually executed.
local WaypointCoordinate=airwing:GetCoordinate():GetIntermediateCoordinate(targetcoord, 0.5)
-- Add mission to airwing.
airwing:AddMission(mission, Nassets, WaypointCoordinate)
return
end
else
---
-- Missions NOT in PLANNED state
---
end
end
end
--- Check resources. --- Check resources.
-- @param #WINGCOMMANDER self -- @param #WINGCOMMANDER self
-- @return #table -- @return #table
@@ -266,10 +365,10 @@ function WINGCOMMANDER:CheckResources()
local airwing=_airwing --Ops.AirWing#AIRWING local airwing=_airwing --Ops.AirWing#AIRWING
-- Get Number of assets that can do this type of missions. -- Get Number of assets that can do this type of missions.
local _,nassets=airwing:CanMission(MissionType) local _,assets=airwing:CanMission(MissionType)
-- Add up airwing resources. -- Add up airwing resources.
capabilities[MissionType]=capabilities[MissionType]+nassets capabilities[MissionType]=capabilities[MissionType]+#assets
end end
end end