local MizGroupsManager = require("classes.helpers.MizGroupsManager") local Persistence = require("classes.persistence.Persistence") local SpearheadEvents = require("classes.spearhead_events") local Util = require("classes.util.Util") ---@class SpawnManager : OnUnitLostListener ---@field private _persistedUnits table ---@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 ---@return SpawnManager 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 = 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(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 = 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 Persistence.UnitKilled( name, object:getPoint(), heading, object:getTypeName() ) end end ---@param groupName string function SpawnManager:SpawnCorpsesOnly(groupName) if groupName == nil then return end end do --- privates ---@private ---@param spawnData SpawnData ---@param override SpawnOverrides? ---@param isPersistent boolean? ---@return Group|nil function SpawnManager:SpawnGroupInternal(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 = Util.deepCopyTable(spawnData.groupTemplate) --[[ 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 local units = spawnTemplate["units"] --[[@as Array]] for _, unit in pairs(units) do local name = unit["name"] --[[@as string]] SpearheadEvents.addOnUnitLostEventListener(name, self) if override and override.emptyLoadouts == true then if unit["payload"] and unit["payload"]["pylons"] then local payload = unit["payload"] --[[@as table]] payload["pylons"] = {} --[[@as table]] end end if unit["parking"] then unit["parking_landing"] = unit["parking"] --[[@as number]] end if unit["parking_id"] then unit["parking_landing_id"] = unit["parking_id"] --[[@as number]] 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 SpearheadEvents.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 = Util.deepCopyTable(spawnData.groupTemplate) --for static Objecst groupNames and unit names are the same and is always 1:1 local persistentState = 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 local units = spawnTemplate["units"] --[[@as Array
]] local firstUnit = units[1] --[[@as table]] firstUnit["x"] = persistentState.pos.x --[[@as number]] firstUnit["y"] = persistentState.pos.z --[[@as number]] firstUnit["heading"] = persistentState.heading or 0 --[[@as number]] 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 SpearheadEvents.addOnUnitLostEventListener(groupName, self) end return object end ---@private ---@param unit Unit function SpawnManager:CheckUnitAndReplaceIfPersistentDead(unit) if not unit then return end local deadState = 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 return 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