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.
-- DONE: Payloads as resources.
-- TODO: Spawn in air or hot.
-- TODO: Define CAP zones.
-- TODO: Define TANKER zones for refuelling.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
+9 -1
View File
@@ -54,6 +54,7 @@
-- @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 Ops.AirWing#AIRWING airwing The assigned airwing.
-- @field #string squadname Name of the assigned Airwing squadron.
-- @field #table assets Airwing Assets assigned for this mission.
-- @field #number nassets Number of required assets by the Airwing.
@@ -436,6 +437,13 @@ function AUFTRAG:SetWeaponType(WeaponType)
return self
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
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -525,7 +533,7 @@ end
--- Get coordinate of target. First unit/group of the set is used.
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE The target coordinate or nil.
-- @return Core.Point#COORDINATE The target coordinate or nil.
function AUFTRAG:GetTargetCoordinate()
if self.engageTargetGroupset then
+5 -5
View File
@@ -3140,7 +3140,6 @@ function FLIGHTGROUP:onafterMissionStart(From, Event, To, Mission)
-- Set mission status.
Mission:Start()
--Mission.status=AUFTRAG.Status.STARTED
-- Route flight to mission zone.
self:RouteToMission(Mission, 5)
@@ -3159,19 +3158,20 @@ function FLIGHTGROUP:onafterMissionExecute(From, Event, To, Mission)
self:I(self.lid..text)
MESSAGE:New(text, 120, "DEBUG"):ToAllIf(true)
-- Set mission status.
Mission:Execute()
--Mission.status=AUFTRAG.Status.EXECUTING
end
--- On after "MissionCancel" event. Cancels the current mission.
--- On after "MissionCancel" event. Cancels the mission.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @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.
self:TaskCancel()
+101 -30
View File
@@ -17,7 +17,9 @@
-- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #string lid Class id string for output to DCS log file.
-- @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
--- Be surprised!
@@ -32,13 +34,14 @@
--
-- @field #INTEL
INTEL = {
ClassName = "INTEL",
Debug = nil,
lid = nil,
filter = nil,
detectionset = nil,
DetectedItems = {},
DetectedGroups = {},
ClassName = "INTEL",
Debug = nil,
lid = nil,
filter = nil,
detectionset = nil,
Contacts = {},
ContactsLost = {},
ContactsUnknown = {},
}
--- Detected item info.
@@ -56,7 +59,7 @@ INTEL = {
--- INTEL class version.
-- @field #string version
INTEL.version="0.0.1"
INTEL.version="0.0.2"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -87,9 +90,6 @@ function INTEL:New(DetectionSet)
-- Start State.
self:SetStartState("Stopped")
-- Init set of detected units.
self.detectedunits=SET_UNIT:New()
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
@@ -97,12 +97,8 @@ function INTEL:New(DetectionSet)
self:AddTransition("*", "Detect", "*") -- INTEL status update
self:AddTransition("*", "DetectedUnit", "*") --
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.
self:AddTransition("*", "NewContact", "*") --
self:AddTransition("*", "LostContact", "*") --
------------------------
@@ -153,12 +149,21 @@ end
-- User functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set livery.
--- Set accept zones.
-- @param #INTEL self
-- @param #string liveryname Name of the livery.
-- @param Core.Set#SET_ZONE AcceptZoneSet Set of accept zones
-- @return #INTEL self
function INTEL:SetLivery(liveryname)
self.livery=liveryname
function INTEL:SetAcceptZones(AcceptZoneSet)
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
@@ -175,7 +180,7 @@ end
function INTEL:onafterStart(From, Event, To)
-- 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)
-- Start the status monitoring.
@@ -197,8 +202,8 @@ function INTEL:onafterStatus(From, Event, To)
self:UpdateIntel()
-- 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())
self:I(self.sid..text)
local text=string.format("Status=%s", fsmstate)
self:I(self.lid..text)
self:__Status(-30)
@@ -224,12 +229,22 @@ function INTEL:UpdateIntel()
end
-- TODO: Filter units from accept/reject zones.
-- TODO: Filter unit types.
-- TODO: Filter detection methods?
self:CreateDetectedItems(DetectedSet)
--[[
-- Newly detected units.
local detectednew=DetectedSet:GetSetComplement(self.detectedunits)
-- Previously detected units which got lost.
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: Combine units to groups for all, new and lost.
-- TODO: process detected set asynchroniously for better performance.
@@ -259,34 +274,90 @@ function INTEL:CreateDetectedItems(detectedunitset)
for _,_group in pairs(detectedgroupset.Set) do
local group=_group --Wrapper.Group#GROUP
local detecteditem=self:GetDetectedItemByName(group:GetName())
local groupname=group:GetName()
local detecteditem=self:GetContactByName(groupname)
if detecteditem then
---
-- Detected item already exists ==> Update data.
---
detecteditem.Tdetected=timer.getAbsTime()
detecteditem.position=group:GetCoordinate()
else
---
-- 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
-- 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
--- Create detected items.
-- @param #INTEL self
-- @param #string name Name of the detected item.
-- @param #string groupname Name of the contact group.
-- @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
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+135 -36
View File
@@ -17,7 +17,8 @@
-- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #string lid Class id string for output to DCS log file.
-- @field #table airwings Table of airwings.
-- @extends Core.Fsm#FSM
-- @field #table missionqueue Mission queue.
-- @extends Ops.Intelligence#INTEL
--- Be surprised!
--
@@ -35,22 +36,21 @@ WINGCOMMANDER = {
Debug = nil,
lid = nil,
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.
-- @type WINGCOMMANDER.Recourses
--
-- @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.
--- Contact details.
-- @type WINGCOMMANDER.Contact
-- @field Ops.Auftrag#AUFTRAG mission The assigned mission.
-- @extends Ops.Intelligence#INTEL.DetectedItem
--- WINGCOMMANDER class version.
-- @field #string version
@@ -84,9 +84,7 @@ function WINGCOMMANDER:New(AgentSet)
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Sitrep", "*") -- WINGCOMMANDER status update
--self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
------------------------
@@ -110,12 +108,12 @@ function WINGCOMMANDER:New(AgentSet)
-- @param #WINGCOMMANDER self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "FlightStatus".
-- @function [parent=#WINGCOMMANDER] WingCommanderStatus
--- Triggers the FSM event "Status".
-- @function [parent=#WINGCOMMANDER] Status
-- @param #WINGCOMMANDER self
--- Triggers the FSM event "SkipperStatus" after a delay.
-- @function [parent=#WINGCOMMANDER] __WingCommanderStatus
-- @function [parent=#WINGCOMMANDER] __Status
-- @param #WINGCOMMANDER self
-- @param #number delay Delay in seconds.
@@ -167,8 +165,10 @@ function WINGCOMMANDER:onafterStart(From, Event, To)
local text=string.format("Starting Wing Commander")
self:I(self.lid..text)
-- Start the status monitoring.
self:__SitRep(-1)
-- Start parent INTEL.
self:GetParent(self).onafterStart(self, From, Event, To)
end
--- On after "Sitrep" event.
@@ -177,18 +177,19 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @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.
local fsmstate=self:GetState()
-- Short info.
local text=string.format("No activities")
local capabilities=self:CheckResources()
--local capabilities=self:CheckResources()
-- Number of assets total, on mission, available
-- Number of assets available of each mission type.
@@ -196,10 +197,25 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To)
self:I(self.lid..text)
if DetectedGroupsUnknown then
for _,_group in pairs(DetectedGroupsUnknown) do
local group=_group --Wrapper.Group#GROUP
-- Clean up missions where the contact was lost.
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
@@ -207,14 +223,11 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To)
local attribute=group:GetAttribute()
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
--TODO: Something like get closest AIRWING or squadron?
-- Launch even from multiple airwings? Currently Navail is like this.
end
if category==Group.Category.AIRPLANE or category==Group.Category.HELICOPTER then
mission=AUFTRAG:NewINTERCEPT(group)
elseif category==Group.Category.GROUND then
@@ -231,27 +244,113 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To)
end
mission=AUFTRAG:NewBAI(group)
elseif category==Group.Category.SHIP then
--TODO: ANTISHIP
end
-- Add mission to queue.
if mission then
table.insert(self.missionqueue, mission)
end
end
end
end
-- Check mission queue and assign one PLANNED mission.
self:CheckMissionQueue()
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 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.
-- @param #WINGCOMMANDER self
-- @return #table
@@ -266,10 +365,10 @@ function WINGCOMMANDER:CheckResources()
local airwing=_airwing --Ops.AirWing#AIRWING
-- 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.
capabilities[MissionType]=capabilities[MissionType]+nassets
capabilities[MissionType]=capabilities[MissionType]+#assets
end
end