he cargo dispatcher will now:

Give aircraft 10 full minutes to taxi and take off before declaring them stuck
Prevent multiple aircraft from spawning simultaneously at the same airbase
Provide detailed diagnostic information about stuck aircraft (including speed)
Log when aircraft successfully take off for better visibility
Issue warnings after 3 failures at any specific airbase
This commit is contained in:
iTracerFacer
2025-12-09 21:39:41 -06:00
parent 5377738925
commit 48c56398ac
3 changed files with 30 additions and 10 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

+30 -10
View File
@@ -107,7 +107,7 @@ end
Advanced logging configuration and helper function for debug output. Advanced logging configuration and helper function for debug output.
]] ]]
local ADVANCED_LOGGING = { local ADVANCED_LOGGING = {
enableDetailedLogging = false, enableDetailedLogging = true,
logPrefix = "[TADC Cargo]" logPrefix = "[TADC Cargo]"
} }
@@ -141,6 +141,10 @@ end
local CARGO_DISPATCH_COOLDOWN = DISPATCHER_CONFIG and DISPATCHER_CONFIG.cooldown or 300 -- default 5 minutes local CARGO_DISPATCH_COOLDOWN = DISPATCHER_CONFIG and DISPATCHER_CONFIG.cooldown or 300 -- default 5 minutes
local lastDispatchAttempt = { red = {}, blue = {} } local lastDispatchAttempt = { red = {}, blue = {} }
-- Per-airbase spawn throttling to prevent runway congestion (minimum time between spawns at same airbase)
local AIRBASE_SPAWN_THROTTLE = 120 -- 2 minutes between spawns at same airbase
local lastSpawnAtAirbase = { red = {}, blue = {} }
local function getCoalitionSide(coalitionKey) local function getCoalitionSide(coalitionKey)
if coalitionKey == 'blue' then return coalition.side.BLUE end if coalitionKey == 'blue' then return coalition.side.BLUE end
if coalitionKey == 'red' then return coalition.side.RED end if coalitionKey == 'red' then return coalition.side.RED end
@@ -335,6 +339,15 @@ local function dispatchCargo(squadron, coalitionKey)
log("No valid origin airfield found for cargo dispatch to " .. squadron.airbaseName .. " (avoiding same origin/destination)") log("No valid origin airfield found for cargo dispatch to " .. squadron.airbaseName .. " (avoiding same origin/destination)")
return return
end end
-- Check airbase spawn throttle to prevent runway congestion
lastSpawnAtAirbase[coalitionKey] = lastSpawnAtAirbase[coalitionKey] or {}
local lastSpawnTime = lastSpawnAtAirbase[coalitionKey][origin]
if lastSpawnTime and (timer.getTime() - lastSpawnTime) < AIRBASE_SPAWN_THROTTLE then
log("Skipping dispatch from " .. origin .. " (spawn throttle active - preventing runway congestion)", true)
return
end
local destination = squadron.airbaseName local destination = squadron.airbaseName
local cargoTemplate = config.cargoTemplate local cargoTemplate = config.cargoTemplate
-- Safety: check if destination has suitable parking for larger transports. If not, warn in log. -- Safety: check if destination has suitable parking for larger transports. If not, warn in log.
@@ -497,8 +510,11 @@ local function dispatchCargo(squadron, coalitionKey)
mission.spawnPos = spawnPos mission.spawnPos = spawnPos
mission.spawnTime = timer.getTime() mission.spawnTime = timer.getTime()
-- Track spawn time for this airbase to enforce throttling
lastSpawnAtAirbase[coalitionKey][origin] = timer.getTime()
log("RAT spawned cargo aircraft group: " .. tostring(spawnedGroup:GetName())) log("RAT spawned cargo aircraft group: " .. tostring(spawnedGroup:GetName()) .. " from " .. origin)
-- CRITICAL FIX: Force group to start/activate immediately after spawn -- CRITICAL FIX: Force group to start/activate immediately after spawn
-- This addresses the MOOSE IsAlive=false issue where RAT spawns groups in inactive state -- This addresses the MOOSE IsAlive=false issue where RAT spawns groups in inactive state
@@ -558,9 +574,9 @@ local function dispatchCargo(squadron, coalitionKey)
collectgarbage('step', 10) -- GC after verification collectgarbage('step', 10) -- GC after verification
end, {}, timer.getTime() + 2) end, {}, timer.getTime() + 2)
-- Temporary debug: log group state every 10s for 5 minutes to trace landing/parking behavior -- Debug logging: log group state every 20s for 12 minutes (600s takeoff window + 2 min buffer) to trace taxi/takeoff/landing behavior
local debugChecks = 30 -- 30 * 10s = 5 minutes (reduced from 10 minutes to limit memory impact) local debugChecks = 36 -- 36 * 20s = 12 minutes
local checkInterval = 10 local checkInterval = 20
local function debugLogState(iter) local function debugLogState(iter)
if iter > debugChecks then if iter > debugChecks then
collectgarbage('step', 20) -- Final cleanup after debug sequence collectgarbage('step', 20) -- Final cleanup after debug sequence
@@ -744,25 +760,29 @@ local function monitorCargoMissions()
end end
end end
-- Check for stuck aircraft -- Check for stuck aircraft (increased to 10 minutes to allow for long taxi distances)
if mission.status == "enroute" and mission.group and mission.group:IsAlive() and mission.spawnTime then if mission.status == "enroute" and mission.group and mission.group:IsAlive() and mission.spawnTime then
local timeSinceSpawn = timer.getTime() - mission.spawnTime local timeSinceSpawn = timer.getTime() - mission.spawnTime
if timeSinceSpawn > 60 then -- Check after 1 minute if timeSinceSpawn > 600 then -- Check after 10 minutes
local dcsGroup = mission.group:GetDCSObject() local dcsGroup = mission.group:GetDCSObject()
if dcsGroup then if dcsGroup then
local units = dcsGroup:getUnits() local units = dcsGroup:getUnits()
if units and #units > 0 then if units and #units > 0 then
local unit = units[1] local unit = units[1]
if not unit:inAir() then if not unit:inAir() then
-- Aircraft is stuck, not airborne -- Aircraft is stuck, not airborne after 10 minutes
log("Cargo aircraft failed to take off from " .. tostring(mission.origin) .. ": " .. tostring(mission.group:GetName())) local vel = (unit.getVelocity and unit:getVelocity()) or {x=0,y=0,z=0}
local speed = math.sqrt((vel.x or 0)^2 + (vel.y or 0)^2 + (vel.z or 0)^2)
log("Cargo aircraft failed to take off from " .. tostring(mission.origin) .. " after 10 minutes: " .. tostring(mission.group:GetName()) .. " (speed: " .. string.format("%.1f", speed) .. " m/s)")
mission.group:Destroy() mission.group:Destroy()
mission.status = "failed" mission.status = "failed"
stuckCounts[coalitionKey][mission.origin] = (stuckCounts[coalitionKey][mission.origin] or 0) + 1 stuckCounts[coalitionKey][mission.origin] = (stuckCounts[coalitionKey][mission.origin] or 0) + 1
local count = stuckCounts[coalitionKey][mission.origin] local count = stuckCounts[coalitionKey][mission.origin]
if count >= 3 then if count >= 3 then
MESSAGE:New("WARNING: Airbase '" .. tostring(mission.origin) .. "' has caused " .. tostring(count) .. " cargo aircraft to fail takeoff. Mission maker: reconfigure cargo operations to avoid this airbase.", 60):ToAll() MESSAGE:New("WARNING: Airbase '" .. tostring(mission.origin) .. "' has caused " .. tostring(count) .. " cargo aircraft to fail takeoff after 10 minutes. Mission maker: reconfigure cargo operations to avoid this airbase or check for parking/runway issues.", 60):ToAll()
end end
else
log("Cargo aircraft from " .. tostring(mission.origin) .. " successfully airborne: " .. tostring(mission.group:GetName()), true)
end end
end end
end end
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB