Fixed bugs found in v0.0.2
This commit is contained in:
@@ -1,69 +1,88 @@
|
||||
|
||||
---@class CapBase : OnStageChangedListener
|
||||
---@field groupNames Array<string>
|
||||
---@field database Database
|
||||
---@field airbaseName string
|
||||
---@field logger table
|
||||
---@field activeStage number
|
||||
---@field capConfig table
|
||||
---@field activeCapStages number
|
||||
---@field lastStatesByName table<string, string>
|
||||
---@field groupsByName table<string, CapGroup>
|
||||
---@field PrimaryGroups Array<CapGroup>
|
||||
---@field BackupGroups Array<CapGroup>
|
||||
local CapBase = {}
|
||||
|
||||
|
||||
local CheckReschedulingAsync = function(self, time)
|
||||
self:CheckAndScheduleCAP()
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param airbaseId number
|
||||
---@param database table
|
||||
---@param airbaseName string
|
||||
---@param database Database
|
||||
---@param logger table
|
||||
---@param capConfig table
|
||||
---@param stageConfig table
|
||||
---@return table
|
||||
function CapBase:new(airbaseId, database, logger, capConfig, stageConfig)
|
||||
local o = {}
|
||||
setmetatable(o, { __index = self })
|
||||
---@return CapBase
|
||||
function CapBase.new(airbaseName, database, logger, capConfig, stageConfig)
|
||||
|
||||
CapBase.__index = CapBase
|
||||
local self = setmetatable({}, { __index = CapBase }) --[[@as CapBase]]
|
||||
|
||||
o.groupNames = database:getCapGroupsAtAirbase(airbaseId)
|
||||
o.database = database
|
||||
o.airbaseId = airbaseId
|
||||
o.logger = logger
|
||||
o.activeStage = 0
|
||||
o.capConfig = capConfig
|
||||
o.activeCapStages = (stageConfig or {}).capActiveStages or 10
|
||||
self.groupNames = database:getCapGroupsAtAirbase(airbaseName)
|
||||
self.database = database
|
||||
|
||||
self.airbaseName = airbaseName
|
||||
self.logger = logger
|
||||
self.activeStage = 0
|
||||
self.capConfig = capConfig
|
||||
self.activeCapStages = (stageConfig or {}).capActiveStages or 10
|
||||
|
||||
o.lastStatesByName = {}
|
||||
o.groupsByName = {}
|
||||
o.PrimaryGroups = {}
|
||||
o.BackupGroups = {}
|
||||
self.lastStatesByName = {}
|
||||
self.groupsByName = {}
|
||||
self.PrimaryGroups = {}
|
||||
self.BackupGroups = {}
|
||||
|
||||
local CheckReschedulingAsync = function(self, time)
|
||||
self:CheckAndScheduleCAP()
|
||||
end
|
||||
|
||||
o.OnGroupStateUpdated = function (self, capGroup)
|
||||
--[[
|
||||
There is no update needed for INTRANSIT, ONSTATION or REARMING as the PREVIOUS state already was checked and nothing changes in the actual overal state.
|
||||
]]--
|
||||
if capGroup.state == Spearhead.internal.CapGroup.GroupState.INTRANSIT
|
||||
or capGroup.state == Spearhead.internal.CapGroup.GroupState.ONSTATION
|
||||
or capGroup.state == Spearhead.internal.CapGroup.GroupState.REARMING
|
||||
then
|
||||
return
|
||||
end
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 1)
|
||||
end
|
||||
|
||||
for key, name in pairs(o.groupNames) do
|
||||
local capGroup = Spearhead.internal.CapGroup:new(name, airbaseId, logger, database, capConfig)
|
||||
for key, name in pairs(self.groupNames) do
|
||||
local capGroup = Spearhead.internal.CapGroup.new(name, airbaseName, logger, database, capConfig)
|
||||
if capGroup then
|
||||
o.groupsByName[name] = capGroup
|
||||
self.groupsByName[name] = capGroup
|
||||
|
||||
if capGroup.isBackup ==true then
|
||||
table.insert(o.BackupGroups, capGroup)
|
||||
table.insert(self.BackupGroups, capGroup)
|
||||
else
|
||||
table.insert(o.PrimaryGroups, capGroup)
|
||||
table.insert(self.PrimaryGroups, capGroup)
|
||||
end
|
||||
|
||||
capGroup:AddOnStateUpdatedListener(o)
|
||||
capGroup:AddOnStateUpdatedListener(self)
|
||||
end
|
||||
end
|
||||
logger:info("Airbase with Id '" .. airbaseId .. "' has a total of " .. Spearhead.Util.tableLength(o.groupsByName) .. "cap flights registered")
|
||||
logger:info("Airbase with name '" .. airbaseName .. "' has a total of " .. Spearhead.Util.tableLength(self.groupsByName) .. "cap flights registered")
|
||||
|
||||
o.SpawnIfApplicable = function(self)
|
||||
self.logger:debug("Check spawns for airbase " .. self.airbaseId )
|
||||
|
||||
Spearhead.Events.AddStageNumberChangedListener(self)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function CapBase:onGroupStateUpdated(capGroup)
|
||||
--[[
|
||||
There is no update needed for INTRANSIT, ONSTATION or REARMING as the PREVIOUS state already was checked and nothing changes in the actual overal state.
|
||||
]]--
|
||||
if capGroup.state == Spearhead.internal.CapGroup.GroupState.INTRANSIT
|
||||
or capGroup.state == Spearhead.internal.CapGroup.GroupState.ONSTATION
|
||||
or capGroup.state == Spearhead.internal.CapGroup.GroupState.REARMING
|
||||
then
|
||||
return
|
||||
end
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 1)
|
||||
end
|
||||
|
||||
function CapBase:SpawnIfApplicable()
|
||||
self.logger:debug("Check spawns for airbase " .. self.airbaseName )
|
||||
for groupName, capGroup in pairs(self.groupsByName) do
|
||||
|
||||
local activeStage = tostring(self.activeStage)
|
||||
local targetStage = capGroup:GetTargetZone(activeStage)
|
||||
local targetStage = capGroup:GetTargetZone(self.activeStage)
|
||||
|
||||
if targetStage ~= nil and capGroup.state == Spearhead.internal.CapGroup.GroupState.UNSPAWNED then
|
||||
capGroup:SpawnOnTheRamp()
|
||||
@@ -71,9 +90,9 @@ function CapBase:new(airbaseId, database, logger, capConfig, stageConfig)
|
||||
end
|
||||
end
|
||||
|
||||
o.CheckAndScheduleCAP = function (self)
|
||||
function CapBase:CheckAndScheduleCAP()
|
||||
|
||||
self.logger:debug("Check taskings for airbase " .. self.airbaseId )
|
||||
self.logger:debug("Check taskings for airbase " .. self.airbaseName )
|
||||
|
||||
local countPerStage = {}
|
||||
local requiredPerStage = {}
|
||||
@@ -156,29 +175,25 @@ function CapBase:new(airbaseId, database, logger, capConfig, stageConfig)
|
||||
end
|
||||
end
|
||||
|
||||
o.OnStageNumberChanged = function (self, number)
|
||||
self.activeStage = number
|
||||
self:SpawnIfApplicable()
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 5)
|
||||
end
|
||||
|
||||
---Check if any CAP is active when a certain stage is active
|
||||
---@param self table
|
||||
---@param stageNumber number
|
||||
---@return boolean
|
||||
o.IsBaseActiveWhenStageIsActive = function (self, stageNumber)
|
||||
for _, group in pairs(self.PrimaryGroups) do
|
||||
local target = group:GetTargetZone(stageNumber)
|
||||
if target ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
Spearhead.Events.AddStageNumberChangedListener(o)
|
||||
return o
|
||||
function CapBase:OnStageNumberChanged(number)
|
||||
self.activeStage = number
|
||||
self:SpawnIfApplicable()
|
||||
timer.scheduleFunction(CheckReschedulingAsync, self, timer.getTime() + 5)
|
||||
end
|
||||
|
||||
|
||||
---@param stageNumber number
|
||||
---@return boolean
|
||||
function CapBase:IsBaseActiveWhenStageIsActive(stageNumber)
|
||||
for _, group in pairs(self.PrimaryGroups) do
|
||||
local target = group:GetTargetZone(stageNumber)
|
||||
if target ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
if not Spearhead.internal then Spearhead.internal = {} end
|
||||
Spearhead.internal.CapAirbase = CapBase
|
||||
+294
-274
@@ -77,7 +77,7 @@ local function setTaskAsync(input, time)
|
||||
local groupName = input.groupName
|
||||
local group = Group.getByName(groupName)
|
||||
|
||||
if task then
|
||||
if task and group then
|
||||
group:getController():setTask(task)
|
||||
if input.logger ~= nil then
|
||||
input.logger:debug("task set succesfully to group " .. groupName)
|
||||
@@ -86,6 +86,21 @@ local function setTaskAsync(input, time)
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
---@class OnUpdateListener
|
||||
---@field onGroupStateUpdated fun(self: OnUpdateListener, capGroup: CapGroup)
|
||||
|
||||
---@class CapGroup : OnUnitLostListener
|
||||
---@field isBackup boolean
|
||||
---@field groupName string
|
||||
---@field assignedStageNumber string
|
||||
---@field private airbaseName string
|
||||
---@field private logger Logger
|
||||
---@field private database Database
|
||||
---@field private capConfig table
|
||||
---@field private capZonesConfig table<string, string>
|
||||
---@field private aliveUnits table<string, boolean>
|
||||
---@field private onStatusUpdatedListener Array<OnUpdateListener>
|
||||
local CapGroup = {}
|
||||
|
||||
CapGroup.GroupState = {
|
||||
@@ -103,300 +118,305 @@ local function SetReadyOnRampAsync(self, time)
|
||||
self:SetState(CapGroup.GroupState.READYONRAMP)
|
||||
end
|
||||
|
||||
local RESPAWN_AFTER_TOUCHDOWN_SECONDS = 180
|
||||
|
||||
---comment
|
||||
---@param groupName string
|
||||
---@param airbaseId number
|
||||
---@param logger table logger dependency injection
|
||||
---@param database table database dependency injection
|
||||
---@param airbaseName string
|
||||
---@param logger Logger logger dependency injection
|
||||
---@param database Database database dependency injection
|
||||
---@param capConfig table config dependency injection
|
||||
---@return table? o
|
||||
function CapGroup:new(groupName, airbaseId, logger, database, capConfig)
|
||||
local o = {}
|
||||
setmetatable(o, { __index = self })
|
||||
---@return CapGroup? self
|
||||
function CapGroup.new(groupName, airbaseName, logger, database, capConfig)
|
||||
|
||||
local RESPAWN_AFTER_TOUCHDOWN_SECONDS = 180
|
||||
CapGroup.__index = CapGroup
|
||||
local self = setmetatable({}, CapGroup)
|
||||
|
||||
Spearhead.DcsUtil.DestroyGroup(groupName)
|
||||
|
||||
-- initials
|
||||
o.groupName = groupName
|
||||
o.airbaseId = airbaseId
|
||||
o.logger = logger
|
||||
o.database = database
|
||||
self.groupName = groupName
|
||||
self.airbaseName = airbaseName
|
||||
|
||||
local airbase = Airbase.getByName(airbaseName)
|
||||
if airbase == nil then
|
||||
logger:error("Airbase with name " .. airbaseName .. " does not exist")
|
||||
return nil
|
||||
end
|
||||
|
||||
self.airbaseId = airbase:getID()
|
||||
self.logger = logger
|
||||
self.database = database
|
||||
|
||||
local parsed = CapHelper.ParseGroupName(groupName)
|
||||
if parsed == nil then return nil end
|
||||
o.capZonesConfig = parsed.zonesConfig
|
||||
o.isBackup = parsed.isBackup
|
||||
self.capZonesConfig = parsed.zonesConfig
|
||||
self.isBackup = parsed.isBackup
|
||||
|
||||
--vars
|
||||
o.assignedStageNumber = nil
|
||||
self.assignedStageNumber = nil
|
||||
|
||||
o.state = CapGroup.GroupState.UNSPAWNED
|
||||
o.aliveUnits = {}
|
||||
o.landedUnits = {}
|
||||
o.unitCount = 0
|
||||
o.onStationSince = 0
|
||||
o.currentCapTaskingDuration = 0
|
||||
o.markedForDespawn = false
|
||||
self.state = CapGroup.GroupState.UNSPAWNED
|
||||
self.aliveUnits = {}
|
||||
self.landedUnits = {}
|
||||
self.unitCount = 0
|
||||
self.onStationSince = 0
|
||||
self.currentCapTaskingDuration = 0
|
||||
self.markedForDespawn = false
|
||||
|
||||
self.onStatusUpdatedListener = {}
|
||||
|
||||
--config
|
||||
o.capConfig = capConfig
|
||||
self.capConfig = capConfig
|
||||
|
||||
---comment
|
||||
---@param self table
|
||||
---@param currentActive number
|
||||
---@return table
|
||||
o.GetTargetZone = function (self, currentActive)
|
||||
return self.capZonesConfig[tostring(currentActive)]
|
||||
end
|
||||
|
||||
o.SetState = function(self, state)
|
||||
self.state = state
|
||||
self:PublishUnitUpdatedEvent()
|
||||
end
|
||||
|
||||
o.StartRearm = function(self)
|
||||
self:SpawnOnTheRamp()
|
||||
self:SetState(CapGroup.GroupState.REARMING)
|
||||
timer.scheduleFunction(SetReadyOnRampAsync, self, timer.getTime() + self.capConfig:getRearmDelay() - RESPAWN_AFTER_TOUCHDOWN_SECONDS)
|
||||
end
|
||||
|
||||
o.SpawnOnTheRamp = function(self)
|
||||
self.markedForDespawn = false
|
||||
self.logger:debug("Spawning group " .. self.groupName)
|
||||
self.aliveUnits = {}
|
||||
self.landedUnits = {}
|
||||
self.onStationSince = 0
|
||||
|
||||
local group = Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName, nil, nil, true)
|
||||
if group then
|
||||
self.unitCount = group:getInitialSize()
|
||||
|
||||
if self.state == CapGroup.GroupState.UNSPAWNED then
|
||||
self:SetState(CapGroup.GroupState.READYONRAMP)
|
||||
end
|
||||
|
||||
for _, unit in pairs(group:getUnits()) do
|
||||
local name = unit:getName()
|
||||
self.aliveUnits[name] = true
|
||||
self.landedUnits[name] = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
o.Despawn = function(self)
|
||||
self.logger:debug("Despawning group " .. self.groupName)
|
||||
Spearhead.DcsUtil.DestroyGroup(self.groupName)
|
||||
self:SetState(CapGroup.GroupState.UNSPAWNED)
|
||||
end
|
||||
|
||||
o.SendRTB = function(self)
|
||||
local group = Group.getByName(self.groupName)
|
||||
if group and group:isExist() then
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local rtbTask, errormessage = Spearhead.RouteUtil.CreateRTBMission(self.groupName, self.airbaseId, speed)
|
||||
if rtbTask then
|
||||
timer.scheduleFunction(setTaskAsync, { task = rtbTask, groupName = self.groupName, logger = self.logger }, timer.getTime() + 3)
|
||||
else
|
||||
self.logger:error("No RTB task could be created for group: " .. self.groupName .. " due to " .. errormessage)
|
||||
if self.markedForDespawn == true then
|
||||
self:Despawn()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
o.SendRTBAndDespawn = function(self)
|
||||
self.markedForDespawn = true
|
||||
o.SendRTB(self)
|
||||
end
|
||||
|
||||
---Starts and send this group to perform CAP at a stage
|
||||
---@param self any
|
||||
---@param stageZoneNumber string
|
||||
o.SendToStage = function(self, stageZoneNumber)
|
||||
if self.state == CapGroup.GroupState.DEAD or self.state == CapGroup.GroupState.RTB then
|
||||
return --Can't task a unit that's dead or RTB
|
||||
end
|
||||
|
||||
self.assignedStageNumber = stageZoneNumber
|
||||
local group = Group.getByName(self.groupName)
|
||||
if group and group:isExist() then
|
||||
self.logger:debug("Sending group out " .. self.groupName)
|
||||
local controller = group:getController()
|
||||
local capPoints = database:getCapRouteInZone(stageZoneNumber, self.airbaseId)
|
||||
|
||||
local altitude = math.random(self.capConfig:getMinAlt(), self.capConfig:getMaxAlt())
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local attackHelos = false
|
||||
local deviationDistance = self.capConfig:getMaxDeviationRange()
|
||||
local capTask
|
||||
if self.state == CapGroup.GroupState.ONRAMP or self.onStationSince == 0 then
|
||||
controller:setCommand({
|
||||
id = 'Start',
|
||||
params = {}
|
||||
})
|
||||
local duration = math.random(self.capConfig:getMinDurationOnStation(), self.capConfig:getmaxDurationOnStation())
|
||||
self.currentCapTaskingDuration = duration
|
||||
|
||||
|
||||
capTask = Spearhead.RouteUtil.createCapMission(self.groupName, self.airbaseId, capPoints.point1, capPoints.point2, altitude, speed, duration, attackHelos, deviationDistance)
|
||||
else
|
||||
local duration = self.currentCapTaskingDuration - (timer.getTime() - o.onStationSince)
|
||||
capTask = Spearhead.RouteUtil.createCapMission(self.groupName, self.airbaseId, capPoints.point1, capPoints.point2, altitude, speed, duration, attackHelos, deviationDistance)
|
||||
end
|
||||
|
||||
if capTask then
|
||||
timer.scheduleFunction(setTaskAsync,
|
||||
{ task = capTask, groupName = self.groupName, logger = self.logger }, timer.getTime() + 3)
|
||||
end
|
||||
self:SetState(CapGroup.GroupState.INTRANSIT)
|
||||
end
|
||||
end
|
||||
|
||||
---Starts and send a unit to another airbase
|
||||
---@param self table
|
||||
---@param airdomeId any
|
||||
o.SendToAirbase = function(self, airdomeId)
|
||||
self.airbaseId = airdomeId
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local rtbTask = Spearhead.RouteUtil.CreateRTBMission(self.groupName, airdomeId, speed)
|
||||
local group = Group.getByName(self.groupName)
|
||||
local controller = group:getController()
|
||||
controller:setCommand({
|
||||
id = 'Start',
|
||||
params = {}
|
||||
})
|
||||
timer.scheduleFunction(setTaskAsync, { task = rtbTask, groupName = self.groupName, logger = self.logger },
|
||||
timer.getTime() + 5)
|
||||
end
|
||||
|
||||
o.OnGroupRTB = function(self, groupName)
|
||||
if groupName == self.groupName then
|
||||
self.logger:debug("Setting group " ..
|
||||
groupName ..
|
||||
" to state RTB after a total of " ..
|
||||
timer.getTime() - self.onStationSince .. "s of the " .. self.currentCapTaskingDuration .. "s")
|
||||
self:SetState(CapGroup.GroupState.RTB)
|
||||
end
|
||||
end
|
||||
|
||||
o.OnGroupRTBInTen = function(self, groupName)
|
||||
if groupName == self.groupName then
|
||||
self:SetState(CapGroup.GroupState.RTBINTEN)
|
||||
end
|
||||
end
|
||||
|
||||
o.OnGroupOnStation = function(self, groupName)
|
||||
if groupName == self.groupName then
|
||||
self.onStationSince = timer.getTime()
|
||||
self.logger:debug("Setting group " .. groupName .. " to state Onstation")
|
||||
self:SetState(CapGroup.GroupState.ONSTATION)
|
||||
end
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param self table
|
||||
---@param proActive boolean Will check all units in group for aliveness
|
||||
o.UpdateState = function(self, proActive)
|
||||
local landed = false
|
||||
local landedCount = 0
|
||||
for name, landedBool in pairs(self.landedUnits) do
|
||||
if landedBool == true then
|
||||
landedCount = landedCount + 1
|
||||
landed = true
|
||||
end
|
||||
end
|
||||
|
||||
local deadCount = 0
|
||||
for name, isAlive in pairs(self.aliveUnits) do
|
||||
if isAlive == false then
|
||||
deadCount = deadCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function DelayedStartRearm(input, time)
|
||||
local capGroup = input.self
|
||||
capGroup:StartRearm()
|
||||
end
|
||||
|
||||
if landedCount + deadCount == self.unitCount then
|
||||
if landed then
|
||||
if self.markedForDespawn == true then
|
||||
self:Despawn()
|
||||
else
|
||||
timer.scheduleFunction(DelayedStartRearm, { self = self }, timer.getTime() + RESPAWN_AFTER_TOUCHDOWN_SECONDS)
|
||||
end
|
||||
else
|
||||
if self.markedForDespawn == true then
|
||||
self:Despawn()
|
||||
else
|
||||
local delay = self.capConfig:getDeathDelay() - self.capConfig:getRearmDelay() + RESPAWN_AFTER_TOUCHDOWN_SECONDS
|
||||
timer.scheduleFunction(DelayedStartRearm, { self = self }, timer.getTime() + delay)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
o.eventListeners = {}
|
||||
---comment
|
||||
---@param self table
|
||||
---@param listener table object with function OnGroupStateUpdated(capGroupTable)
|
||||
o.AddOnStateUpdatedListener = function(self, listener)
|
||||
if type(listener) ~= "table" then
|
||||
self.logger:error("Listener not of type table for AddOnStateUpdatedListener")
|
||||
return
|
||||
end
|
||||
|
||||
if listener.OnGroupStateUpdated == nil then
|
||||
self.logger:error("Listener does not implement OnGroupStateUpdated")
|
||||
return
|
||||
end
|
||||
table.insert(self.eventListeners, listener)
|
||||
end
|
||||
|
||||
o.PublishUnitUpdatedEvent = function(self)
|
||||
for _, callable in pairs(self.eventListeners) do
|
||||
local _, error = pcall(function()
|
||||
callable:OnGroupStateUpdated(self)
|
||||
end)
|
||||
if error then
|
||||
self.logger:error(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
o.OnUnitLanded = function(self, initiatorUnit, airbase)
|
||||
if airbase then
|
||||
local airdomeId = airbase:getID()
|
||||
self.airbaseId = airdomeId
|
||||
end
|
||||
local name = initiatorUnit:getName()
|
||||
self.logger:debug("Received unit land event for unit " .. name .. " of group " .. self.groupName)
|
||||
|
||||
self.landedUnits[name] = true
|
||||
self:UpdateState(false)
|
||||
end
|
||||
|
||||
o.OnUnitLost = function(self, initiatorUnit)
|
||||
self.logger:debug("Received unit lost event for group " .. self.groupName)
|
||||
if initiatorUnit then
|
||||
self.aliveUnits[initiatorUnit:getName()] = false
|
||||
end
|
||||
self:UpdateState(false)
|
||||
end
|
||||
|
||||
Spearhead.Events.addOnGroupRTBListener(o.groupName, o)
|
||||
Spearhead.Events.addOnGroupRTBInTenListener(o.groupName, o)
|
||||
Spearhead.Events.addOnGroupOnStationListener(o.groupName, o)
|
||||
Spearhead.Events.addOnGroupRTBListener(self.groupName, self)
|
||||
Spearhead.Events.addOnGroupRTBInTenListener(self.groupName, self)
|
||||
Spearhead.Events.addOnGroupOnStationListener(self.groupName, self)
|
||||
local units = Group.getByName(groupName):getUnits()
|
||||
for key, unit in pairs(units) do
|
||||
Spearhead.Events.addOnUnitLandEventListener(unit:getName(), o)
|
||||
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), o)
|
||||
Spearhead.Events.addOnUnitLandEventListener(unit:getName(), self)
|
||||
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
|
||||
end
|
||||
return o
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---@param currentActive number
|
||||
---@return string
|
||||
function CapGroup:GetTargetZone(currentActive)
|
||||
return self.capZonesConfig[tostring(currentActive)]
|
||||
end
|
||||
|
||||
function CapGroup:SetState(state)
|
||||
self.state = state
|
||||
self:PublishUnitUpdatedEvent()
|
||||
end
|
||||
|
||||
function CapGroup:StartRearm()
|
||||
self:SpawnOnTheRamp()
|
||||
self:SetState(CapGroup.GroupState.REARMING)
|
||||
timer.scheduleFunction(SetReadyOnRampAsync, self, timer.getTime() + self.capConfig:getRearmDelay() - RESPAWN_AFTER_TOUCHDOWN_SECONDS)
|
||||
end
|
||||
|
||||
function CapGroup:SpawnOnTheRamp()
|
||||
self.markedForDespawn = false
|
||||
self.logger:debug("Spawning group " .. self.groupName)
|
||||
self.aliveUnits = {}
|
||||
self.landedUnits = {}
|
||||
self.onStationSince = 0
|
||||
|
||||
local group = Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName, nil, nil, true)
|
||||
if group then
|
||||
self.unitCount = group:getInitialSize()
|
||||
|
||||
if self.state == CapGroup.GroupState.UNSPAWNED then
|
||||
self:SetState(CapGroup.GroupState.READYONRAMP)
|
||||
end
|
||||
|
||||
for _, unit in pairs(group:getUnits()) do
|
||||
local name = unit:getName()
|
||||
self.aliveUnits[name] = true
|
||||
self.landedUnits[name] = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapGroup:Despawn()
|
||||
self.logger:debug("Despawning group " .. self.groupName)
|
||||
Spearhead.DcsUtil.DestroyGroup(self.groupName)
|
||||
self:SetState(CapGroup.GroupState.UNSPAWNED)
|
||||
end
|
||||
|
||||
function CapGroup:SendRTB()
|
||||
local group = Group.getByName(self.groupName)
|
||||
if group and group:isExist() then
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local rtbTask, errormessage = Spearhead.RouteUtil.CreateRTBMission(self.groupName, self.airbaseId, speed)
|
||||
if rtbTask then
|
||||
timer.scheduleFunction(setTaskAsync, { task = rtbTask, groupName = self.groupName, logger = self.logger }, timer.getTime() + 3)
|
||||
else
|
||||
self.logger:error("No RTB task could be created for group: " .. self.groupName .. " due to " .. errormessage)
|
||||
if self.markedForDespawn == true then
|
||||
self:Despawn()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapGroup:SendRTBAndDespawn()
|
||||
self.markedForDespawn = true
|
||||
self:SendRTB()
|
||||
end
|
||||
|
||||
---@param stageZoneNumber string
|
||||
function CapGroup:SendToStage(stageZoneNumber)
|
||||
if self.state == CapGroup.GroupState.DEAD or self.state == CapGroup.GroupState.RTB then
|
||||
return --Can't task a unit that's dead or RTB
|
||||
end
|
||||
|
||||
self.assignedStageNumber = stageZoneNumber
|
||||
local group = Group.getByName(self.groupName)
|
||||
if group and group:isExist() then
|
||||
self.logger:debug("Sending group out " .. self.groupName)
|
||||
local controller = group:getController()
|
||||
local capPoints = self.database:getCapRouteInZone(stageZoneNumber, self.airbaseName)
|
||||
|
||||
local altitude = math.random(self.capConfig:getMinAlt(), self.capConfig:getMaxAlt())
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local attackHelos = false
|
||||
local deviationDistance = self.capConfig:getMaxDeviationRange()
|
||||
local capTask
|
||||
if self.state == CapGroup.GroupState.ONRAMP or self.onStationSince == 0 then
|
||||
controller:setCommand({
|
||||
id = 'Start',
|
||||
params = {}
|
||||
})
|
||||
local duration = math.random(self.capConfig:getMinDurationOnStation(), self.capConfig:getmaxDurationOnStation())
|
||||
self.currentCapTaskingDuration = duration
|
||||
|
||||
|
||||
capTask = Spearhead.RouteUtil.createCapMission(self.groupName, self.airbaseId, capPoints.point1, capPoints.point2, altitude, speed, duration, attackHelos, deviationDistance)
|
||||
else
|
||||
local duration = self.currentCapTaskingDuration - (timer.getTime() - self.onStationSince)
|
||||
capTask = Spearhead.RouteUtil.createCapMission(self.groupName, self.airbaseId, capPoints.point1, capPoints.point2, altitude, speed, duration, attackHelos, deviationDistance)
|
||||
end
|
||||
|
||||
if capTask then
|
||||
timer.scheduleFunction(setTaskAsync,
|
||||
{ task = capTask, groupName = self.groupName, logger = self.logger }, timer.getTime() + 3)
|
||||
end
|
||||
self:SetState(CapGroup.GroupState.INTRANSIT)
|
||||
end
|
||||
end
|
||||
|
||||
---@param airdomeId any
|
||||
function CapGroup:SendToAirbase(airdomeId)
|
||||
self.airbaseId = airdomeId
|
||||
local speed = math.random(self.capConfig:getMinSpeed(), self.capConfig:getMaxSpeed())
|
||||
local rtbTask = Spearhead.RouteUtil.CreateRTBMission(self.groupName, airdomeId, speed)
|
||||
local group = Group.getByName(self.groupName)
|
||||
|
||||
if not group then return end
|
||||
local controller = group:getController()
|
||||
controller:setCommand({
|
||||
id = 'Start',
|
||||
params = {}
|
||||
})
|
||||
timer.scheduleFunction(setTaskAsync, { task = rtbTask, groupName = self.groupName, logger = self.logger },
|
||||
timer.getTime() + 5)
|
||||
end
|
||||
|
||||
function CapGroup:OnGroupRTB(groupName)
|
||||
if groupName == self.groupName then
|
||||
self.logger:debug("Setting group " ..
|
||||
groupName ..
|
||||
" to state RTB after a total of " ..
|
||||
timer.getTime() - self.onStationSince .. "s of the " .. self.currentCapTaskingDuration .. "s")
|
||||
self:SetState(CapGroup.GroupState.RTB)
|
||||
end
|
||||
end
|
||||
|
||||
function CapGroup:OnGroupRTBInTen(groupName)
|
||||
if groupName == self.groupName then
|
||||
self:SetState(CapGroup.GroupState.RTBINTEN)
|
||||
end
|
||||
end
|
||||
|
||||
function CapGroup:OnGroupOnStation(groupName)
|
||||
if groupName == self.groupName then
|
||||
self.onStationSince = timer.getTime()
|
||||
self.logger:debug("Setting group " .. groupName .. " to state Onstation")
|
||||
self:SetState(CapGroup.GroupState.ONSTATION)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param proActive boolean Will check all units in group for aliveness
|
||||
function CapGroup:UpdateState(proActive)
|
||||
local landed = false
|
||||
local landedCount = 0
|
||||
for name, landedBool in pairs(self.landedUnits) do
|
||||
if landedBool == true then
|
||||
landedCount = landedCount + 1
|
||||
landed = true
|
||||
end
|
||||
end
|
||||
|
||||
local deadCount = 0
|
||||
for name, isAlive in pairs(self.aliveUnits) do
|
||||
if isAlive == false then
|
||||
deadCount = deadCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function DelayedStartRearm(input, time)
|
||||
local capGroup = input.self
|
||||
capGroup:StartRearm()
|
||||
end
|
||||
|
||||
if landedCount + deadCount == self.unitCount then
|
||||
if landed then
|
||||
if self.markedForDespawn == true then
|
||||
self:Despawn()
|
||||
else
|
||||
timer.scheduleFunction(DelayedStartRearm, { self = self }, timer.getTime() + RESPAWN_AFTER_TOUCHDOWN_SECONDS)
|
||||
end
|
||||
else
|
||||
if self.markedForDespawn == true then
|
||||
self:Despawn()
|
||||
else
|
||||
local delay = self.capConfig:getDeathDelay() - self.capConfig:getRearmDelay() + RESPAWN_AFTER_TOUCHDOWN_SECONDS
|
||||
timer.scheduleFunction(DelayedStartRearm, { self = self }, timer.getTime() + delay)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param listener table object with function OnGroupStateUpdated(capGroupTable)
|
||||
function CapGroup:AddOnStateUpdatedListener(listener)
|
||||
if type(listener) ~= "table" then
|
||||
self.logger:error("Listener not of type table for AddOnStateUpdatedListener")
|
||||
return
|
||||
end
|
||||
|
||||
if listener.onGroupStateUpdated == nil then
|
||||
self.logger:error("Listener does not implement onGroupStateUpdated")
|
||||
return
|
||||
end
|
||||
table.insert(self.onStatusUpdatedListener, listener)
|
||||
end
|
||||
|
||||
function CapGroup:PublishUnitUpdatedEvent()
|
||||
for _, callable in pairs(self.onStatusUpdatedListener) do
|
||||
local _, error = pcall(function()
|
||||
callable:onGroupStateUpdated(self)
|
||||
end)
|
||||
if error then
|
||||
self.logger:error(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CapGroup:OnUnitLanded(initiatorUnit, airbase)
|
||||
if airbase then
|
||||
self.airbaseName = airbase:getName()
|
||||
end
|
||||
local name = initiatorUnit:getName()
|
||||
self.logger:debug("Received unit land event for unit " .. name .. " of group " .. self.groupName)
|
||||
|
||||
self.landedUnits[name] = true
|
||||
self:UpdateState(false)
|
||||
end
|
||||
|
||||
function CapGroup:OnUnitLost(initiatorUnit)
|
||||
self.logger:debug("Received unit lost event for group " .. self.groupName)
|
||||
if initiatorUnit then
|
||||
self.aliveUnits[initiatorUnit:getName()] = false
|
||||
end
|
||||
self:UpdateState(false)
|
||||
end
|
||||
|
||||
|
||||
if not Spearhead.internal then Spearhead.internal = {} end
|
||||
Spearhead.internal.CapGroup = CapGroup
|
||||
|
||||
@@ -7,10 +7,14 @@ do
|
||||
|
||||
local initiated = false
|
||||
|
||||
---comment
|
||||
---@param database Database
|
||||
---@param capConfig any
|
||||
---@param stageConfig any
|
||||
function GlobalCapManager.start(database, capConfig, stageConfig)
|
||||
if initiated == true then return end
|
||||
|
||||
local logger = Spearhead.LoggerTemplate:new("AirbaseManager", capConfig.logLevel)
|
||||
local logger = Spearhead.LoggerTemplate.new("AirbaseManager", capConfig.logLevel)
|
||||
|
||||
local zones = database:getStagezoneNames()
|
||||
if zones then
|
||||
@@ -19,13 +23,12 @@ do
|
||||
airbasesPerStage[stageName] = {}
|
||||
end
|
||||
|
||||
local airbaseIds = database:getAirbaseIdsInStage(stageName)
|
||||
if airbaseIds then
|
||||
for _, id in pairs(airbaseIds) do
|
||||
local airbaseName = Spearhead.DcsUtil.getAirbaseName(id)
|
||||
local airbaseNames = database:getAirbaseNamesInStage(stageName)
|
||||
if airbaseNames then
|
||||
for _, airbaseName in pairs(airbaseNames) do
|
||||
if airbaseName then
|
||||
local airbaseSpecificLogger = Spearhead.LoggerTemplate:new("CAP_" .. airbaseName, capConfig.logLevel)
|
||||
local airbase = Spearhead.internal.CapAirbase:new(id, database, airbaseSpecificLogger, capConfig, stageConfig)
|
||||
local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, capConfig.logLevel)
|
||||
local airbase = Spearhead.internal.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig)
|
||||
if airbase then
|
||||
table.insert(airbasesPerStage[stageName], airbase)
|
||||
allAirbasesByName[airbaseName] = airbase
|
||||
|
||||
Reference in New Issue
Block a user