Finalized

This commit is contained in:
2026-02-06 23:36:44 -05:00
parent 8e2c12500a
commit afadd2e07c

View File

@@ -13,6 +13,7 @@ local LANDTRAIN_SAVED_POS_X_KEY = "landtrainSavedPosX"
local LANDTRAIN_SAVED_POS_Y_KEY = "landtrainSavedPosY" local LANDTRAIN_SAVED_POS_Y_KEY = "landtrainSavedPosY"
local LANDTRAIN_SAVED_POS_Z_KEY = "landtrainSavedPosZ" local LANDTRAIN_SAVED_POS_Z_KEY = "landtrainSavedPosZ"
local LANDTRAIN_SAVED_DIR_KEY = "landtrainSavedDir" local LANDTRAIN_SAVED_DIR_KEY = "landtrainSavedDir"
local LANDTRAIN_ATTACHMENT_BASE_OFFSETS = {}
local function emitLandtrainLog(line) local function emitLandtrainLog(line)
print(line) print(line)
@@ -48,6 +49,42 @@ local function hasAttachmentById(vehicle, attachmentId)
return script:getAttachmentById(attachmentId) ~= nil return script:getAttachmentById(attachmentId) ~= nil
end end
local function isUsableAttachmentPair(towingVehicle, towedVehicle, attachmentA, attachmentB)
if attachmentA == nil or attachmentB == nil or attachmentA == attachmentB then
return false
end
return hasAttachmentById(towingVehicle, attachmentA) and hasAttachmentById(towedVehicle, attachmentB)
end
local function getAttachmentBaseOffsetKey(script, attachmentId)
if script == nil or attachmentId == nil then return nil end
local scriptName = script.getName and script:getName() or tostring(script)
return tostring(scriptName) .. "|" .. tostring(attachmentId)
end
local function cacheAttachmentBaseOffset(script, attachmentId)
local key = getAttachmentBaseOffsetKey(script, attachmentId)
if key == nil or LANDTRAIN_ATTACHMENT_BASE_OFFSETS[key] ~= nil then
return
end
local attachment = script and script:getAttachmentById(attachmentId) or nil
if attachment == nil then
return
end
local offset = attachment:getOffset()
LANDTRAIN_ATTACHMENT_BASE_OFFSETS[key] = {
x = offset:x(),
y = offset:y(),
z = offset:z()
}
end
local function getAttachmentBaseOffset(script, attachmentId)
local key = getAttachmentBaseOffsetKey(script, attachmentId)
if key == nil then return nil end
return LANDTRAIN_ATTACHMENT_BASE_OFFSETS[key]
end
local function getTowbarStyleAttachmentPair(towingVehicle, towedVehicle) local function getTowbarStyleAttachmentPair(towingVehicle, towedVehicle)
local attachmentA = nil local attachmentA = nil
local attachmentB = nil local attachmentB = nil
@@ -133,20 +170,73 @@ local function chooseLandtrainAttachmentPair(towingVehicle, towedVehicle, prefer
end end
local function chooseLandtrainTowbarPair(towingVehicle, towedVehicle, preferredA, preferredB) local function chooseLandtrainTowbarPair(towingVehicle, towedVehicle, preferredA, preferredB)
local towbarA, towbarB = getTowbarStyleAttachmentPair(towingVehicle, towedVehicle) if isUsableAttachmentPair(towingVehicle, towedVehicle, preferredA, preferredB) then
if towbarA ~= towbarB and hasAttachmentById(towingVehicle, towbarA) and hasAttachmentById(towedVehicle, towbarB) then
return towbarA, towbarB
end
if preferredA ~= nil and preferredB ~= nil and preferredA ~= preferredB
and hasAttachmentById(towingVehicle, preferredA)
and hasAttachmentById(towedVehicle, preferredB) then
return preferredA, preferredB return preferredA, preferredB
end end
-- Match Towbar's load reapply pair selection before Landtrain-specific fallbacks.
local towbarA = (towingVehicle and towingVehicle:getTowAttachmentSelf()) or "trailer"
local towbarB = (towedVehicle and towedVehicle:getTowAttachmentSelf()) or "trailerfront"
if isUsableAttachmentPair(towingVehicle, towedVehicle, towbarA, towbarB) then
return towbarA, towbarB
end
local styleA, styleB = getTowbarStyleAttachmentPair(towingVehicle, towedVehicle)
if isUsableAttachmentPair(towingVehicle, towedVehicle, styleA, styleB) then
return styleA, styleB
end
return chooseLandtrainAttachmentPair(towingVehicle, towedVehicle, preferredA, preferredB) return chooseLandtrainAttachmentPair(towingVehicle, towedVehicle, preferredA, preferredB)
end end
local function clearChangedTowedAttachmentOffset(vehicle)
if vehicle == nil then return end
local modData = vehicle:getModData()
if modData == nil or modData["isChangedTowedAttachment"] ~= true then return end
local script = vehicle:getScript()
local changedAttachmentId = modData["towBarChangedAttachmentId"]
if changedAttachmentId == nil and vehicle.getTowAttachmentSelf then
changedAttachmentId = vehicle:getTowAttachmentSelf()
end
if script ~= nil and changedAttachmentId ~= nil then
cacheAttachmentBaseOffset(script, changedAttachmentId)
local baseOffset = getAttachmentBaseOffset(script, changedAttachmentId)
local towedAttachment = script:getAttachmentById(changedAttachmentId)
if towedAttachment ~= nil then
if baseOffset ~= nil then
towedAttachment:getOffset():set(baseOffset.x, baseOffset.y, baseOffset.z)
else
local offset = towedAttachment:getOffset()
local storedShift = tonumber(modData["towBarChangedOffsetZShift"])
if storedShift ~= nil then
towedAttachment:getOffset():set(offset:x(), offset:y(), offset:z() - storedShift)
else
local zShift = offset:z() > 0 and -1 or 1
towedAttachment:getOffset():set(offset:x(), offset:y(), offset:z() + zShift)
end
end
end
end
modData["isChangedTowedAttachment"] = false
modData["towBarChangedAttachmentId"] = nil
modData["towBarChangedOffsetZShift"] = nil
vehicle:transmitModData()
end
local function updateAttachmentsForRigidTowNoStack(towingVehicle, towedVehicle, attachmentA, attachmentB)
if TowBarMod == nil or TowBarMod.Utils == nil or TowBarMod.Utils.updateAttachmentsForRigidTow == nil then
return false
end
local towedScript = towedVehicle and towedVehicle:getScript() or nil
cacheAttachmentBaseOffset(towedScript, attachmentB)
clearChangedTowedAttachmentOffset(towedVehicle)
TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicle, attachmentA, attachmentB)
return true
end
local function dumpTowState(prefix, vehicle) local function dumpTowState(prefix, vehicle)
if not LANDTRAIN_DEBUG then return end if not LANDTRAIN_DEBUG then return end
if vehicle == nil then if vehicle == nil then
@@ -287,7 +377,9 @@ local function storeLandtrainFrontLinkData(towingVehicle, towedVehicle, attachme
towingModData[LANDTRAIN_REAR_SQL_ID_KEY] = nil towingModData[LANDTRAIN_REAR_SQL_ID_KEY] = nil
end end
towingVehicle:transmitModData() towingVehicle:transmitModData()
local resolvedA, resolvedB = chooseLandtrainTowbarPair(towingVehicle, towedVehicle, attachmentA, attachmentB) local preferredA = attachmentA or towedModData[LANDTRAIN_FRONT_ATTACHMENT_A_KEY]
local preferredB = attachmentB or towedModData[LANDTRAIN_FRONT_ATTACHMENT_B_KEY]
local resolvedA, resolvedB = chooseLandtrainTowbarPair(towingVehicle, towedVehicle, preferredA, preferredB)
towedModData[LANDTRAIN_FRONT_ATTACHMENT_A_KEY] = resolvedA towedModData[LANDTRAIN_FRONT_ATTACHMENT_A_KEY] = resolvedA
towedModData[LANDTRAIN_FRONT_ATTACHMENT_B_KEY] = resolvedB towedModData[LANDTRAIN_FRONT_ATTACHMENT_B_KEY] = resolvedB
towedVehicle:transmitModData() towedVehicle:transmitModData()
@@ -737,7 +829,7 @@ local function attachSavedLandtrainLink(playerObj, link, delayTicks)
end end
local originalScriptName = rearVehicle:getScriptName() local originalScriptName = rearVehicle:getScriptName()
TowBarMod.Utils.updateAttachmentsForRigidTow(frontVehicle, rearVehicle, link.attachmentA, link.attachmentB) updateAttachmentsForRigidTowNoStack(frontVehicle, rearVehicle, link.attachmentA, link.attachmentB)
rearVehicle:setScriptName("notTowingA_Trailer") rearVehicle:setScriptName("notTowingA_Trailer")
local args = { local args = {
vehicleA = frontVehicle:getId(), vehicleA = frontVehicle:getId(),
@@ -971,7 +1063,10 @@ local function captureTowbarFrontLink(towingVehicle)
return nil return nil
end end
local attachmentA, attachmentB = chooseLandtrainTowbarPair(frontVehicle, towingVehicle, nil, nil) local towingModData = towingVehicle:getModData()
local savedAttachmentA = towingModData and towingModData[LANDTRAIN_FRONT_ATTACHMENT_A_KEY] or nil
local savedAttachmentB = towingModData and towingModData[LANDTRAIN_FRONT_ATTACHMENT_B_KEY] or nil
local attachmentA, attachmentB = chooseLandtrainTowbarPair(frontVehicle, towingVehicle, savedAttachmentA, savedAttachmentB)
local link = { local link = {
frontVehicle = frontVehicle, frontVehicle = frontVehicle,
towingVehicle = towingVehicle, towingVehicle = towingVehicle,
@@ -1005,7 +1100,7 @@ local function restoreTowbarFrontLink(playerObj, link)
end end
ltLog("restoreTowbarFrontLink restoring front=" .. vehLabel(frontVehicle) .. " middle=" .. vehLabel(towingVehicle)) ltLog("restoreTowbarFrontLink restoring front=" .. vehLabel(frontVehicle) .. " middle=" .. vehLabel(towingVehicle))
TowBarMod.Utils.updateAttachmentsForRigidTow(frontVehicle, towingVehicle, link.attachmentA, link.attachmentB) updateAttachmentsForRigidTowNoStack(frontVehicle, towingVehicle, link.attachmentA, link.attachmentB)
towingVehicle:setScriptName("notTowingA_Trailer") towingVehicle:setScriptName("notTowingA_Trailer")
local args = { local args = {
@@ -1079,6 +1174,22 @@ local function ensureTowAttachmentsForTrailers()
end end
end end
local function captureTowbarAttachmentDefaults()
local scriptManager = getScriptManager()
if scriptManager == nil then return end
local vehicleScripts = scriptManager:getAllVehicleScripts()
if vehicleScripts == nil then return end
for i = 0, vehicleScripts:size() - 1 do
local script = vehicleScripts:get(i)
if script ~= nil then
cacheAttachmentBaseOffset(script, "trailer")
cacheAttachmentBaseOffset(script, "trailerfront")
end
end
end
local function menuHasTowbarAttachSlice(menu) local function menuHasTowbarAttachSlice(menu)
if menu == nil or menu.slices == nil then return false end if menu == nil or menu.slices == nil then return false end
local attachAction = TowBarMod and TowBarMod.Hook and TowBarMod.Hook.attachByTowBarAction or nil local attachAction = TowBarMod and TowBarMod.Hook and TowBarMod.Hook.attachByTowBarAction or nil
@@ -1598,7 +1709,9 @@ local function startLandtrainInstallWatchdog()
end end
Events.OnGameBoot.Add(ensureTowAttachmentsForTrailers) Events.OnGameBoot.Add(ensureTowAttachmentsForTrailers)
Events.OnGameBoot.Add(captureTowbarAttachmentDefaults)
Events.OnGameBoot.Add(startLandtrainInstallWatchdog) Events.OnGameBoot.Add(startLandtrainInstallWatchdog)
Events.OnGameStart.Add(captureTowbarAttachmentDefaults)
Events.OnGameStart.Add(startLandtrainInstallWatchdog) Events.OnGameStart.Add(startLandtrainInstallWatchdog)
Events.OnGameStart.Add(scheduleLandtrainSingleLoadRestore) Events.OnGameStart.Add(scheduleLandtrainSingleLoadRestore)
Events.OnTick.Add(onLandtrainSaveSnapshotTick) Events.OnTick.Add(onLandtrainSaveSnapshotTick)