Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use qbx_vehicles #67

Merged
merged 2 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions client/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ local function kickOutPeds(vehicle)
end
end

---@param vehicleId string
---@param vehicleId number
---@param garageName string
local function takeOutOfGarage(vehicleId, garageName)
if cache.vehicle then
Expand All @@ -91,9 +91,9 @@ local function takeOutOfGarage(vehicleId, garageName)
end
end

---@param data {vehicle: VehicleEntity, garageName: string}
---@param data {vehicle: PlayerVehicle, garageName: string}
local function takeOutDepot(data)
if data.vehicle.depotprice ~= 0 then
if data.vehicle.depotPrice ~= 0 then
local success = lib.callback.await('qbx_garages:server:payDepotPrice', data.vehicle.id)
if not success then
exports.qbx_core:Notify(Lang:t('error.not_enough'), 'error')
Expand All @@ -104,23 +104,23 @@ local function takeOutDepot(data)
takeOutOfGarage(data.vehicle.id, data.garageName)
end

---@param vehicle VehicleEntity
---@param vehicle PlayerVehicle
---@param garageName string
---@param garageInfo GarageConfig
local function displayVehicleInfo(vehicle, garageName, garageInfo)
local engine = qbx.math.round(vehicle.engine / 10)
local body = qbx.math.round(vehicle.body / 10)
local engine = qbx.math.round(vehicle.props.engineHealth / 10)
local body = qbx.math.round(vehicle.props.bodyHealth / 10)
local engineColor = getProgressColor(engine)
local bodyColor = getProgressColor(body)
local fuelColor = getProgressColor(vehicle.fuel)
local fuelColor = getProgressColor(vehicle.props.fuelLevel)
local stateLabel = getStateLabel(vehicle.state)
local vehicleLabel = ('%s %s'):format(VEHICLES[vehicle.vehicle].brand, VEHICLES[vehicle.vehicle].name)
local vehicleLabel = ('%s %s'):format(VEHICLES[vehicle.modelName].brand, VEHICLES[vehicle.modelName].name)

local options = {
{
title = 'Information',
icon = 'circle-info',
description = ('Name: %s\nPlate: %s\nStatus: %s\nImpound Fee: $%s'):format(vehicleLabel, vehicle.plate, stateLabel, lib.math.groupdigits(vehicle.depotprice)),
description = ('Name: %s\nPlate: %s\nStatus: %s\nImpound Fee: $%s'):format(vehicleLabel, vehicle.props.plate, stateLabel, lib.math.groupdigits(vehicle.depotPrice)),
readOnly = true,
},
{
Expand All @@ -141,7 +141,7 @@ local function displayVehicleInfo(vehicle, garageName, garageInfo)
title = 'Fuel',
icon = 'gas-pump',
readOnly = true,
progress = vehicle.fuel,
progress = vehicle.props.fuelLevel,
colorScheme = fuelColor,
}
}
Expand All @@ -151,7 +151,7 @@ local function displayVehicleInfo(vehicle, garageName, garageInfo)
options[#options + 1] = {
title = 'Take out',
icon = 'fa-truck-ramp-box',
description = ('$%s'):format(lib.math.groupdigits(vehicle.depotprice)),
description = ('$%s'):format(lib.math.groupdigits(vehicle.depotPrice)),
arrow = true,
onSelect = function()
takeOutDepot({
Expand Down Expand Up @@ -197,6 +197,7 @@ end
---@param garageName string
---@param garageInfo GarageConfig
local function openGarageMenu(garageName, garageInfo)
---@type PlayerVehicle[]?
local vehicleEntities = lib.callback.await('qbx_garages:server:getGarageVehicles', false, garageName)

if not vehicleEntities then
Expand All @@ -207,12 +208,12 @@ local function openGarageMenu(garageName, garageInfo)
local options = {}
for i = 1, #vehicleEntities do
local vehicleEntity = vehicleEntities[i]
local vehicleLabel = ('%s %s'):format(VEHICLES[vehicleEntity.vehicle].brand, VEHICLES[vehicleEntity.vehicle].name)
local vehicleLabel = ('%s %s'):format(VEHICLES[vehicleEntity.modelName].brand, VEHICLES[vehicleEntity.modelName].name)
local stateLabel = getStateLabel(vehicleEntity.state)

options[#options + 1] = {
title = vehicleLabel,
description = ('%s | %s'):format(stateLabel, vehicleEntity.plate),
description = ('%s | %s'):format(stateLabel, vehicleEntity.props.plate),
arrow = true,
onSelect = function()
displayVehicleInfo(vehicleEntity, garageName, garageInfo)
Expand Down
68 changes: 45 additions & 23 deletions server/main.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
---@class PlayerVehicle
---@field id number
---@field citizenid? string
---@field modelName string
---@field garage string
---@field state VehicleState
---@field depotPrice integer
---@field props table ox_lib properties table

Config = require 'config.server'
SharedConfig = require 'config.shared'
VEHICLES = exports.qbx_core:GetVehiclesByName()
Expand All @@ -22,38 +31,50 @@ function GetGarageType(garage)
end
end

---@alias VehicleEntity table

---@param source number
---@param garageName string
---@return VehicleEntity[]?
---@return PlayerVehicle[]?
lib.callback.register('qbx_garages:server:getGarageVehicles', function(source, garageName)
local garageType = GetGarageType(garageName)
local player = exports.qbx_core:GetPlayer(source)
if garageType == GarageType.PUBLIC then -- Public garages give player cars in the garage only
local result = Storage.fetchGaragedVehicles(garageName, player.PlayerData.citizenid)
return result[1] and result
local playerVehicles = exports.qbx_vehicles:GetPlayerVehicles({
garage = garageName,
citizenid = player.PlayerData.citizenid,
states = VehicleState.GARAGED,
})
return playerVehicles[1] and playerVehicles
elseif garageType == GarageType.DEPOT then -- Depot give player cars that are not in garage only
local result = Storage.fetchOutVehicles(player.PlayerData.citizenid)
local playerVehicles = exports.qbx_vehicles:GetPlayerVehicles({
citizenid = player.PlayerData.citizenid,
states = VehicleState.OUT,
})
local toSend = {}
if not result[1] then return end
for _, vehicle in pairs(result) do -- Check vehicle type against depot type
if not FindPlateOnServer(vehicle.plate) then
if not playerVehicles[1] then return end
for _, vehicle in pairs(playerVehicles) do -- Check vehicle type against depot type
if not FindPlateOnServer(vehicle.props.plate) then
local vehicleType = SharedConfig.garages[garageName].vehicleType
if (vehicleType == VehicleType.AIR and (VEHICLES[vehicle.vehicle].category == 'helicopters' or VEHICLES[vehicle.vehicle].category == 'planes')) or
(vehicleType == VehicleType.SEA and VEHICLES[vehicle.vehicle].category == 'boats') or
(vehicleType == VehicleType.CAR and VEHICLES[vehicle.vehicle].category ~= 'helicopters' and VEHICLES[vehicle.vehicle].category ~= 'planes' and VEHICLES[vehicle.vehicle].category ~= 'boats') then
if (vehicleType == VehicleType.AIR and (VEHICLES[vehicle.modelName].category == 'helicopters' or VEHICLES[vehicle.modelName].category == 'planes')) or
(vehicleType == VehicleType.SEA and VEHICLES[vehicle.modelName].category == 'boats') or
(vehicleType == VehicleType.CAR and VEHICLES[vehicle.modelName].category ~= 'helicopters' and VEHICLES[vehicle.modelName].category ~= 'planes' and VEHICLES[vehicle.modelName].category ~= 'boats') then
toSend[#toSend + 1] = vehicle
end
end
end
return toSend
elseif garageType == GarageType.HOUSE or not Config.sharedGarages then -- House/Personal Job/Gang garages give all cars in the garage
local result = Storage.fetchGaragedVehicles(garageName, player.PlayerData.citizenid)
return result[1] and result
local playerVehicles = exports.qbx_vehicles:GetPlayerVehicles({
garage = garageName,
citizenid = player.PlayerData.citizenid,
states = VehicleState.GARAGED,
})
return playerVehicles[1] and playerVehicles
else -- Job/Gang shared garages
local result = Storage.fetchGaragedVehicles(garageName)
return result[1] and result
local playerVehicles = exports.qbx_vehicles:GetPlayerVehicles({
garage = garageName,
states = VehicleState.GARAGED,
})
return playerVehicles[1] and playerVehicles
end
end)

Expand All @@ -69,23 +90,23 @@ local function isParkable(source, vehicleId, garageName)
if garageType == GarageType.PUBLIC then -- All players can park in public garages
return true
elseif garageType == GarageType.HOUSE then -- House garages only for player cars that have keys of the house
local owner = Storage.fetchVehicleOwner(vehicleId)
return Config.hasHouseGarageKey(garageName, owner)
local playerVehicle = exports.qbx_vehicles:GetPlayerVehicle(vehicleId)
return Config.hasHouseGarageKey(garageName, playerVehicle.citizenid)
elseif garageType == GarageType.JOB then
if player.PlayerData.job?.name ~= garage.group then return false end
if Config.sharedGarages then
return true
else
local owner = Storage.fetchVehicleOwner(vehicleId)
return owner == player.PlayerData.citizenid
local playerVehicle = exports.qbx_vehicles:GetPlayerVehicle(vehicleId)
return playerVehicle.citizenid == player.PlayerData.citizenid
end
elseif garageType == GarageType.GANG then
if player.PlayerData.gang?.name ~= garage.group then return false end
if Config.sharedGarages then
return true
else
local owner = Storage.fetchVehicleOwner(vehicleId)
return owner == player.PlayerData.citizenid
local playerVehicle = exports.qbx_vehicles:GetPlayerVehicle(vehicleId)
return playerVehicle.citizenid == player.PlayerData.citizenid
end
end
error("Unhandled GarageType: " .. garageType)
Expand Down Expand Up @@ -131,7 +152,8 @@ lib.callback.register('qbx_garages:server:payDepotPrice', function(source, vehic
local cashBalance = player.PlayerData.money.cash
local bankBalance = player.PlayerData.money.bank

local depotPrice = Storage.fetchVehicleDepotPrice(vehicleId)
local vehicle = exports.qbx_vehicles:GetPlayerVehicle(vehicleId)
local depotPrice = vehicle.depotPrice
if not depotPrice or depotPrice == 0 then return true end
if cashBalance >= depotPrice then
player.Functions.RemoveMoney('cash', depotPrice, 'paid-depot')
Expand Down
10 changes: 5 additions & 5 deletions server/spawn-vehicle.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ lib.callback.register('qbx_garages:server:spawnVehicle', function (source, vehic
return
end

local metadata = Storage.fetchVehicleProps(vehicleId)
if garageType == GarageType.DEPOT and FindPlateOnServer(metadata.props.plate) then -- If depot, check if vehicle is not already spawned on the map
local playerVehicle = exports.qbx_vehicles:GetPlayerVehicle(vehicleId)
if garageType == GarageType.DEPOT and FindPlateOnServer(playerVehicle.props.plate) then -- If depot, check if vehicle is not already spawned on the map
return exports.qbx_core:Notify(source, Lang:t('error.not_impound'), 'error', 5000)
end

local warpPed = SharedConfig.takeOut.warpInVehicle and GetPlayerPed(source)
local netId, veh = qbx.spawnVehicle({ spawnSource = garage.spawn, model = metadata.props.model, props = metadata.props, warp = warpPed})
local netId, veh = qbx.spawnVehicle({ spawnSource = garage.spawn, model = playerVehicle.props.model, props = playerVehicle.props, warp = warpPed})

if SharedConfig.takeOut.doorsLocked then
SetVehicleDoorsLocked(veh, 2)
end

TriggerClientEvent('vehiclekeys:client:SetOwner', source, metadata.props.plate)
TriggerClientEvent('vehiclekeys:client:SetOwner', source, playerVehicle.props.plate)

Entity(veh).state:set('vehicleid', vehicleId, false)
setVehicleStateToOut(vehicleId, metadata.modelName)
setVehicleStateToOut(vehicleId, playerVehicle.modelName)
return netId
end)
48 changes: 0 additions & 48 deletions server/storage.lua
Original file line number Diff line number Diff line change
@@ -1,46 +1,3 @@
---Fetches vehicles by citizenid
---@param garageName string
---@param citizenId? string
---@return VehicleEntity[]
local function fetchGaragedVehicles(garageName, citizenId)
if citizenId then
return MySQL.query.await('SELECT * FROM player_vehicles WHERE citizenid = ? AND garage = ? AND state = ?', {citizenId, garageName, VehicleState.GARAGED})
else
return MySQL.query.await('SELECT * FROM player_vehicles WHERE garage = ? AND state = ?', {garageName, VehicleState.GARAGED})
end
end

---@param citizenId string
---@return VehicleEntity[]
local function fetchOutVehicles(citizenId)
return MySQL.query.await('SELECT * FROM player_vehicles WHERE citizenid = ? AND state = ?', {citizenId, VehicleState.OUT})
end

---@alias CitizenId string

---@param vehicleId string
---@return CitizenId owner
local function fetchVehicleOwner(vehicleId)
return MySQL.scalar.await('SELECT citizenid FROM player_vehicles WHERE id = ?', {vehicleId})
end

---@param vehicleId string
---@return number
local function fetchVehicleDepotPrice(vehicleId)
return MySQL.scalar.await('SELECT depotprice FROM player_vehicles WHERE id = ?', {vehicleId})
end

---@param vehicleId string
---@return {props: table, modelName: string}
local function fetchVehicleProps(vehicleId)
local vehicle = MySQL.single.await('SELECT mods, vehicle FROM player_vehicles WHERE id = ?', {vehicleId})
assert(vehicle.mods ~= nil, "vehicle mods is nil for vehicleId=" .. vehicleId)
return {
props = json.decode(vehicle.mods),
modelName = vehicle.vehicle
}
end

---@async
---@param vehicleId string
---@param props table ox_lib vehicle properties table
Expand All @@ -63,11 +20,6 @@ local function setVehicleStateToOut(vehicleId, depotPrice)
end

return {
fetchGaragedVehicles = fetchGaragedVehicles,
fetchOutVehicles = fetchOutVehicles,
fetchVehicleOwner = fetchVehicleOwner,
fetchVehicleDepotPrice = fetchVehicleDepotPrice,
fetchVehicleProps = fetchVehicleProps,
saveVehicle = saveVehicle,
moveOutVehiclesIntoGarages = moveOutVehiclesIntoGarages,
setVehicleStateToOut = setVehicleStateToOut,
Expand Down
1 change: 1 addition & 0 deletions shared/types.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---@enum VehicleState
VehicleState = {
OUT = 0,
GARAGED = 1,
Expand Down