42.20 and Towtrucks
This commit is contained in:
@@ -128,61 +128,54 @@ local function sendTowAttachCommand(playerObj, args)
|
||||
end
|
||||
|
||||
local TowbarVariantSize = 24
|
||||
local TowbarNormalStart = 0
|
||||
local TowbarLargeStart = 24
|
||||
local TowbarMaxIndex = TowbarVariantSize - 1
|
||||
local VanillaScaleMin = 1.5
|
||||
local VanillaScaleMax = 2.0
|
||||
local TowbarFirstZ = 1.0
|
||||
local TowbarSlotStep = 0.1
|
||||
-- Measured from Towbar.fbx at its original 0.01 script scale. The visual is
|
||||
-- enlarged uniformly, so its center must move outward by the scaled half-length
|
||||
-- to keep the inner end on the same vehicle-hitbox contact point.
|
||||
local TowbarVisualScale = 2.5
|
||||
local TowbarModelLength = 0.9714089036
|
||||
local TowbarScaledModelLength = TowbarModelLength * TowbarVisualScale
|
||||
local TowbarModelHalfLength = TowbarScaledModelLength / 2
|
||||
|
||||
local function getVehicleModelScale(script)
|
||||
local function getTowbarFrontEdgeZ(script)
|
||||
if not script then return nil end
|
||||
|
||||
local ok, result = pcall(function()
|
||||
return script:getModelScale()
|
||||
local ok, shape = pcall(function()
|
||||
return script:getPhysicsChassisShape()
|
||||
end)
|
||||
if ok and type(result) == "number" then
|
||||
return result
|
||||
end
|
||||
if not ok or not shape then return nil end
|
||||
|
||||
ok, result = pcall(function()
|
||||
local model = script:getModel()
|
||||
if model then
|
||||
return model:getScale()
|
||||
end
|
||||
local shapeOk, shapeZ = pcall(function()
|
||||
return shape:z()
|
||||
end)
|
||||
if not shapeOk or type(shapeZ) ~= "number" or shapeZ <= 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local centerOk, center = pcall(function()
|
||||
return script:getCenterOfMassOffset()
|
||||
end)
|
||||
if ok and type(result) == "number" then
|
||||
return result
|
||||
end
|
||||
if not centerOk or not center then return nil end
|
||||
|
||||
return nil
|
||||
end
|
||||
local zOk, centerZ = pcall(function()
|
||||
return center:z()
|
||||
end)
|
||||
if not zOk or type(centerZ) ~= "number" then return nil end
|
||||
|
||||
local function isVanillaScale(script)
|
||||
local modelScale = getVehicleModelScale(script)
|
||||
if modelScale == nil then
|
||||
return true
|
||||
end
|
||||
|
||||
local configuredMin = TowBarMod.Config and tonumber(TowBarMod.Config.vanillaTowbarModelScaleMin)
|
||||
local configuredMax = TowBarMod.Config and tonumber(TowBarMod.Config.vanillaTowbarModelScaleMax)
|
||||
local minScale = configuredMin or VanillaScaleMin
|
||||
local maxScale = configuredMax or VanillaScaleMax
|
||||
return modelScale >= minScale and modelScale <= maxScale
|
||||
end
|
||||
|
||||
local function getTowbarIndexVanilla(script)
|
||||
local z = script:getPhysicsChassisShape():z() / 2 - 0.1
|
||||
local index = math.floor((z * 2 / 3 - 1) * 10)
|
||||
return math.max(0, math.min(TowbarMaxIndex, index))
|
||||
return centerZ + shapeZ / 2
|
||||
end
|
||||
|
||||
local function getTowbarModelSlot(script)
|
||||
if not isVanillaScale(script) then
|
||||
-- KI5/small-scale vehicles use the normal towbar0 mesh at Z=1.
|
||||
return 0
|
||||
end
|
||||
return getTowbarIndexVanilla(script)
|
||||
local frontEdgeZ = getTowbarFrontEdgeZ(script)
|
||||
if frontEdgeZ == nil then return nil end
|
||||
|
||||
-- Model offsets position the mesh origin. Move its center outward so the
|
||||
-- towbar's inner end, rather than its center, meets the vehicle hitbox.
|
||||
local modelCenterZ = frontEdgeZ + TowbarModelHalfLength
|
||||
local index = math.floor(((modelCenterZ - TowbarFirstZ) / TowbarSlotStep) + 0.5)
|
||||
return math.max(0, math.min(TowbarMaxIndex, index))
|
||||
end
|
||||
|
||||
local function setTowBarModelVisible(vehicle, isVisible)
|
||||
@@ -210,7 +203,7 @@ local function setTowBarModelVisible(vehicle, isVisible)
|
||||
|
||||
local index = getTowbarModelSlot(script)
|
||||
local part = normalPart
|
||||
if part then
|
||||
if part and index ~= nil then
|
||||
part:setModelVisible("towbar" .. index, true)
|
||||
end
|
||||
|
||||
@@ -409,14 +402,10 @@ local function recoverTowBarVehicleAfterLoad(playerObj, vehicle, retriesLeft)
|
||||
|
||||
if towingVehicle then
|
||||
-- Apply rigid spacing as soon as the tow link exists to avoid a visible
|
||||
-- bumper-to-bumper snap while waiting for reattach recovery.
|
||||
-- bumper-to-bumper snap. Server/SP reconciliation owns recovery and
|
||||
-- never refunds or consumes an item while loading a save.
|
||||
TowBarMod.Hook.setVehiclePostAttach(nil, vehicle)
|
||||
end
|
||||
|
||||
if localPlayer and towingVehicle then
|
||||
if reattachTowBarPairAfterCleanDetach(localPlayer, towingVehicle, vehicle, false) then
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if localPlayer and retries > 0 then
|
||||
@@ -425,9 +414,8 @@ local function recoverTowBarVehicleAfterLoad(playerObj, vehicle, retriesLeft)
|
||||
return
|
||||
end
|
||||
|
||||
-- Fallback: keep original post-attach restoration behavior.
|
||||
setTowBarModelVisible(vehicle, true)
|
||||
TowBarMod.Hook.setVehiclePostAttach(nil, vehicle)
|
||||
-- Leave reciprocal saved state untouched. The authoritative audit will
|
||||
-- reconnect it when both vehicle chunks are loaded.
|
||||
end
|
||||
|
||||
function TowBarMod.Hook.setVehiclePostAttach(playerObj, towedVehicle, retriesLeft)
|
||||
@@ -514,8 +502,6 @@ end
|
||||
function TowBarMod.Hook.cleanupDetachedTowBar(towingVehicle, towedVehicle)
|
||||
if towingVehicle == nil or towedVehicle == nil then return end
|
||||
|
||||
TowBarMod.Utils.updateAttachmentsOnDefaultValues(towingVehicle, towedVehicle)
|
||||
|
||||
local towingModData = towingVehicle:getModData()
|
||||
local towedModData = towedVehicle:getModData()
|
||||
if not towingModData or not towedModData then return end
|
||||
@@ -523,17 +509,25 @@ function TowBarMod.Hook.cleanupDetachedTowBar(towingVehicle, towedVehicle)
|
||||
if towedModData.towBarOriginalScriptName then
|
||||
TowBarMod.Hook.setVehicleScriptWithTowBarHidden(towedVehicle, towedModData.towBarOriginalScriptName)
|
||||
end
|
||||
-- A very fast break can happen while the temporary fake-trailer script is
|
||||
-- still active. Restore the real script first so the saved offsets are
|
||||
-- written back to the actual vehicle attachments, not the temporary script.
|
||||
TowBarMod.Utils.updateAttachmentsOnDefaultValues(towingVehicle, towedVehicle)
|
||||
restoreFreeRollingTowState(towedVehicle, towedModData)
|
||||
|
||||
towingModData["isTowingByTowBar"] = false
|
||||
towingModData["towed"] = false
|
||||
towingModData["towBarTowedVehicleId"] = nil
|
||||
towingModData["towBarTowedVehicleSqlId"] = nil
|
||||
towingModData["towBarTowingVehicleId"] = nil
|
||||
towingModData["towBarTowingVehicleSqlId"] = nil
|
||||
towingModData["towBarExpectedAttachment"] = nil
|
||||
towedModData["isTowingByTowBar"] = false
|
||||
towedModData["towed"] = false
|
||||
towedModData["towBarTowedVehicleId"] = nil
|
||||
towedModData["towBarTowedVehicleSqlId"] = nil
|
||||
towedModData["towBarTowingVehicleId"] = nil
|
||||
towedModData["towBarTowingVehicleSqlId"] = nil
|
||||
towedModData["towBarExpectedAttachment"] = nil
|
||||
towedModData.towBarOriginalScriptName = nil
|
||||
towedModData.towBarOriginalMass = nil
|
||||
@@ -762,7 +756,6 @@ function TowBarMod.Hook.devShowAllTowbarModels(playerObj, vehicle)
|
||||
local script = vehicle:getScript()
|
||||
local chassisZ = script and script:getPhysicsChassisShape():z() or 0
|
||||
local halfZ = chassisZ / 2
|
||||
local modelScale = script and getVehicleModelScale(script) or nil
|
||||
local index = 0
|
||||
if script then
|
||||
index = getTowbarModelSlot(script)
|
||||
@@ -770,7 +763,7 @@ function TowBarMod.Hook.devShowAllTowbarModels(playerObj, vehicle)
|
||||
local selectedPart = "towbar"
|
||||
print("[TowBar DEV] Vehicle: " .. tostring(vehicle:getScriptName()))
|
||||
print("[TowBar DEV] chassisShape.z = " .. tostring(chassisZ) .. ", half = " .. tostring(halfZ))
|
||||
print("[TowBar DEV] modelScale = " .. tostring(modelScale) .. ", part = " .. selectedPart)
|
||||
print("[TowBar DEV] frontEdgeZ = " .. tostring(script and getTowbarFrontEdgeZ(script) or nil) .. ", part = " .. selectedPart)
|
||||
print("[TowBar DEV] Formula picks index = " .. tostring(index) .. " (towbar" .. tostring(index) .. " at Z offset " .. tostring(1.0 + index * 0.1) .. ")")
|
||||
print("[TowBar DEV] Showing towbar0..towbar23 on both parts")
|
||||
for j = 0, TowbarVariantSize - 1 do
|
||||
|
||||
Reference in New Issue
Block a user