Merge pull request #2532 from FlightControl-Master/leka1986-patch-3

Update DynamicCargo.lua
This commit is contained in:
Thomas
2026-03-03 19:57:32 +01:00
committed by GitHub
+539 -59
View File
@@ -28,9 +28,9 @@
-- @field #string version.
-- @field #string CargoState.
-- @field #table DCS#Vec3 LastPosition.
-- @field #number Interval Check Interval. 20 secs default.
-- @field #number Interval Check interval. 5 secs default.
-- @field #boolean testing
-- @field Core.Timer#TIMER timer Timmer to run intervals
-- @field Core.Timer#TIMER timer Compatibility field; updates are handled by one class-wide scheduler.
-- @field #string Owner The playername who has created, loaded or unloaded this cargo. Depends on state.
-- @extends Wrapper.Positionable#POSITIONABLE
@@ -50,7 +50,16 @@ DYNAMICCARGO = {
ClassName = "DYNAMICCARGO",
verbose = 0,
testing = false,
Interval = 10,
Interval = 5,
C130AttachDistance = 10,
C130DetachDistance = 14,
C130AirborneAGL = 8,
C130LandedAGL = 0.5,
C130StabilityEpsilon = 0.05,
C130RequireAirborne = true,
C130OwnerResolveMove2D = 10,
C130OwnerResolveNear2D = 4,
C130OwnerResolveMax3D = 250,
}
@@ -110,6 +119,10 @@ DYNAMICCARGO.AircraftTypes = {
["CH-47Fbl1"] = "CH-47Fbl1",
["Mi-8MTV2"] = "Mi-8MTV2",
["Mi-8MT"] = "Mi-8MT",
["UH-1H"] = "UH-1H",
["Mi-24P"] = "Mi-24P",
["UH-60L"] = "UH-60L",
["UH-60L_DAP"] = "UH-60L_DAP",
["C-130J-30"] = "C-130J-30",
}
@@ -135,17 +148,46 @@ DYNAMICCARGO.AircraftDimensions = {
["length"] = 15,
["ropelength"] = 30,
},
["UH-1H"] = {
["width"] = 4,
["height"] = 4,
["length"] = 9,
["ropelength"] = 25,
},
["Mi-24P"] = {
["width"] = 4,
["height"] = 5,
["length"] = 11,
["ropelength"] = 25,
},
["UH-60L"] = {
["width"] = 4,
["height"] = 5,
["length"] = 10,
["ropelength"] = 25,
},
["UH-60L_DAP"] = {
["width"] = 4,
["height"] = 5,
["length"] = 10,
["ropelength"] = 25,
},
["C-130J-30"] = {
["width"] = 4,
["height"] = 12,
["length"] = 35,
["ropelength"] = 0,
["attach"] = 10,
["detach"] = 14,
},
}
--- DYNAMICCARGO class version.
-- @field #string version
DYNAMICCARGO.version="0.1.0"
DYNAMICCARGO._TrackedCargo = DYNAMICCARGO._TrackedCargo or {}
DYNAMICCARGO._GlobalTimer = DYNAMICCARGO._GlobalTimer or nil
DYNAMICCARGO._GlobalTimerInterval = DYNAMICCARGO._GlobalTimerInterval or nil
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -170,8 +212,17 @@ function DYNAMICCARGO:Register(CargoName)
self.StaticName = CargoName
self.LastPosition = self:GetCoordinate()
self._spawnVec3 = self.LastPosition and self.LastPosition:GetVec3() or nil
self.CargoState = DYNAMICCARGO.State.NEW
self._attached = false
self._detached = false
self._wasAirborne = false
self._landAglConfirm = nil
self._ownerResolved = false
self._carrierUnitName = nil
self._carrierGroupName = nil
self._carrierTypeName = nil
self.Interval = DYNAMICCARGO.Interval or 10
@@ -185,9 +236,10 @@ function DYNAMICCARGO:Register(CargoName)
self.lid = string.format("DYNAMICCARGO %s", CargoName)
self.Owner = string.match(CargoName,"^(.+)|%d%d:%d%d|PKG%d+") or "None"
self.timer = TIMER:New(DYNAMICCARGO._UpdatePosition,self)
self.timer:Start(self.Interval,self.Interval)
-- Keep a compatibility field, while updates are driven by one class-wide scheduler.
self.timer = nil
DYNAMICCARGO._TrackCargo(self)
if not _DYNAMICCARGO_HELOS then
_DYNAMICCARGO_HELOS = SET_CLIENT:New():FilterAlive():FilterFunction(DYNAMICCARGO._FilterHeloTypes):FilterStart()
@@ -267,6 +319,55 @@ function DYNAMICCARGO:IsRemoved()
end
end
--- Returns true if this cargo is attached to a detected carrier.
-- @param #DYNAMICCARGO self
-- @return #boolean Outcome
function DYNAMICCARGO:IsAttached()
return self._attached == true
end
--- Returns true if this cargo was detached from a detected carrier.
-- @param #DYNAMICCARGO self
-- @return #boolean Outcome
function DYNAMICCARGO:IsDetached()
return self._detached == true
end
--- Returns true if this cargo has seen airborne transport in this cycle.
-- @param #DYNAMICCARGO self
-- @return #boolean Outcome
function DYNAMICCARGO:WasAirborneTransport()
return self._wasAirborne == true
end
--- Returns true if this cargo has reached landed stable confirmation.
-- @param #DYNAMICCARGO self
-- @return #boolean Outcome
function DYNAMICCARGO:IsLandedStable()
return self.CargoState == DYNAMICCARGO.State.UNLOADED and self._detached == true
end
--- Returns last known carrier unit name.
-- @param #DYNAMICCARGO self
-- @return #string Unit name
function DYNAMICCARGO:GetCarrierUnitName()
return self._carrierUnitName
end
--- Returns last known carrier type name.
-- @param #DYNAMICCARGO self
-- @return #string Type name
function DYNAMICCARGO:GetCarrierTypeName()
return self._carrierTypeName
end
--- Returns last known carrier group name.
-- @param #DYNAMICCARGO self
-- @return #string Group name
function DYNAMICCARGO:GetCarrierGroupName()
return self._carrierGroupName
end
--- [CTLD] Get number of crates this DYNAMICCARGO consists of. Always one.
-- @param #DYNAMICCARGO self
-- @return #number crate number, always one
@@ -398,6 +499,372 @@ end
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- [Internal] Check whether an aircraft typename is a C-130J for special handling.
-- @param #DYNAMICCARGO self
-- @param #string TypeName
-- @return #boolean Outcome
function DYNAMICCARGO:_IsC130Type(TypeName)
return TypeName == "C-130J-30"
end
--- [Internal] Safe AGL calculation helper.
-- @param #DYNAMICCARGO self
-- @param Core.Point#COORDINATE Coord
-- @return #number AGL in meters
function DYNAMICCARGO:_GetAGL(Coord)
if not Coord then return -1 end
return (Coord.y or 0) - Coord:GetLandHeight()
end
--- [Internal] Resolve player name for a client.
-- @param #DYNAMICCARGO self
-- @param Wrapper.Client#CLIENT Client
-- @return #string Player name
function DYNAMICCARGO:_GetPlayerNameForClient(Client)
if not Client then return self.Owner or "None" end
return Client:GetPlayerName() or _DATABASE:_FindPlayerNameByUnitName(Client:GetName()) or self.Owner or "None"
end
--- [Internal] Store current carrier identity fields.
-- @param #DYNAMICCARGO self
-- @param Wrapper.Client#CLIENT Client
-- @param #string PlayerName
-- @return #DYNAMICCARGO self
function DYNAMICCARGO:_SetCarrierFromClient(Client, PlayerName)
if not Client then return self end
self._carrierUnitName = Client:GetName() or self._carrierUnitName
self._carrierTypeName = Client:GetTypeName() or self._carrierTypeName
local grp = Client:GetGroup()
if grp then
self._carrierGroupName = grp:GetName() or self._carrierGroupName
end
self.Owner = PlayerName or self:_GetPlayerNameForClient(Client)
return self
end
--- [Internal] Get scheduler interval for global dynamic cargo updates.
-- @return #number Interval in seconds
function DYNAMICCARGO._GetSchedulerInterval()
return DYNAMICCARGO.Interval or 5
end
--- [Internal] Count currently tracked dynamic cargo objects.
-- @return #number Count
function DYNAMICCARGO._CountTracked()
local n = 0
for _,_ in pairs(DYNAMICCARGO._TrackedCargo or {}) do
n = n + 1
end
return n
end
--- [Internal] Stop global scheduler when no tracked cargo remains.
function DYNAMICCARGO._StopGlobalSchedulerIfIdle()
if DYNAMICCARGO._CountTracked() > 0 then
return
end
if DYNAMICCARGO._GlobalTimer and DYNAMICCARGO._GlobalTimer:IsRunning() then
DYNAMICCARGO._GlobalTimer:Stop()
end
DYNAMICCARGO._GlobalTimer = nil
DYNAMICCARGO._GlobalTimerInterval = nil
end
--- [Internal] Ensure global scheduler is running for tracked cargo updates.
function DYNAMICCARGO._EnsureGlobalScheduler()
local interval = DYNAMICCARGO._GetSchedulerInterval()
if DYNAMICCARGO._GlobalTimer and DYNAMICCARGO._GlobalTimer:IsRunning() then
if DYNAMICCARGO._GlobalTimerInterval == interval then
return
end
DYNAMICCARGO._GlobalTimer:Stop()
DYNAMICCARGO._GlobalTimer = nil
DYNAMICCARGO._GlobalTimerInterval = nil
end
if DYNAMICCARGO._CountTracked() < 1 then
return
end
DYNAMICCARGO._GlobalTimer = TIMER:New(DYNAMICCARGO._UpdateAllTracked)
DYNAMICCARGO._GlobalTimer:Start(interval, interval)
DYNAMICCARGO._GlobalTimerInterval = interval
end
--- [Internal] Add one dynamic cargo object to global tracking.
-- @param #DYNAMICCARGO Cargo
function DYNAMICCARGO._TrackCargo(Cargo)
if not Cargo or not Cargo.StaticName then
return
end
DYNAMICCARGO._TrackedCargo = DYNAMICCARGO._TrackedCargo or {}
DYNAMICCARGO._TrackedCargo[Cargo.StaticName] = Cargo
DYNAMICCARGO._EnsureGlobalScheduler()
end
--- [Internal] Remove one dynamic cargo object from global tracking.
-- @param #string CargoName
function DYNAMICCARGO._UntrackCargo(CargoName)
if not CargoName or not DYNAMICCARGO._TrackedCargo then
DYNAMICCARGO._StopGlobalSchedulerIfIdle()
return
end
DYNAMICCARGO._TrackedCargo[CargoName] = nil
DYNAMICCARGO._StopGlobalSchedulerIfIdle()
end
--- [Internal] Update all tracked dynamic cargo objects in one scheduler tick.
function DYNAMICCARGO._UpdateAllTracked()
local tracked = DYNAMICCARGO._TrackedCargo or {}
local names = {}
for name,_ in pairs(tracked) do
names[#names + 1] = name
end
for _,name in ipairs(names) do
local cargo = tracked[name]
if cargo then
cargo:_UpdatePosition()
end
end
DYNAMICCARGO._StopGlobalSchedulerIfIdle()
end
--- [Internal] Find tracked client by unit name in current dynamic cargo helo set.
-- @param #DYNAMICCARGO self
-- @param #string UnitName
-- @return Wrapper.Client#CLIENT Client
function DYNAMICCARGO:_FindClientByUnitName(UnitName)
if not UnitName or UnitName == "" or not _DYNAMICCARGO_HELOS then return nil end
for _,_helo in pairs(_DYNAMICCARGO_HELOS:GetAliveSet() or {}) do
local helo = _helo -- Wrapper.Client#CLIENT
if helo and helo:IsAlive() and helo:GetName() == UnitName then
return helo
end
end
return nil
end
--- [Internal] Get best known carrier client from stored names/owner.
-- @param #DYNAMICCARGO self
-- @return Wrapper.Client#CLIENT Client
function DYNAMICCARGO:_GetKnownCarrierClient()
local client = nil
if self._carrierUnitName then
client = self:_FindClientByUnitName(self._carrierUnitName)
end
if (not client) and self.Owner and self.Owner ~= "None" then
local byPlayer = CLIENT:FindByPlayerName(self.Owner)
if byPlayer and byPlayer:IsAlive() then
client = byPlayer
end
end
return client
end
--- [Internal] Find nearest live C-130 client.
-- @param #DYNAMICCARGO self
-- @param Core.Point#COORDINATE Pos
-- @param #number Max3D Maximum 3D distance
-- @return Wrapper.Client#CLIENT Client
-- @return #string PlayerName
-- @return #number Dist2D
-- @return #number Dist3D
function DYNAMICCARGO:_FindNearestC130(Pos, Max3D)
if not Pos or not _DYNAMICCARGO_HELOS then return nil, nil, nil, nil end
local bestClient = nil
local bestName = nil
local best2D = math.huge
local best3D = math.huge
local bestOwnerMatch = false
local max3D = Max3D or DYNAMICCARGO.C130OwnerResolveMax3D
local preferredOwner = self.Owner
if preferredOwner == "" or preferredOwner == "None" then
preferredOwner = nil
end
for _,_helo in pairs(_DYNAMICCARGO_HELOS:GetAliveSet() or {}) do
local helo = _helo -- Wrapper.Client#CLIENT
if helo and helo:IsAlive() then
local typename = helo:GetTypeName()
if self:_IsC130Type(typename) then
local hpos = helo:GetCoordinate()
if hpos then
local d3 = hpos:Get3DDistance(Pos)
if d3 <= max3D then
local d2 = hpos:Get2DDistance(Pos)
local pname = self:_GetPlayerNameForClient(helo)
local ownerMatch = preferredOwner and pname and pname == preferredOwner or false
if (ownerMatch and not bestOwnerMatch) or ((ownerMatch == bestOwnerMatch) and d3 < best3D) then
bestClient = helo
bestName = pname
best2D = d2
best3D = d3
bestOwnerMatch = ownerMatch
end
end
end
end
end
end
return bestClient, bestName, best2D, best3D
end
--- [Internal] Resolve/rebind owner to nearest valid C-130 after movement from spawn.
-- @param #DYNAMICCARGO self
-- @param Core.Point#COORDINATE Pos
-- @return Wrapper.Client#CLIENT Client
function DYNAMICCARGO:_ResolveC130Owner(Pos)
if not Pos or not self._spawnVec3 then return nil end
local moved2D = UTILS.VecDist2D(Pos, self._spawnVec3)
if moved2D < (DYNAMICCARGO.C130OwnerResolveMove2D or 10) then
return nil
end
local max3D = DYNAMICCARGO.C130OwnerResolveMax3D or 250
local known = self:_GetKnownCarrierClient()
if known and known:IsAlive() and self:_IsC130Type(known:GetTypeName()) then
local kpos = known:GetCoordinate()
if kpos and kpos:Get3DDistance(Pos) <= max3D then
self:_SetCarrierFromClient(known)
return known
end
end
local nearest, playerName, d2 = self:_FindNearestC130(Pos, DYNAMICCARGO.C130OwnerResolveMax3D)
if nearest and d2 and d2 <= (DYNAMICCARGO.C130OwnerResolveNear2D or 4) then
self:_SetCarrierFromClient(nearest, playerName)
self._ownerResolved = true
self:T(self.lid.." C130 owner re-resolved to "..tostring(self._carrierUnitName).." / "..tostring(self.Owner))
return nearest
end
return nil
end
--- [Internal] Determine whether to run C-130 transport-state handling for this cargo tick.
-- @param #DYNAMICCARGO self
-- @param Core.Point#COORDINATE Pos
-- @return #boolean Outcome
function DYNAMICCARGO:_ShouldUseC130State(Pos)
if self:_IsC130Type(self._carrierTypeName) then
return true
end
local known = self:_GetKnownCarrierClient()
if known and self:_IsC130Type(known:GetTypeName()) then
self:_SetCarrierFromClient(known)
return true
end
if self._attached or self._detached or self._wasAirborne then
return true
end
if self.CargoState == DYNAMICCARGO.State.NEW or self.CargoState == DYNAMICCARGO.State.UNLOADED then
local nearest, _, d2 = self:_FindNearestC130(Pos, DYNAMICCARGO.C130AttachDistance + 50)
if nearest and d2 and d2 <= (DYNAMICCARGO.C130AttachDistance + 5) then
return true
end
end
return false
end
--- [Internal] C-130-specific transport state update.
-- @param #DYNAMICCARGO self
-- @param Core.Point#COORDINATE Pos
-- @return #DYNAMICCARGO self
function DYNAMICCARGO:_UpdatePositionC130(Pos)
local attachDist = DYNAMICCARGO.C130AttachDistance or 10
local detachDist = DYNAMICCARGO.C130DetachDistance or 14
local airborneAgl = DYNAMICCARGO.C130AirborneAGL or 8
local landedAgl = DYNAMICCARGO.C130LandedAGL or 0.5
local stableEps = DYNAMICCARGO.C130StabilityEpsilon or 0.05
local requireAirborne = DYNAMICCARGO.C130RequireAirborne ~= false
local cargoAgl = self:_GetAGL(Pos)
local carrier = self:_GetKnownCarrierClient()
if carrier and not self:_IsC130Type(carrier:GetTypeName()) then
carrier = nil
end
if not carrier then
carrier = self:_ResolveC130Owner(Pos)
end
-- Attach detection: grounded C-130 close to cargo.
if (self.CargoState == DYNAMICCARGO.State.NEW or self.CargoState == DYNAMICCARGO.State.UNLOADED) and (not self._attached) then
if not carrier then
local nearest, pname, d2 = self:_FindNearestC130(Pos, DYNAMICCARGO.C130OwnerResolveMax3D)
if nearest and d2 and d2 <= attachDist and not nearest:InAir() then
carrier = nearest
self:_SetCarrierFromClient(nearest, pname)
end
end
if carrier and carrier:IsAlive() then
local hpos = carrier:GetCoordinate()
if hpos and (not carrier:InAir()) and hpos:Get2DDistance(Pos) <= attachDist then
self._attached = true
self._detached = false
self._wasAirborne = false
self._landAglConfirm = nil
self:_SetCarrierFromClient(carrier)
if self.CargoState ~= DYNAMICCARGO.State.LOADED then
self.CargoState = DYNAMICCARGO.State.LOADED
self:T(self.lid.." C130 attach: "..tostring(self.Owner))
_DATABASE:CreateEventDynamicCargoLoaded(self)
end
end
end
end
if self.CargoState == DYNAMICCARGO.State.LOADED then
if not carrier then
carrier = self:_ResolveC130Owner(Pos)
end
local carrierInAir = false
local dist2D = math.huge
local carrierAgl = -1
if carrier and carrier:IsAlive() then
local hpos = carrier:GetCoordinate()
if hpos then
dist2D = hpos:Get2DDistance(Pos)
carrierAgl = self:_GetAGL(hpos)
end
carrierInAir = carrier:InAir()
self:_SetCarrierFromClient(carrier)
end
if cargoAgl >= airborneAgl or carrierAgl >= airborneAgl then
self._wasAirborne = true
end
-- Detach only when actually airborne and separated.
if self._attached and carrierInAir and dist2D > detachDist then
self._attached = false
self._detached = true
self._landAglConfirm = nil
self:T(self.lid.." C130 detach at d2="..tostring(UTILS.Round(dist2D,2)))
end
-- Fallback detach if carrier reference is stale but cargo already transitioned airborne.
if self._attached and (not carrier or not carrier:IsAlive()) and self._wasAirborne and cargoAgl <= airborneAgl then
self._attached = false
self._detached = true
self._landAglConfirm = nil
self:T(self.lid.." C130 detach fallback (carrier stale)")
end
local canUnload = self._detached and ((not requireAirborne) or self._wasAirborne)
if canUnload then
local moved3D = self.LastPosition and UTILS.VecDist3D(Pos, self.LastPosition) or math.huge
local stable = moved3D <= stableEps
if cargoAgl <= landedAgl and stable then
if self._landAglConfirm then
self.CargoState = DYNAMICCARGO.State.UNLOADED
self:T(self.lid.." C130 landed-stable unload by "..tostring(self.Owner))
_DATABASE:CreateEventDynamicCargoUnloaded(self)
else
self._landAglConfirm = true
end
else
self._landAglConfirm = nil
end
end
end
return self
end
--- [Internal] _Get helo hovering intel
-- @param #DYNAMICCARGO self
-- @param Wrapper.Unit#UNIT Unit The Unit to test
@@ -444,35 +911,37 @@ function DYNAMICCARGO:_GetPossibleHeloNearby(pos,loading)
local hpos = helo:GetCoordinate()
-- TODO Check unloading via sling load?
local typename = helo:GetTypeName()
local dimensions = DYNAMICCARGO.AircraftDimensions[typename]
local hovering, height = self:_HeloHovering(helo,dimensions.ropelength)
local helolanded = not helo:InAir()
self:T(self.lid.." InAir: AGL/Hovering: "..hpos.y-hpos:GetLandHeight().."/"..tostring(hovering))
if hpos and typename and dimensions then
local delta2D = hpos:Get2DDistance(pos)
local delta3D = hpos:Get3DDistance(pos)
if self.testing then
self:T(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D))
self:T(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength))
self:T(string.format("Helo hovering: %s at %dm",tostring(hovering),height))
end
-- unloading from ground
if loading~=true and (delta2D > dimensions.length or delta2D > dimensions.width) and helolanded then -- Theoretically the cargo could still be attached to the sling if landed next to the cargo. But once moved again it would go back into loaded state once lifted again.
success = true
Helo = helo
Playername = name
end
-- unloading from hover/rope
if loading~=true and delta3D > dimensions.ropelength then
success = true
Helo = helo
Playername = name
end
-- loading
if loading == true and ((delta2D < dimensions.length and delta2D < dimensions.width and helolanded) or (delta3D == dimensions.ropelength and helo:InAir())) then -- Loaded via ground or sling
success = true
Helo = helo
Playername = name
if not self:_IsC130Type(typename) then
local dimensions = DYNAMICCARGO.AircraftDimensions[typename]
if hpos and typename and dimensions then
local hovering, height = self:_HeloHovering(helo,dimensions.ropelength)
local helolanded = not helo:InAir()
self:T(self.lid.." InAir: AGL/Hovering: "..hpos.y-hpos:GetLandHeight().."/"..tostring(hovering))
local delta2D = hpos:Get2DDistance(pos)
local delta3D = hpos:Get3DDistance(pos)
if self.testing then
self:T(string.format("Cargo relative position: 2D %dm | 3D %dm",delta2D,delta3D))
self:T(string.format("Helo dimension: length %dm | width %dm | rope %dm",dimensions.length,dimensions.width,dimensions.ropelength))
self:T(string.format("Helo hovering: %s at %dm",tostring(hovering),height))
end
-- unloading from ground
if loading~=true and (delta2D > dimensions.length or delta2D > dimensions.width) and helolanded then -- Theoretically the cargo could still be attached to the sling if landed next to the cargo. But once moved again it would go back into loaded state once lifted again.
success = true
Helo = helo
Playername = name
end
-- unloading from hover/rope
if loading~=true and delta3D > dimensions.ropelength then
success = true
Helo = helo
Playername = name
end
-- loading
if loading == true and ((delta2D < dimensions.length and delta2D < dimensions.width and helolanded) or (delta3D == dimensions.ropelength and helo:InAir())) then -- Loaded via ground or sling
success = true
Helo = helo
Playername = name
end
end
end
end
@@ -490,21 +959,31 @@ function DYNAMICCARGO:_UpdatePosition()
self:T(string.format("Cargo position: x=%d, y=%d, z=%d",pos.x,pos.y,pos.z))
self:T(string.format("Last position: x=%d, y=%d, z=%d",self.LastPosition.x,self.LastPosition.y,self.LastPosition.z))
end
if UTILS.Round(UTILS.VecDist3D(pos,self.LastPosition),2) > 0.5 then -- This checks if the cargo has moved more than 0.5m since last check. If so then the cargo is loaded
---------------
-- LOAD Cargo
---------------
if self.CargoState == DYNAMICCARGO.State.NEW or self.CargoState == DYNAMICCARGO.State.UNLOADED then
local isloaded, client, playername = self:_GetPossibleHeloNearby(pos,true)
self:T(self.lid.." moved! NEW -> LOADED by "..tostring(playername))
self.CargoState = DYNAMICCARGO.State.LOADED
self.Owner = playername
_DATABASE:CreateEventDynamicCargoLoaded(self)
end
local moved = UTILS.Round(UTILS.VecDist3D(pos,self.LastPosition),2) > 0.5
if self:_ShouldUseC130State(pos) then
self:_UpdatePositionC130(pos)
self.LastPosition = pos
elseif moved then -- This checks if the cargo has moved more than 0.5m since last check. If so then the cargo is loaded
---------------
-- LOAD Cargo
---------------
if self.CargoState == DYNAMICCARGO.State.NEW or self.CargoState == DYNAMICCARGO.State.UNLOADED then
local isloaded, client, playername = self:_GetPossibleHeloNearby(pos,true)
if isloaded then
self:T(self.lid.." moved! NEW -> LOADED by "..tostring(playername))
self.CargoState = DYNAMICCARGO.State.LOADED
self.Owner = playername
if client then
self:_SetCarrierFromClient(client, playername)
end
_DATABASE:CreateEventDynamicCargoLoaded(self)
end
end
self.LastPosition = pos
---------------
-- UNLOAD Cargo
---------------
-- If the cargo is stationary then we need to end this condition here to check whether it is unloaded or still onboard or still hooked if anyone can hover that precisly
-- If the cargo is stationary then we need to end this condition here to check whether it is unloaded or still onboard or still hooked if anyone can hover that precisly
elseif self.CargoState == DYNAMICCARGO.State.LOADED then
-- TODO add checker if we are in flight somehow
-- ensure not just the helo is moving
@@ -518,36 +997,37 @@ function DYNAMICCARGO:_UpdatePosition()
local client
local playername = self.Owner
if count > 0 then
self:T(self.lid.." Possible alive helos: "..count or -1)
isunloaded, client, playername = self:_GetPossibleHeloNearby(pos,false)
self:T(self.lid.." Possible alive helos: "..count or -1)
isunloaded, client, playername = self:_GetPossibleHeloNearby(pos,false)
if isunloaded then
self:T(self.lid.." moved! LOADED -> UNLOADED by "..tostring(playername))
self.CargoState = DYNAMICCARGO.State.UNLOADED
self.Owner = playername
if client then
self:_SetCarrierFromClient(client, playername)
end
_DATABASE:CreateEventDynamicCargoUnloaded(self)
end
end
end
end
self.LastPosition = pos
--end
else
---------------
-- REMOVED Cargo
---------------
if self.timer and self.timer:IsRunning() then
self.timer:Stop()
self.timer=nil
if self.CargoState ~= DYNAMICCARGO.State.REMOVED then
DYNAMICCARGO._UntrackCargo(self.StaticName)
self.timer=nil
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
self.CargoState = DYNAMICCARGO.State.REMOVED
_DATABASE:CreateEventDynamicCargoRemoved(self)
end
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
self.CargoState = DYNAMICCARGO.State.REMOVED
_DATABASE:CreateEventDynamicCargoRemoved(self)
end
return self
end
--- [USER] Destroy a DYNAMICCARGO object.
-- @param #DYNAMICCARGO self
-- @param #boolean GenerateEvent (Optional) Set to false to remove an item silently. Defaults to true.
-- @param #boolean GenerateEvent Set to false to remove an item silently. Defaults to true.
-- @return #boolean Return Returns nil if the object could not be found, else returns true.
function DYNAMICCARGO:Destroy(GenerateEvent)
local DCSObject = self:GetDCSObject()