Files
2026-08-19 12:12:12 -04:00

105 lines
4.5 KiB
Lua

if isServer() then return end
if not TowBarMod then TowBarMod = {} end
TowBarMod.RigidTow = TowBarMod.RigidTow or {}
local RigidTow = TowBarMod.RigidTow
local function isExactPairLinked(towingVehicle, towedVehicle)
return towingVehicle and towedVehicle
and towingVehicle:getVehicleTowing() == towedVehicle
and towedVehicle:getVehicleTowedBy() == towingVehicle
end
local function hasConflictingLink(vehicle, expectedOther)
if not vehicle or not expectedOther then return true end
local towing = vehicle:getVehicleTowing()
local towedBy = vehicle:getVehicleTowedBy()
return (towing ~= nil and towing ~= expectedOther)
or (towedBy ~= nil and towedBy ~= expectedOther)
end
local function attachmentExists(vehicle, attachmentId)
if not vehicle or type(attachmentId) ~= "string" then return false end
local script = vehicle:getScript()
return script ~= nil and script:getAttachmentById(attachmentId) ~= nil
end
local function breakExactPair(towingVehicle, towedVehicle)
if not towingVehicle or not towedVehicle then return end
if towingVehicle:getVehicleTowing() == towedVehicle
or towingVehicle:getVehicleTowedBy() == towedVehicle then
towingVehicle:breakConstraint(true, true)
elseif towedVehicle:getVehicleTowing() == towingVehicle
or towedVehicle:getVehicleTowedBy() == towingVehicle then
towedVehicle:breakConstraint(true, true)
end
end
function RigidTow.attach(towingVehicle, towedVehicle, attachmentA, attachmentB)
if not towingVehicle or not towedVehicle or towingVehicle == towedVehicle then return false end
if hasConflictingLink(towingVehicle, towedVehicle)
or hasConflictingLink(towedVehicle, towingVehicle) then
return false
end
if not attachmentExists(towingVehicle, attachmentA)
or not attachmentExists(towedVehicle, attachmentB) then
return false
end
if TowBarMod.Utils and TowBarMod.Utils.updateAttachmentsForRigidTow then
TowBarMod.Utils.updateAttachmentsForRigidTow(
towingVehicle, towedVehicle, attachmentA, attachmentB
)
end
-- Match the proven wrecker sequence exactly. The fake trailer script is
-- used only while Bullet creates the rigid constraint; leaving it active
-- until the broader post-attach hook is unreliable in multiplayer because
-- that hook may return early while vehicle state is still replicating.
local towedModData = towedVehicle:getModData()
local currentScript = towedVehicle:getScriptName()
local originalScript = towedModData and towedModData.towBarOriginalScriptName or nil
if originalScript == nil and currentScript ~= "notTowingA_Trailer" then
originalScript = currentScript
if towedModData then
towedModData.towBarOriginalScriptName = originalScript
end
end
if originalScript == nil or originalScript == "notTowingA_Trailer" then
return false
end
breakExactPair(towingVehicle, towedVehicle)
if TowBarMod.Hook and TowBarMod.Hook.applyFreeRollingTowState then
TowBarMod.Hook.applyFreeRollingTowState(towedVehicle)
elseif TowBarMod.Hook and TowBarMod.Hook.setVehiclePostAttach then
-- Compatibility fallback for older hook modules and the regression
-- harness. Current builds expose the narrower free-roll helper.
TowBarMod.Hook.setVehiclePostAttach(nil, towedVehicle, towingVehicle)
end
if TowBarMod.Hook and TowBarMod.Hook.setVehicleScriptWithTowBarHidden then
TowBarMod.Hook.setVehicleScriptWithTowBarHidden(towedVehicle, "notTowingA_Trailer")
else
towedVehicle:setScriptName("notTowingA_Trailer")
end
towingVehicle:addPointConstraint(nil, towedVehicle, attachmentA, attachmentB, true)
if TowBarMod.Hook and TowBarMod.Hook.setVehicleScriptWithTowBarHidden then
TowBarMod.Hook.setVehicleScriptWithTowBarHidden(towedVehicle, originalScript)
else
towedVehicle:setScriptName(originalScript)
end
if TowBarMod.Hook and TowBarMod.Hook.setVehiclePostAttach then
-- Multiplayer updates the reciprocal towing getters after this Lua
-- call. The authoritative sync already validated the pair, so finalize
-- with the known towing vehicle instead of treating that delay as a
-- failed constraint submission.
TowBarMod.Hook.setVehiclePostAttach(nil, towedVehicle, towingVehicle)
end
return true
end
RigidTow.isExactPairLinked = isExactPairLinked
RigidTow.breakExactPair = breakExactPair