Enhance cargo mission handling with stuck aircraft safety checks and improved logging

This commit is contained in:
iTracerFacer 2025-11-15 01:13:05 -06:00
parent d79e5e2878
commit 99842f8b36

View File

@ -48,6 +48,11 @@ if DISPATCHER_CONFIG.ALLOW_FALLBACK_TO_INMEM_TEMPLATE == nil then
DISPATCHER_CONFIG.ALLOW_FALLBACK_TO_INMEM_TEMPLATE = false DISPATCHER_CONFIG.ALLOW_FALLBACK_TO_INMEM_TEMPLATE = false
end end
-- Stuck-aircraft safety net defaults
DISPATCHER_CONFIG.stuckTimeout = DISPATCHER_CONFIG.stuckTimeout or 300
DISPATCHER_CONFIG.stuckMovementThreshold = DISPATCHER_CONFIG.stuckMovementThreshold or 40
DISPATCHER_CONFIG.stuckSpeedThreshold = DISPATCHER_CONFIG.stuckSpeedThreshold or 2
--[[ --[[
CARGO SUPPLY CONFIGURATION CARGO SUPPLY CONFIGURATION
-------------------------------------------------------------------------- --------------------------------------------------------------------------
@ -55,18 +60,18 @@ end
]] ]]
local CARGO_SUPPLY_CONFIG = { local CARGO_SUPPLY_CONFIG = {
red = { red = {
supplyAirfields = { "Afrikanda", "Kalevala", "Poduzhemye", "Severomorsk-1", "Severomorsk-3", "Murmansk International", "Kilpyavr", "Olenya", "Monchegorsk" }, -- replace with your RED supply airbase names supplyAirfields = { "Kalevala", "Poduzhemye", "Severomorsk-1", "Severomorsk-3", "Murmansk International", "Kilpyavr", "Olenya", "Monchegorsk" }, -- replace with your RED supply airbase names
cargoTemplate = "CARGO_RED_AN26", -- replace with your RED cargo aircraft template name cargoTemplate = "CARGO_RED_AN26", -- replace with your RED cargo aircraft template name
threshold = 0.90 -- ratio below which to trigger resupply (testing) threshold = 0.90 -- ratio below which to trigger resupply (testing)
}, },
blue = { blue = {
supplyAirfields = { "Banak", "Kittila", "Alta", "Sodankyla", "Enontekio", "Kirkenes", "Ivalo", "Luostari Pechenga", "Koshka Yavr" }, -- replace with your BLUE supply airbase names supplyAirfields = { "Banak", "Kittila", "Alta", "Sodankyla", "Enontekio", "Kirkenes", "Ivalo", }, -- replace with your BLUE supply airbase names
cargoTemplate = "CARGO_BLUE_C130", -- replace with your BLUE cargo aircraft template name cargoTemplate = "CARGO_BLUE_C130", -- replace with your BLUE cargo aircraft template name
threshold = 0.90 -- ratio below which to trigger resupply (testing) threshold = 0.90 -- ratio below which to trigger resupply (testing)
} }
} }
-- _G.TDAC_CargoDispatcher_TestSpawn("CARGO_BLUE_C130", "Banak", "Luostari Pechenga")
--[[ --[[
UTILITY STUBS UTILITY STUBS
@ -373,7 +378,11 @@ local function dispatchCargo(squadron, coalitionKey)
-- before MOOSE has a chance to finalize the OnSpawnGroup callback. -- before MOOSE has a chance to finalize the OnSpawnGroup callback.
_pendingStartTime = timer.getTime(), _pendingStartTime = timer.getTime(),
_spawnPos = nil, _spawnPos = nil,
_gracePeriod = DISPATCHER_CONFIG.gracePeriod or 8 _gracePeriod = DISPATCHER_CONFIG.gracePeriod or 8,
lastKnownPos = nil,
lastMoveTime = nil,
_lastSpeed = 0,
_stuckHandled = false
} }
-- Helper to finalize mission after successful spawn -- Helper to finalize mission after successful spawn
@ -535,6 +544,9 @@ local function dispatchCargo(squadron, coalitionKey)
finalizeMissionAfterSpawn(spawnedGroup, spawnPos) finalizeMissionAfterSpawn(spawnedGroup, spawnPos)
mission.status = "enroute" mission.status = "enroute"
mission._pendingStartTime = timer.getTime() mission._pendingStartTime = timer.getTime()
mission.lastKnownPos = spawnPos
mission.lastMoveTime = timer.getTime()
mission._lastSpeed = 0
announceToCoalition(coalitionKey, "CARGO aircraft departing (airborne) for " .. destination .. ". Defend it!") announceToCoalition(coalitionKey, "CARGO aircraft departing (airborne) for " .. destination .. ". Defend it!")
end) end)
@ -648,6 +660,52 @@ local function monitorCargoMissions()
end end
end end
local now = timer.getTime()
local dcsGroup = mission.group and mission.group:GetDCSObject()
if dcsGroup and mission.group and mission.group:IsAlive() then
local units = dcsGroup:getUnits()
if units and #units > 0 then
local unit = units[1]
local pos = unit:getPoint()
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)
mission._lastSpeed = speed
if mission.lastKnownPos then
local dx = pos.x - mission.lastKnownPos.x
local dz = pos.z - mission.lastKnownPos.z
local moved = math.sqrt(dx * dx + dz * dz)
if moved >= (DISPATCHER_CONFIG.stuckMovementThreshold or 40) then
mission.lastKnownPos = pos
mission.lastMoveTime = now
end
else
mission.lastKnownPos = pos
mission.lastMoveTime = now
end
end
end
local lastMove = mission.lastMoveTime or mission._pendingStartTime
if mission.group and mission.group:IsAlive() and not mission._stuckHandled then
if lastMove and (now - lastMove) >= (DISPATCHER_CONFIG.stuckTimeout or 300) then
local speed = mission._lastSpeed or 0
if speed <= (DISPATCHER_CONFIG.stuckSpeedThreshold or 2) then
mission._stuckHandled = true
mission.status = "failed"
log("Cargo mission stuck for " .. tostring(mission.destination) .. "; destroying group to free runway")
announceToCoalition(coalitionKey, "Resupply mission to " .. mission.destination .. " aborted (aircraft stuck). Replacement flight queued.")
lastDispatchAttempt[coalitionKey] = lastDispatchAttempt[coalitionKey] or {}
lastDispatchAttempt[coalitionKey][mission.destination] = now - CARGO_DISPATCH_COOLDOWN
local okDestroy, errDestroy = pcall(function() mission.group:Destroy(false) end)
if not okDestroy then
log("ERROR: Failed to destroy stuck cargo group for " .. tostring(mission.destination) .. ": " .. tostring(errDestroy))
else
mission.group = nil
end
end
end
end
local graceElapsed = mission._pendingStartTime and (timer.getTime() - mission._pendingStartTime > (mission._gracePeriod or 8)) local graceElapsed = mission._pendingStartTime and (timer.getTime() - mission._pendingStartTime > (mission._gracePeriod or 8))
-- Only allow mission to be failed after grace period, and only if group is truly dead. -- Only allow mission to be failed after grace period, and only if group is truly dead.