105 lines
4.5 KiB
Lua
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
|