Performance enhancments.

This commit is contained in:
iTracerFacer 2025-11-12 08:51:49 -06:00
parent f169d825d9
commit f2a88f85e9
4 changed files with 178 additions and 48 deletions

View File

@ -236,12 +236,32 @@ log("[DEBUG] Alakurtti zone initialization complete")
-- Global cached unit set - created once and maintained automatically by MOOSE
local CachedUnitSet = nil
-- Utility to guard point-in-zone checks that may throw when objects despawn mid-loop
local function IsUnitInZone(unit, zone)
if not unit or not zone then return false end
local ok, point = pcall(function()
return unit:GetPointVec3()
end)
if not ok or not point then
return false
end
local inZone = false
pcall(function()
inZone = zone:IsPointVec3InZone(point)
end)
return inZone
end
-- Initialize the cached unit set once
local function InitializeCachedUnitSet()
if not CachedUnitSet then
CachedUnitSet = SET_UNIT:New()
:FilterCategories({"ground", "plane", "helicopter"}) -- Only scan relevant unit types
:FilterOnce() -- Don't filter continuously, we'll use the live set
:FilterStart() -- Keep the set updated by MOOSE without recreating it
log("[PERFORMANCE] Initialized cached unit set for zone scanning")
end
end
@ -260,14 +280,12 @@ local function GetZoneForceStrengths(ZoneCapture)
local blueCount = 0
local neutralCount = 0
-- Get all units in the zone using MOOSE's zone scanning
local unitsInZone = SET_UNIT:New()
:FilterZones({zone})
:FilterOnce()
if unitsInZone then
unitsInZone:ForEachUnit(function(unit)
if unit and unit:IsAlive() then
-- Ensure the cached set exists before scanning
InitializeCachedUnitSet()
if CachedUnitSet then
CachedUnitSet:ForEachUnit(function(unit)
if unit and unit:IsAlive() and IsUnitInZone(unit, zone) then
local unitCoalition = unit:GetCoalition()
if unitCoalition == coalition.side.RED then
redCount = redCount + 1
@ -302,50 +320,48 @@ local function GetRedUnitMGRSCoords(ZoneCapture)
local coords = {}
-- Get all units in the zone using MOOSE's zone scanning
local unitsInZone = SET_UNIT:New()
:FilterZones({zone})
:FilterOnce()
-- Ensure the cached set exists before scanning
InitializeCachedUnitSet()
local totalUnits = 0
local redUnits = 0
local unitsWithCoords = 0
if unitsInZone then
unitsInZone:ForEachUnit(function(unit)
totalUnits = totalUnits + 1
if unit and unit:IsAlive() then
if CachedUnitSet then
CachedUnitSet:ForEachUnit(function(unit)
if unit and unit:IsAlive() and IsUnitInZone(unit, zone) then
totalUnits = totalUnits + 1
local unitCoalition = unit:GetCoalition()
-- Only process RED units
if unitCoalition == coalition.side.RED then
redUnits = redUnits + 1
local coord = unit:GetCoordinate()
if coord then
-- Try multiple methods to get coordinates
local mgrs = nil
local success_mgrs = false
-- Method 1: Try ToStringMGRS
success_mgrs, mgrs = pcall(function()
return coord:ToStringMGRS(5)
end)
-- Method 2: Try ToStringMGRS without precision parameter
if not success_mgrs or not mgrs then
success_mgrs, mgrs = pcall(function()
return coord:ToStringMGRS()
end)
end
-- Method 3: Try ToMGRS
if not success_mgrs or not mgrs then
success_mgrs, mgrs = pcall(function()
return coord:ToMGRS()
end)
end
-- Method 4: Fallback to Lat/Long
if not success_mgrs or not mgrs then
success_mgrs, mgrs = pcall(function()
@ -353,7 +369,7 @@ local function GetRedUnitMGRSCoords(ZoneCapture)
return string.format("N%s E%s", lat, lon)
end)
end
if success_mgrs and mgrs then
unitsWithCoords = unitsWithCoords + 1
local unitType = unit:GetTypeName() or "Unknown"

View File

@ -5,7 +5,8 @@
DESCRIPTION:
This script monitors RED and BLUE squadrons for low aircraft counts and automatically dispatches CARGO aircraft from a list of supply airfields to replenish them. It spawns cargo aircraft and routes them to destination airbases. Delivery detection and replenishment is handled by the main TADC system.
This script monitors RED and BLUE squadrons for low aircraft counts and automatically dispatches CARGO aircraft from a list of supply airfields to replenish them.
It spawns cargo aircraft and routes them to destination airbases. Delivery detection and replenishment is handled by the main TADC system.
CONFIGURATION:
- Update static templates and airfield lists as needed for your mission.
@ -271,9 +272,9 @@ local function cleanupCargoMissions()
for _, coalitionKey in ipairs({"red", "blue"}) do
for i = #cargoMissions[coalitionKey], 1, -1 do
local m = cargoMissions[coalitionKey][i]
if m.status == "failed" then
if m.status == "failed" or m.status == "completed" then
if not (m.group and m.group:IsAlive()) then
log("Cleaning up failed cargo mission: " .. (m.group and m.group:GetName() or "nil group") .. " status: failed")
log("Cleaning up " .. m.status .. " cargo mission: " .. (m.group and m.group:GetName() or "nil group"))
table.remove(cargoMissions[coalitionKey], i)
end
end
@ -451,6 +452,8 @@ local function dispatchCargo(squadron, coalitionKey)
rat:SetDeparture(origin)
rat:SetDestination(destination)
rat:NoRespawn()
rat:InitUnControlled(false) -- force departing transports to spawn in a controllable state
rat:InitLateActivated(false)
rat:SetSpawnLimit(1)
rat:SetSpawnDelay(1)

View File

@ -276,6 +276,105 @@ local airbaseHealthStatus = {
blue = {}
}
local function coalitionKeyFromSide(side)
if side == coalition.side.RED then return "red" end
if side == coalition.side.BLUE then return "blue" end
return nil
end
local function cleanupInterceptorEntry(interceptorName, coalitionKey)
if not interceptorName or not coalitionKey then return end
if activeInterceptors[coalitionKey] then
activeInterceptors[coalitionKey][interceptorName] = nil
end
if aircraftSpawnTracking[coalitionKey] then
aircraftSpawnTracking[coalitionKey][interceptorName] = nil
end
end
local function destroyInterceptorGroup(interceptor, coalitionKey, delaySeconds)
if not interceptor then return end
local name = nil
if interceptor.GetName then
local ok, value = pcall(function() return interceptor:GetName() end)
if ok then name = value end
end
local resolvedKey = coalitionKey
if not resolvedKey and interceptor.GetCoalition then
local ok, side = pcall(function() return interceptor:GetCoalition() end)
if ok then
resolvedKey = coalitionKeyFromSide(side)
end
end
local function doDestroy()
if interceptor and interceptor.IsAlive and interceptor:IsAlive() then
pcall(function() interceptor:Destroy() end)
end
if name and resolvedKey then
cleanupInterceptorEntry(name, resolvedKey)
end
end
if delaySeconds and delaySeconds > 0 then
timer.scheduleFunction(function()
doDestroy()
return
end, {}, timer.getTime() + delaySeconds)
else
doDestroy()
end
end
local function finalizeCargoMission(cargoGroup, squadron, coalitionKey)
if not cargoMissions or not coalitionKey or not squadron or not squadron.airbaseName then
return
end
local coalitionBucket = cargoMissions[coalitionKey]
if type(coalitionBucket) ~= "table" then
return
end
local groupName = nil
if cargoGroup and cargoGroup.GetName then
local ok, value = pcall(function() return cargoGroup:GetName() end)
if ok then groupName = value end
end
for idx = #coalitionBucket, 1, -1 do
local mission = coalitionBucket[idx]
if mission and mission.destination == squadron.airbaseName then
local missionGroupName = nil
if mission.group and mission.group.GetName then
local ok, value = pcall(function() return mission.group:GetName() end)
if ok then missionGroupName = value end
end
if not groupName or missionGroupName == groupName then
mission.status = "completed"
mission.completedAt = timer.getTime()
if mission.group and mission.group.Destroy then
local targetGroup = mission.group
timer.scheduleFunction(function()
pcall(function()
if targetGroup and targetGroup.IsAlive and targetGroup:IsAlive() then
targetGroup:Destroy()
end
end)
return
end, {}, timer.getTime() + 90)
end
table.remove(coalitionBucket, idx)
end
end
end
end
-- Logging function
local function log(message, detailed)
if not detailed or ADVANCED_SETTINGS.enableDetailedLogging then
@ -709,6 +808,8 @@ local function processCargoDelivery(cargoGroup, squadron, coalitionSide, coaliti
MESSAGE:New(msg, 10):ToCoalition(coalitionSide)
USERSOUND:New("Cargo_Delivered.ogg"):ToCoalition(coalitionSide)
end
finalizeCargoMission(cargoGroup, squadron, coalitionKey)
end
-- Event handler for cargo aircraft landing (backup for actual landings)
@ -1271,10 +1372,9 @@ local function monitorStuckAircraft()
-- Mark airbase as having stuck aircraft
airbaseHealthStatus[coalitionKey][trackingData.airbase] = "stuck-aircraft"
-- Remove the stuck aircraft
trackingData.group:Destroy()
activeInterceptors[coalitionKey][aircraftName] = nil
aircraftSpawnTracking[coalitionKey][aircraftName] = nil
-- Remove the stuck aircraft and clear tracking
pcall(function() trackingData.group:Destroy() end)
cleanupInterceptorEntry(aircraftName, coalitionKey)
-- Reassign squadron to alternative airbase
reassignSquadronToAlternativeAirbase(trackingData.squadron, coalitionKey)
@ -1342,9 +1442,14 @@ local function sendInterceptorHome(interceptor, coalitionSide)
SCHEDULER:New(nil, function()
local coalitionKey = (coalitionSide == coalition.side.RED) and "red" or "blue"
if activeInterceptors[coalitionKey][interceptor:GetName()] then
activeInterceptors[coalitionKey][interceptor:GetName()] = nil
log("Cleaned up " .. coalitionName .. " " .. interceptor:GetName() .. " after RTB", true)
local name = nil
if interceptor and interceptor.GetName then
local ok, value = pcall(function() return interceptor:GetName() end)
if ok then name = value end
end
if name and activeInterceptors[coalitionKey][name] then
destroyInterceptorGroup(interceptor, coalitionKey, 0)
log("Cleaned up " .. coalitionName .. " " .. name .. " after RTB", true)
end
end, {}, flightTime)
else
@ -1616,6 +1721,7 @@ local function launchInterceptor(threatGroup, coalitionSide)
log("ERROR: Failed to create SPAWN object for " .. coalitionName .. " " .. squadron.templateName)
return
end
spawn:InitCleanUp(900)
local interceptors = {}
@ -1674,11 +1780,14 @@ local function launchInterceptor(threatGroup, coalitionSide)
-- Emergency cleanup (safety net)
SCHEDULER:New(nil, function()
if activeInterceptors[coalitionKey][interceptor:GetName()] then
log("Emergency cleanup of " .. coalitionName .. " " .. interceptor:GetName() .. " (should have RTB'd)")
activeInterceptors[coalitionKey][interceptor:GetName()] = nil
-- Also clean up spawn tracking
aircraftSpawnTracking[coalitionKey][interceptor:GetName()] = nil
local name = nil
if interceptor and interceptor.GetName then
local ok, value = pcall(function() return interceptor:GetName() end)
if ok then name = value end
end
if name and activeInterceptors[coalitionKey][name] then
log("Emergency cleanup of " .. coalitionName .. " " .. name .. " (should have RTB'd)")
destroyInterceptorGroup(interceptor, coalitionKey, 0)
end
end, {}, coalitionSettings.emergencyCleanupTime)
end
@ -2351,15 +2460,15 @@ local menuAdminRed = MENU_COALITION:New(coalition.side.RED, "Admin / Debug", men
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Emergency Cleanup Interceptors", menuAdminBlue, function()
local cleaned = 0
for _, interceptors in pairs(activeInterceptors.red) do
for name, interceptors in pairs(activeInterceptors.red) do
if interceptors and interceptors.group and not interceptors.group:IsAlive() then
interceptors.group = nil
cleanupInterceptorEntry(name, "red")
cleaned = cleaned + 1
end
end
for _, interceptors in pairs(activeInterceptors.blue) do
for name, interceptors in pairs(activeInterceptors.blue) do
if interceptors and interceptors.group and not interceptors.group:IsAlive() then
interceptors.group = nil
cleanupInterceptorEntry(name, "blue")
cleaned = cleaned + 1
end
end
@ -2368,15 +2477,15 @@ end)
MENU_COALITION_COMMAND:New(coalition.side.RED, "Emergency Cleanup Interceptors", menuAdminRed, function()
local cleaned = 0
for _, interceptors in pairs(activeInterceptors.red) do
for name, interceptors in pairs(activeInterceptors.red) do
if interceptors and interceptors.group and not interceptors.group:IsAlive() then
interceptors.group = nil
cleanupInterceptorEntry(name, "red")
cleaned = cleaned + 1
end
end
for _, interceptors in pairs(activeInterceptors.blue) do
for name, interceptors in pairs(activeInterceptors.blue) do
if interceptors and interceptors.group and not interceptors.group:IsAlive() then
interceptors.group = nil
cleanupInterceptorEntry(name, "blue")
cleaned = cleaned + 1
end
end

View File

@ -444,6 +444,8 @@ local function dispatchCargo(squadron, coalitionKey)
rat:SetDeparture(origin)
rat:SetDestination(destination)
rat:NoRespawn()
rat:InitUnControlled(false) -- ensure template-level 'Uncontrolled' flag does not leave transports parked
rat:InitLateActivated(false)
rat:SetSpawnLimit(1)
rat:SetSpawnDelay(1)
-- Ensure RAT takes off immediately from the runway (hot start) instead of staying parked