This commit is contained in:
2026-08-30 14:12:43 +02:00
parent 27548d69bb
commit 51bed10822
16 changed files with 214 additions and 49 deletions
+5 -2
View File
@@ -392,9 +392,12 @@ function CapBase:CheckAndScheduleIntercept()
end
end
end
end
function CapBase:OnStageNumberChanged(number)
function CapBase:OnStageNumberChanged(number, laneIdentifier)
-- only react on "main" lane changes, ignore other lanes for now
if laneIdentifier ~= nil then return end
self.activeStage = number
if self:IsBaseActiveWhenStageIsActive(number) == true then
@@ -2,6 +2,9 @@ local SpearheadEvents = require("classes.spearhead_events")
local RTBMission = require("classes.capClasses.taskings.RTB")
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local GlobalConfig = require("classes.configuration.GlobalConfig")
local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing")
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
---@class AirGroup : OnUnitLostListener
---@field protected _logger Logger
@@ -12,9 +15,12 @@ local DcsUtil = require("classes.util.DcsUtil")
---@field protected _config CapConfig
---@field protected _checkLivenessNumber number
---@field protected _spawnManager SpawnManager
---@field protected _routeDrawing CustomDrawing?
local AirGroup = {}
AirGroup.__index = AirGroup
local globalConfig = GlobalConfig.New()
---@param logger Logger
---@param groupName string
---@param groupType AirGroupType
@@ -28,6 +34,7 @@ function AirGroup:New(groupName, groupType, config, logger, spawnManager)
self._config = config
self._logger = logger
self._spawnManager = spawnManager
self._routeDrawing = nil
local group = Group.getByName(self._groupName)
if group then
@@ -92,6 +99,27 @@ function AirGroup:SetMissionPrivate(mission)
if group and mission then
group:getController():setTask(mission)
self._logger:debug("mission - Task set for group: " .. self._groupName)
if globalConfig:isDebugMenuEnabled() == true then
-- draw the mission route for debugging purposes
if self._routeDrawing then
self._routeDrawing:Remove()
end
local points = {}
if mission and mission.params and mission.params.route and mission.params.route.points then
for _, wp in pairs(mission.params.route.points) do
if wp.x and wp.y then
table.insert(points, { x = wp.x, y = wp.y })
end
end
end
local colorString = DrawingHelper.ColorTableToColorString({ 1, 0, 0, 1 })
self._routeDrawing = CustomDrawing.FromPoints(points, colorString, 5, 2)
self._routeDrawing:Draw()
end
end
end
@@ -6,6 +6,7 @@ local briefingMessageTime = nil
---@class GlobalConfig
---@field private _briefingTime number
---@field private _debugEnabled boolean
---@field private _debugMenuEnabled boolean
local GlobalConfig = {}
GlobalConfig.__index = GlobalConfig;
@@ -27,6 +28,8 @@ function GlobalConfig.New()
self._debugEnabled = false
end
self._debugMenuEnabled = SpearheadConfig.debugMenuEnabled == true
end
return self
@@ -40,6 +43,10 @@ function GlobalConfig:isDebugEnabled()
return self._debugEnabled or false
end
---@return boolean
function GlobalConfig:isDebugMenuEnabled()
return self._debugMenuEnabled or false
end
return GlobalConfig
+3 -1
View File
@@ -127,7 +127,9 @@ function FleetGroup:new(fleetGroupName, database, logger)
end
end
o.OnStageNumberChanged = function(self, number)
o.OnStageNumberChanged = function(self, number, laneIdentifier)
-- only react on "main" lane changes, ignore other lanes for now
if laneIdentifier ~= nil then return end
local targetZone = self.targetZonePerStage[tostring(number)]
if targetZone and targetZone ~= self.currentTargetZone then
local points = self.pointsPerZone[targetZone]
+10 -9
View File
@@ -13,7 +13,7 @@ do
---@field unitsStates table<string, UnitState>
---@field random_missions table<string, MissionState>
---@field deliveredKilos table<string, number>
---@field activeStage integer|nil
---@field activeStageInStageLane table<string, number>
---@class UnitState
---@field isDead boolean
@@ -33,7 +33,7 @@ do
unitsStates = {},
random_missions = {},
deliveredKilos = {},
activeStage = nil
activeStageInStageLane = {}
}
local logger = {}
@@ -230,9 +230,11 @@ do
end
---Sets the stage in the persistence table
---@param stageLane string?
---@param stageNumber number
Persistence.SetActiveStage = function(stageNumber)
tables.activeStage = stageNumber
Persistence.SetActiveStage = function(stageLane, stageNumber)
stageLane = stageLane or "nil"
tables.activeStageInStageLane[stageLane] = stageNumber
Persistence._updateRequired = true
end
@@ -256,12 +258,11 @@ do
end
---Get the active stage as in the persistance file
---@param stageLane string?
---@return integer|nil
Persistence.GetActiveStage = function()
if tables.activeStage then
return tables.activeStage
end
return nil
Persistence.GetActiveStage = function(stageLane)
stageLane = stageLane or "nil"
return tables.activeStageInStageLane[stageLane]
end
---comment
+4 -4
View File
@@ -45,13 +45,13 @@ do
end
---@class OnStageNumberChangeCompleteListener
---@field OnStageNumberChangeComplete fun(self:OnStageNumberChangeCompleteListener, number:integer)
---@field OnStageNumberChangeComplete fun(self:OnStageNumberChangeCompleteListener, number:integer, laneIdentifier:string?)
local OnStageNumberChangeCompleteListeners = {}
---@param listener OnStageNumberChangeCompleteListener
SpearheadEvents.AddStageNumberChangeCompleteListener = function(listener)
if type(listener) ~= "table" or type(listener.OnStageNumberChangeComplete) ~= "function" then
warn("Event handler not of type table/object with function OnStageNumberChangeComplete(self, number)")
warn("Event handler not of type table/object with function OnStageNumberChangeComplete(self, number, laneIdentifier)")
return
end
table.insert(OnStageNumberChangeCompleteListeners, listener)
@@ -61,7 +61,7 @@ do
---@param laneIdentifier string?
SpearheadEvents.PublishStageNumberChanged = function(newStageNumber, laneIdentifier)
pcall(function ()
Persistence.SetActiveStage(newStageNumber)
Persistence.SetActiveStage(laneIdentifier, newStageNumber)
end)
for _, callable in pairs(OnStageNumberChangedListeners) do
@@ -82,7 +82,7 @@ do
for _, callable in pairs(OnStageNumberChangeCompleteListeners) do
local succ, err = pcall(function()
callable:OnStageNumberChangeComplete(newStageNumber)
callable:OnStageNumberChangeComplete(newStageNumber, laneIdentifier)
end)
if err then
logError(err)
@@ -3,13 +3,14 @@ local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local Logger = require("classes.util.Logger")
local MissionEditorWarnings = require("classes.util.MissionEditorWarnings")
local PersistenceConfig = require("classes.configuration.PersistenceConfig")
local ExtraStage = require("classes.stageClasses.Stages.ExtraStage")
local PrimaryStage = require("classes.stageClasses.Stages.PrimaryStage")
local WaitingStage = require("classes.stageClasses.Stages.WaitingStage")
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
local StageRepository = require("classes.stageClasses.StageRepository")
local StageLane = require("classes.stageClasses.StageLane")
local Persistence = require("classes.persistence.Persistence")
local currentStage = -99
@@ -33,7 +34,7 @@ local singletonInstance = nil
---@param logLevel LogLevel
---@param spawnManager SpawnManager
---@return GlobalStageManager
function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnManager)
function GlobalStageManager.new(database, stageConfig, logLevel, spawnManager)
if singletonInstance ~= nil then
return singletonInstance
@@ -47,7 +48,7 @@ function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnMa
self.database = database
self.stageConfig = stageConfig
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
self._stageRepository = StageRepository.new()
self._stageRepository = StageRepository.getInstance()
self.logger = logger
if stageConfig.isAutoStages ~= true then
@@ -92,6 +93,38 @@ function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnMa
return self
end
function GlobalStageManager:Start()
self.logger:info("Starting GlobalStageManager")
local startingStage = self.stageConfig.startingStage or 1
local persistenceConfig = PersistenceConfig.new()
if persistenceConfig:isEnabled() == true then
self.logger:info("Persistence is enabled, loading stage state from persistence")
local stageLanes = self._stageRepository:getAllStageLanes()
for _, stageLane in pairs(stageLanes) do
local stageLaneIdentifier = stageLane:GetStageLaneIdentifier()
local persistedStage = Persistence.GetActiveStage(stageLaneIdentifier)
if persistedStage then
self.logger:info("Loaded persisted stage " .. persistedStage .. " for lane " .. (stageLaneIdentifier or "default"))
stageLane:SetActiveStageIndex(persistedStage)
Events.PublishStageNumberChanged(persistedStage, stageLaneIdentifier)
else
stageLane:SetActiveStageIndex(startingStage)
Events.PublishStageNumberChanged(startingStage, stageLaneIdentifier)
end
end
else
self.logger:info("Persistence is disabled, starting at stage " .. startingStage)
local stageLanes = self._stageRepository:getAllStageLanes()
for _, stageLane in pairs(stageLanes) do
stageLane:SetActiveStageIndex(startingStage)
Events.PublishStageNumberChanged(startingStage, stageLane:GetStageLaneIdentifier())
end
end
end
---@class StageNameParseResult
---@field isValid boolean
---@field orderNumber integer
@@ -204,10 +237,9 @@ function GlobalStageManager:OnStageComplete(stage)
-- COMPLETION IN THE DEFAULT LANE
-- 1. Check if any lane is at status "BetweenChapters" and the next chapter start is "next stage index"
local allLanes = self._stageRepository:getAllStageLanes()
for _, lane in ipairs(allLanes) do
if lane:GetStageLaneIdentifier() ~= StageLane.DefaultLaneKey and lane:GetStageLaneState() == "InChapter" then
if lane:GetStageLaneIdentifier() ~= StageLane.DefaultLaneKey and lane:GetStageLaneState() == "BetweenChapters" then
local nextChapterStart = lane:GetNextChapterStart()
if nextChapterStart == nextStageIndex then
self.logger:debug("Lane " .. (lane:GetStageLaneIdentifier() or "default") .. " is at chapter start for next stage index " .. nextStageIndex)
@@ -275,14 +307,19 @@ function GlobalStageManager:IsStageComplete(stageNumber, stageLaneIdentifier)
end
---@public
function GlobalStageManager:OnStageNumberChanged(stageNumber)
function GlobalStageManager:OnStageNumberChanged(stageNumber, stageLaneIdentifier)
-- only react on "main" lane changes, ignore other lanes for now
if stageLaneIdentifier ~= nil then return end
self.logger:debug("Stage number changed to: " .. tostring(stageNumber))
currentStage = stageNumber
self:UpdateDrawings(stageNumber)
end
function GlobalStageManager:OnStageNumberChangeComplete(stageNumber)
function GlobalStageManager:OnStageNumberChangeComplete(stageNumber, stageLaneIdentifier)
-- only react on "main" lane changes, ignore other lanes for now
if stageLaneIdentifier ~= nil then return end
self.logger:debug("Stage number change complete to: " .. tostring(stageNumber))
local groups = {}
@@ -5,14 +5,27 @@ local StageLane = require("classes.stageClasses.StageLane")
local StageRepository = {}
StageRepository.__index = StageRepository
local instance = nil
---@private
---@return StageRepository
function StageRepository.new()
local self = setmetatable({}, StageRepository)
self.StageLanes = {}
self.StageLanes[tostring(StageLane.DefaultLaneKey)] = StageLane.New(StageLane.DefaultLaneKey)
instance = self
return self
end
---@return StageRepository
StageRepository.getInstance = function()
if instance == nil then
instance = StageRepository.new()
end
return instance
end
---@param laneName string? `nil` for default lane
---@return StageLane?
@@ -329,6 +329,23 @@ function Stage:GetStageIndex()
return self.stageNumber
end
---@return string
function Stage:GetStageName()
return self.stageName
end
function Stage:GetMissions()
local missions = {}
for _, mission in pairs(self._db.missions) do
table.insert(missions, mission)
end
for _, sam in pairs(self._db.sams) do
table.insert(missions, sam)
end
return missions
end
---comment
function Stage:CheckAndUpdateSelf()
self._logger:debug("Checking on Stage: " .. self.zoneName)
@@ -389,7 +406,7 @@ function Stage:IsMissionComplete(missionName)
return mission:getState() == "COMPLETED"
end
---private use only
-- private usage only
function Stage:NotifyComplete()
self._logger:info("Stage complete: " .. (self.stageName or self.stageNumber or "unknown"))
@@ -514,7 +531,12 @@ end
---comment
---@param self Stage
---@param number integer
function Stage:OnStageNumberChanged(number)
---@param stageLaneIdentifier string?
function Stage:OnStageNumberChanged(number, stageLaneIdentifier)
if stageLaneIdentifier ~= self._stageLaneIdentifier then
return
end
if self._activeStage == number then --only activate once for a stage
return
@@ -36,7 +36,12 @@ end
---comment
---@param self ExtraStage
---@param number integer
function ExtraStage:OnStageNumberChanged(number)
---@param stageLaneIdentifier string?
function ExtraStage:OnStageNumberChanged(number, stageLaneIdentifier)
if stageLaneIdentifier ~= self._stageLaneIdentifier then
return
end
if self._activeStage == number then --only activate once for a stage
return
@@ -33,6 +33,36 @@ function CustomDrawing.New(drawingObject)
return self
end
---@param points Array<Vec2>
---@param colorString string
---@param lineStyle LineType
---@param lineThickness number
---@return CustomDrawing?
function CustomDrawing.FromPoints(points, colorString, lineStyle, lineThickness)
if points == nil or #points < 3 then
drawingLogger:warn("CustomDrawing.FromPoints called with nil or less than 3 points")
return nil
end
---@type FreeLine
local drawingObject = {
mapX = 0,
mapY = 0,
points = points,
lineMode = "free",
name = "custom_drawing_" .. tostring(math.random(1000000)),
primitiveType = "Polygon",
polygonMode = "free",
visible = true,
style = DrawingHelper.ToLineStyleString(lineStyle),
colorString = colorString,
thickness = lineThickness,
closed = false
}
return CustomDrawing.New(drawingObject)
end
---@param zone SpearheadTriggerZone
---@param colorString string
---@param fillColorString string
@@ -266,7 +266,7 @@ function DrawingHelper.ColorToColorTable(hexStr)
return { r, g , b , a }
end
---@param rgba table
---@param rgba table { r, g, b, a }
---@return string
function DrawingHelper.ColorTableToColorString(rgba)
if rgba == nil or #rgba < 4 or rgba[1] == nil or rgba[2] == nil or rgba[3] == nil or rgba[4] == nil then
@@ -126,6 +126,11 @@ function Mission:NotifyMissionComplete()
end
function Mission:ForceMissionComplete()
self._state = "COMPLETED"
self:NotifyMissionComplete()
end
function Mission:MarkMissionAreaToGroup(groupId) end
---endregion
+20 -19
View File
@@ -5,9 +5,11 @@ local DcsUtil = require("classes.util.DcsUtil")
local Database = require("classes.spearhead_db")
local SpearheadEvents = require("classes.spearhead_events")
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
local GlobalConfig = require("classes.configuration.GlobalConfig")
local CapConfig = require("classes.configuration.CapConfig")
local StageConfig = require("classes.configuration.StageConfig")
local Persistence = require("classes.persistence.Persistence")
local PersistenceConfig = require("classes.configuration.PersistenceConfig")
local SpawnManager = require("classes.helpers.SpawnManager")
local DetectionManager = require("classes.capClasses.detection.DetectionManager")
local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
@@ -33,19 +35,11 @@ MissionCommandsHelper.getOrCreate() -- initiate
local capConfig = CapConfig:new();
local stageConfig = StageConfig:getInstance();
local startingStage = stageConfig.startingStage or 1
if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then
standardLogger:info("Persistence enabled")
local persistenceConfig = PersistenceConfig.new()
if persistenceConfig and persistenceConfig:isEnabled() == true then
local persistenceLogger = Logger.new("Persistence", defaultLogLevel)
Persistence.Init(persistenceLogger)
local persistanceStage = Persistence.GetActiveStage()
if persistanceStage then
standardLogger:info("Persistance activated and using persistant active stage: " .. persistanceStage)
startingStage = persistanceStage
end
else
standardLogger:info("Persistence disabled")
end
local spawnLogger = Logger.new("SpawnManager", defaultLogLevel)
@@ -54,16 +48,9 @@ local detectionLogger = Logger.new("DetectionManager", defaultLogLevel)
local detectionManager = DetectionManager.New(detectionLogger)
GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel, spawnManager)
local globalStageManager = GlobalStageManager.NewAndStart(databaseManager, stageConfig, defaultLogLevel, spawnManager)
local globalStageManager = GlobalStageManager.new(databaseManager, stageConfig, defaultLogLevel, spawnManager)
GlobalFleetManager.start(databaseManager)
local SetStageDelayed = function(number, time)
SpearheadEvents.PublishStageNumberChanged(number)
return nil
end
timer.scheduleFunction(SetStageDelayed, startingStage, timer.getTime() + 3)
env.info(startTime .. "ms / " .. timer.getTime() * 1000 .. "ms")
local duration = (timer.getTime() * 1000) - startTime
standardLogger:info("Spearhead Initialisation duration: " .. tostring(duration) .. "ms")
@@ -72,3 +59,17 @@ local missionEditorWarningsLogger = Logger.new("MissionEditorWarnings", defaultL
MissionEditorWarnings.WriteAll(missionEditorWarningsLogger)
globalStageManager:PrintMermaidStage()
local startDelayed = function()
globalStageManager:Start()
return nil
end
timer.scheduleFunction(startDelayed, nil, timer.getTime() + 5) -- delay start by 5 seconds so every deleted item it first removed entirely
local globalConfig = GlobalConfig.New()
if globalConfig and globalConfig:isDebugMenuEnabled() == true then
local DebugMenu = require("classes.debug.DebugMenu")
local debugMenu = DebugMenu.new()
debugMenu:RegisterMenus()
end