123 lines
4.0 KiB
Lua
123 lines
4.0 KiB
Lua
if not TowBarMod then TowBarMod = {} end
|
|
TowBarMod.Persistence = TowBarMod.Persistence or {}
|
|
|
|
local Persistence = TowBarMod.Persistence
|
|
local RegistryName = "TowBar.PersistentPairsV2"
|
|
|
|
local function getRegistry()
|
|
if not ModData or not ModData.getOrCreate then return nil end
|
|
local registry = ModData.getOrCreate(RegistryName)
|
|
registry.pairs = registry.pairs or {}
|
|
return registry
|
|
end
|
|
|
|
local function getSqlId(vehicle)
|
|
if not vehicle or not vehicle.getSqlId then return nil end
|
|
local ok, sqlId = pcall(function() return vehicle:getSqlId() end)
|
|
if ok and type(sqlId) == "number" and sqlId >= 0 then return sqlId end
|
|
return nil
|
|
end
|
|
|
|
local function makeKey(kind, towingSqlId, towedSqlId)
|
|
if type(kind) ~= "string" or type(towingSqlId) ~= "number" or type(towedSqlId) ~= "number" then
|
|
return nil
|
|
end
|
|
return kind .. ":" .. tostring(towingSqlId) .. ":" .. tostring(towedSqlId)
|
|
end
|
|
|
|
local function transmit()
|
|
if isServer and isServer() and ModData.transmit then
|
|
ModData.transmit(RegistryName)
|
|
end
|
|
end
|
|
|
|
function Persistence.savePair(kind, towingVehicle, towedVehicle, attachmentA, attachmentB, heightLevel)
|
|
local towingSqlId = getSqlId(towingVehicle)
|
|
local towedSqlId = getSqlId(towedVehicle)
|
|
local key = makeKey(kind, towingSqlId, towedSqlId)
|
|
local registry = getRegistry()
|
|
if not key or not registry then return false end
|
|
local previous = registry.pairs[key]
|
|
if previous and previous.attachmentA == attachmentA and previous.attachmentB == attachmentB
|
|
and previous.heightLevel == heightLevel then
|
|
return true
|
|
end
|
|
registry.pairs[key] = {
|
|
kind = kind,
|
|
towingSqlId = towingSqlId,
|
|
towedSqlId = towedSqlId,
|
|
attachmentA = attachmentA,
|
|
attachmentB = attachmentB,
|
|
heightLevel = heightLevel
|
|
}
|
|
transmit()
|
|
return true
|
|
end
|
|
|
|
function Persistence.getPair(kind, towingVehicle, towedVehicle)
|
|
local key = makeKey(kind, getSqlId(towingVehicle), getSqlId(towedVehicle))
|
|
local registry = getRegistry()
|
|
return key and registry and registry.pairs[key] or nil
|
|
end
|
|
|
|
function Persistence.removePair(kind, towingVehicle, towedVehicle)
|
|
local key = makeKey(kind, getSqlId(towingVehicle), getSqlId(towedVehicle))
|
|
local registry = getRegistry()
|
|
if not key or not registry or registry.pairs[key] == nil then return false end
|
|
registry.pairs[key] = nil
|
|
transmit()
|
|
return true
|
|
end
|
|
|
|
function Persistence.forEachPair(kind, callback)
|
|
local registry = getRegistry()
|
|
if not registry or not callback then return end
|
|
for _, record in pairs(registry.pairs) do
|
|
if type(record) == "table" and record.kind == kind then callback(record) end
|
|
end
|
|
end
|
|
|
|
function Persistence.notePeerAvailability(state, available)
|
|
state = state or {}
|
|
if not available then
|
|
state.peerMissing = true
|
|
return state
|
|
end
|
|
if state.peerMissing then
|
|
-- A missing vehicle means its cell was not loaded. When both members
|
|
-- return, treat the absent native constraint as load recovery rather
|
|
-- than a runtime break of a previously confirmed pair.
|
|
state.peerMissing = nil
|
|
state.confirmed = false
|
|
state.pendingUntil = nil
|
|
state.unlinkedSince = nil
|
|
end
|
|
return state
|
|
end
|
|
|
|
function Persistence.advanceRecoveryState(state, now, linked, occupied, retryMs, breakMs)
|
|
state = state or {}
|
|
if linked then
|
|
state.confirmed = true
|
|
state.pendingUntil = nil
|
|
state.unlinkedSince = nil
|
|
return state, "adopt"
|
|
end
|
|
if occupied then
|
|
state.unlinkedSince = nil
|
|
return state, "wait"
|
|
end
|
|
if state.confirmed then
|
|
state.unlinkedSince = state.unlinkedSince or now
|
|
if now - state.unlinkedSince >= breakMs then return state, "break" end
|
|
return state, "wait"
|
|
end
|
|
if not state.pendingUntil or now >= state.pendingUntil then
|
|
state.pendingUntil = now + retryMs
|
|
return state, "restore"
|
|
end
|
|
return state, "wait"
|
|
end
|
|
|
|
Persistence.getSqlId = getSqlId
|