Fixed bugs found in v0.0.2

This commit is contained in:
2025-05-01 21:53:54 +02:00
parent d16792064f
commit fc726cbb37
18 changed files with 737 additions and 694 deletions
+1
View File
@@ -540,6 +540,7 @@ end
do -- Controller
---@class Controller
---@field setTask fun(self:Controller, task: Task) Sets the task of the controller to the passed task
---@field setCommand function
Controller = Controller
Binary file not shown.
+85 -70
View File
@@ -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
View File
@@ -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
+10 -7
View File
@@ -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
+1 -1
View File
@@ -6,7 +6,7 @@ local fleetGroups = {}
GlobalFleetManager.start = function(database)
local logger = Spearhead.LoggerTemplate:new("CARRIERFLEET", "INFO")
local logger = Spearhead.LoggerTemplate.new("CARRIERFLEET", "INFO")
local all_groups = Spearhead.DcsUtil.getAllGroupNames()
for _, groupName in pairs(all_groups) do
+57 -68
View File
@@ -800,14 +800,15 @@ do -- INIT DCS_UTIL
end
---Get the starting coalition of a farp or airbase
---@param airbase Airbase
---@return number? coalition
function DCS_UTIL.getStartingCoalition(baseId)
if baseId == nil then
function DCS_UTIL.getStartingCoalition(airbase)
if airbase == nil then
return nil
end
--STRING based dictionary otherwise it'll be a string/collapsed array
baseId = tostring(baseId) or "nil"
local baseId = tostring(airbase:getID())
local result = DCS_UTIL.__airportsStartingCoalition[baseId]
if result == nil then
@@ -920,86 +921,74 @@ do -- INIT DCS_UTIL
end
Spearhead.DcsUtil = DCS_UTIL
--- @class Logger
--- @field LoggerName string the name of the logger
--- @field LogLevel string the log level of the logger
local LOGGER = {}
do
local PreFix = "Spearhead"
--- @class Logger
--- @field debug fun(self:Logger, text:string)
--- @field info fun(self:Logger, text:string)
--- @field warn fun(self:Logger, text:string)
--- @field error fun(self:Logger, text:string)
---comment
---@param logger_name any
---@param logLevel LogLevel
---@return Logger
function LOGGER:new(logger_name, logLevel)
local o = {}
setmetatable(o, { __index = self })
o.LoggerName = logger_name or "(loggername not set)"
o.LogLevel = logLevel or "INFO"
function LOGGER.new(logger_name, logLevel)
LOGGER.__index = LOGGER
local self = setmetatable({}, LOGGER)
self.LoggerName = logger_name or "(loggername not set)"
self.LogLevel = logLevel or "INFO"
---comment
---@param self table self logger
---@param message any the message
o.info = function(self, message)
if message == nil then
return
end
message = UTIL.toString(message)
return self
end
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
---@param message any the message
function LOGGER:info(message)
if message == nil then
return
end
message = UTIL.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
end
---comment
---@param message string
function LOGGER:warn(message)
if message == nil then
return
end
message = UTIL.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" then
env.warning("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
end
---@param message any -- the message
function LOGGER:error(message)
if message == nil then
return
end
---comment
---@param message string
o.warn = function(self, message)
if message == nil then
return
end
message = UTIL.toString(message)
message = UTIL.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" or self.LogLevel == "ERROR" then
env.error("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
end
---@param message any the message
function LOGGER:debug(message)
if message == nil then
return
end
---comment
---@param self table -- logger
---@param message any -- the message
o.error = function(self, message)
if message == nil then
return
end
message = UTIL.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" or self.logLevel == "ERROR" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
message = UTIL.toString(message)
if self.LogLevel == "DEBUG" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "][DEBUG] " .. message)
end
---write debug
---@param self table
---@param message any the message
o.debug = function(self, message)
if message == nil then
return
end
message = UTIL.toString(message)
if self.LogLevel == "DEBUG" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "][DEBUG] " .. message)
end
end
return o
end
end
Spearhead.LoggerTemplate = LOGGER
@@ -1015,7 +1004,7 @@ Spearhead.LoadingDone = function()
return
end
local warningLogger = Spearhead.LoggerTemplate:new("MISSIONPARSER", "INFO")
local warningLogger = Spearhead.LoggerTemplate.new("MISSIONPARSER", "INFO")
if Spearhead.Util.tableLength(Spearhead.MissionEditingWarnings) > 0 then
for key, message in pairs(Spearhead.MissionEditingWarnings) do
warningLogger:warn(message)
+211 -204
View File
@@ -17,6 +17,7 @@
---@field BlueSamDataPerZone table<string, BlueSamData>
---@field MissionZoneData table<string, MissionZoneData>
---@field FarpZoneData table<string,FarpZoneData>
---@field missionCodes table<string, boolean>
---@class CapData
---@field routes Array<CapRoute>
@@ -59,9 +60,9 @@
local Database = {}
---comment
---@param Logger table
---@param Logger Logger
---@return Database
function Database.New(Logger, debug)
function Database.New(Logger)
---@type DatabaseTables
local tables = {
@@ -81,7 +82,8 @@ function Database.New(Logger, debug)
AirbaseDataPerAirfield = {},
BlueSamDataPerZone = {},
MissionZoneData = {},
FarpZoneData = {}
FarpZoneData = {},
missionCodes = {}
}
Database.__index = Database
@@ -90,7 +92,7 @@ function Database.New(Logger, debug)
self._logger = Logger
self._tables = tables
Logger:debug("Initiating tables")
self._logger:debug("Initiating tables")
do -- INIT ZONE TABLES
for zone_ind, zone_data in pairs(Spearhead.DcsUtil.__trigger_zones) do
@@ -118,7 +120,7 @@ function Database.New(Logger, debug)
RandomMissionZones = {},
MiscGroups = {}
}
self._tables.StageZones[zone_name] = zone_data
self._tables.StageZones[zone_name] = stageData
end
end
@@ -152,7 +154,7 @@ function Database.New(Logger, debug)
end
end
Logger:debug("initiated zone tables, continuing with descriptions")
self._logger:debug("initiated zone tables, continuing with descriptions")
do --load markers
if env.mission.drawings and env.mission.drawings.layers then
for i, layer in pairs(env.mission.drawings.layers) do
@@ -237,13 +239,6 @@ function Database.New(Logger, debug)
end
end
Logger:info("initiated the database with amount of zones: ")
Logger:info("Stages: " .. Spearhead.Util.tableLength(self._tables.StageZones))
Logger:info("Total Missions: " .. Spearhead.Util.tableLength(self._tables.MissionZoneData))
Logger:info("Random Missions: " .. Spearhead.Util.tableLength(self._tables.RandomMissionZones))
Logger:info("Farps: " .. Spearhead.Util.tableLength(self._tables.AllFarpZones))
Logger:info("Airbases: " .. Spearhead.Util.tableLength(self._tables.AirbaseDataPerAirfield))
for _, missionZone in pairs(self._tables.MissionZones) do
if self._tables.DescriptionsByMission[missionZone] == nil then
Spearhead.AddMissionEditorWarning("Mission with zonename: " ..
@@ -261,34 +256,7 @@ function Database.New(Logger, debug)
end
end
local is_group_taken = {}
do
local all_groups = Spearhead.DcsUtil.getAllGroupNames()
for _, value in pairs(all_groups) do
is_group_taken[value] = false
end
end
local getAvailableGroups = function()
local result = {}
for name, value in pairs(is_group_taken) do
if value == false then
table.insert(result, name)
end
end
return result
end
local getAvailableCAPGroups = function()
local result = {}
for name, value in pairs(is_group_taken) do
if value == false and Spearhead.Util.startswith(name, "CAP") then
table.insert(result, name)
end
end
return result
end
---@private
---@param baseName string
---@return AirbaseData
@@ -305,159 +273,7 @@ function Database.New(Logger, debug)
return baseData
end
---@private
function Database:loadCapUnits()
local all_groups = getAvailableCAPGroups()
local airbases = world.getAirbases()
for _, airbase in pairs(airbases) do
local baseId = airbase:getID()
local point = airbase:getPoint()
local zone = Spearhead.DcsUtil.getAirbaseZoneById(baseId) or { x = point.x, z = point.z, radius = 4000 }
local baseData = self:getOrCreateAirbaseData(airbase:getName())
local groups = Spearhead.DcsUtil.areGroupsInCustomZone(all_groups, zone)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(baseData.CapGroups, groupName)
end
self._tables.AirbaseDataPerAirfield[airbase:getName()] = baseData
end
end
---@private
function Database:loadBlueSamUnits()
local all_groups = Spearhead.DcsUtil.getAllGroupNames()
for _, blueSamZone in pairs(self._tables.BlueSams) do
self._tables.BlueSamDataPerZone[blueSamZone] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, blueSamZone)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.BlueSamDataPerZone[blueSamZone].Groups, groupName)
end
end
end
---@private
function Database:loadMissionzoneUnits()
local all_groups = getAvailableGroups()
for _, missionZoneName in pairs(self._tables.MissionZones) do
self._tables.MissionZoneData[missionZoneName] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.MissionZoneData[missionZoneName].Groups, groupName)
end
end
end
---@private
function Database:loadRandomMissionzoneUnits()
local all_groups = getAvailableGroups()
for _, missionZoneName in pairs(self._tables.RandomMissionZones) do
self._tables.MissionZoneData[missionZoneName] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.MissionZoneData[missionZoneName].Groups, groupName)
end
end
end
---@private
function Database:loadFarpGroups()
local all_groups = getAvailableGroups()
for _, farpZone in pairs(self._tables.AllFarpZones) do
self._tables.FarpZoneData[farpZone] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, farpZone)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.FarpZoneData[farpZone].Groups, groupName)
end
end
end
function Database:loadAirbaseGroups()
local all_groups = getAvailableGroups()
for _, stageZone in pairs(self._tables.StageZones) do
for _, baseName in pairs(stageZone.AirbaseNames) do
local base = Airbase.getByName(baseName)
if base then
local basedata = self:getOrCreateAirbaseData(baseName)
local baseId = base:getID()
local point = base:getPoint()
local airbaseZone = Spearhead.DcsUtil.getAirbaseZoneById(baseId) or { x = point.x, z = point.z, radius = 4000 }
if airbaseZone and base:getDesc().category == Airbase.Category.AIRDROME then
local groups = Spearhead.DcsUtil.areGroupsInCustomZone(all_groups, airbaseZone)
for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName)
if object then
if object:getCoalition() == coalition.side.RED then
table.insert(basedata.RedGroups, groupName)
is_group_taken[groupName] = true
elseif object:getCoalition() == coalition.side.BLUE then
table.insert(basedata.BlueGroups, groupName)
is_group_taken[groupName] = true
end
end
else
local group = Group.getByName(groupName)
if group then
if group:getCoalition() == coalition.side.RED then
table.insert(basedata.RedGroups, groupName)
is_group_taken[groupName] = true
elseif group:getCoalition() == coalition.side.BLUE then
table.insert(basedata.BlueGroups, groupName)
is_group_taken[groupName] = true
end
end
end
end
end
end
end
end
end
---@private
function Database:loadMiscGroupsInStages()
local all_groups = getAvailableGroups()
for _, stageZone in pairs(self._tables.StageZones) do
stageZone.MiscGroups = {}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, stageZone.StageZoneName)
for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName)
if object and object:getCoalition() ~= coalition.side.NEUTRAL then
is_group_taken[groupName] = true
table.insert(stageZone.MiscGroups, groupName)
end
else
local group = Group.getByName(groupName)
if group and group:getCoalition() ~= coalition.side.NEUTRAL then
is_group_taken[groupName] = true
table.insert(stageZone.MiscGroups, groupName)
end
end
end
end
end
self:loadCapUnits()
self:loadBlueSamUnits()
@@ -526,10 +342,200 @@ function Database.New(Logger, debug)
end
end
self._logger:info("initiated the database with amount of zones: ")
self._logger:info("Stages: " .. Spearhead.Util.tableLength(self._tables.StageZones))
self._logger:info("Total Missions: " .. Spearhead.Util.tableLength(self._tables.MissionZoneData))
self._logger:info("Random Missions: " .. Spearhead.Util.tableLength(self._tables.RandomMissionZones))
self._logger:info("Farps: " .. Spearhead.Util.tableLength(self._tables.AllFarpZones))
self._logger:info("Airbases: " .. Spearhead.Util.tableLength(self._tables.AirbaseDataPerAirfield))
return self
end
local is_group_taken = {}
do
local all_groups = Spearhead.DcsUtil.getAllGroupNames()
for _, value in pairs(all_groups) do
is_group_taken[value] = false
end
end
local getAvailableGroups = function()
local result = {}
for name, value in pairs(is_group_taken) do
if value == false then
table.insert(result, name)
end
end
return result
end
local getAvailableCAPGroups = function()
local result = {}
for name, value in pairs(is_group_taken) do
if value == false and Spearhead.Util.startswith(name, "CAP") then
table.insert(result, name)
end
end
return result
end
---@private
function Database:loadCapUnits()
local all_groups = getAvailableCAPGroups()
local airbases = world.getAirbases()
for _, airbase in pairs(airbases) do
local baseId = airbase:getID()
local point = airbase:getPoint()
local zone = Spearhead.DcsUtil.getAirbaseZoneById(baseId) or { x = point.x, z = point.z, radius = 4000 }
local baseData = self:getOrCreateAirbaseData(airbase:getName())
local groups = Spearhead.DcsUtil.areGroupsInCustomZone(all_groups, zone)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(baseData.CapGroups, groupName)
end
self._tables.AirbaseDataPerAirfield[airbase:getName()] = baseData
end
end
---@private
function Database:loadBlueSamUnits()
local all_groups = Spearhead.DcsUtil.getAllGroupNames()
for _, blueSamZone in pairs(self._tables.BlueSams) do
self._tables.BlueSamDataPerZone[blueSamZone] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, blueSamZone)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.BlueSamDataPerZone[blueSamZone].Groups, groupName)
end
end
end
---@private
function Database:loadMissionzoneUnits()
local all_groups = getAvailableGroups()
for _, missionZoneName in pairs(self._tables.MissionZones) do
self._tables.MissionZoneData[missionZoneName] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.MissionZoneData[missionZoneName].Groups, groupName)
end
end
end
---@private
function Database:loadRandomMissionzoneUnits()
local all_groups = getAvailableGroups()
for _, missionZoneName in pairs(self._tables.RandomMissionZones) do
self._tables.MissionZoneData[missionZoneName] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.MissionZoneData[missionZoneName].Groups, groupName)
end
end
end
---@private
function Database:loadFarpGroups()
local all_groups = getAvailableGroups()
for _, farpZone in pairs(self._tables.AllFarpZones) do
self._tables.FarpZoneData[farpZone] = {
Groups = {}
}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, farpZone)
for _, groupName in pairs(groups) do
is_group_taken[groupName] = true
table.insert(self._tables.FarpZoneData[farpZone].Groups, groupName)
end
end
end
function Database:loadAirbaseGroups()
local all_groups = getAvailableGroups()
for _, stageZone in pairs(self._tables.StageZones) do
for _, baseName in pairs(stageZone.AirbaseNames) do
local base = Airbase.getByName(baseName)
if base then
local basedata = self:getOrCreateAirbaseData(baseName)
local baseId = base:getID()
local point = base:getPoint()
local airbaseZone = Spearhead.DcsUtil.getAirbaseZoneById(baseId) or { x = point.x, z = point.z, radius = 4000 }
if airbaseZone and base:getDesc().category == Airbase.Category.AIRDROME then
local groups = Spearhead.DcsUtil.areGroupsInCustomZone(all_groups, airbaseZone)
for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName)
if object then
if object:getCoalition() == coalition.side.RED then
table.insert(basedata.RedGroups, groupName)
is_group_taken[groupName] = true
elseif object:getCoalition() == coalition.side.BLUE then
table.insert(basedata.BlueGroups, groupName)
is_group_taken[groupName] = true
end
end
else
local group = Group.getByName(groupName)
if group then
if group:getCoalition() == coalition.side.RED then
table.insert(basedata.RedGroups, groupName)
is_group_taken[groupName] = true
elseif group:getCoalition() == coalition.side.BLUE then
table.insert(basedata.BlueGroups, groupName)
is_group_taken[groupName] = true
end
end
end
end
end
end
end
end
end
---@private
function Database:loadMiscGroupsInStages()
local all_groups = getAvailableGroups()
for _, stageZone in pairs(self._tables.StageZones) do
stageZone.MiscGroups = {}
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, stageZone.StageZoneName)
for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName)
if object and object:getCoalition() ~= coalition.side.NEUTRAL then
is_group_taken[groupName] = true
table.insert(stageZone.MiscGroups, groupName)
end
else
local group = Group.getByName(groupName)
if group and group:getCoalition() ~= coalition.side.NEUTRAL then
is_group_taken[groupName] = true
table.insert(stageZone.MiscGroups, groupName)
end
end
end
end
end
function Database:GetDescriptionForMission(missionZoneName)
return self._tables.DescriptionsByMission[missionZoneName]
@@ -595,7 +601,7 @@ end
---@return table result a list of stage zone names
function Database:getStagezoneNames()
return self._tables.AllZoneNames
return self._tables.StageZoneNames
end
function Database:getCarrierRouteZones()
@@ -628,19 +634,22 @@ function Database:getMissionBriefingForMissionZone(missionZoneName)
return self._tables.DescriptionsByMission[missionZoneName]
end
---@param self table
---@param stageName string
---@return table result airbase Names
function Database:getAirbaseIdsInStage(stageName)
return self.tables.airbasesPerStage[stageName] or {}
function Database:getAirbaseNamesInStage(stageName)
local stageData = self._tables.StageZones[stageName]
if not stageData then return {} end
return stageData.AirbaseNames or {}
end
---@param airbaseName string
---@return Array<string>?
---@return Array<string>
function Database:getCapGroupsAtAirbase(airbaseName)
local airbaseData = self._tables.AirbaseDataPerAirfield[airbaseName]
if not airbaseData then return nil end
if not airbaseData then return {} end
return airbaseData.CapGroups
end
@@ -682,15 +691,13 @@ function Database:getMiscGroupsAtStage(stageName)
return stageZone.MiscGroups
end
---comment
---@param self table
---@return integer|nil
function Database:GetNewMissionCode(self)
function Database:GetNewMissionCode()
local code = nil
local tries = 0
while code == nil and tries < 10 do
local random = math.random(1000, 9999)
if self.tables.missionCodes[random] == nil then
if self._tables.missionCodes[random] == nil then
code = random
end
tries = tries + 1
+2 -2
View File
@@ -7,7 +7,7 @@ do
---@param logLevel LogLevel
SpearheadEvents.Init = function(logLevel)
logger = Spearhead.LoggerTemplate:new("Events", logLevel)
logger = Spearhead.LoggerTemplate.new("Events", logLevel)
end
@@ -68,7 +68,7 @@ do
logError(err)
end
end
Spearhead.LoggerTemplate.new("Events", "INFO"):info("Published stage number changed to: " .. tostring(newStageNumber))
Spearhead.StageNumber = newStageNumber
end
end
+4
View File
@@ -303,6 +303,10 @@ do --setup route util
local group = Group.getByName(groupName)
local pos;
local i = 1
if group == nil then
return nil, "No group found for name " .. groupName
end
local units = group:getUnits()
while pos == nil and i <= Spearhead.Util.tableLength(units) do
local unit = units[i]
+6 -5
View File
@@ -21,7 +21,7 @@ GlobalStageManager = {}
---@param stageConfig StageConfig
---@return nil
function GlobalStageManager:NewAndStart(database, stageConfig)
local logger = Spearhead.LoggerTemplate:new("StageManager", stageConfig.logLevel)
local logger = Spearhead.LoggerTemplate.new("StageManager", stageConfig.logLevel)
logger:info("Using Stage Log Level: " .. stageConfig.logLevel)
local o = {}
setmetatable(o, { __index = self })
@@ -86,7 +86,9 @@ function GlobalStageManager:NewAndStart(database, stageConfig)
end
}
for _, stageName in pairs(database:getStagezoneNames()) do
logger:debug("Found stage zone with name: " .. stageName)
if Spearhead.Util.startswith(stageName, "missionstage", true) then
local valid = true
@@ -98,7 +100,6 @@ function GlobalStageManager:NewAndStart(database, stageConfig)
if Spearhead.Util.tableLength(split) < 3 then
Spearhead.AddMissionEditorWarning("Stage zone with name " .. stageName .. " does not have a stage name")
valid = false
end
local orderNumber = nil
@@ -108,7 +109,7 @@ function GlobalStageManager:NewAndStart(database, stageConfig)
if Spearhead.Util.startswith(orderNumberString, "x") == true then
isSideStage = true
local orderNumberString = string.gsub(orderNumberString, "x", "")
orderNumberString = string.gsub(orderNumberString, "x", "")
orderNumber = tonumber(orderNumberString)
else
orderNumber = tonumber(split[2])
@@ -121,7 +122,7 @@ function GlobalStageManager:NewAndStart(database, stageConfig)
end
local stageDisplayName = split[3]
local stagelogger = Spearhead.LoggerTemplate:new(stageName, stageConfig.logLevel)
local stagelogger = Spearhead.LoggerTemplate.new(stageName, stageConfig.logLevel)
if valid == true and orderNumber then
---@type StageInitData
@@ -174,7 +175,7 @@ function GlobalStageManager:NewAndStart(database, stageConfig)
end
if valid == true then
local stagelogger = Spearhead.LoggerTemplate:new(stageName, stageConfig.logLevel)
local stagelogger = Spearhead.LoggerTemplate.new(stageName, stageConfig.logLevel)
---@type WaitingStageInitData
local initData = {
+17 -3
View File
@@ -17,6 +17,7 @@ function SpearheadGroup.New(groupName)
self.isStatic = Spearhead.DcsUtil.IsGroupStatic(groupName) == true
self.groupName = groupName
self.isSpawned = false
return self
end
@@ -44,9 +45,9 @@ function SpearheadGroup:Spawn()
if self.isSpawned == true then return end
local group = Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName)
if group then
for _, unit in pairs(group:getUnits()) do
local spawned, isStatic = Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName)
if spawned and isStatic == false then
for _, unit in pairs(spawned:getUnits()) do
local deathState = Spearhead.classes.persistence.Persistence.UnitDeadState(unit:getName())
if deathState and deathState.isDead == true then
@@ -58,6 +59,12 @@ function SpearheadGroup:Spawn()
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
end
elseif spawned and isStatic == true then
if spawned then
Spearhead.Events.addOnUnitLostEventListener(spawned:getName(), self)
end
else
Spearhead.LoggerTemplate.new("SPEARHEADGROUP", "ERROR"):error("Failed to spawn group: " .. self.groupName)
end
self.isSpawned = true
@@ -73,9 +80,15 @@ end
function SpearheadGroup:GetCoalition()
if self.isStatic == true then
local object = StaticObject.getByName(self.groupName)
if object == nil then
return 0
end
return object:getCoalition()
else
local group = Group.getByName(self.groupName)
if group == nil then
return 0
end
return group:getCoalition()
end
end
@@ -102,6 +115,7 @@ function SpearheadGroup:GetUnits()
end
else
local group = Group.getByName(self.groupName)
if not group then return {} end
for _, unit in pairs(group:getUnits()) do
table.insert(result, unit)
end
+17 -17
View File
@@ -6,16 +6,16 @@
---@field private _red_groups Array<SpearheadGroup>
---@field private _blue_groups Array<SpearheadGroup>
---@field private _cleanup_units table<string, boolean>
---@field private _airbase table?
---@field private _airbase Airbase?
---@field private _initialSide number?
local StageBase = {}
---comment
---@param databaseManager table
---@param databaseManager Database
---@param logger table
---@param airbaseId integer
---@param airbaseName string
---@return StageBase
function StageBase.New(databaseManager, logger, airbaseId)
function StageBase.New(databaseManager, logger, airbaseName)
StageBase.__index = StageBase
local self = setmetatable({}, StageBase)
@@ -27,35 +27,35 @@ function StageBase.New(databaseManager, logger, airbaseId)
self._blue_groups = {}
self._cleanup_units = {}
self._airbase = Spearhead.DcsUtil.getAirbaseById(airbaseId)
self._initialSide = Spearhead.DcsUtil.getStartingCoalition(airbaseId)
self._airbase = Airbase.getByName(airbaseName)
self._initialSide = Spearhead.DcsUtil.getStartingCoalition(self._airbase)
do --init
local redUnitsPos = {}
local blueUnitsPos = {}
do -- fill tables
local redGroups = databaseManager:getRedGroupsAtAirbase(airbaseId)
local redGroups = databaseManager:getRedGroupsAtAirbase(airbaseName)
if redGroups then
for _, groupName in pairs(redGroups) do
local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName)
table.insert(self._red_groups, shGroup)
for _, groupName in pairs(redGroups) do
local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName)
table.insert(self._red_groups, shGroup)
for _, unit in shGroup:GetUnits() do
redUnitsPos[unit:getName()] = unit:getPoint()
for _, unit in pairs(shGroup:GetUnits()) do
redUnitsPos[unit:getName()] = unit:getPoint()
end
shGroup:Destroy()
end
shGroup:Destroy()
end
end
local blueGroups = databaseManager:getBlueGroupsAtAirbase(airbaseId)
local blueGroups = databaseManager:getBlueGroupsAtAirbase(airbaseName)
if blueGroups then
for _, groupName in pairs(blueGroups) do
local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName)
table.insert(self._blue_groups, shGroup)
for _, unit in shGroup:GetUnits() do
for _, unit in pairs(shGroup:GetUnits()) do
blueUnitsPos[unit:getName()] = unit:getPoint()
end
@@ -43,23 +43,16 @@
--- @field protected OnPostBlueActivated fun(self:Stage)?
local Stage = {}
Stage.__index = Stage
local stageDrawingId = 100
---comment
---@param database Database
---@param stageConfig StageConfig
---@param logger any
---@param initData StageInitData
---@param missionPriority MissionPriority
---@return Stage
function Stage.New(database, stageConfig, logger, initData, missionPriority)
function Stage:superNew(database, stageConfig, logger, initData, missionPriority)
logger:debug("[BaseStage] Initiating stage with name: " .. initData.stageZoneName)
local SpearheadGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup
Stage.__index = Stage
local o = {}
local self = setmetatable(o, Stage)
self.zoneName = initData.stageZoneName
self.stageNumber = initData.stageNumber
self._isActive = false
@@ -148,10 +141,10 @@ function Stage.New(database, stageConfig, logger, initData, missionPriority)
mission:AddMissionCompleteListener(self)
end
local airbaseIds = database:getAirbaseIdsInStage(self.zoneName)
if airbaseIds ~= nil and type(airbaseIds) == "table" then
for _, airbaseId in pairs(airbaseIds) do
local airbase = Spearhead.classes.stageClasses.SpecialZones.StageBase.New(database, logger, airbaseId)
local airbaseNames = database:getAirbaseNamesInStage(self.zoneName)
if airbaseNames ~= nil and type(airbaseNames) == "table" then
for _, airbaseName in pairs(airbaseNames) do
local airbase = Spearhead.classes.stageClasses.SpecialZones.StageBase.New(database, logger, airbaseName)
table.insert(self._db.airbases, airbase)
end
end
+7 -8
View File
@@ -2,6 +2,10 @@
---@class ExtraStage : Stage
local ExtraStage = {}
ExtraStage.__index = ExtraStage
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(ExtraStage, Stage)
---comment
---@param database Database
---@param stageConfig StageConfig
@@ -10,20 +14,15 @@ local ExtraStage = {}
---@return ExtraStage
function ExtraStage.New(database, stageConfig, logger, initData)
-- "Import"
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(ExtraStage, Stage)
ExtraStage.__index = ExtraStage
local self = Stage.New(database, stageConfig, logger, initData, "secondary") --[[@as ExtraStage]]
setmetatable(self, ExtraStage)
local self = setmetatable({}, { __index = ExtraStage }) --[[@as ExtraStage]]
self:superNew(database, stageConfig, logger, initData)
self.OnPostBlueActivated = function (selfStage)
selfStage:MarkStage("GRAY")
end
self.OnPostStageComplete = function (selfStage)
self:ActivateBlueStage()
selfStage:ActivateBlueStage()
end
return self
+7 -7
View File
@@ -2,6 +2,10 @@
---@class PrimaryStage : Stage
local PrimaryStage = {}
PrimaryStage.__index = PrimaryStage
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(PrimaryStage, Stage)
---comment
---@param database Database
---@param stageConfig StageConfig
@@ -10,14 +14,10 @@ local PrimaryStage = {}
---@return PrimaryStage
function PrimaryStage.New(database, stageConfig, logger, initData)
-- "Import"
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(PrimaryStage, Stage)
PrimaryStage.__index = PrimaryStage
setmetatable(PrimaryStage, {__index = Stage})
local self = setmetatable({}, { __index = PrimaryStage }) --[[@as PrimaryStage]]
self:superNew(database, stageConfig, logger, initData)
return self
local o = Stage.New(database, stageConfig, logger, initData, "primary") --[[@as PrimaryStage]]
return o
end
if not Spearhead.classes then Spearhead.classes = {} end
+5 -8
View File
@@ -4,6 +4,9 @@
---@field private _startTime number
local WaitingStage = {}
WaitingStage.__index = WaitingStage
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(WaitingStage, Stage)
---@class WaitingStageInitData : StageInitData
---@field waitingSeconds integer
@@ -17,14 +20,8 @@ local WaitingStageInitData = {}
---@return WaitingStage
function WaitingStage.New(database, stageConfig, logger, initData)
-- "Import"
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(WaitingStage, Stage)
WaitingStage.__index = WaitingStage
setmetatable(WaitingStage, {__index = Stage})
local self = Stage.New(database, stageConfig, logger, initData, "primary") --[[@as WaitingStage]]
setmetatable(self, WaitingStage)
local self = setmetatable({}, { __index = WaitingStage }) --[[@as WaitingStage]]
self:superNew(database, stageConfig, logger, initData)
self._waitTimeSeconds = 5
if initData.waitingSeconds and initData.waitingSeconds > 5 then self._waitTimeSeconds = initData.waitingSeconds end
+4 -4
View File
@@ -12,9 +12,9 @@ local startTime = timer.getTime() * 1000
Spearhead.Events.Init("DEBUG")
local dbLogger = Spearhead.LoggerTemplate:new("database", "INFO")
local standardLogger = Spearhead.LoggerTemplate:new("", "INFO")
local databaseManager = Spearhead.DB.New(dbLogger, debug)
local dbLogger = Spearhead.LoggerTemplate.new("database", "INFO")
local standardLogger = Spearhead.LoggerTemplate.new("", "INFO")
local databaseManager = Spearhead.DB.New(dbLogger)
local capConfig = Spearhead.internal.configuration.CapConfig:new();
local stageConfig = Spearhead.internal.configuration.StageConfig:new();
@@ -22,7 +22,7 @@ local stageConfig = Spearhead.internal.configuration.StageConfig:new();
local startingStage = stageConfig.startingStage or 1
if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then
standardLogger:info("Persistence enabled")
local persistenceLogger = Spearhead.LoggerTemplate:new("Persistence", "INFO")
local persistenceLogger = Spearhead.LoggerTemplate.new("Persistence", "INFO")
Spearhead.classes.persistence.Persistence.Init(persistenceLogger)
local persistanceStage = Spearhead.classes.persistence.Persistence.GetActiveStage()