lb-phone
-- izaap_garage integration for lb-phone (ESX)
-- Replace GetPlayerVehicles + GetVehicle with this.
local function Trim(s)
s = tostring(s or "")
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
local function SafeDecode(v)
if type(v) == "table" then return v end
if type(v) ~= "string" then return {} end
local s = Trim(v)
if s == "" then return {} end
local first = s:sub(1, 1)
if first ~= "{" and first ~= "[" then return {} end
local ok, obj = pcall(json.decode, s)
return (ok and type(obj) == "table") and obj or {}
end
local function HasColumn(tableName, columnName)
local row = MySQL.single.await([[
SELECT 1 as ok
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = ?
AND COLUMN_NAME = ?
LIMIT 1
]], { tableName, columnName })
return row ~= nil
end
local ESX_COLS = nil
local function EnsureCols()
if ESX_COLS then return ESX_COLS end
ESX_COLS = {
stored = HasColumn("owned_vehicles", "stored") and "stored" or (HasColumn("owned_vehicles", "state") and "state" or nil),
parking = HasColumn("owned_vehicles", "parking") and "parking" or (HasColumn("owned_vehicles", "garage") and "garage" or nil),
modsJson = HasColumn("owned_vehicles", "mods") and "mods" or (HasColumn("owned_vehicles", "vehicle") and "vehicle" or nil),
vehName = HasColumn("owned_vehicles", "vehicle") and "vehicle" or nil,
impounded = HasColumn("owned_vehicles", "impounded") and "impounded" or nil,
impound_id = HasColumn("owned_vehicles", "impound_id") and "impound_id" or nil,
imp_label = HasColumn("owned_vehicles", "impound_label") and "impound_label" or nil,
imp_reason = HasColumn("owned_vehicles", "impound_reason") and "impound_reason" or nil,
imp_rel = HasColumn("owned_vehicles", "impound_release_at") and "impound_release_at" or nil,
imp_fee = HasColumn("owned_vehicles", "impound_fee") and "impound_fee" or nil,
imp_fee_b = HasColumn("owned_vehicles", "impound_fee_before") and "impound_fee_before" or nil,
imp_fee_a = HasColumn("owned_vehicles", "impound_fee_after") and "impound_fee_after" or nil,
}
return ESX_COLS
end
local function GetGarageLabelFromRow(row)
local cols = EnsureCols()
if GetResourceState("izaap_garage") ~= "started" then
return row[cols.parking] or "Garage"
end
local g = row[cols.parking]
if not g or Trim(g) == "" then return "Garage" end
-- Your export accepts index (1-based) OR label; returning label is fine
local data = exports["izaap_garage"]:getGarageByIndex(g)
return (data and data.label) or (data and data.Label) or g
end
local function GetImpoundLabelFromRow(row)
local cols = EnsureCols()
if GetResourceState("izaap_garage") ~= "started" then
return "Impound"
end
local label = cols.imp_label and row[cols.imp_label] or nil
if label and Trim(label) ~= "" then return label end
local id = cols.impound_id and tonumber(row[cols.impound_id]) or nil
if id and id > 0 then
local imp = exports["izaap_garage"]:getImpoundByIndex(id)
return (imp and imp.label) or (imp and imp.Label) or "Impound"
end
return "Impound"
end
local function ReadStatsFromProps(props)
props = type(props) == "table" and props or {}
local fuel = tonumber(props.izaap_fuel or props.fuelLevel or props.fuel) -- 0-100
local eng = tonumber(props.izaap_engine or props.engineHealth or props.engine) -- 0-1000
local body = tonumber(props.izaap_body or props.bodyHealth or props.body) -- 0-1000
local stats = {}
if fuel then stats.fuel = math.floor(fuel + 0.5) end
if eng then stats.engine = math.floor((eng / 10) + 0.5) end
if body then stats.body = math.floor((body / 10) + 0.5) end
return stats
end
function GetPlayerVehicles(source)
local cols = EnsureCols()
local vehicles = MySQL.query.await("SELECT * FROM owned_vehicles WHERE owner = ?", { GetIdentifier(source) }) or {}
local toSend = {}
for i = 1, #vehicles do
local v = vehicles[i] or {}
local storedRaw = cols.stored and v[cols.stored] or 0
local storedNum = tonumber(storedRaw) or 0
local impounded = false
if cols.impounded then
impounded = (tonumber(v[cols.impounded]) or 0) == 1
else
-- fallback legacy: some schemas use stored==2 for impound
impounded = storedNum == 2
end
local stored = (storedNum == 1) and true or false
local location = stored and GetGarageLabelFromRow(v) or "out"
if impounded then
location = GetImpoundLabelFromRow(v)
end
local props = SafeDecode(cols.modsJson and v[cols.modsJson] or nil)
local stats = ReadStatsFromProps(props)
local model = props.model
if model == nil and cols.vehName then
-- some ESX schemas store spawn name in `vehicle` as string
local maybe = v[cols.vehName]
if type(maybe) == "string" and Trim(maybe) ~= "" and not tonumber(maybe) then
model = maybe
end
end
local impoundReason = nil
if impounded then
local reason = cols.imp_reason and v[cols.imp_reason] or nil
local retrievable = cols.imp_rel and tonumber(v[cols.imp_rel]) or nil
local price =
(cols.imp_fee and tonumber(v[cols.imp_fee])) or
(cols.imp_fee_b and tonumber(v[cols.imp_fee_b])) or
(cols.imp_fee_a and tonumber(v[cols.imp_fee_a])) or
nil
impoundReason = {
reason = (type(reason) == "string" and Trim(reason) ~= "" and reason) or nil,
retrievable = retrievable,
price = price
}
end
toSend[#toSend+1] = {
plate = v.plate,
type = nil,
location = location,
impounded = impounded,
statistics = stats,
impoundReason = impoundReason,
model = model
}
end
return toSend
end
---------------------------------------------------------------------------------------------
function GetVehicle(source, plate)
local cols = EnsureCols()
plate = Trim(plate or "")
if plate == "" then return end
-- only allow taking out if stored=1 and not impounded
local storedCol = cols.stored or "stored"
local storedCheck = ("`%s` = 1"):format(storedCol)
if cols.impounded then
storedCheck = storedCheck .. " AND `impounded` = 0"
end
local vehicle = MySQL.single.await(
("SELECT * FROM owned_vehicles WHERE owner = ? AND plate = ? AND %s LIMIT 1"):format(storedCheck),
{ GetIdentifier(source), plate }
)
if not vehicle then
return
end
-- mark as out
MySQL.update(
("UPDATE owned_vehicles SET `%s` = 0 WHERE plate = ?"):format(storedCol),
{ plate }
)
-- return model for phone usage
local props = SafeDecode(cols.modsJson and vehicle[cols.modsJson] or nil)
vehicle.model = props.model
return vehicle
endLast updated