working
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
if isClient() then return end
|
||||
|
||||
if not TowBarMod then TowBarMod = {} end
|
||||
TowBarMod.Landtrain = TowBarMod.Landtrain or {}
|
||||
if TowBarMod.Landtrain._serverTowAttachmentsLoaded then return end
|
||||
TowBarMod.Landtrain._serverTowAttachmentsLoaded = true
|
||||
|
||||
local function log(msg)
|
||||
print("[Landtrain][Server] " .. tostring(msg))
|
||||
end
|
||||
|
||||
local function addMissingTowAttachments(script)
|
||||
if not script then return 0 end
|
||||
|
||||
local wheelCount = script:getWheelCount()
|
||||
local yOffset = -0.5
|
||||
if wheelCount > 0 then
|
||||
local wheel = script:getWheel(0)
|
||||
if wheel and wheel:getOffset() then
|
||||
yOffset = wheel:getOffset():y() + 0.1
|
||||
end
|
||||
end
|
||||
|
||||
local chassis = script:getPhysicsChassisShape()
|
||||
if not chassis then return 0 end
|
||||
|
||||
local changed = 0
|
||||
|
||||
if script:getAttachmentById("trailer") == nil then
|
||||
local rearAttach = ModelAttachment.new("trailer")
|
||||
rearAttach:getOffset():set(0, yOffset, -chassis:z() / 2 - 0.1)
|
||||
rearAttach:setZOffset(-1)
|
||||
script:addAttachment(rearAttach)
|
||||
changed = changed + 1
|
||||
end
|
||||
|
||||
if script:getAttachmentById("trailerfront") == nil then
|
||||
local frontAttach = ModelAttachment.new("trailerfront")
|
||||
frontAttach:getOffset():set(0, yOffset, chassis:z() / 2 + 0.1)
|
||||
frontAttach:setZOffset(1)
|
||||
script:addAttachment(frontAttach)
|
||||
changed = changed + 1
|
||||
end
|
||||
|
||||
return changed
|
||||
end
|
||||
|
||||
local function ensureTowAttachmentsServer()
|
||||
local sm = getScriptManager()
|
||||
if sm == nil then
|
||||
log("ScriptManager unavailable; skipping tow attachment bootstrap")
|
||||
return
|
||||
end
|
||||
|
||||
local scripts = sm:getAllVehicleScripts()
|
||||
if scripts == nil then
|
||||
log("Vehicle script list unavailable; skipping tow attachment bootstrap")
|
||||
return
|
||||
end
|
||||
|
||||
local patchedScripts = 0
|
||||
local addedAttachments = 0
|
||||
for i = 0, scripts:size() - 1 do
|
||||
local script = scripts:get(i)
|
||||
local added = addMissingTowAttachments(script)
|
||||
if added > 0 then
|
||||
patchedScripts = patchedScripts + 1
|
||||
addedAttachments = addedAttachments + added
|
||||
end
|
||||
end
|
||||
|
||||
log("Tow attachment bootstrap complete: scripts=" .. tostring(patchedScripts) .. ", attachments=" .. tostring(addedAttachments))
|
||||
end
|
||||
|
||||
Events.OnGameBoot.Add(ensureTowAttachmentsServer)
|
||||
|
||||
log("LandtrainTowAttachmentsServer loaded")
|
||||
124
42.13/media/lua/server/Landtrain/LandtrainTowSyncServer.lua
Normal file
124
42.13/media/lua/server/Landtrain/LandtrainTowSyncServer.lua
Normal file
@@ -0,0 +1,124 @@
|
||||
if isClient() then return end
|
||||
|
||||
if not TowBarMod then TowBarMod = {} end
|
||||
TowBarMod.Landtrain = TowBarMod.Landtrain or {}
|
||||
if TowBarMod.Landtrain._towSyncServerLoaded then return end
|
||||
TowBarMod.Landtrain._towSyncServerLoaded = true
|
||||
|
||||
local SYNC_DELAY_TICKS = 2
|
||||
local pending = {}
|
||||
|
||||
local function log(msg)
|
||||
print("[Landtrain][TowSyncServer] " .. tostring(msg))
|
||||
end
|
||||
|
||||
local function queueSync(kind, player, args)
|
||||
if not args then return end
|
||||
table.insert(pending, {
|
||||
kind = kind,
|
||||
ticks = SYNC_DELAY_TICKS,
|
||||
player = player,
|
||||
args = args
|
||||
})
|
||||
end
|
||||
|
||||
local function vehicleHasAttachment(vehicle, attachmentId)
|
||||
if not vehicle or not attachmentId then return false end
|
||||
local script = vehicle:getScript()
|
||||
return script ~= nil and script:getAttachmentById(attachmentId) ~= nil
|
||||
end
|
||||
|
||||
local function isLinked(vehicleA, vehicleB)
|
||||
if not vehicleA or not vehicleB then return false end
|
||||
return vehicleA:getVehicleTowing() == vehicleB and vehicleB:getVehicleTowedBy() == vehicleA
|
||||
end
|
||||
|
||||
local function resolveAttachmentA(args, vehicleA)
|
||||
if args and args.attachmentA then return args.attachmentA end
|
||||
if vehicleA and vehicleA:getTowAttachmentSelf() then return vehicleA:getTowAttachmentSelf() end
|
||||
return "trailer"
|
||||
end
|
||||
|
||||
local function resolveAttachmentB(args, vehicleB)
|
||||
if args and args.attachmentB then return args.attachmentB end
|
||||
if vehicleB and vehicleB:getTowAttachmentSelf() then return vehicleB:getTowAttachmentSelf() end
|
||||
return "trailerfront"
|
||||
end
|
||||
|
||||
local function processAttach(item)
|
||||
local args = item.args or {}
|
||||
local vehicleA = args.vehicleA and getVehicleById(args.vehicleA) or nil
|
||||
local vehicleB = args.vehicleB and getVehicleById(args.vehicleB) or nil
|
||||
if not vehicleA or not vehicleB then
|
||||
log("attach sync skipped: missing vehicle A=" .. tostring(args.vehicleA) .. " B=" .. tostring(args.vehicleB))
|
||||
return
|
||||
end
|
||||
|
||||
local attachmentA = resolveAttachmentA(args, vehicleA)
|
||||
local attachmentB = resolveAttachmentB(args, vehicleB)
|
||||
|
||||
local linked = isLinked(vehicleA, vehicleB)
|
||||
if not linked then
|
||||
if not vehicleHasAttachment(vehicleA, attachmentA) or not vehicleHasAttachment(vehicleB, attachmentB) then
|
||||
log("attach sync failed: missing attachment A=" .. tostring(attachmentA) .. " B=" .. tostring(attachmentB))
|
||||
return
|
||||
end
|
||||
|
||||
vehicleA:addPointConstraint(item.player, vehicleB, attachmentA, attachmentB)
|
||||
linked = isLinked(vehicleA, vehicleB)
|
||||
if not linked then
|
||||
log("attach sync failed: server link not established A=" .. tostring(vehicleA:getId()) .. " B=" .. tostring(vehicleB:getId()))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
sendServerCommand("landtrain", "forceAttachSync", {
|
||||
vehicleA = vehicleA:getId(),
|
||||
vehicleB = vehicleB:getId(),
|
||||
attachmentA = attachmentA,
|
||||
attachmentB = attachmentB
|
||||
})
|
||||
end
|
||||
|
||||
local function processDetach(item)
|
||||
local args = item.args or {}
|
||||
local vehicleAId = args.towingVehicle or args.vehicleA or args.vehicle
|
||||
local vehicleBId = args.vehicleB
|
||||
|
||||
sendServerCommand("landtrain", "forceDetachSync", {
|
||||
vehicleA = vehicleAId,
|
||||
vehicleB = vehicleBId
|
||||
})
|
||||
end
|
||||
|
||||
local function processPending()
|
||||
if #pending == 0 then return end
|
||||
|
||||
for i = #pending, 1, -1 do
|
||||
local item = pending[i]
|
||||
item.ticks = item.ticks - 1
|
||||
if item.ticks <= 0 then
|
||||
if item.kind == "attach" then
|
||||
processAttach(item)
|
||||
elseif item.kind == "detach" then
|
||||
processDetach(item)
|
||||
end
|
||||
table.remove(pending, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onClientCommand(module, command, player, args)
|
||||
if module == "vehicle" and command == "attachTrailer" then
|
||||
queueSync("attach", player, args)
|
||||
elseif module == "vehicle" and command == "detachTrailer" then
|
||||
queueSync("detach", player, args)
|
||||
elseif module == "towbar" and command == "detachTowBar" then
|
||||
queueSync("detach", player, args)
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnClientCommand.Add(onClientCommand)
|
||||
Events.OnTick.Add(processPending)
|
||||
|
||||
log("LandtrainTowSyncServer loaded")
|
||||
Reference in New Issue
Block a user