Refactored Persistance managed by SpawnManager for groups, and added … (#53)

* Refactored Persistance managed by SpawnManager for groups, and added Persistence for buildables
* get last file based on the iteration number
* Working persistence of everything as a MVP version
This commit is contained in:
2025-07-11 20:06:09 +02:00
committed by GitHub
parent 3d19137970
commit b6a1285bde
30 changed files with 994 additions and 763 deletions
Binary file not shown.
+5 -4
View File
@@ -32,8 +32,9 @@ end
---@param stageConfig table ---@param stageConfig table
---@param runwayBombingTracker RunwayBombingTracker ---@param runwayBombingTracker RunwayBombingTracker
---@param detectionManager DetectionManager ---@param detectionManager DetectionManager
---@param spawnManager SpawnManager
---@return CapBase ---@return CapBase
function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runwayBombingTracker, detectionManager) function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager)
CapBase.__index = CapBase CapBase.__index = CapBase
local self = setmetatable({}, { __index = CapBase }) --[[@as CapBase]] local self = setmetatable({}, { __index = CapBase }) --[[@as CapBase]]
@@ -53,7 +54,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw
local baseData = database:getAirbaseDataForZone(airbaseName) local baseData = database:getAirbaseDataForZone(airbaseName)
if baseData and baseData.CapGroups then if baseData and baseData.CapGroups then
for key, name in pairs(baseData.CapGroups) do for key, name in pairs(baseData.CapGroups) do
local capGroup = Spearhead.classes.capClasses.airGroups.CapGroup.New(name, capConfig, logger) local capGroup = Spearhead.classes.capClasses.airGroups.CapGroup.New(name, capConfig, logger, spawnManager)
if capGroup then if capGroup then
self.capGroupsByName[name] = capGroup self.capGroupsByName[name] = capGroup
end end
@@ -62,7 +63,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw
if baseData and baseData.SweepGroups then if baseData and baseData.SweepGroups then
for key, name in pairs(baseData.SweepGroups) do for key, name in pairs(baseData.SweepGroups) do
local sweepGroup = Spearhead.classes.capClasses.airGroups.SweepGroup.New(name, capConfig, logger) local sweepGroup = Spearhead.classes.capClasses.airGroups.SweepGroup.New(name, capConfig, logger, spawnManager)
if sweepGroup then if sweepGroup then
self.sweepGroupsByName[name] = sweepGroup self.sweepGroupsByName[name] = sweepGroup
end end
@@ -71,7 +72,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw
if baseData and baseData.InterceptGroups then if baseData and baseData.InterceptGroups then
for key, name in pairs(baseData.InterceptGroups) do for key, name in pairs(baseData.InterceptGroups) do
local interceptGroup = Spearhead.classes.capClasses.airGroups.InterceptGroup.New(name, capConfig, logger, detectionManager) local interceptGroup = Spearhead.classes.capClasses.airGroups.InterceptGroup.New(name, capConfig, logger, detectionManager, spawnManager)
if interceptGroup then if interceptGroup then
self.interceptGroupsByName[name] = interceptGroup self.interceptGroupsByName[name] = interceptGroup
end end
+5 -2
View File
@@ -13,7 +13,8 @@ do
---@param stageConfig StageConfig ---@param stageConfig StageConfig
---@param detectionManager DetectionManager ---@param detectionManager DetectionManager
---@param logLevel LogLevel ---@param logLevel LogLevel
function GlobalCapManager.start(database, capConfig, detectionManager, stageConfig, logLevel) ---@param spawnManager SpawnManager
function GlobalCapManager.start(database, capConfig, detectionManager, stageConfig, logLevel, spawnManager)
if initiated == true then return end if initiated == true then return end
local logger = Spearhead.LoggerTemplate.new("AirbaseManager", logLevel) local logger = Spearhead.LoggerTemplate.new("AirbaseManager", logLevel)
@@ -32,7 +33,9 @@ do
for _, airbaseName in pairs(airbaseNames) do for _, airbaseName in pairs(airbaseNames) do
if airbaseName then if airbaseName then
local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, logLevel) local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, logLevel)
local airbase = Spearhead.classes.capClasses.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker, detectionManager)
local airbase = Spearhead.classes.capClasses.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager)
if airbase then if airbase then
table.insert(airbasesPerStage[stageName], airbase) table.insert(airbasesPerStage[stageName], airbase)
allAirbasesByName[airbaseName] = airbase allAirbasesByName[airbaseName] = airbase
+14 -4
View File
@@ -6,6 +6,7 @@
---@field protected _isSpawned boolean ---@field protected _isSpawned boolean
---@field protected _config CapConfig ---@field protected _config CapConfig
---@field protected _checkLivenessNumber number ---@field protected _checkLivenessNumber number
---@field protected _spawnManager SpawnManager
local AirGroup = {} local AirGroup = {}
AirGroup.__index = AirGroup AirGroup.__index = AirGroup
@@ -13,13 +14,15 @@ AirGroup.__index = AirGroup
---@param groupName string ---@param groupName string
---@param groupType AirGroupType ---@param groupType AirGroupType
---@param config CapConfig ---@param config CapConfig
function AirGroup:New(groupName, groupType, config, logger) ---@param spawnManager SpawnManager
function AirGroup:New(groupName, groupType, config, logger, spawnManager)
self._groupName = groupName self._groupName = groupName
self._groupType = groupType self._groupType = groupType
self._isSpawned = false self._isSpawned = false
self._state = "UnSpawned" -- Default state self._state = "UnSpawned" -- Default state
self._config = config self._config = config
self._logger = logger self._logger = logger
self._spawnManager = spawnManager
local group = Group.getByName(self._groupName) local group = Group.getByName(self._groupName)
if group then if group then
@@ -31,7 +34,8 @@ function AirGroup:New(groupName, groupType, config, logger)
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self) Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
Spearhead.Events.addOnUnitLandEventListener(unit:getName(), self) Spearhead.Events.addOnUnitLandEventListener(unit:getName(), self)
end end
Spearhead.DcsUtil.DestroyGroup(self._groupName)
spawnManager:DestroyGroup(groupName)
end end
end end
@@ -135,13 +139,19 @@ function AirGroup:SpawnInternal(force, withoutLoadout)
if self._isSpawned and force ~= true then return end if self._isSpawned and force ~= true then return end
local group, isStatic = Spearhead.DcsUtil.SpawnGroupTemplate(self._groupName, nil, nil, true, nil, withoutLoadout) ---@type SpawnOverrides
local overrides = {
emptyLoadouts = withoutLoadout,
uncontrolled = true
}
local group, isStatic = self._spawnManager:SpawnGroup(self._groupName, overrides, false)
if isStatic == true then if isStatic == true then
--- If For Some reaons someone tries to schedule static units as CAP classes --- If For Some reaons someone tries to schedule static units as CAP classes
self._state = "UnSpawned" self._state = "UnSpawned"
return return
end end
group = group --[[@as Group]]
if group then if group then
self._group = group self._group = group
self._isSpawned = true self._isSpawned = true
+3 -2
View File
@@ -10,12 +10,13 @@ CapGroup.__index = CapGroup
---@param groupName string ---@param groupName string
---@param config CapConfig ---@param config CapConfig
---@param logger Logger ---@param logger Logger
---@param spawnManager SpawnManager
---@return CapGroup ---@return CapGroup
function CapGroup.New(groupName, config, logger) function CapGroup.New(groupName, config, logger, spawnManager)
setmetatable(CapGroup, Spearhead.classes.capClasses.airGroups.AirGroup) setmetatable(CapGroup, Spearhead.classes.capClasses.airGroups.AirGroup)
local self = setmetatable({}, CapGroup) --[[@as CapGroup]] local self = setmetatable({}, CapGroup) --[[@as CapGroup]]
Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "CAP", config, logger) Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "CAP", config, logger, spawnManager)
self._targetZoneIdPerStage = {} self._targetZoneIdPerStage = {}
@@ -18,12 +18,13 @@ InterceptGroup.__index = InterceptGroup
---@param config CapConfig ---@param config CapConfig
---@param logger Logger ---@param logger Logger
---@param detectionManager DetectionManager ---@param detectionManager DetectionManager
---@param spawnManager SpawnManager
---@return InterceptGroup? ---@return InterceptGroup?
function InterceptGroup.New(groupName, config, logger, detectionManager) function InterceptGroup.New(groupName, config, logger, detectionManager, spawnManager)
setmetatable(InterceptGroup, Spearhead.classes.capClasses.airGroups.AirGroup) setmetatable(InterceptGroup, Spearhead.classes.capClasses.airGroups.AirGroup)
local self = setmetatable({}, InterceptGroup) local self = setmetatable({}, InterceptGroup)
Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "INTERCEPT", config, logger) Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "INTERCEPT", config, logger, spawnManager)
local group = Group.getByName(groupName) local group = Group.getByName(groupName)
if not group then if not group then
+3 -2
View File
@@ -8,11 +8,12 @@ SweepGroup.__index = SweepGroup
---@param groupName string ---@param groupName string
---@param config CapConfig ---@param config CapConfig
---@param logger Logger ---@param logger Logger
---@param spawnManager SpawnManager
---@return SweepGroup ---@return SweepGroup
function SweepGroup.New(groupName, config, logger) function SweepGroup.New(groupName, config, logger, spawnManager)
setmetatable(SweepGroup, Spearhead.classes.capClasses.airGroups.AirGroup) setmetatable(SweepGroup, Spearhead.classes.capClasses.airGroups.AirGroup)
local self = setmetatable({}, SweepGroup) --[[@as SweepGroup]] local self = setmetatable({}, SweepGroup) --[[@as SweepGroup]]
Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "SWEEP", config, logger) Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "SWEEP", config, logger, spawnManager)
self._targetZoneIdPerStage = {} self._targetZoneIdPerStage = {}
self:InitWithName(groupName) self:InitWithName(groupName)
+1 -1
View File
@@ -8,7 +8,7 @@ GlobalFleetManager.start = function(database)
local logger = Spearhead.LoggerTemplate.new("CARRIERFLEET", "INFO") local logger = Spearhead.LoggerTemplate.new("CARRIERFLEET", "INFO")
local all_groups = Spearhead.DcsUtil.getAllGroupNames() local all_groups = Spearhead.classes.helpers.MizGroupsManager.getAllGroupNames()
for _, groupName in pairs(all_groups) do for _, groupName in pairs(all_groups) do
if Spearhead.Util.startswith(string.lower(groupName), "carriergroup" ) == true then if Spearhead.Util.startswith(string.lower(groupName), "carriergroup" ) == true then
logger:info("Registering " .. groupName .. " as a managed fleet") logger:info("Registering " .. groupName .. " as a managed fleet")
+81
View File
@@ -0,0 +1,81 @@
---@class SpawnData
---@field groupTemplate table
---@field isStatic boolean
---@field category number
---@field country number
---@class MizGroupsManager
---@field private _groupNames Array<string>
---@field private _spawnTemplateData table<string, SpawnData>
local MizGroupsManager = {}
MizGroupsManager._groupNames = {}
MizGroupsManager._spawnTemplateData = {}
do --init
for coalition_name, coalition_data in pairs(env.mission.coalition) do
local coalition_nr = Spearhead.DcsUtil.stringToCoalition(coalition_name)
if coalition_data.country then
for country_index, country_data in pairs(coalition_data.country) do
for category_name, categorydata in pairs(country_data) do
local category_id = Spearhead.DcsUtil.stringToGroupCategory(category_name)
if category_id ~= nil and type(categorydata) == "table" and categorydata.group ~= nil and type(categorydata.group) == "table" then
for group_index, group in pairs(categorydata.group) do
local name = group.name
local skippable = false
local isStatic = false
if category_id == Spearhead.DcsUtil.GroupCategory.STATIC then
isStatic = true
local unit = group.units[1]
if unit and unit.category == "Heliports" then
skippable = true
elseif unit and unit.name then
name = unit.name
else
env.error("Group " .. name .. " has no units, skipping it.")
skippable = true
end
end
if skippable == false then
MizGroupsManager._spawnTemplateData[name] =
{
isStatic = isStatic,
country = country_data.id,
category = category_id,
groupTemplate = group
}
table.insert(MizGroupsManager._groupNames, name)
end
end
end
end
end
end
end
end
---@return Array<string>
function MizGroupsManager.getAllGroupNames()
return MizGroupsManager._groupNames
end
---@return boolean?
---@param groupName string
function MizGroupsManager.IsGroupStatic(groupName)
local spawnData = MizGroupsManager._spawnTemplateData[groupName]
if spawnData then
return spawnData.isStatic
end
return nil
end
---@return SpawnData?
function MizGroupsManager.getSpawnTemplateData(groupName)
return MizGroupsManager._spawnTemplateData[groupName]
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.helpers then Spearhead.classes.helpers = {} end
Spearhead.classes.helpers.MizGroupsManager = MizGroupsManager
+348
View File
@@ -0,0 +1,348 @@
---@class SpawnManager : OnUnitLostListener
---@field private _persistedUnits table<string,boolean>
---@field private _logger Logger
local SpawnManager = {}
SpawnManager.__index = SpawnManager
---@class SpawnOverrides
---@field countryID number?
---@field emptyLoadouts boolean? if true, the group will spawn with empty loadouts
---@field route table? route of the group. If nil will be the default route.
---@field uncontrolled boolean? Sets the group to be uncontrolled on spawn
---@param logger Logger
function SpawnManager.new(logger)
local self = setmetatable({}, SpawnManager)
self._logger = logger
self._persistedUnits = {} -- Stores units that should be persisted by name
return self
end
---comment
---@param groupName string
---@param overrides SpawnOverrides? overrides for the spawn
---@param isGroupPersistant boolean? whether or not a group and all its units should be persisted.
---@return StaticObject|Group|nil spawned
---@return boolean isStatic
function SpawnManager:SpawnGroup(groupName, overrides, isGroupPersistant)
local spawnData = Spearhead.classes.helpers.MizGroupsManager.getSpawnTemplateData(groupName)
if spawnData == nil then
env.error("SpawnManager:SpawnGroup - No spawn template found for group: " .. groupName)
return nil, false
end
if spawnData.isStatic == true then
return self:SpawnStaticInternal(groupName, spawnData, overrides, isGroupPersistant), true
else
return self:SpawnGroupInternal(groupName, spawnData, overrides, isGroupPersistant), false
end
end
function SpawnManager:DestroyGroup(groupName)
if groupName == nil then return end
if self:IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName)
if object ~= nil then
object:destroy()
else
env.error("SpawnManager:DestroyGroup - Static object not found: " .. groupName)
end
else
local group = Group.getByName(groupName)
if group and group:isExist() then
group:destroy()
else
env.error("SpawnManager:DestroyGroup - Group not found or does not exist: " .. groupName)
end
end
end
---comment
---@param groupName string
---@return boolean
function SpawnManager:IsGroupStatic(groupName)
local isStatic = Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName)
if isStatic ~= nil then return isStatic end
return StaticObject.getByName(groupName) ~= nil
end
---@param object Object
function SpawnManager:OnUnitLost(object)
local name = object:getName()
if self._persistedUnits[name] then
local heading = 0
local pos = object:getPosition()
if pos then
heading = math.atan2(pos.x.z, pos.x.x)
if heading < 0 then
heading = heading + 2*math.pi
end
heading = heading
end
Spearhead.classes.persistence.Persistence.UnitKilled(
name,
object:getPoint(),
heading,
object:getTypeName()
)
end
end
function SpawnManager:SpawnCorpsesOnly(groupName)
end
do --- privates
---@private
---@param groupName string
---@param spawnData SpawnData
---@param override SpawnOverrides?
---@param isPersistent boolean?
---@return Group|nil
function SpawnManager:SpawnGroupInternal(groupName, spawnData, override, isPersistent)
if not spawnData then return end
local country = spawnData.country
if override then
country = override.countryID or spawnData.country
end
local spawnTemplate = Spearhead.Util.deepCopyTable(spawnData.groupTemplate)
---@type Array<string>
local removeableUnitNames = {}
--[[
TODO: Spawn units at "current"/LastKnown position with them going to the next waypoint.
ONLY when perstable data is found.
]]
if spawnTemplate and spawnTemplate["units"] then
for _, unit in pairs(spawnTemplate["units"]) do
local name = unit["name"]
Spearhead.Events.addOnUnitLostEventListener(name, self)
local state = Spearhead.classes.persistence.Persistence.UnitState(name)
if state then
if state.isDead == true then
removeableUnitNames[#removeableUnitNames+1] = name
end
end
if override and override.emptyLoadouts == true then
if unit["payload"] and unit["payload"]["pylons"] then
unit["payload"]["pylons"] = {}
end
end
if unit["parking"] then
unit["parking_landing"] = unit["parking"]
end
if unit["parking_id"] then
unit["parking_landing_id"] = unit["parking_id"]
end
end
if override and override.route ~= nil then
spawnTemplate["route"] = override.route
end
if override and override.uncontrolled ~= nil then
spawnTemplate["uncontrolled"] = override.uncontrolled
end
local group = coalition.addGroup(country, spawnData.category, spawnTemplate)
for _, unit in pairs(group:getUnits()) do
self:CheckUnitAndReplaceIfPersistentDead(unit)
if isPersistent == true then
self._persistedUnits[unit:getName()] = true
end
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
end
return group
end
return nil
end
---@private
---@param groupName string
---@param spawnData SpawnData
---@param isPersistent any
---@param overrides SpawnOverrides?
---@return StaticObject?
function SpawnManager:SpawnStaticInternal(groupName, spawnData, overrides, isPersistent)
if not spawnData then return end
local country = spawnData.country
if overrides then
country = overrides.countryID or spawnData.country
end
local spawnTemplate = Spearhead.Util.deepCopyTable(spawnData.groupTemplate)
--for static Objecst groupNames and unit names are the same and is always 1:1
local persistentState = Spearhead.classes.persistence.Persistence.UnitState(groupName)
if persistentState then
if persistentState.isDead == true then
spawnTemplate["dead"] = true
if persistentState.pos then
spawnTemplate["x"] = persistentState.pos.x
spawnTemplate["y"] = persistentState.pos.z
if spawnTemplate["units"] and spawnTemplate["units"][1] then
spawnTemplate["units"][1]["x"] = persistentState.pos.x
spawnTemplate["units"][1]["y"] = persistentState.pos.z
spawnTemplate["units"][1]["heading"] = persistentState.heading or 0
end
end
end
end
---disable diagnostic as -1 is actually valid
---@diagnostic disable-next-line: param-type-mismatch
coalition.addGroup(country, -1, spawnTemplate)
local object = StaticObject.getByName(groupName)
if object == nil then
env.error("Could not retrieve spawned static object after spawning with name: " .. groupName)
return nil
end
if isPersistent == true then
self._persistedUnits[groupName] = true
Spearhead.Events.addOnUnitLostEventListener(groupName, self)
end
return object
end
---@private
---@param unit Unit
function SpawnManager:CheckUnitAndReplaceIfPersistentDead(unit)
if not unit then return end
local deadState = Spearhead.classes.persistence.Persistence.UnitState(unit:getName())
if deadState and deadState.isDead == true then
unit:destroy() -- Destroy the unit if it is dead
local staticObject = {
["heading"] = deadState.heading or 0,
["type"] = deadState.type or unit:getTypeName(),
["name"] = unit:getName() .. "_dead",
["x"] = deadState.pos.x,
["y"] = deadState.pos.z,
["dead"] = true,
}
coalition.addStaticObject(unit:getCountry(), staticObject)
end
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.helpers then Spearhead.classes.helpers = {} end
Spearhead.classes.helpers.SpawnManager = SpawnManager
--Old Spawn Method
-- --- spawns the units as specified in the mission file itself
-- --- location and route can be nil and will then use default route
-- ---@param groupName string
-- ---@param location table? vector 3 data. { x , z, alt }
-- ---@param route table? route of the group. If nil wil be the default route.
-- ---@param uncontrolled boolean? Sets the group to be uncontrolled on spawn
-- ---@param countryId CountryID? Overwrites the country
-- ---@param emptyLoadouts boolean? If true, the group will spawn with empty loadouts
-- ---@return table? new_group the Group class that was spawned
-- ---@return boolean? isStatic whether the group is a static or not
-- function DCS_UTIL.SpawnGroupTemplate(groupName, location, route, uncontrolled, countryId, emptyLoadouts)
-- if groupName == nil then
-- return nil, nil
-- end
-- local template = DCS_UTIL.GetMizGroupOrDefault(groupName, nil)
-- if template == nil then
-- return nil, nil
-- end
-- if template.category == DCS_UTIL.GroupCategory.STATIC then
-- --TODO: Implement location and route stuff
-- local spawn_template = template.group_template
-- local country = countryId or template.country_id
-- ---disable diagnostic as -1 is actually valid
-- ---@diagnostic disable-next-line: param-type-mismatch
-- coalition.addGroup(country, -1, spawn_template)
-- local object = StaticObject.getByName(spawn_template.name)
-- if object then
-- return object, true
-- end
-- else
-- local spawn_template = Spearhead.Util.deepCopyTable(template.group_template)
-- if location ~= nil then
-- local x_offset
-- if location.x ~= nil then x_offset = spawn_template.x - location.x end
-- local y_offset
-- if location.z ~= nil then y_offset = spawn_template.y - location.z end
-- spawn_template.x = location.x
-- spawn_template.y = location.z
-- for i, unit in pairs(spawn_template.units) do
-- unit.x = unit.x - x_offset
-- unit.y = unit.y - y_offset
-- unit.alt = location.alt
-- end
-- end
-- if spawn_template.units then
-- for _, unit in pairs(spawn_template.units) do
-- if unit["parking"] then
-- unit["parking_landing"] = unit["parking"]
-- end
-- if unit["parking_id"] then
-- unit["parking_landing_id"] = unit["parking_id"]
-- end
-- end
-- if emptyLoadouts == true then
-- for _, unit in pairs(spawn_template.units) do
-- if unit["payload"] and unit["payload"]["pylons"] then
-- unit["payload"]["pylons"] = {}
-- end
-- end
-- end
-- end
-- if route ~= nil then
-- spawn_template.route = route
-- end
-- if uncontrolled ~= nil then
-- spawn_template.uncontrolled = uncontrolled
-- end
-- local country = countryId or template.country_id
-- local new_group = coalition.addGroup(country, template.category, spawn_template)
-- return new_group, false
-- end
-- end
+160 -54
View File
@@ -1,43 +1,54 @@
---@class Perstistence
---@field private _path string
---@field private _updateRequired boolean
local Persistence = {} local Persistence = {}
do do
local EXTENSION = "spearhead"
---@class PersistentData ---@class PersistentData
---@field dead_units table<string, DeathState> ---@field version string
---@field unitsStates table<string, UnitState>
---@field random_missions table<string, MissionState> ---@field random_missions table<string, MissionState>
---@field deliveredKilos table<string, number>
---@field activeStage integer|nil ---@field activeStage integer|nil
---@class DeathState ---@class UnitState
---@field isDead boolean ---@field isDead boolean
---@field pos Vec3 ---@field pos Vec3?
---@field heading number ---@field heading number?
---@field type string ---@field type string?
---@field country_id integer
local persistanceWriteIntervalSeconds = 15 local persistanceWriteIntervalSeconds = 15
local enabled = false local enabled = false
local version = "1.0.0"
---@type PersistentData ---@type PersistentData
local tables = { local tables = {
dead_units = {}, version = version,
unitsStates = {},
random_missions = {}, random_missions = {},
deliveredKilos = {},
activeStage = nil activeStage = nil
} }
local logger = {} local logger = {}
if SpearheadConfig == nil then SpearheadConfig = {} end if SpearheadConfig == nil then SpearheadConfig = {} end
if SpearheadConfig.Persistence == nil then SpearheadConfig.Persistence = {} end if SpearheadConfig.Persistence == nil then SpearheadConfig.Persistence = {} end
local path = nil
local updateRequired = false
local createFileIfNotExists = function() local createFileIfNotExists = function(path)
if not path then return end if not path or path == "" then
logger:error("Persistence file path is not set, cannot create file")
return
end
local f = io.open(path, "r") local f = io.open(path, "r")
if f == nil then if f == nil then
logger:info("Persistence file does not exist, creating new one at: " .. path)
f = io.open(path, "w+") f = io.open(path, "w+")
if f == nil then if f == nil then
logger:error("Could not create a file") logger:error("Could not create a file")
@@ -45,53 +56,42 @@ do
f:write("{}") f:write("{}")
f:close() f:close()
end end
logger:info("Created new persistence file at: " .. path)
else else
f:close() f:close()
end end
end end
local loadTablesFromFile = function() ---@param path string
local loadTablesFromFile = function(path)
if not path then return end if not path then return end
logger:info("Loading data from persistance file...") logger:info("Loading data from persistance file...")
local f = io.open(path, "r") local f = io.open(path, "r")
if f == nil then if f == nil then
logger:error("Could not open persistence file for reading: " .. path)
return return
end end
local json = f:read("*a") local json = f:read("*a")
f:close() f:close()
logger:debug("Loaded persistence file content: " .. json)
local lua = net.json2lua(json) --[[@as PersistentData]] local lua = net.json2lua(json) --[[@as PersistentData]]
if lua.activeStage then if lua then
logger:info("Found active stage from save: " .. lua.activeStage) tables = lua
tables.activeStage = lua.activeStage logger:debug("Loaded persistence data: " .. Spearhead.Util.toString(lua))
else
logger:error("Could not load persistence file, using default tables")
end end
if lua.dead_units then if tables.version == nil then tables.version = version end
logger:debug("Found saved dead units")
for name, deadState in pairs(lua.dead_units) do
logger:debug("Found saved dead unit: " .. name)
if type(deadState) == "table" then
tables.dead_units[name] = {
isDead = deadState.isDead == true,
pos = deadState.pos,
heading = deadState.heading,
type = deadState.type,
country_id = deadState.country_id
}
end
end
end
end end
local writeToFile = function() local writeToFile = function()
if not path then return end if not Persistence._path then return end
local path = Persistence._path
local f = io.open(path, "w+") local f = io.open(path, "w+")
if f == nil then if f == nil then
error("Could not open file for writing") error("Could not open file for writing")
@@ -104,11 +104,13 @@ do
if f ~= nil then if f ~= nil then
f:close() f:close()
end end
Persistence._updateRequired = false
logger:info("Wrote persistence data to file")
end end
local UpdateContinuous = function(null, time) local UpdateContinuous = function(null, time)
env.info("[Spearhead][Persistence] Checking up on persistence state...")
if updateRequired then if Persistence._updateRequired == true then
local status, result = pcall(writeToFile) local status, result = pcall(writeToFile)
if status == false then if status == false then
env.error("[Spearhead][Persistence] Could not write state to file: " .. result) env.error("[Spearhead][Persistence] Could not write state to file: " .. result)
@@ -129,33 +131,107 @@ do
end end
local warnForNonPersistenceContinous = function(null, time)
trigger.action.outText("Persistence was enabeld, however, io and lfs are not available and no persistence will be done. Make sure to either disable persistence or fix the issues before continuing.", 10)
return time + 9
end
---@param dir string @BaseDirectory
---@return string
local getLastFileOrDefault = function(dir, startsWith, default)
local latestFile, lastNumber = default, 0
for file in lfs.dir(dir) do
local split = Spearhead.Util.split_string(file, ".")
local doesStartWith = Spearhead.Util.startswith(file, startsWith, true)
if split and #split > 0 and split[#split] == EXTENSION and doesStartWith == true then
local numberString = split[#split-1]
local number = tonumber(numberString)
if number ~= nil and number > lastNumber then
lastNumber = number
latestFile = file
end
end
end
return latestFile
end
---comment ---comment
---@param persistenceLogger Logger ---@param persistenceLogger Logger
Persistence.Init = function(persistenceLogger) Persistence.Init = function(persistenceLogger)
logger = persistenceLogger logger = persistenceLogger
logger:info("Initiating Persistence Manager") logger:info("Initiating Persistence Manager")
logger:debug("Initiating Persistence Manager")
if lfs == nil or io == nil then if lfs == nil or io == nil then
logger:error("lfs and io seem to be sanitized. Persistence is skipped and disabled") logger:error("lfs and io seem to be sanitized. Persistence is skipped and disabled")
enabled = false
timer.scheduleFunction(warnForNonPersistenceContinous, nil, timer.getTime() + 10)
return return
end end
path = (SpearheadConfig.Persistence.directory or (lfs.writedir() .. "\\Data" )) .. "\\" .. (SpearheadConfig.Persistence.fileName or "Spearhead_Persistence.json") ---@type string
local dir = lfs.writedir() .. "\\Data"
local fileName = "Spearhead_Persistence.0.spearhead"
if SpearheadConfig and SpearheadConfig.Persistence then
if SpearheadConfig.Persistence.fileName then
logger:info("Persistence file path: " .. path) local userFileName = SpearheadConfig.Persistence.fileName
local split = Spearhead.Util.split_string(userFileName, ".")
createFileIfNotExists() if not split and #split < 3 then
loadTablesFromFile() split[#split+1] = "0"
split[#split+1] = "spearhead"
end
if tonumber(split[#split-1]) == nil then
split[#split+1] = "0"
split[#split+1] = "spearhead"
end
fileName = table.concat(split, ".")
end
if SpearheadConfig.Persistence.directory ~= nil then
dir = SpearheadConfig.Persistence.directory
end
end
local split = Spearhead.Util.split_string(fileName, ".")
local matchingPart = table.concat(Spearhead.Util.sublist(split, 1, #split-2), ".")
local lastFile = getLastFileOrDefault(dir--[[@as string]], matchingPart, fileName)
local fileSplit = Spearhead.Util.split_string(lastFile, ".")
fileSplit[#fileSplit-1] = tostring(tonumber(fileSplit[#fileSplit-1]) + 1)
fileName = table.concat(fileSplit, ".")
if lastFile ~= fileName then
logger:info("Found last persistence file: " .. lastFile)
else
logger:info("No previous persistence file found, using default: " .. fileName)
end
logger:info("New Persistence file name: " .. tostring(fileName))
local lastPath = dir .. "\\" .. lastFile
local path = dir .. "\\" .. fileName
Persistence._path = path
createFileIfNotExists(path)
loadTablesFromFile(lastPath)
timer.scheduleFunction(UpdateContinuous, nil, timer.getTime() + 120) timer.scheduleFunction(UpdateContinuous, nil, timer.getTime() + 120)
enabled = true enabled = true
Persistence.UpdateNow()
end end
---Sets the stage in the persistence table ---Sets the stage in the persistence table
---@param stageNumber number ---@param stageNumber number
Persistence.SetActiveStage = function(stageNumber) Persistence.SetActiveStage = function(stageNumber)
tables.activeStage = stageNumber tables.activeStage = stageNumber
updateRequired = true Persistence._updateRequired = true
end end
---comment ---comment
@@ -166,7 +242,7 @@ do
if tables.random_missions == nil then tables.random_missions = {} end if tables.random_missions == nil then tables.random_missions = {} end
tables.random_missions[string.lower(missionName)] = pickedZone tables.random_missions[string.lower(missionName)] = pickedZone
updateRequired = true Persistence._updateRequired = true
end end
---Get the picked random mission from the persistence file ---Get the picked random mission from the persistence file
@@ -186,19 +262,49 @@ do
return nil return nil
end end
---Check if the unit was dead during the last save. Nil if persitance not enabled ---comment
---@param zoneName string
---@param kilos number
Persistence.SetZoneDeliveredKilos = function(zoneName, kilos)
if enabled == false then return end
if tables.deliveredKilos == nil then
tables.deliveredKilos = {}
end
tables.deliveredKilos[zoneName] = kilos
Persistence._updateRequired = true
end
Persistence.GetZoneDeliveredKilos = function(zoneName)
if enabled == false then return 0 end
if tables.deliveredKilos == nil then
tables.deliveredKilos = {}
end
return tables.deliveredKilos[zoneName] or 0
end
---Check if the unit was dead during the last save. Nil if persitance not enabled or no state is found
---@param unitName string name ---@param unitName string name
---@return DeathState|nil { isDead, pos = {x,y,z}, heading, type, country_id } ---@return UnitState|nil { isDead, pos = {x,y,z}, heading, type, country_id }
Persistence.UnitDeadState = function(unitName) Persistence.UnitState = function(unitName)
if Persistence.isEnabled() == false then if Persistence.isEnabled() == false then
return nil return nil
end end
local entry = tables.dead_units[unitName] local entry = tables.unitsStates[unitName]
if entry then if entry then
return entry return entry
else else
return { isDead = false } ---@type UnitState
local state = {
isDead = false
}
return state
end end
end end
@@ -207,19 +313,19 @@ do
---@param position Vec3 { x, y ,z } ---@param position Vec3 { x, y ,z }
---@param heading number ---@param heading number
---@param type string ---@param type string
---@param country_id number Persistence.UnitKilled = function (name, position, heading, type)
Persistence.UnitKilled = function (name, position, heading, type, country_id)
if enabled == false then return end if enabled == false then return end
tables.dead_units[name] = { logger:debug("Unit killed: " .. name .. ".. => persistenting")
tables.unitsStates[name] = {
isDead = true, isDead = true,
pos = position, pos = position,
heading = heading, heading = heading,
type = type, type = type,
country_id = country_id,
isCleaned = false isCleaned = false
} }
updateRequired = true Persistence._updateRequired = true
end end
end end
+13 -226
View File
@@ -67,6 +67,18 @@ do -- INIT UTIL
return list[random] return list[random]
end end
---@param list Array
---@param start number start
---@param n number length
---@return Array
function UTIL.sublist(list, start, n)
local result = {}
for i = start, n do
result[#result + 1] = list[i]
end
return result
end
---@param str string ---@param str string
---@param find string ---@param find string
---@param replace string ---@param replace string
@@ -504,17 +516,6 @@ do -- INIT DCS_UTIL
} }
]] -- ]] --
---@class MizGroupData
---@field category GroupCategory
---@field country_id integer
---@field group_template table
---@type table<string, MizGroupData>
DCS_UTIL.__miz_groups = {}
DCS_UTIL.__groupNames = {}
DCS_UTIL.__blueGroupNames = {}
DCS_UTIL.__redGroupNames = {}
--[[ --[[
zone = { zone = {
name, name,
@@ -574,54 +575,6 @@ do -- INIT DCS_UTIL
DCS_UTIL.__warehouseStartingCoalition = {} DCS_UTIL.__warehouseStartingCoalition = {}
function DCS_UTIL.__INIT() function DCS_UTIL.__INIT()
do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment
do -- init group tables
for coalition_name, coalition_data in pairs(env.mission.coalition) do
local coalition_nr = DCS_UTIL.stringToCoalition(coalition_name)
if coalition_data.country then
for country_index, country_data in pairs(coalition_data.country) do
for category_name, categorydata in pairs(country_data) do
local category_id = DCS_UTIL.stringToGroupCategory(category_name)
if category_id ~= nil and type(categorydata) == "table" and categorydata.group ~= nil and type(categorydata.group) == "table" then
for group_index, group in pairs(categorydata.group) do
local name = group.name
local skippable = false
if category_id == DCS_UTIL.GroupCategory.STATIC then
local unit = group.units[1]
if unit and unit.category == "Heliports" then
skippable = true
elseif unit then
name = unit.name
else
env.error("Group " .. name .. " has no units, skipping it.")
skippable = true
end
end
if skippable == false then
table.insert(DCS_UTIL.__groupNames, name)
DCS_UTIL.__miz_groups[name] =
{
category = category_id,
country_id = country_data.id,
group_template = group
}
if coalition_nr == 1 then
table.insert(DCS_UTIL.__redGroupNames, name)
elseif coalition_nr == 2 then
table.insert(DCS_UTIL.__blueGroupNames, name)
end
end
end
end
end
end
end
end
end
do --init trigger zones do --init trigger zones
for i, trigger_zone in pairs(env.mission.triggers.zones) do for i, trigger_zone in pairs(env.mission.triggers.zones) do
@@ -750,31 +703,6 @@ do -- INIT DCS_UTIL
return -1 return -1
end end
---checks if the groupname is a static group
---@param groupName string
function DCS_UTIL.IsGroupStatic(groupName)
if DCS_UTIL.__miz_groups[groupName] then
return DCS_UTIL.__miz_groups[groupName].category == DCS_UTIL.GroupCategory.STATIC
end
return StaticObject.getByName(groupName) ~= nil
end
---destroy the given group
---@param groupName string
function DCS_UTIL.DestroyGroup(groupName)
if DCS_UTIL.IsGroupStatic(groupName) then
local object = StaticObject.getByName(groupName)
if object ~= nil then
object:destroy()
end
else
local group = Group.getByName(groupName)
if group and group:isExist() then
group:destroy()
end
end
end
---destroy the given unit ---destroy the given unit
---@param unitName string ---@param unitName string
@@ -1050,42 +978,6 @@ do -- INIT DCS_UTIL
end end
end end
--- get the group config as per start of the mission
--- group = {
--- category,
--- country_id,
--- group_template
--- }
---@param groupname string groupName you're looking for
function DCS_UTIL.GetMizGroupOrDefault(groupname, default)
local group = DCS_UTIL.__miz_groups[groupname]
if group == nil then
return default
end
return group
end
---comment Get all group names. Can be a LOT
---Includes statics
---@return table groups
function DCS_UTIL.getAllGroupNames()
return DCS_UTIL.__groupNames
end
---comment Get all BLUE group names. Can be a LOT
---Includes statics
---@return table groups
function DCS_UTIL.getAllBlueGroupNames()
return DCS_UTIL.__blueGroupNames
end
---comment Get all RED group names. Can be a LOT
---Includes statics
---@return table groups
function DCS_UTIL.getAllRedGroupNames()
return DCS_UTIL.__redGroupNames
end
---comment Get all units that are players ---comment Get all units that are players
---@return Array<Unit> units ---@return Array<Unit> units
function DCS_UTIL.getAllPlayerUnits() function DCS_UTIL.getAllPlayerUnits()
@@ -1134,27 +1026,6 @@ do -- INIT DCS_UTIL
return result return result
end end
---Spawn an corpse
---@param countryId number countryId
---@param unitType string
---@param location table { z, y, z}
---@param heading number
function DCS_UTIL.SpawnCorpse(countryId, unitName, unitType, location, heading)
local name = "dead_" .. unitName
local staticObj = {
["heading"] = heading,
--["shape_name"] = "stolovaya",
["type"] = unitType,
["name"] = name,
["y"] = location.z,
["x"] = location.x,
["dead"] = true,
}
coalition.addStaticObject(countryId, staticObj)
end
function DCS_UTIL.CleanCorpse(unitName) function DCS_UTIL.CleanCorpse(unitName)
local unitName = "dead_" .. unitName local unitName = "dead_" .. unitName
@@ -1296,90 +1167,6 @@ do -- INIT DCS_UTIL
end end
end end
--- spawns the units as specified in the mission file itself
--- location and route can be nil and will then use default route
---@param groupName string
---@param location table? vector 3 data. { x , z, alt }
---@param route table? route of the group. If nil wil be the default route.
---@param uncontrolled boolean? Sets the group to be uncontrolled on spawn
---@param countryId CountryID? Overwrites the country
---@param emptyLoadouts boolean? If true, the group will spawn with empty loadouts
---@return table? new_group the Group class that was spawned
---@return boolean? isStatic whether the group is a static or not
function DCS_UTIL.SpawnGroupTemplate(groupName, location, route, uncontrolled, countryId, emptyLoadouts)
if groupName == nil then
return nil, nil
end
local template = DCS_UTIL.GetMizGroupOrDefault(groupName, nil)
if template == nil then
return nil, nil
end
if template.category == DCS_UTIL.GroupCategory.STATIC then
--TODO: Implement location and route stuff
local spawn_template = template.group_template
local country = countryId or template.country_id
---disable diagnostic as -1 is actually valid
---@diagnostic disable-next-line: param-type-mismatch
coalition.addGroup(country, -1, spawn_template)
local object = StaticObject.getByName(spawn_template.name)
if object then
return object, true
end
else
local spawn_template = Spearhead.Util.deepCopyTable(template.group_template)
if location ~= nil then
local x_offset
if location.x ~= nil then x_offset = spawn_template.x - location.x end
local y_offset
if location.z ~= nil then y_offset = spawn_template.y - location.z end
spawn_template.x = location.x
spawn_template.y = location.z
for i, unit in pairs(spawn_template.units) do
unit.x = unit.x - x_offset
unit.y = unit.y - y_offset
unit.alt = location.alt
end
end
if spawn_template.units then
for _, unit in pairs(spawn_template.units) do
if unit["parking"] then
unit["parking_landing"] = unit["parking"]
end
if unit["parking_id"] then
unit["parking_landing_id"] = unit["parking_id"]
end
end
if emptyLoadouts == true then
for _, unit in pairs(spawn_template.units) do
if unit["payload"] and unit["payload"]["pylons"] then
unit["payload"]["pylons"] = {}
end
end
end
end
if route ~= nil then
spawn_template.route = route
end
if uncontrolled ~= nil then
spawn_template.uncontrolled = uncontrolled
end
local country = countryId or template.country_id
local new_group = coalition.addGroup(country, template.category, spawn_template)
return new_group, false
end
end
---@return number? id ---@return number? id
function DCS_UTIL.GetNeutralCountry() function DCS_UTIL.GetNeutralCountry()
@@ -1393,7 +1180,7 @@ do -- INIT DCS_UTIL
function DCS_UTIL.NeedsRTBInTen(groupName, fuelOffset) function DCS_UTIL.NeedsRTBInTen(groupName, fuelOffset)
local isBingo = Spearhead.DcsUtil.IsBingoFuel(groupName, fuelOffset) local isBingo = DCS_UTIL.IsBingoFuel(groupName, fuelOffset)
if isBingo then return true end if isBingo then return true end
local aliveUnits = 0 local aliveUnits = 0
+6 -6
View File
@@ -470,7 +470,7 @@ end
---@private ---@private
function Database:initAvailableUnits() function Database:initAvailableUnits()
do do
local all_groups = Spearhead.DcsUtil.getAllGroupNames() local all_groups = Spearhead.classes.helpers.MizGroupsManager.getAllGroupNames()
for _, value in pairs(all_groups) do for _, value in pairs(all_groups) do
is_group_taken[value] = false is_group_taken[value] = false
end end
@@ -637,7 +637,7 @@ end
---@private ---@private
function Database:loadBlueSamUnits() function Database:loadBlueSamUnits()
local all_groups = Spearhead.DcsUtil.getAllGroupNames() local all_groups = Spearhead.classes.helpers.MizGroupsManager.getAllGroupNames()
for _, blueSamZone in pairs(self._tables.BlueSams) do for _, blueSamZone in pairs(self._tables.BlueSams) do
local samData = self:getOrCreateBlueSamDataForZone(blueSamZone) local samData = self:getOrCreateBlueSamDataForZone(blueSamZone)
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, blueSamZone) local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, blueSamZone)
@@ -659,7 +659,7 @@ function Database:loadMissionzoneUnits()
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName) local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName)
for _, groupName in pairs(groups) do for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then if Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName) local object = StaticObject.getByName(groupName)
if object and object:getCoalition() == coalition.side.RED then if object and object:getCoalition() == coalition.side.RED then
@@ -691,7 +691,7 @@ function Database:loadRandomMissionzoneUnits()
} }
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName) local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, missionZoneName)
for _, groupName in pairs(groups) do for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then if Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName) local object = StaticObject.getByName(groupName)
if object and object:getCoalition() == coalition.side.RED then if object and object:getCoalition() == coalition.side.RED then
@@ -752,7 +752,7 @@ function Database:loadAirbaseGroups()
if airbaseZone and base:getDesc().category == Airbase.Category.AIRDROME then if airbaseZone and base:getDesc().category == Airbase.Category.AIRDROME then
local groups = Spearhead.DcsUtil.areGroupsInCustomZone(all_groups, airbaseZone) local groups = Spearhead.DcsUtil.areGroupsInCustomZone(all_groups, airbaseZone)
for _, groupName in pairs(groups) do for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then if Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName) local object = StaticObject.getByName(groupName)
if object then if object then
if object:getCoalition() == coalition.side.RED then if object:getCoalition() == coalition.side.RED then
@@ -790,7 +790,7 @@ function Database:loadMiscGroupsInStages()
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, stageZone.StageZoneName) local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, stageZone.StageZoneName)
for _, groupName in pairs(groups) do for _, groupName in pairs(groups) do
if Spearhead.DcsUtil.IsGroupStatic(groupName) == true then if Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName) == true then
local object = StaticObject.getByName(groupName) local object = StaticObject.getByName(groupName)
if object and object:getCoalition() ~= coalition.side.NEUTRAL then if object and object:getCoalition() ~= coalition.side.NEUTRAL then
is_group_taken[groupName] = true is_group_taken[groupName] = true
+4 -4
View File
@@ -355,17 +355,17 @@ do
local AI_GROUPS = {} local AI_GROUPS = {}
local function CheckAndTriggerSpawnAsync(unit, time) local function CheckAndTriggerSpawnAsync(unit, time)
local function isPlayer(unit) local function isPlayer(unit)
if unit == nil then return false, "unit is nil" end if unit == nil then return false, "unit is nil" end
if unit.getGroup == nil then return false, 'no get group function in unit object, most likely static' end if unit.getGroup == nil then return false, 'no get group function in unit object, most likely static' end
if Object.getCategory(unit) ~= Object.Category.UNIT then
return false, "object is not a unit"
end
if unit:isExist() ~= true then return false, "unit does not exist" end if unit:isExist() ~= true then return false, "unit does not exist" end
local group = unit:getGroup() local group = unit:getGroup()
if group ~= nil then if group ~= nil then
if Spearhead.DcsUtil.IsGroupStatic(group:getName()) == true then
return false
end
if AI_GROUPS[group:getName()] == true then if AI_GROUPS[group:getName()] == true then
return false return false
end end
+5 -4
View File
@@ -20,8 +20,9 @@ GlobalStageManager = {}
---@param database Database ---@param database Database
---@param stageConfig StageConfig ---@param stageConfig StageConfig
---@param logLevel LogLevel ---@param logLevel LogLevel
---@param spawnManager SpawnManager
---@return nil ---@return nil
function GlobalStageManager:NewAndStart(database, stageConfig, logLevel) function GlobalStageManager:NewAndStart(database, stageConfig, logLevel, spawnManager)
local logger = Spearhead.LoggerTemplate.new("StageManager", logLevel) local logger = Spearhead.LoggerTemplate.new("StageManager", logLevel)
logger:info("Using Stage Log Level: " .. logLevel) logger:info("Using Stage Log Level: " .. logLevel)
local o = {} local o = {}
@@ -134,13 +135,13 @@ function GlobalStageManager:NewAndStart(database, stageConfig, logLevel)
} }
if isSideStage == true then if isSideStage == true then
local stage = Spearhead.classes.stageClasses.Stages.ExtraStage.New(database, stageConfig, stagelogger, initData) local stage = Spearhead.classes.stageClasses.Stages.ExtraStage.New(database, stageConfig, stagelogger, initData, spawnManager)
stage:AddStageCompleteListener(OnStageCompleteListener) stage:AddStageCompleteListener(OnStageCompleteListener)
if SideStageByIndex[tostring(orderNumber)] == nil then SideStageByIndex[tostring(orderNumber)] = {} end if SideStageByIndex[tostring(orderNumber)] == nil then SideStageByIndex[tostring(orderNumber)] = {} end
table.insert(SideStageByIndex[tostring(orderNumber)], stage) table.insert(SideStageByIndex[tostring(orderNumber)], stage)
else else
local stage = Spearhead.classes.stageClasses.Stages.PrimaryStage.New(database, stageConfig, stagelogger, initData) local stage = Spearhead.classes.stageClasses.Stages.PrimaryStage.New(database, stageConfig, stagelogger, initData, spawnManager)
stage:AddStageCompleteListener(OnStageCompleteListener) stage:AddStageCompleteListener(OnStageCompleteListener)
if StagesByIndex[tostring(orderNumber)] == nil then StagesByIndex[tostring(orderNumber)] = {} end if StagesByIndex[tostring(orderNumber)] == nil then StagesByIndex[tostring(orderNumber)] = {} end
@@ -185,7 +186,7 @@ function GlobalStageManager:NewAndStart(database, stageConfig, logLevel)
stageZoneName = stageName, stageZoneName = stageName,
waitingSeconds = waitingSeconds --[[@as integer]] waitingSeconds = waitingSeconds --[[@as integer]]
} }
local waitingStage = Spearhead.classes.stageClasses.Stages.WaitingStage.New(database, stageConfig, stagelogger, initData) local waitingStage = Spearhead.classes.stageClasses.Stages.WaitingStage.New(database, stageConfig, stagelogger, initData, spawnManager)
if WaitingStagesByIndex[tostring(stageIndex)] == nil then if WaitingStagesByIndex[tostring(stageIndex)] == nil then
WaitingStagesByIndex[tostring(stageIndex)] = {} WaitingStagesByIndex[tostring(stageIndex)] = {}
+44 -84
View File
@@ -2,22 +2,38 @@
---@class SpearheadGroup : OnUnitLostListener ---@class SpearheadGroup : OnUnitLostListener
---@field groupName string ---@field private _groupName string
---@field private _isStatic boolean ---@field private _isStatic boolean
---@field private _isSpawned boolean ---@field private _isSpawned boolean
---@field private _spawnManager SpawnManager
---@field private _isPersistent boolean
local SpearheadGroup = {} local SpearheadGroup = {}
SpearheadGroup.__index = SpearheadGroup SpearheadGroup.__index = SpearheadGroup
function SpearheadGroup.New(groupName) ---comment
---@param groupName string
---@param spawnManager SpawnManager
---@param isPersistent boolean?
---@return SpearheadGroup
function SpearheadGroup.New(groupName, spawnManager, isPersistent)
local self = setmetatable({}, SpearheadGroup) local self = setmetatable({}, SpearheadGroup)
self._isStatic = Spearhead.DcsUtil.IsGroupStatic(groupName) == true if isPersistent == nil then isPersistent = false end
self.groupName = groupName
self._spawnManager = spawnManager
self._isStatic = spawnManager:IsGroupStatic(groupName) == true
self._groupName = groupName
self._isSpawned = false self._isSpawned = false
self._isPersistent = isPersistent
return self return self
end end
function SpearheadGroup:GetName()
return self._groupName
end
function SpearheadGroup:IsSpawned() function SpearheadGroup:IsSpawned()
return self._isSpawned return self._isSpawned
end end
@@ -26,26 +42,7 @@ function SpearheadGroup:SpawnCorpsesOnly()
if self._isSpawned == true then return end if self._isSpawned == true then return end
local group, isStatic = Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName) self._spawnManager:SpawnCorpsesOnly(self._groupName)
if isStatic == true then
self._isStatic = true
local deathState = Spearhead.classes.persistence.Persistence.UnitDeadState(self.groupName)
if deathState and deathState.isDead == true then
Spearhead.DcsUtil.DestroyGroup(self.groupName)
Spearhead.DcsUtil.SpawnCorpse(deathState.country_id, self.groupName, deathState.type, deathState.pos, deathState.heading)
end
else
if group then
for _, unit in pairs(group:getUnits()) do
local deathState = Spearhead.classes.persistence.Persistence.UnitDeadState(unit:getName())
Spearhead.DcsUtil.DestroyUnit(unit:getName())
if deathState and deathState.isDead == true then
Spearhead.DcsUtil.SpawnCorpse(deathState.country_id, unit:getName(), deathState.type, deathState.pos, deathState.heading)
end
end
end
end
self._isSpawned = true self._isSpawned = true
end end
@@ -55,52 +52,19 @@ function SpearheadGroup:Spawn(lateStart)
if self._isSpawned == true then return end if self._isSpawned == true then return end
local spawned, isStatic = Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName, nil, nil, lateStart) ---@type SpawnOverrides
if spawned and isStatic == false then local overrides = {
for _, unit in pairs(spawned:getUnits()) do uncontrolled = lateStart or false,
local deathState = Spearhead.classes.persistence.Persistence.UnitDeadState(unit:getName()) }
if deathState and deathState.isDead == true then
Spearhead.DcsUtil.DestroyUnit(self.groupName, unit:getName())
Spearhead.DcsUtil.SpawnCorpse(deathState.country_id, unit:getName(), deathState.type, deathState.pos, deathState.heading)
else
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
end
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
local spawnedObject, isStatic = self._spawnManager:SpawnGroup(self._groupName, overrides, self._isPersistent)
self._isStatic = isStatic
self._isSpawned = true self._isSpawned = true
end end
function SpearheadGroup:Activate()
if self._isStatic == true then return end
local group = Group.getByName(self.groupName)
if group then
group:activate()
local controller = group:getController()
if controller then
controller:setCommand({
id = 'Start',
params = {}
})
end
end
end
function SpearheadGroup:Destroy() function SpearheadGroup:Destroy()
self._isSpawned = false self._isSpawned = false
Spearhead.DcsUtil.DestroyGroup(self.groupName) self._spawnManager:DestroyGroup(self._groupName)
end end
---@return boolean ---@return boolean
@@ -112,13 +76,13 @@ end
---@return integer ---@return integer
function SpearheadGroup:GetCoalition() function SpearheadGroup:GetCoalition()
if self._isStatic == true then if self._isStatic == true then
local object = StaticObject.getByName(self.groupName) local object = StaticObject.getByName(self._groupName)
if object == nil then if object == nil then
return 0 return 0
end end
return object:getCoalition() return object:getCoalition()
else else
local group = Group.getByName(self.groupName) local group = Group.getByName(self._groupName)
if group == nil then if group == nil then
return 0 return 0
end end
@@ -126,28 +90,18 @@ function SpearheadGroup:GetCoalition()
end end
end end
function SpearheadGroup:OnUnitLost(object)
local name = object:getName()
local pos = object:getPoint()
local type = object:getDesc().typeName
local position = object:getPosition()
local heading = math.atan2(position.x.z, position.x.x)
local country_id = object:getCountry()
Spearhead.classes.persistence.Persistence.UnitKilled(name, pos, heading, type, country_id)
end
---comment ---comment
---@return table result list of objects ---@return table result list of objects
function SpearheadGroup:GetObjects() function SpearheadGroup:GetObjects()
local result = {} local result = {}
if self._isStatic == true then if self._isStatic == true then
local staticObject = StaticObject.getByName(self.groupName) local staticObject = StaticObject.getByName(self._groupName)
if staticObject then if staticObject then
table.insert(result, staticObject) table.insert(result, staticObject)
end end
else else
local group = Group.getByName(self.groupName) local group = Group.getByName(self._groupName)
if not group then return {} end if not group then return {} end
for _, unit in pairs(group:getUnits()) do for _, unit in pairs(group:getUnits()) do
table.insert(result, unit) table.insert(result, unit)
@@ -165,7 +119,7 @@ function SpearheadGroup:GetAsUnits()
end end
local result = {} local result = {}
local group = Group.getByName(self.groupName) local group = Group.getByName(self._groupName)
if not group then return {} end if not group then return {} end
for _, unit in pairs(group:getUnits()) do for _, unit in pairs(group:getUnits()) do
table.insert(result, unit) table.insert(result, unit)
@@ -178,12 +132,12 @@ function SpearheadGroup:GetAllUnitPositions()
local result = {} local result = {}
if self._isStatic == true then if self._isStatic == true then
local staticObject = StaticObject.getByName(self.groupName) local staticObject = StaticObject.getByName(self._groupName)
if staticObject then if staticObject then
table.insert(result, staticObject:getPoint()) table.insert(result, staticObject:getPoint())
end end
else else
local group = Group.getByName(self.groupName) local group = Group.getByName(self._groupName)
if not group then return {} end if not group then return {} end
for _, unit in pairs(group:getUnits()) do for _, unit in pairs(group:getUnits()) do
table.insert(result, unit:getPoint()) table.insert(result, unit:getPoint())
@@ -196,9 +150,15 @@ function SpearheadGroup:SetInvisible()
if self._isStatic == true then if self._isStatic == true then
local country = Spearhead.DcsUtil.GetNeutralCountry() local country = Spearhead.DcsUtil.GetNeutralCountry()
Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName, nil, nil, nil, country)
---@type SpawnOverrides
local overrides = {
countryID = country
}
self._spawnManager:SpawnGroup(self._groupName, overrides, self._isPersistent)
else else
local group = Group.getByName(self.groupName) local group = Group.getByName(self._groupName)
if group then if group then
local setInvisible = { local setInvisible = {
id = 'SetInvisible', id = 'SetInvisible',
@@ -215,7 +175,7 @@ end
function SpearheadGroup:SetVisible() function SpearheadGroup:SetVisible()
local group = Group.getByName(self.groupName) local group = Group.getByName(self._groupName)
if group then if group then
local setInvisible = { local setInvisible = {
id = 'SetInvisible', id = 'SetInvisible',
+20 -43
View File
@@ -1,5 +1,5 @@
---@class BlueSam : OnCrateDroppedListener, MissionCompleteListener ---@class BlueSam : BuildableZone
---@field Activate fun(self: BlueSam) ---@field Activate fun(self: BlueSam)
---@field private _database Database ---@field private _database Database
---@field private _logger Logger ---@field private _logger Logger
@@ -11,13 +11,16 @@
---@field private _unitsPerCrate number? ---@field private _unitsPerCrate number?
---@field private _buildableMission BuildableMission? ---@field private _buildableMission BuildableMission?
local BlueSam = {} local BlueSam = {}
BlueSam.__index = BlueSam
---@param database Database ---@param database Database
---@param logger Logger ---@param logger Logger
---@param zoneName string ---@param zoneName string
---@param spawnManager SpawnManager
---@return BlueSam? ---@return BlueSam?
function BlueSam.New(database, logger, zoneName) function BlueSam.New(database, logger, zoneName, spawnManager)
BlueSam.__index = BlueSam
setmetatable(BlueSam, Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone)
local self = setmetatable({}, BlueSam) local self = setmetatable({}, BlueSam)
self._database = database self._database = database
@@ -44,14 +47,18 @@ function BlueSam.New(database, logger, zoneName)
local redUnitsPos = {} local redUnitsPos = {}
for _, groupName in pairs(blueSamData.groups) do local buildable = false
local SpearheadGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName) if self._buildableCrateKilos and self._buildableCrateKilos > 0 then
if SpearheadGroup then buildable = true
if SpearheadGroup:GetCoalition() == 2 then
table.insert(self._blueGroups, SpearheadGroup)
end end
for _, groupName in pairs(blueSamData.groups) do
local SpearheadGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName, spawnManager, true)
if SpearheadGroup then
if SpearheadGroup:GetCoalition() == 2 or SpearheadGroup:GetCoalition() == 0 then
table.insert(self._blueGroups, SpearheadGroup)
end
for _, unit in pairs(SpearheadGroup:GetObjects()) do for _, unit in pairs(SpearheadGroup:GetObjects()) do
if SpearheadGroup:GetCoalition() == 1 then if SpearheadGroup:GetCoalition() == 1 then
@@ -76,21 +83,11 @@ function BlueSam.New(database, logger, zoneName)
end end
end end
if self._buildableCrateKilos ~= nil and self._buildableCrateKilos ~= 0 then
self._logger:debug("Buildable mission creating for zone: " .. zoneName .. " with crates: " .. self._buildableCrateKilos)
local noLandingZone = self:GetNoLandingZone()
local zone = Spearhead.DcsUtil.getZoneByName(zoneName) local zone = Spearhead.DcsUtil.getZoneByName(zoneName)
if zone then if zone then
self._buildableMission = Spearhead.classes.stageClasses.missions.BuildableMission.new(database, logger, zone, noLandingZone, self._buildableCrateKilos, "SAM_CRATE") Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone.New(self, zone, self._buildableCrateKilos or 0, "SAM_CRATE", self._blueGroups, logger, database)
self._buildableMission:AddOnCrateDroppedOfListener(self)
self._buildableMission:AddMissionCompleteListener(self)
end end
end
return self return self
end end
@@ -132,21 +129,14 @@ function BlueSam:Activate()
if self._buildableMission == nil then if self._buildableMission == nil then
self:SpawnGroups() self:SpawnGroups()
else else
self._buildableMission:SpawnActive() self:StartBuildable()
end end
end end
function BlueSam:SpawnGroups() function BlueSam:SpawnGroups()
for unitName, needsCleanup in pairs(self._cleanupUnits) do for unitName, needsCleanup in pairs(self._cleanupUnits) do
if needsCleanup == true then
Spearhead.DcsUtil.DestroyUnit(unitName) Spearhead.DcsUtil.DestroyUnit(unitName)
else
local deathState = Spearhead.classes.persistence.Persistence.UnitDeadState(unitName)
if deathState and deathState.isDead == true then
Spearhead.DcsUtil.SpawnCorpse(deathState.country_id, unitName, deathState.type, deathState.pos, deathState.heading)
end
end
end end
for _, group in pairs(self._blueGroups) do for _, group in pairs(self._blueGroups) do
@@ -154,25 +144,12 @@ function BlueSam:SpawnGroups()
end end
end end
function BlueSam:OnBuildingComplete()
---@param buildableMission BuildableMission
---@param kilos number
function BlueSam:OnCrateDroppedOff(buildableMission, kilos)
self._logger:debug("Crate dropped off in zone: " .. self._zoneName)
self._receivedKilos = self._receivedKilos + kilos
end
---@param buildableMission Mission
function BlueSam:OnMissionComplete(buildableMission)
self._logger:debug("Buildable mission complete for zone: " .. self._zoneName)
self:SpawnGroups() self:SpawnGroups()
end end
if Spearhead == nil then Spearhead = {} end if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
+10 -152
View File
@@ -1,16 +1,12 @@
---@class FarpZone : OnCrateDroppedListener, MissionCompleteListener ---@class FarpZone: BuildableZone
---@field private _startingFarp boolean ---@field private _startingFarp boolean
---@field private _groups Array<SpearheadGroup> ---@field private _groups Array<SpearheadGroup>
---@field private _padNames Array<string> ---@field private _padNames Array<string>
---@field private _database Database ---@field private _database Database
---@field private _logger Logger ---@field private _logger Logger
---@field private _zoneName string ---@field private _zoneName string
---@field private _requiredBuildingKilos number
---@field private _receivedBuildingKilos number
---@field private _groupsPerKilo number
---@field private _buildableMission BuildableMission?
---@field private _supplyHubs Array<SupplyHub> ---@field private _supplyHubs Array<SupplyHub>
local FarpZone = {} local FarpZone = {}
FarpZone.__index = FarpZone FarpZone.__index = FarpZone
@@ -19,10 +15,10 @@ FarpZone.__index = FarpZone
---@param database Database ---@param database Database
---@param logger Logger ---@param logger Logger
---@param zoneName string ---@param zoneName string
---@param spawnManager SpawnManager
---@return FarpZone ---@return FarpZone
function FarpZone.New(database, logger, zoneName) function FarpZone.New(database, logger, zoneName, spawnManager)
setmetatable(FarpZone, Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone)
FarpZone.__index = FarpZone
local self = setmetatable({}, FarpZone) local self = setmetatable({}, FarpZone)
self._database = database self._database = database
@@ -54,33 +50,17 @@ function FarpZone.New(database, logger, zoneName)
end end
end end
for _, groupName in pairs(farpData.groups) do for _, groupName in pairs(farpData.groups) do
local group = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName) local group = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName, spawnManager, true)
table.insert(self._groups, group) table.insert(self._groups, group)
group:Destroy() group:Destroy()
end end
self._requiredBuildingKilos = farpData.buildingKilos
self._receivedBuildingKilos = 0
if self._requiredBuildingKilos ~= nil and self._requiredBuildingKilos > 0 then
self._logger:debug("FARP zone " .. zoneName .. " requires " .. self._requiredBuildingKilos .. " crates to be dropped off")
local noLandingZone = self:GetNoLandingZone()
local zone = Spearhead.DcsUtil.getZoneByName(zoneName) local zone = Spearhead.DcsUtil.getZoneByName(zoneName)
if zone then if zone then
self._buildableMission = Spearhead.classes.stageClasses.missions.BuildableMission.new(database, logger, zone, noLandingZone, self._requiredBuildingKilos, "FARP_CRATE") Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone.New(self, zone, farpData.buildingKilos or 0, "FARP_CRATE", self._groups, logger, database)
if self._buildableMission then
self._buildableMission:AddOnCrateDroppedOfListener(self)
self._buildableMission:AddMissionCompleteListener(self)
end end
local totalGroups = Spearhead.Util.tableLength(self._groups)
self._groupsPerKilo = totalGroups / self._requiredBuildingKilos
end
end
end
if self._buildableMission == nil then
self._logger:debug("No buildable mission for zone: " .. zoneName)
end end
self:Deactivate() self:Deactivate()
@@ -101,7 +81,7 @@ function FarpZone:Activate()
self:SetPadsBlue() self:SetPadsBlue()
self:ActivateSupplyHubs() self:ActivateSupplyHubs()
else else
self._buildableMission:SpawnActive() self:StartBuildable()
end end
end end
@@ -109,101 +89,13 @@ function FarpZone:Deactivate()
self:NeutralisePads() self:NeutralisePads()
end end
---@class UnpackCrateParam function FarpZone:OnBuildingComplete()
---@field self FarpZone
---@field kilos number
---@field groupsPerKilo number
---@field kilosPerSecond number
---@field unpackedItems number
---@field unpackedKilos number
---@param params UnpackCrateParam
---@param time number
local startUnpackingCrate = function(params, time)
local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2)
local alreadySpawned = params.unpackedItems / params.groupsPerKilo
local diff = unpacked - alreadySpawned
local amount = math.floor(diff * params.groupsPerKilo)
local spawned = params.self:SpawnAmount(amount)
params.unpackedItems = params.unpackedItems + amount
params.unpackedKilos = unpacked
if params.unpackedKilos >= params.kilos or spawned == false then
params.self:FinaliseCrate(params.kilos)
return
end
return time + 2
end
---comment
---@param amount number
---@return boolean
function FarpZone:SpawnAmount(amount)
local function spawnOne()
for _, group in pairs(self._groups) do
if group:IsSpawned() == false then
group:Spawn()
return true
end
end
return nil
end
for i = 1, amount do
local spawned = spawnOne()
if spawned ~= true then
self._logger:debug("No more groups to spawn in zone: " .. self._zoneName)
return false
end
end
return true
end
---@param buildableMission BuildableMission
function FarpZone:OnCrateDroppedOff(buildableMission, kilos)
self._logger:debug("Crate dropped off in zone: " .. self._zoneName)
local timeToUnpack = (kilos / 500) * 15
---@type UnpackCrateParam
local params = {
self = self,
groupsPerKilo = self._groupsPerKilo,
unpackedItems = 0,
kilosPerSecond = kilos/timeToUnpack,
unpackedKilos = 0,
kilos = kilos
}
timer.scheduleFunction(startUnpackingCrate, params, timer.getTime() + 2)
end
---@param kilos number
function FarpZone:FinaliseCrate(kilos)
self._receivedBuildingKilos = self._receivedBuildingKilos + kilos
if self._receivedBuildingKilos >= self._requiredBuildingKilos then
self:BuildUp() self:BuildUp()
self:SetPadsBlue() self:SetPadsBlue()
self:ActivateSupplyHubs() self:ActivateSupplyHubs()
end
end
---@param buildableMission Mission
function FarpZone:OnMissionComplete(buildableMission)
self._logger:debug("Buildable mission complete for zone: " .. self._zoneName)
-- self:BuildUp()
-- self:SetPadsBlue()
-- self:ActivateSupplyHubs()
end end
---@private
function FarpZone:BuildUp() function FarpZone:BuildUp()
for _, group in pairs(self._groups) do for _, group in pairs(self._groups) do
group:Spawn() group:Spawn()
@@ -239,40 +131,6 @@ function FarpZone:SetPadsBlue()
end end
end end
---@private
---@return SpearheadTriggerZone?
function FarpZone:GetNoLandingZone()
---@type Array<Vec2>
local points = {}
for _, group in pairs(self._groups) do
for _, unitPos in pairs(group:GetAllUnitPositions()) do
table.insert(points, { x = unitPos.x, y = unitPos.z })
end
end
local vecs = Spearhead.Util.getConvexHull(points)
local zone = Spearhead.DcsUtil.getZoneByName(self._zoneName)
if zone == nil then
self._logger:error("Zone not found: " .. self._zoneName)
return nil
end
---@type SpearheadTriggerZone
local spearheadZone = {
name = self._zoneName .. "_noland",
location = zone.location,
verts = vecs,
radius = 0,
zone_type = "Polygon"
}
return spearheadZone
end
if Spearhead == nil then Spearhead = {} end if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
+14 -134
View File
@@ -1,4 +1,4 @@
---@class StageBase : OnCrateDroppedListener, MissionCompleteListener ---@class StageBase : BuildableZone
---@field private _database Database ---@field private _database Database
---@field private _logger Logger ---@field private _logger Logger
---@field private _red_groups Array<SpearheadGroup> ---@field private _red_groups Array<SpearheadGroup>
@@ -12,14 +12,16 @@
---@field private _receivedBuildingKilos number ---@field private _receivedBuildingKilos number
---@field private _buildableMission BuildableMission? ---@field private _buildableMission BuildableMission?
local StageBase = {} local StageBase = {}
StageBase.__index = StageBase
---comment ---comment
---@param databaseManager Database ---@param databaseManager Database
---@param logger table ---@param logger table
---@param airbaseName string ---@param airbaseName string
---@param spawnManager SpawnManager
---@return StageBase? ---@return StageBase?
function StageBase.New(databaseManager, logger, airbaseName) function StageBase.New(databaseManager, logger, airbaseName, spawnManager)
StageBase.__index = StageBase setmetatable(StageBase, Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone)
local self = setmetatable({}, StageBase) local self = setmetatable({}, StageBase)
self._database = databaseManager self._database = databaseManager
@@ -47,7 +49,7 @@ function StageBase.New(databaseManager, logger, airbaseName)
local blueUnitsPos = {} local blueUnitsPos = {}
for _, groupName in pairs(airbaseData.RedGroups) do for _, groupName in pairs(airbaseData.RedGroups) do
local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName) local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName, spawnManager, true)
table.insert(self._red_groups, shGroup) table.insert(self._red_groups, shGroup)
for _, unit in pairs(shGroup:GetObjects()) do for _, unit in pairs(shGroup:GetObjects()) do
@@ -58,7 +60,7 @@ function StageBase.New(databaseManager, logger, airbaseName)
end end
for _, groupName in pairs(airbaseData.BlueGroups) do for _, groupName in pairs(airbaseData.BlueGroups) do
local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName) local shGroup = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName, spawnManager, true)
table.insert(self._blue_groups, shGroup) table.insert(self._blue_groups, shGroup)
for _, unit in pairs(shGroup:GetObjects()) do for _, unit in pairs(shGroup:GetObjects()) do
@@ -92,22 +94,9 @@ function StageBase.New(databaseManager, logger, airbaseName)
end end
end end
if airbaseData.buildingKilos ~= nil and airbaseData.buildingKilos > 0 then
self._logger:debug("Airbase " .. airbaseName .. " requires " .. tostring(airbaseData.buildingKilos) .. " kilos to be dropped off")
self._requiredBuildingKilos = airbaseData.buildingKilos
self._receivedBuildingKilos = 0
self._groupsPerKilo = Spearhead.Util.tableLength(self._blue_groups) / self._requiredBuildingKilos
local zone = Spearhead.DcsUtil.getAirbaseZoneByName(airbaseName) local zone = Spearhead.DcsUtil.getAirbaseZoneByName(airbaseName)
if zone then if zone then
self._buildableMission = Spearhead.classes.stageClasses.missions.BuildableMission.new(databaseManager, logger, zone, self:GetNoLandingZone(), self._requiredBuildingKilos, "AIRBASE_CRATE") Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone.New(self, zone, airbaseData.buildingKilos or 0, "AIRBASE_CRATE", self._blue_groups, logger, databaseManager)
end
if self._buildableMission then
self._buildableMission:AddOnCrateDroppedOfListener(self)
else
self._logger:error("Failed to create buildable mission for airbase: " .. airbaseName)
end
end end
end end
@@ -172,11 +161,12 @@ function StageBase:ActivateBlueStage()
self:CleanRedUnits() self:CleanRedUnits()
if self._buildableMission and self._buildableMission:getState() ~= "COMPLETED" then if self._buildableMission then
self._buildableMission:SpawnActive() self:StartBuildable()
return else
end
self:FinaliseBlueStage() self:FinaliseBlueStage()
end
end end
function StageBase:FinaliseBlueStage() function StageBase:FinaliseBlueStage()
@@ -192,119 +182,9 @@ function StageBase:FinaliseBlueStage()
end end
end end
do ---Building parts
---@class UnpackAirbaseCrateParam
---@field self StageBase
---@field kilos number
---@field groupsPerKilo number
---@field kilosPerSecond number
---@field unpackedItems number
---@field unpackedKilos number
---@param params UnpackAirbaseCrateParam function StageBase:OnBuildingComplete()
---@param time number
local startUnpackingCrate = function(params, time)
local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2)
local alreadySpawned = params.unpackedItems / params.groupsPerKilo
local diff = unpacked - alreadySpawned
local amount = math.floor(diff * params.groupsPerKilo)
local spawned = params.self:SpawnAmount(amount)
params.unpackedItems = params.unpackedItems + amount
params.unpackedKilos = unpacked
if params.unpackedKilos >= params.kilos or spawned == false then
params.self:FinaliseCrate(params.kilos)
return
end
return time + 2
end
---comment
---@param amount number
---@return boolean
function StageBase:SpawnAmount(amount)
local function spawnOne()
for _, group in pairs(self._blue_groups) do
if group:IsSpawned() == false then
group:Spawn()
return true
end
end
return nil
end
for i = 1, amount do
local spawned = spawnOne()
if spawned ~= true then
self._logger:debug("No more groups to spawn at base: " .. self._airbase:getName())
return false
end
end
return true
end
---@param buildableMission BuildableMission
function StageBase:OnCrateDroppedOff(buildableMission, kilos)
self._logger:debug("Crate dropped off at base: " .. self._airbase:getName())
local timeToUnpack = (kilos / 500) * 30
---@type UnpackAirbaseCrateParam
local params = {
self = self,
groupsPerKilo = self._groupsPerKilo,
unpackedItems = 0,
kilosPerSecond = kilos / timeToUnpack,
unpackedKilos = 0,
kilos = kilos
}
timer.scheduleFunction(startUnpackingCrate, params, timer.getTime() + 2)
end
---@private
---@return SpearheadTriggerZone?
function StageBase:GetNoLandingZone()
---@type Array<Vec2>
local points = {}
for _, group in pairs(self._blue_groups) do
for _, unitPos in pairs(group:GetAllUnitPositions()) do
table.insert(points, { x = unitPos.x, y = unitPos.z })
end
end
local vecs = Spearhead.Util.getConvexHull(points)
local pos = self._airbase:getPoint()
local location = {
x = pos.x,
y = pos.z
}
---@type SpearheadTriggerZone
local spearheadZone = {
name = self._airbase:getName() .. "_noland",
location = location,
verts = vecs,
radius = 0,
zone_type = "Polygon"
}
return spearheadZone
end
---@param kilos number
function StageBase:FinaliseCrate(kilos)
self._receivedBuildingKilos = self._receivedBuildingKilos + kilos
if self._receivedBuildingKilos >= self._requiredBuildingKilos then
self:FinaliseBlueStage() self:FinaliseBlueStage()
end
end
end end
@@ -0,0 +1,204 @@
---@class BuildableZone : OnCrateDroppedListener
---@field protected _targetZone SpearheadTriggerZone
---@field protected _requiredKilos number
---@field protected _buildableMission BuildableMission?
---@field protected _buildableGroups Array<SpearheadGroup>
---@field private _groupsPerKilo number
---@field private _receivedBuildingKilos number
---@field private _buildableLogger Logger
---@field protected OnBuildingComplete fun(self:BuildableZone)
local BuildableZone = {}
BuildableZone.__index = BuildableZone
---@param targetZone SpearheadTriggerZone
---@param kilosRequired number
---@param buildableGroups Array<SpearheadGroup>
---@param database Database
---@param crateType SupplyType
---@param logger Logger
function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroups, logger, database)
self._targetZone = targetZone
self._requiredKilos = kilosRequired or 0
self._buildableGroups = buildableGroups or {}
self._buildableLogger = logger
local totalGroups = Spearhead.Util.tableLength(self._buildableGroups)
self._groupsPerKilo = totalGroups / self._requiredKilos
self._receivedBuildingKilos = 0
local persistedKilos = Spearhead.classes.persistence.Persistence.GetZoneDeliveredKilos(targetZone.name)
if persistedKilos and persistedKilos > 0 then
self._receivedBuildingKilos = persistedKilos
---@param params UnpackCrateParam
---@param time number
local startUnpackingCrate = function(params, time)
local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2)
local alreadySpawned = params.unpackedItems / params.groupsPerKilo
local diff = unpacked - alreadySpawned
local amount = math.floor(diff * params.groupsPerKilo)
local spawned = params.self:SpawnAmount(amount)
params.unpackedItems = params.unpackedItems + amount
params.unpackedKilos = unpacked
if params.unpackedKilos >= params.kilos or spawned == false then
return
end
return time + 0.5
end
---@type UnpackCrateParam
local params = {
self = self,
groupsPerKilo = self._groupsPerKilo,
unpackedItems = 0,
kilosPerSecond = persistedKilos/30,
unpackedKilos = 0,
kilos = persistedKilos
}
timer.scheduleFunction(startUnpackingCrate, params, timer.getTime() + 5)
kilosRequired = kilosRequired - persistedKilos
end
local noLandingZone = self:GetNoLandingZone()
if kilosRequired and kilosRequired > 0 then
self._buildableMission = Spearhead.classes.stageClasses.missions.BuildableMission.new(database, logger, targetZone, noLandingZone, kilosRequired, crateType)
self._buildableMission:AddOnCrateDroppedOfListener(self)
else
self._buildableMission = nil
end
if self._buildableMission == nil then
self._buildableLogger:debug("No buildable mission for zone: " .. targetZone.name)
end
end
---@protected
function BuildableZone:StartBuildable()
self._buildableMission:SpawnActive()
end
---@protected
function BuildableZone:OnBuildingComplete() end
---@class UnpackCrateParam
---@field self BuildableZone
---@field kilos number
---@field groupsPerKilo number
---@field kilosPerSecond number
---@field unpackedItems number
---@field unpackedKilos number
---@param mission BuildableMission?
---@param kilos number
function BuildableZone:OnCrateDroppedOff(mission, kilos)
self._buildableLogger:debug("Crate dropped off in zone: " .. self._targetZone.name)
local timeToUnpack = (kilos / 500) * 15
---@type UnpackCrateParam
local params = {
self = self,
groupsPerKilo = self._groupsPerKilo,
unpackedItems = 0,
kilosPerSecond = kilos/timeToUnpack,
unpackedKilos = 0,
kilos = kilos
}
---@param params UnpackCrateParam
---@param time number
local startUnpackingCrate = function(params, time)
local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2)
local alreadySpawned = params.unpackedItems / params.groupsPerKilo
local diff = unpacked - alreadySpawned
local amount = math.floor(diff * params.groupsPerKilo)
local spawned = params.self:SpawnAmount(amount)
params.unpackedItems = params.unpackedItems + amount
params.unpackedKilos = unpacked
if params.unpackedKilos >= params.kilos or spawned == false then
params.self:FinaliseCrate(params.kilos)
return
end
return time + 2
end
timer.scheduleFunction(startUnpackingCrate, params, timer.getTime() + 2)
end
---@param kilos number
function BuildableZone:FinaliseCrate(kilos)
self._receivedBuildingKilos = self._receivedBuildingKilos + kilos
Spearhead.classes.persistence.Persistence.SetZoneDeliveredKilos(self._targetZone.name, self._receivedBuildingKilos)
if self._receivedBuildingKilos >= self._requiredKilos then
self:OnBuildingComplete()
end
end
---@private
---@return SpearheadTriggerZone?
function BuildableZone:GetNoLandingZone()
---@type Array<Vec2>
local points = {}
for _, group in pairs(self._buildableGroups) do
for _, unitPos in pairs(group:GetAllUnitPositions()) do
table.insert(points, { x = unitPos.x, y = unitPos.z })
end
end
local vecs = Spearhead.Util.getConvexHull(points)
---@type SpearheadTriggerZone
local spearheadZone = {
name = self._targetZone.name .. "_noland",
location = self._targetZone.location,
verts = vecs,
radius = 0,
zone_type = "Polygon"
}
return spearheadZone
end
---comment
---@param amount number
---@return boolean
function BuildableZone:SpawnAmount(amount)
local function spawnOne()
for _, group in pairs(self._buildableGroups) do
if group:IsSpawned() == false then
group:Spawn()
return true
end
end
return nil
end
for i = 1, amount do
local spawned = spawnOne()
if spawned ~= true then
self._buildableLogger:debug("No more groups to spawn in zone: " .. self._targetZone.name)
return false
end
end
return true
end
if not Spearhead then Spearhead = {} end
Spearhead.classes = Spearhead.classes or {}
Spearhead.classes.stageClasses = Spearhead.classes.stageClasses or {}
Spearhead.classes.stageClasses.SpecialZones = Spearhead.classes.stageClasses.SpecialZones or {}
Spearhead.classes.stageClasses.SpecialZones.abstract = Spearhead.classes.stageClasses.SpecialZones.abstract or {}
Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone = BuildableZone
@@ -63,8 +63,9 @@ Stage.StageColors = {
---@param logger Logger ---@param logger Logger
---@param initData StageInitData ---@param initData StageInitData
---@param missionPriority MissionPriority ---@param missionPriority MissionPriority
---@param spawnManager SpawnManager
---@return Stage ---@return Stage
function Stage:superNew(database, stageConfig, logger, initData, missionPriority) function Stage:superNew(database, stageConfig, logger, initData, missionPriority, spawnManager)
logger:debug("[BaseStage] Initiating stage with name: " .. initData.stageZoneName) logger:debug("[BaseStage] Initiating stage with name: " .. initData.stageZoneName)
@@ -109,7 +110,7 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
local farpNames = database:getFarpNamesInStage(self.zoneName) local farpNames = database:getFarpNamesInStage(self.zoneName)
for _, farpName in pairs(farpNames) do for _, farpName in pairs(farpNames) do
local farp = Spearhead.classes.stageClasses.SpecialZones.FarpZone.New(database, logger, farpName) local farp = Spearhead.classes.stageClasses.SpecialZones.FarpZone.New(database, logger, farpName, spawnManager)
table.insert(self._db.farps, farp) table.insert(self._db.farps, farp)
end end
@@ -141,7 +142,7 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
self._logger:debug("Found " .. Spearhead.Util.tableLength(missionZones) .. " mission zones for stage: " .. self.zoneName) self._logger:debug("Found " .. Spearhead.Util.tableLength(missionZones) .. " mission zones for stage: " .. self.zoneName)
for _, missionZone in pairs(missionZones) do for _, missionZone in pairs(missionZones) do
local mission = Spearhead.classes.stageClasses.missions.ZoneMission.new(missionZone, self._missionPriority, database, logger, self) local mission = Spearhead.classes.stageClasses.missions.ZoneMission.new(missionZone, self._missionPriority, database, logger, self, spawnManager)
if mission then if mission then
self._db.missionsByCode[mission.code] = mission self._db.missionsByCode[mission.code] = mission
@@ -164,7 +165,7 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
---@type table<string, Array<Mission>> ---@type table<string, Array<Mission>>
local randomMissionByName = {} local randomMissionByName = {}
for _, missionZoneName in pairs(randomMissionNames) do for _, missionZoneName in pairs(randomMissionNames) do
local mission = Spearhead.classes.stageClasses.missions.ZoneMission.new(missionZoneName, self._missionPriority, database, logger, self) local mission = Spearhead.classes.stageClasses.missions.ZoneMission.new(missionZoneName, self._missionPriority, database, logger, self, spawnManager)
if mission then if mission then
if randomMissionByName[mission.name] == nil then if randomMissionByName[mission.name] == nil then
randomMissionByName[mission.name] = {} randomMissionByName[mission.name] = {}
@@ -217,22 +218,22 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
local airbaseNames = database:getAirbaseNamesInStage(self.zoneName) local airbaseNames = database:getAirbaseNamesInStage(self.zoneName)
if airbaseNames ~= nil and type(airbaseNames) == "table" then if airbaseNames ~= nil and type(airbaseNames) == "table" then
for _, airbaseName in pairs(airbaseNames) do for _, airbaseName in pairs(airbaseNames) do
local airbase = Spearhead.classes.stageClasses.SpecialZones.StageBase.New(database, logger, airbaseName) local airbase = Spearhead.classes.stageClasses.SpecialZones.StageBase.New(database, logger, airbaseName, spawnManager)
table.insert(self._db.airbases, airbase) table.insert(self._db.airbases, airbase)
end end
end end
for _, samZoneName in pairs(database:getBlueSamsInStage(self.zoneName)) do for _, samZoneName in pairs(database:getBlueSamsInStage(self.zoneName)) do
local blueSam = Spearhead.classes.stageClasses.SpecialZones.BlueSam.New(database, logger, samZoneName) local blueSam = Spearhead.classes.stageClasses.SpecialZones.BlueSam.New(database, logger, samZoneName, spawnManager)
table.insert(self._db.blueSams, blueSam) table.insert(self._db.blueSams, blueSam)
end end
local miscGroups = database:getMiscGroupsAtStage(self.zoneName) local miscGroups = database:getMiscGroupsAtStage(self.zoneName)
for _, groupName in pairs(miscGroups) do for _, groupName in pairs(miscGroups) do
local miscGroup = SpearheadGroup.New(groupName) local miscGroup = SpearheadGroup.New(groupName, spawnManager, true)
table.insert(self._db.miscGroups, miscGroup) table.insert(self._db.miscGroups, miscGroup)
Spearhead.DcsUtil.DestroyGroup(groupName) miscGroup:Destroy()
end end
end end
+3 -2
View File
@@ -9,14 +9,15 @@ ExtraStage.__index = ExtraStage
---@param stageConfig StageConfig ---@param stageConfig StageConfig
---@param logger any ---@param logger any
---@param initData StageInitData ---@param initData StageInitData
---@param spawnManager SpawnManager
---@return ExtraStage ---@return ExtraStage
function ExtraStage.New(database, stageConfig, logger, initData) function ExtraStage.New(database, stageConfig, logger, initData, spawnManager)
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(ExtraStage, Stage) setmetatable(ExtraStage, Stage)
local self = setmetatable({}, { __index = ExtraStage }) --[[@as ExtraStage]] local self = setmetatable({}, { __index = ExtraStage }) --[[@as ExtraStage]]
self:superNew(database, stageConfig, logger, initData, "secondary") self:superNew(database, stageConfig, logger, initData, "secondary", spawnManager)
self.OnPostBlueActivated = function (selfStage) self.OnPostBlueActivated = function (selfStage)
+3 -2
View File
@@ -9,14 +9,15 @@ PrimaryStage.__index = PrimaryStage
---@param stageConfig StageConfig ---@param stageConfig StageConfig
---@param logger any ---@param logger any
---@param initData StageInitData ---@param initData StageInitData
---@param spawnManager SpawnManager
---@return PrimaryStage ---@return PrimaryStage
function PrimaryStage.New(database, stageConfig, logger, initData) function PrimaryStage.New(database, stageConfig, logger, initData, spawnManager)
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(PrimaryStage, Stage) setmetatable(PrimaryStage, Stage)
local self = setmetatable({}, { __index = PrimaryStage }) --[[@as PrimaryStage]] local self = setmetatable({}, { __index = PrimaryStage }) --[[@as PrimaryStage]]
self:superNew(database, stageConfig, logger, initData, "primary") self:superNew(database, stageConfig, logger, initData, "primary", spawnManager)
return self return self
end end
+3 -2
View File
@@ -15,14 +15,15 @@ local WaitingStageInitData = {}
---@param stageConfig StageConfig ---@param stageConfig StageConfig
---@param logger any ---@param logger any
---@param initData WaitingStageInitData ---@param initData WaitingStageInitData
---@param spawnManager SpawnManager
---@return WaitingStage ---@return WaitingStage
function WaitingStage.New(database, stageConfig, logger, initData) function WaitingStage.New(database, stageConfig, logger, initData, spawnManager)
local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage local Stage = Spearhead.classes.stageClasses.Stages.BaseStage.Stage
setmetatable(WaitingStage, Stage) setmetatable(WaitingStage, Stage)
local self = setmetatable({}, { __index = WaitingStage }) --[[@as WaitingStage]] local self = setmetatable({}, { __index = WaitingStage }) --[[@as WaitingStage]]
self:superNew(database, stageConfig, logger, initData, "none") self:superNew(database, stageConfig, logger, initData, "none", spawnManager)
self._waitTimeSeconds = 5 self._waitTimeSeconds = 5
if initData.waitingSeconds and initData.waitingSeconds > 5 then self._waitTimeSeconds = initData.waitingSeconds end if initData.waitingSeconds and initData.waitingSeconds > 5 then self._waitTimeSeconds = initData.waitingSeconds end
@@ -155,7 +155,7 @@ function BuildableMission:SpawnActive()
self._logger:debug("Spawning buildable mission: " .. self.code) self._logger:debug("Spawning buildable mission: " .. self.code)
if self._noLandingZone == nil then if self._noLandingZone == nil then
self._logger:error("No no landing zone found for mission: " .. self.code) self._logger:error("No nolanding zone found for mission: " .. self.code)
return return
end end
@@ -65,8 +65,9 @@ MINIMAL_UNITS_ALIVE_RATIO = 0.21
---@param database Database ---@param database Database
---@param logger Logger ---@param logger Logger
---@param parentStage Stage ---@param parentStage Stage
---@param spawnManager SpawnManager
---@return ZoneMission? ---@return ZoneMission?
function ZoneMission.new(zoneName, priority, database, logger, parentStage) function ZoneMission.new(zoneName, priority, database, logger, parentStage, spawnManager)
local Mission = Spearhead.classes.stageClasses.missions.baseMissions.Mission local Mission = Spearhead.classes.stageClasses.missions.baseMissions.Mission
ZoneMission.__index = ZoneMission ZoneMission.__index = ZoneMission
setmetatable(ZoneMission, Mission) setmetatable(ZoneMission, Mission)
@@ -128,7 +129,7 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage)
if not missionData then return end if not missionData then return end
for _, groupName in pairs(missionData.BlueGroups) do for _, groupName in pairs(missionData.BlueGroups) do
local spearheadGroup = SpearheadGroup.New(groupName) local spearheadGroup = SpearheadGroup.New(groupName, spawnManager, true)
if spearheadGroup then if spearheadGroup then
table.insert(self._missionGroups.blueGroups, spearheadGroup) table.insert(self._missionGroups.blueGroups, spearheadGroup)
end end
@@ -136,7 +137,7 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage)
end end
for _, groupName in pairs(missionData.RedGroups) do for _, groupName in pairs(missionData.RedGroups) do
local spearheadGroup = SpearheadGroup.New(groupName) local spearheadGroup = SpearheadGroup.New(groupName, spawnManager, true)
table.insert(self._missionGroups.redGroups, spearheadGroup) table.insert(self._missionGroups.redGroups, spearheadGroup)
local isGroupTarget = Spearhead.Util.startswith(string.lower(groupName), "tgt_") local isGroupTarget = Spearhead.Util.startswith(string.lower(groupName), "tgt_")
+3 -3
View File
@@ -86,9 +86,9 @@ SpearheadConfig = {
--- enables or disables the persistence logic in spearhead --- enables or disables the persistence logic in spearhead
enabled = false, enabled = false,
--- sets the directory where the persistence file is stored --- sets the directory where the persistence file is stored <br>
--- if nil then lfs.writedir() will be used. --- if nil then lfs.writedir()/Data will be used. <br>
--- which will --- which will Result in <Saved Games>/<DCS Saved Games Folder>/Data/
directory = nil , directory = nil ,
--- the filename of the persistence file. Should end with .json for convention, but any text extension should do. --- the filename of the persistence file. Should end with .json for convention, but any text extension should do.
+4
View File
@@ -16,6 +16,9 @@ assert(loadfile(classPath .. "spearhead_db.lua"))()
assert(loadfile(classPath .. "fleetClasses\\FleetGroup.lua"))() assert(loadfile(classPath .. "fleetClasses\\FleetGroup.lua"))()
assert(loadfile(classPath .. "fleetClasses\\GlobalFleetManager.lua"))() assert(loadfile(classPath .. "fleetClasses\\GlobalFleetManager.lua"))()
assert(loadfile(classPath .. "helpers\\MizGroupsManager.lua"))()
assert(loadfile(classPath .. "helpers\\SpawnManager.lua"))()
assert(loadfile(classPath .. "configuration\\CapConfig.lua"))() assert(loadfile(classPath .. "configuration\\CapConfig.lua"))()
assert(loadfile(classPath .. "configuration\\StageConfig.lua"))() assert(loadfile(classPath .. "configuration\\StageConfig.lua"))()
@@ -39,6 +42,7 @@ assert(loadfile(classPath .. "stageClasses\\helpers\\SupplyConfig.lua"))()
assert(loadfile(classPath .. "stageClasses\\helpers\\SupplyUnitsTracker.lua"))() assert(loadfile(classPath .. "stageClasses\\helpers\\SupplyUnitsTracker.lua"))()
assert(loadfile(classPath .. "stageClasses\\helpers\\BattleManager.lua"))() assert(loadfile(classPath .. "stageClasses\\helpers\\BattleManager.lua"))()
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\abstract\\BuildableZone.lua"))()
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\StageBase.lua"))() assert(loadfile(classPath .. "stageClasses\\SpecialZones\\StageBase.lua"))()
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\BlueSam.lua"))() assert(loadfile(classPath .. "stageClasses\\SpecialZones\\BlueSam.lua"))()
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\FarpZone.lua"))() assert(loadfile(classPath .. "stageClasses\\SpecialZones\\FarpZone.lua"))()
+2 -2
View File
@@ -64,7 +64,7 @@ SpearheadConfig = {
--- io and lfs cannot be sanitized in the MissionScripting.lua --- io and lfs cannot be sanitized in the MissionScripting.lua
--- enables or disables the persistence logic in spearhead --- enables or disables the persistence logic in spearhead
enabled = false, enabled = true,
--- sets the directory where the persistence file is stored --- sets the directory where the persistence file is stored
--- if nil then lfs.writedir() will be used. --- if nil then lfs.writedir() will be used.
@@ -72,7 +72,7 @@ SpearheadConfig = {
directory = nil , directory = nil ,
--- the filename of the persistence file. Should end with .json for convention, but any text extension should do. --- the filename of the persistence file. Should end with .json for convention, but any text extension should do.
fileName = "Spearhead_Persistence_Dev.json" fileName = "Spearhead_Persistence_Dev"
} }
} }
+5 -2
View File
@@ -33,11 +33,14 @@ else
standardLogger:info("Persistence disabled") standardLogger:info("Persistence disabled")
end end
local spawnLogger = Spearhead.LoggerTemplate.new("SpawnManager", defaultLogLevel)
local spawnManager = Spearhead.classes.helpers.SpawnManager.new(spawnLogger)
local detectionLogger = Spearhead.LoggerTemplate.new("DetectionManager", defaultLogLevel) local detectionLogger = Spearhead.LoggerTemplate.new("DetectionManager", defaultLogLevel)
local detectionManager = Spearhead.classes.capClasses.detection.DetectionManager.New(detectionLogger) local detectionManager = Spearhead.classes.capClasses.detection.DetectionManager.New(detectionLogger)
Spearhead.classes.capClasses.GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel) Spearhead.classes.capClasses.GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel, spawnManager)
Spearhead.internal.GlobalStageManager:NewAndStart(databaseManager, stageConfig, defaultLogLevel) Spearhead.internal.GlobalStageManager:NewAndStart(databaseManager, stageConfig, defaultLogLevel, spawnManager)
Spearhead.internal.GlobalFleetManager.start(databaseManager) Spearhead.internal.GlobalFleetManager.start(databaseManager)
local SetStageDelayed = function(number, time) local SetStageDelayed = function(number, time)