Files
spearhead/classes/helpers/SpawnManager.lua
T
dutchie031 b6a1285bde 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
2025-07-11 20:06:09 +02:00

349 lines
12 KiB
Lua

---@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