42.19 Support
This commit is contained in:
@@ -3,6 +3,8 @@ if not TowBarMod.Config then TowBarMod.Config = {} end
|
||||
|
||||
TowBarMod.Config.lowLevelAnimation = "RemoveGrass"
|
||||
TowBarMod.Config.rigidTowbarDistance = 1.0
|
||||
TowBarMod.Config.towAttachmentExteriorPadding = 0.25
|
||||
TowBarMod.Config.towedVehicleRollingMass = 75
|
||||
TowBarMod.Config.devMode = false
|
||||
TowBarMod.Config.vanillaTowbarModelScaleMin = 1.5
|
||||
TowBarMod.Config.vanillaTowbarModelScaleMax = 2.0
|
||||
|
||||
@@ -1,11 +1,88 @@
|
||||
if not TowBarMod then TowBarMod = {} end
|
||||
if not TowBarMod.Hook then TowBarMod.Hook = {} end
|
||||
|
||||
local TowBarTowMass = 200
|
||||
local DefaultTowBarTowMass = 200
|
||||
local AutoReattachCooldownHours = 1 / 7200 -- 0.5 seconds
|
||||
TowBarMod.Hook.lastAutoReattachAtByVehicle = TowBarMod.Hook.lastAutoReattachAtByVehicle or {}
|
||||
local AutoReattachPlayerCooldownHours = 1 / 14400 -- 0.25 seconds
|
||||
TowBarMod.Hook.lastAutoReattachAtByPlayer = TowBarMod.Hook.lastAutoReattachAtByPlayer or {}
|
||||
local FreeRollTickInterval = 15
|
||||
local freeRollTickCounter = 0
|
||||
|
||||
local function tryVehicleCall(vehicle, methodName, arg)
|
||||
if not vehicle or not methodName then return false, nil end
|
||||
local method = vehicle[methodName]
|
||||
if method == nil then return false, nil end
|
||||
|
||||
return pcall(function()
|
||||
if arg ~= nil then
|
||||
return method(vehicle, arg)
|
||||
end
|
||||
return method(vehicle)
|
||||
end)
|
||||
end
|
||||
|
||||
local function storeOriginalVehicleCall(vehicle, modData, key, getterName)
|
||||
if not vehicle or not modData or modData[key] ~= nil then return end
|
||||
|
||||
local ok, value = tryVehicleCall(vehicle, getterName)
|
||||
if ok and value ~= nil then
|
||||
modData[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
local function applyFreeRollingTowState(vehicle)
|
||||
if not vehicle then return end
|
||||
|
||||
local modData = vehicle:getModData()
|
||||
if not modData then return end
|
||||
|
||||
if modData.towBarOriginalMass == nil then
|
||||
modData.towBarOriginalMass = vehicle:getMass()
|
||||
end
|
||||
if modData.towBarOriginalBrakingForce == nil then
|
||||
modData.towBarOriginalBrakingForce = vehicle:getBrakingForce()
|
||||
end
|
||||
storeOriginalVehicleCall(vehicle, modData, "towBarOriginalParkingBrakeOn", "isParkingBrakeOn")
|
||||
storeOriginalVehicleCall(vehicle, modData, "towBarOriginalParkingBrake", "isParkingBrake")
|
||||
storeOriginalVehicleCall(vehicle, modData, "towBarOriginalHandbrake", "isHandbrake")
|
||||
|
||||
local configuredTowMass = TowBarMod.Config and tonumber(TowBarMod.Config.towedVehicleRollingMass)
|
||||
vehicle:setMass(configuredTowMass or DefaultTowBarTowMass)
|
||||
vehicle:setBrakingForce(0)
|
||||
|
||||
tryVehicleCall(vehicle, "setParkingBrakeOn", false)
|
||||
tryVehicleCall(vehicle, "setParkingBrake", false)
|
||||
tryVehicleCall(vehicle, "setHandbrake", false)
|
||||
tryVehicleCall(vehicle, "setBrake", false)
|
||||
tryVehicleCall(vehicle, "setBraking", false)
|
||||
|
||||
vehicle:constraintChanged()
|
||||
vehicle:updateTotalMass()
|
||||
end
|
||||
|
||||
local function restoreFreeRollingTowState(vehicle, modData)
|
||||
if not vehicle or not modData then return end
|
||||
|
||||
if modData.towBarOriginalMass ~= nil then
|
||||
vehicle:setMass(modData.towBarOriginalMass)
|
||||
end
|
||||
if modData.towBarOriginalBrakingForce ~= nil then
|
||||
vehicle:setBrakingForce(modData.towBarOriginalBrakingForce)
|
||||
end
|
||||
if modData.towBarOriginalParkingBrakeOn ~= nil then
|
||||
tryVehicleCall(vehicle, "setParkingBrakeOn", modData.towBarOriginalParkingBrakeOn)
|
||||
end
|
||||
if modData.towBarOriginalParkingBrake ~= nil then
|
||||
tryVehicleCall(vehicle, "setParkingBrake", modData.towBarOriginalParkingBrake)
|
||||
end
|
||||
if modData.towBarOriginalHandbrake ~= nil then
|
||||
tryVehicleCall(vehicle, "setHandbrake", modData.towBarOriginalHandbrake)
|
||||
end
|
||||
|
||||
vehicle:constraintChanged()
|
||||
vehicle:updateTotalMass()
|
||||
end
|
||||
|
||||
local function isTowBarTowPair(towingVehicle, towedVehicle)
|
||||
if not towingVehicle or not towedVehicle then return false end
|
||||
@@ -269,12 +346,7 @@ local function reattachTowBarPair(playerObj, towingVehicle, towedVehicle, requir
|
||||
TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicle, attachmentA, attachmentB)
|
||||
|
||||
towedModData.towBarOriginalScriptName = towedModData.towBarOriginalScriptName or towedVehicle:getScriptName()
|
||||
if towedModData.towBarOriginalMass == nil then
|
||||
towedModData.towBarOriginalMass = towedVehicle:getMass()
|
||||
end
|
||||
if towedModData.towBarOriginalBrakingForce == nil then
|
||||
towedModData.towBarOriginalBrakingForce = towedVehicle:getBrakingForce()
|
||||
end
|
||||
applyFreeRollingTowState(towedVehicle)
|
||||
|
||||
towingModData["isTowingByTowBar"] = true
|
||||
towedModData["isTowingByTowBar"] = true
|
||||
@@ -376,10 +448,7 @@ function TowBarMod.Hook.setVehiclePostAttach(playerObj, towedVehicle, retriesLef
|
||||
end
|
||||
end
|
||||
|
||||
towedVehicle:setMass(TowBarTowMass)
|
||||
towedVehicle:setBrakingForce(0)
|
||||
towedVehicle:constraintChanged()
|
||||
towedVehicle:updateTotalMass()
|
||||
applyFreeRollingTowState(towedVehicle)
|
||||
|
||||
-- Re-show the towbar model after the script name has been restored.
|
||||
-- setScriptName() resets model visibility, so we must set it again here.
|
||||
@@ -402,8 +471,7 @@ function TowBarMod.Hook.performAttachTowBar(playerObj, towingVehicle, towedVehic
|
||||
local towedModData = towedVehicle:getModData()
|
||||
|
||||
towedModData.towBarOriginalScriptName = towedVehicle:getScriptName()
|
||||
towedModData.towBarOriginalMass = towedVehicle:getMass()
|
||||
towedModData.towBarOriginalBrakingForce = towedVehicle:getBrakingForce()
|
||||
applyFreeRollingTowState(towedVehicle)
|
||||
|
||||
towingModData["isTowingByTowBar"] = true
|
||||
towedModData["isTowingByTowBar"] = true
|
||||
@@ -438,14 +506,7 @@ function TowBarMod.Hook.performDetachTowBar(playerObj, towingVehicle, towedVehic
|
||||
if towedModData.towBarOriginalScriptName then
|
||||
towedVehicle:setScriptName(towedModData.towBarOriginalScriptName)
|
||||
end
|
||||
if towedModData.towBarOriginalMass ~= nil then
|
||||
towedVehicle:setMass(towedModData.towBarOriginalMass)
|
||||
end
|
||||
if towedModData.towBarOriginalBrakingForce ~= nil then
|
||||
towedVehicle:setBrakingForce(towedModData.towBarOriginalBrakingForce)
|
||||
end
|
||||
towedVehicle:constraintChanged()
|
||||
towedVehicle:updateTotalMass()
|
||||
restoreFreeRollingTowState(towedVehicle, towedModData)
|
||||
|
||||
sendClientCommand(playerObj, "towbar", "giveTowBar", { equipPrimary = true })
|
||||
|
||||
@@ -456,6 +517,9 @@ function TowBarMod.Hook.performDetachTowBar(playerObj, towingVehicle, towedVehic
|
||||
towedModData.towBarOriginalScriptName = nil
|
||||
towedModData.towBarOriginalMass = nil
|
||||
towedModData.towBarOriginalBrakingForce = nil
|
||||
towedModData.towBarOriginalParkingBrakeOn = nil
|
||||
towedModData.towBarOriginalParkingBrake = nil
|
||||
towedModData.towBarOriginalHandbrake = nil
|
||||
towingVehicle:transmitModData()
|
||||
towedVehicle:transmitModData()
|
||||
|
||||
@@ -526,6 +590,27 @@ local function forEachCollectionItem(collection, callback)
|
||||
end
|
||||
end
|
||||
|
||||
local function keepTowBarVehiclesFreeRolling()
|
||||
freeRollTickCounter = freeRollTickCounter + 1
|
||||
if freeRollTickCounter < FreeRollTickInterval then
|
||||
return
|
||||
end
|
||||
freeRollTickCounter = 0
|
||||
|
||||
local cell = getCell()
|
||||
if not cell then return end
|
||||
|
||||
local vehicles = cell:getVehicles()
|
||||
if not vehicles then return end
|
||||
|
||||
forEachCollectionItem(vehicles, function(vehicle)
|
||||
local modData = vehicle and vehicle:getModData() or nil
|
||||
if isActiveTowBarTowedVehicle(vehicle, modData) then
|
||||
applyFreeRollingTowState(vehicle)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function TowBarMod.Hook.OnEnterVehicle(character)
|
||||
tryAutoReattachFromCharacter(character)
|
||||
end
|
||||
@@ -716,3 +801,4 @@ if Events.OnGameStart then
|
||||
end
|
||||
Events.OnEnterVehicle.Add(TowBarMod.Hook.OnEnterVehicle)
|
||||
Events.OnSwitchVehicleSeat.Add(TowBarMod.Hook.OnSwitchVehicleSeat)
|
||||
Events.OnTick.Add(keepTowBarVehiclesFreeRolling)
|
||||
|
||||
@@ -23,6 +23,53 @@ local function computeAttachmentHeight(vehicle)
|
||||
return -0.5
|
||||
end
|
||||
|
||||
local function getVehicleHalfLength(script)
|
||||
if not script then return nil end
|
||||
|
||||
local ok, shape = pcall(function()
|
||||
return script:getPhysicsChassisShape()
|
||||
end)
|
||||
if ok and shape then
|
||||
local zOk, z = pcall(function()
|
||||
return shape:z()
|
||||
end)
|
||||
z = zOk and tonumber(z) or nil
|
||||
if z and z > 0 then return z / 2 end
|
||||
end
|
||||
|
||||
ok, shape = pcall(function()
|
||||
return script:getExtents()
|
||||
end)
|
||||
if ok and shape then
|
||||
local zOk, z = pcall(function()
|
||||
return shape:z()
|
||||
end)
|
||||
z = zOk and tonumber(z) or nil
|
||||
if z and z > 0 then return z / 2 end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function getExteriorAttachmentZ(script, attachmentId, originalZ, extraDistance)
|
||||
local halfLength = getVehicleHalfLength(script)
|
||||
if halfLength == nil then return originalZ end
|
||||
|
||||
local configuredPadding = TowBarMod.Config and tonumber(TowBarMod.Config.towAttachmentExteriorPadding)
|
||||
local padding = configuredPadding or 0.25
|
||||
local direction = originalZ >= 0 and 1 or -1
|
||||
if originalZ == 0 and attachmentId == "trailer" then
|
||||
direction = -1
|
||||
end
|
||||
local exteriorZ = direction * (halfLength + padding + (extraDistance or 0))
|
||||
|
||||
if math.abs(originalZ) > math.abs(exteriorZ) then
|
||||
return originalZ
|
||||
end
|
||||
|
||||
return exteriorZ
|
||||
end
|
||||
|
||||
function TowBarMod.Utils.isTrailer(vehicle)
|
||||
return string.match(string.lower(vehicle:getScript():getName()), "trailer")
|
||||
end
|
||||
@@ -93,8 +140,12 @@ function TowBarMod.Utils.getHookTypeVariants(vehicleA, vehicleB, hasTowBar)
|
||||
end
|
||||
|
||||
function TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicle, attachmentA, attachmentB)
|
||||
local towingAttachment = towingVehicle:getScript():getAttachmentById(attachmentA)
|
||||
local towedAttachment = towedVehicle:getScript():getAttachmentById(attachmentB)
|
||||
local towingScript = towingVehicle:getScript()
|
||||
local towedScript = towedVehicle:getScript()
|
||||
if towingScript == nil or towedScript == nil then return end
|
||||
|
||||
local towingAttachment = towingScript:getAttachmentById(attachmentA)
|
||||
local towedAttachment = towedScript:getAttachmentById(attachmentB)
|
||||
if towingAttachment == nil or towedAttachment == nil then return end
|
||||
|
||||
towingAttachment:setUpdateConstraint(false)
|
||||
@@ -109,12 +160,16 @@ function TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicl
|
||||
|
||||
-- Store and update the towing vehicle's attachment Y.
|
||||
local towingModData = towingVehicle:getModData()
|
||||
if towingModData["towBarOriginalTowingOffsetY"] == nil then
|
||||
towingModData["towBarOriginalTowingOffsetY"] = towingAttachment:getOffset():y()
|
||||
local towingOffset = towingAttachment:getOffset()
|
||||
if towingModData["towBarOriginalTowingAttachmentId"] ~= attachmentA
|
||||
or towingModData["towBarOriginalTowingOffsetX"] == nil
|
||||
or towingModData["towBarOriginalTowingOffsetY"] == nil
|
||||
or towingModData["towBarOriginalTowingOffsetZ"] == nil then
|
||||
towingModData["towBarOriginalTowingOffsetX"] = towingOffset:x()
|
||||
towingModData["towBarOriginalTowingOffsetY"] = towingOffset:y()
|
||||
towingModData["towBarOriginalTowingOffsetZ"] = towingOffset:z()
|
||||
towingModData["towBarOriginalTowingAttachmentId"] = attachmentA
|
||||
end
|
||||
local towingOffset = towingAttachment:getOffset()
|
||||
towingAttachment:getOffset():set(towingOffset:x(), towingHeight, towingOffset:z())
|
||||
|
||||
local towedModData = towedVehicle:getModData()
|
||||
local spacingDistance = 1.0
|
||||
@@ -122,6 +177,11 @@ function TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicl
|
||||
spacingDistance = tonumber(TowBarMod.Config.rigidTowbarDistance)
|
||||
end
|
||||
|
||||
local towingBaseX = tonumber(towingModData["towBarOriginalTowingOffsetX"]) or towingOffset:x()
|
||||
local towingBaseZ = tonumber(towingModData["towBarOriginalTowingOffsetZ"]) or towingOffset:z()
|
||||
local towingExteriorZ = getExteriorAttachmentZ(towingScript, attachmentA, towingBaseZ, 0)
|
||||
towingAttachment:getOffset():set(towingBaseX, towingHeight, towingExteriorZ)
|
||||
|
||||
local offset = towedAttachment:getOffset()
|
||||
local storedBaseX = tonumber(towedModData["towBarBaseAttachmentOffsetX"])
|
||||
local storedBaseY = tonumber(towedModData["towBarBaseAttachmentOffsetY"])
|
||||
@@ -140,9 +200,9 @@ function TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicl
|
||||
towedModData["towBarBaseAttachmentOffsetZ"] = baseZ
|
||||
end
|
||||
|
||||
local zDirection = baseZ >= 0 and 1 or -1
|
||||
local zShift = zDirection * spacingDistance
|
||||
towedAttachment:getOffset():set(baseX, towedHeight, baseZ + zShift)
|
||||
local towedExteriorZ = getExteriorAttachmentZ(towedScript, attachmentB, baseZ, spacingDistance)
|
||||
local zShift = towedExteriorZ - baseZ
|
||||
towedAttachment:getOffset():set(baseX, towedHeight, towedExteriorZ)
|
||||
|
||||
towedModData["isChangedTowedAttachment"] = true
|
||||
towedModData["towBarChangedAttachmentId"] = attachmentB
|
||||
@@ -161,14 +221,20 @@ function TowBarMod.Utils.updateAttachmentsOnDefaultValues(towingVehicle, towedVe
|
||||
local zOffset = (towingAttachmentId == "trailer") and -1 or 1
|
||||
towingAttachment:setZOffset(zOffset)
|
||||
|
||||
-- Restore the original Y offset that was overridden by dynamic height.
|
||||
-- Restore the original offset that was overridden for rigid tow spacing.
|
||||
local originalX = tonumber(towingModData["towBarOriginalTowingOffsetX"])
|
||||
local originalY = tonumber(towingModData["towBarOriginalTowingOffsetY"])
|
||||
if originalY ~= nil then
|
||||
local originalZ = tonumber(towingModData["towBarOriginalTowingOffsetZ"])
|
||||
if originalX ~= nil and originalY ~= nil and originalZ ~= nil then
|
||||
towingAttachment:getOffset():set(originalX, originalY, originalZ)
|
||||
elseif originalY ~= nil then
|
||||
local off = towingAttachment:getOffset()
|
||||
towingAttachment:getOffset():set(off:x(), originalY, off:z())
|
||||
end
|
||||
end
|
||||
towingModData["towBarOriginalTowingOffsetX"] = nil
|
||||
towingModData["towBarOriginalTowingOffsetY"] = nil
|
||||
towingModData["towBarOriginalTowingOffsetZ"] = nil
|
||||
towingModData["towBarOriginalTowingAttachmentId"] = nil
|
||||
towingVehicle:transmitModData()
|
||||
|
||||
@@ -249,4 +315,3 @@ local function fixTowAttachmentsForOtherVehicleMods()
|
||||
end
|
||||
|
||||
Events.OnGameBoot.Add(fixTowAttachmentsForOtherVehicleMods)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user