Skip to content

Commit

Permalink
refactor: better persistence handling
Browse files Browse the repository at this point in the history
  • Loading branch information
CodexisPhantom committed Jan 3, 2025
1 parent 2b1868c commit d7f08cf
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 41 deletions.
36 changes: 21 additions & 15 deletions client/vehicle-persistence.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
if GetConvar('qbx:enableVehiclePersistence', 'false') == 'false' then return end

local zones
local cachedProps
local netId
local vehicle
local seat

local zones = {}
local watchedKeys = {
'bodyHealth',
'engineHealth',
Expand Down Expand Up @@ -55,6 +55,21 @@ local function sendPropsDiff()
TriggerServerEvent('qbx_core:server:vehiclePropsChanged', netId, diff)
end

---@param vehicles table
local function createVehicleZones(vehicles)
for id, coords in pairs(vehicles) do
if not zones[id] then
zones[id] = lib.points.new({
distance = 75.0,
coords = coords,
onEnter = function()
TriggerServerEvent('qbx_core:server:spawnVehicle', id, coords)
end
})
end
end
end

lib.onCache('seat', function(newSeat)
if newSeat == -1 then
seat = -1
Expand All @@ -76,21 +91,12 @@ end)

AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
local vehicles = lib.callback.await('qbx_core:server:getVehiclesToSpawn', 2500)
for i = 1, #vehicles do
local data = vehicles[i]
zones[data.id] = lib.points.new({
distance = 75.0,
coords = data.coords,
onEnter = function()
TriggerServerEvent('qbx_core:server:spawnVehicle', data.id, data.coords)
end
})
end
if not vehicles then return end
createVehicleZones(vehicles)
end)

RegisterNetEvent('qbx_core:client:removeVehZone', function(id)
if zones[id] then
zones[id]:remove()
zones[id] = nil
end
if not zones[id] then return end
zones[id]:remove()
zones[id] = nil
end)
4 changes: 4 additions & 0 deletions config/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ return {
return exports.qbx_vehiclekeys:GiveKeys(src, vehicle)
end,

setLockVehicle = function(netId, state)
exports.qbx_vehiclekeys:SetVehicleLockState(netId, state)
end,

getSocietyAccount = function(accountName)
return exports['Renewed-Banking']:getAccountMoney(accountName)
end,
Expand Down
77 changes: 51 additions & 26 deletions server/vehicle-persistence.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
local persistence = GetConvarInt('qbx:enableVehiclePersistence', 0)
print('Vehicle persistence mode ' .. persistence)
local persistence = GetConvar('qbx:enableVehiclePersistence', 'false')

---A persisted vehicle will respawn when deleted. Only works for player owned vehicles.
---Vehicles spawned using lib are automatically persisted
Expand All @@ -18,12 +17,13 @@ end

exports('DisablePersistence', DisablePersistence)

if persistence == 0 then return end
if persistence == 'false' then return end

assert(lib.checkDependency('qbx_vehicles', '1.4.1', true))

local function getVehicleId(vehicle)
return Entity(vehicle).state.vehicleid or exports.qbx_vehicles:GetVehicleIdByPlate(GetVehicleNumberPlateText(vehicle))
return Entity(vehicle).state.vehicleid or
exports.qbx_vehicles:GetVehicleIdByPlate(GetVehicleNumberPlateText(vehicle))
end

RegisterNetEvent('qbx_core:server:vehiclePropsChanged', function(netId, diff)
Expand Down Expand Up @@ -134,48 +134,73 @@ AddEventHandler('entityRemoved', function(entity)
end
end)

if persistence == 1 then return end
if persistence == 'full' then return end

local function checkVehicleExist(plate)
local vehicles = GetGamePool('CVehicle')
for i = 1, #vehicles do
local vehicle = vehicles[i]
local cachedVehicles = {}
local setVehLockState = require 'config.server'.setLockVehicle

---@param plate string
---@return boolean
local function isVehicleSpawned(plate)
for _, vehicle in pairs(GetGamePool('CVehicle')) do
if qbx.getVehiclePlate(vehicle) == plate then
return true
end
end
return false
end

---@param coords vector4
---@param id number
---@param model string
---@param props table
local function spawnVehicle(coords, id, model, props)
local _, veh = qbx.spawnVehicle({
spawnSource = vector4(coords.x, coords.y, coords.z, coords.w),
if not coords or not id or not model or not props then return end

local netId, veh = qbx.spawnVehicle({
spawnSource = vec4(coords.x, coords.y, coords.z, coords.w),
model = model,
props = props
})
exports.qbx_core:EnablePersistence(veh)

cachedVehicles[id] = nil
Entity(veh).state:set('vehicleid', id, false)
SetVehicleDoorsLocked(veh, 2)
TriggerClientEvent('qbx_core:client:removeVehZone', -1, id)
setVehLockState(netId, 2)
end

lib.callback.register('qbx_core:server:getVehiclesToSpawn', function()
local vehicles = {}
local query = 'SELECT id, plate, coords FROM player_vehicles WHERE state = 0'
local results = MySQL.query.await(query)
for _, data in pairs(results) do
local coords = json.decode(data.coords)
if coords and not checkVehicleExist(data.plate) then
vehicles[#vehicles + 1] = {
id = data.id,
coords = coords,
}
return cachedVehicles
end)

AddEventHandler('onResourceStart', function(resourceName)
if resourceName ~= 'qbx_vehicles' then return end

local vehicles = exports.qbx_vehicles:GetPlayerVehicles({ states = 0 })
if not vehicles then return end

for _, vehicle in ipairs(vehicles) do
if vehicle.coords and vehicle.props and vehicle.props.plate and
not isVehicleSpawned(vehicle.props.plate) then
cachedVehicles[vehicle.id] = vehicle.coords
end
end
return vehicles
end)

RegisterNetEvent('qbx_core:server:spawnVehicle', function(id, coords)
if not id or not coords then return end

local cachedCoords = cachedVehicles[id]
if not cachedCoords or
cachedCoords.x ~= coords.x or
cachedCoords.y ~= coords.y or
cachedCoords.z ~= coords.z or
cachedCoords.w ~= coords.w then
return
end

local vehicle = exports.qbx_vehicles:GetPlayerVehicle(id)
if not vehicle then return end
if not vehicle or not vehicle.modelName or not vehicle.props then return end

spawnVehicle(coords, id, vehicle.modelName, vehicle.props)
end)
end)

0 comments on commit d7f08cf

Please sign in to comment.