From 8c3724b11382f0f98b7770b1a93f79ff4cda2f0d Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:30:11 +0100 Subject: [PATCH 01/23] feat: option to delete unpaid financed --- config/server.lua | 3 ++- server/main.lua | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/config/server.lua b/config/server.lua index 9822f82..a23a3bc 100644 --- a/config/server.lua +++ b/config/server.lua @@ -5,5 +5,6 @@ return { paymentInterval = 24, -- time in hours between payment being due preventSelling = false, -- prevents players from using /transfervehicle if financed }, - saleTimeout = 60000 -- Delay between attempts to sell/gift a vehicle. Prevents abuse + saleTimeout = 60000, -- Delay between attempts to sell/gift a vehicle. Prevents abuse + deleteUnpaidFinancedVehicle = false -- true to delete unpaid vehicles from database, otherwise it will edit citizenid to hide from db select } \ No newline at end of file diff --git a/server/main.lua b/server/main.lua index 1fc0dd2..a6a72fa 100644 --- a/server/main.lua +++ b/server/main.lua @@ -424,8 +424,12 @@ RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() local vehicles = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) for _, v in pairs(vehicles) do local plate = v.plate - exports.qbx_vehicles:DeletePlayerVehicles('vehicleId', v.id) - --MySQL.update('UPDATE player_vehicles SET citizenid = ? WHERE id = ?', {'REPO-'..v.citizenid, v.id}) -- Use this if you don't want them to be deleted + if config.deleteUnpaidFinancedVehicle then + exports.qbx_vehicles:DeletePlayerVehicles('vehicleId', v.id) + else + MySQL.update('UPDATE player_vehicles SET citizenid = ? WHERE id = ?', {'REPO-'..v.citizenid, v.id}) -- Use this if you don't want them to be deleted + end + exports.qbx_core:Notify(src, locale('error.repossessed', plate), 'error') end end) From 5a1a36f4f46b95ff163577b0d296f5d5c1baf9f1 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:34:13 +0100 Subject: [PATCH 02/23] fix: load finance functions on need --- server/{storage.lua => finance.lua} | 82 ++++++++++------------------- server/main.lua | 31 ++++++----- 2 files changed, 45 insertions(+), 68 deletions(-) rename server/{storage.lua => finance.lua} (54%) diff --git a/server/storage.lua b/server/finance.lua similarity index 54% rename from server/storage.lua rename to server/finance.lua index a532e5d..92af642 100644 --- a/server/storage.lua +++ b/server/finance.lua @@ -13,64 +13,47 @@ ---@field insertVehicleEntityRequest InsertVehicleEntityRequest ---@field vehicleFinance VehicleFinanceServer +---@class VehicleFinancingEntity +---@field vehicleId integer +---@field balance number +---@field paymentamount number +---@field paymentsleft integer +---@field financetime number + +local finance = {} + ---@param request InsertVehicleEntityWithFinanceRequest -function InsertVehicleEntityWithFinance(request) +function finance.insertVehicleEntityWithFinance(request) + local insertVehicleEntityRequest = request.insertVehicleEntityRequest local vehicleId = exports.qbx_vehicles:CreatePlayerVehicle({ - model = request.insertVehicleEntityRequest.model, - citizenid = request.insertVehicleEntityRequest.citizenId, + model = insertVehicleEntityRequest.model, + citizenid = insertVehicleEntityRequest.citizenId, props = { - plate = request.insertVehicleEntityRequest.plate + plate = insertVehicleEntityRequest.plate } }) + + local vehicleFinance = request.vehicleFinance MySQL.insert('INSERT INTO vehicle_financing (vehicleId, balance, paymentamount, paymentsleft, financetime) VALUES (?, ?, ?, ?, ?)', { vehicleId, - request.vehicleFinance.balance, - request.vehicleFinance.payment, - request.vehicleFinance.paymentsLeft, - request.vehicleFinance.timer + vehicleFinance.balance, + vehicleFinance.payment, + vehicleFinance.paymentsLeft, + vehicleFinance.timer }) return vehicleId end ----@alias VehicleEntity table - ----@class VehicleFinancingEntity ----@field vehicleId integer ----@field balance number ----@field paymentamount number ----@field paymentsleft integer ----@field financetime number - ----@param citizenId string ----@return VehicleEntity[] -function FetchVehicleEntitiesByCitizenId(citizenId) - return MySQL.query.await('SELECT * FROM player_vehicles WHERE citizenid = ?', {citizenId}) -end - ----@param plate string ----@return VehicleEntity -function FetchVehicleEntityByPlate(plate) - return MySQL.single.await('SELECT * FROM player_vehicles WHERE plate = ?', {plate}) -end - ----@param plate string ----@return boolean -function DoesVehicleEntityExist(plate) - local count = MySQL.scalar.await('SELECT COUNT(*) FROM player_vehicles WHERE plate = ?', {plate}) - return count > 0 -end - ---@param time number ---@param vehicleId integer -function UpdateVehicleEntityFinanceTime(time, vehicleId) +function finance.updateVehicleEntityFinanceTime(time, vehicleId) MySQL.update('UPDATE vehicle_financing SET financetime = ? WHERE vehicleId = ?', {time, vehicleId}) end ---@param vehicleFinance VehicleFinanceServer ----@param plate string -function UpdateVehicleFinance(vehicleFinance, plate) - local vehicleId = exports.qbx_vehicles:GetVehicleIdByPlate(plate) +---@param vehicleId number +function finance.updateVehicleFinance(vehicleFinance, vehicleId) if vehicleFinance.balance == 0 then MySQL.query('DELETE FROM vehicle_financing WHERE vehicleId = ?', { vehicleId @@ -86,22 +69,15 @@ function UpdateVehicleFinance(vehicleFinance, plate) end end ----@param citizenId string ----@param license string ----@param vehicleId integer -function UpdateVehicleEntityOwner(citizenId, license, vehicleId) - MySQL.update('UPDATE player_vehicles SET citizenid = ?, license = ? WHERE id = ?', {citizenId, license, vehicleId}) -end - ---@param id integer ---@return VehicleFinancingEntity -function FetchFinancedVehicleEntityById(id) +function finance.fetchFinancedVehicleEntityById(id) return MySQL.single.await('SELECT * FROM vehicle_financing WHERE vehicleId = ? AND balance > 0 AND financetime < 1', {id}) end ---@param vehicleId integer ---@return boolean -function FetchIsFinanced(vehicleId) +function finance.fetchIsFinanced(vehicleId) return MySQL.scalar.await('SELECT 1 FROM vehicle_financing WHERE vehicleId = ? AND balance > 0', { vehicleId }) ~= nil @@ -109,12 +85,8 @@ end ---@param citizenId string ---@return VehicleFinancingEntity -function FetchFinancedVehicleEntitiesByCitizenId(citizenId) +function finance.fetchFinancedVehicleEntitiesByCitizenId(citizenId) return MySQL.query.await('SELECT vehicle_financing.* FROM vehicle_financing INNER JOIN player_vehicles ON player_vehicles.citizenid = ? WHERE vehicle_financing.vehicleId = player_vehicles.id AND vehicle_financing.balance > 0 AND vehicle_financing.financetime > 1', {citizenId}) end ----@param license string ----@return VehicleFinancingEntity -function FetchFinancedVehicleEntitiesByLicense(license) - return MySQL.query.await('SELECT vf.*, p.citizenid FROM vehicle_financing AS vf INNER JOIN players AS p ON p.citizenid = ? INNER JOIN player_vehicles AS pv ON pv.citizenid = p.citizenid AND vf.balance > 0 AND vf.financetime < 1', {license}) -end \ No newline at end of file +return finance \ No newline at end of file diff --git a/server/main.lua b/server/main.lua index a6a72fa..6110d49 100644 --- a/server/main.lua +++ b/server/main.lua @@ -14,14 +14,15 @@ end) -- Deduct stored game time from player on logout RegisterNetEvent('qbx_vehicleshop:server:removePlayer', function(citizenid) if not financeTimer[citizenid] then return end + local finance = require 'server.finance' local playTime = financeTimer[citizenid] - local vehicles = FetchFinancedVehicleEntitiesByCitizenId(citizenid) - for _, v in pairs(vehicles) do + local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(citizenid) + for _, v in ipairs(vehicles) do if v.balance >= 1 then local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60)) if newTime < 0 then newTime = 0 end - UpdateVehicleEntityFinanceTime(newTime, v.vehicleId) + finance.updateVehicleEntityFinanceTime(newTime, v.vehicleId) end end financeTimer[citizenid] = nil @@ -30,16 +31,17 @@ end) -- Deduct stored game time from player on quit because we can't get citizenid AddEventHandler('playerDropped', function() local src = source + local finance = require 'server.finance' local license = GetPlayerIdentifierByType(src, 'license2') or GetPlayerIdentifierByType(src, 'license') if not license then return end - local vehicles = FetchFinancedVehicleEntitiesByLicense(license) + local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(license) if not vehicles then return end for _, v in pairs(vehicles) do local playTime = financeTimer[v.citizenid] if v.balance >= 1 and playTime then local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60)) if newTime < 0 then newTime = 0 end - UpdateVehicleEntityFinanceTime(newTime, v.vehicleId) + finance.updateVehicleEntityFinanceTime(newTime, v.vehicleId) end end if vehicles[1] and financeTimer[vehicles[1].citizenid] then @@ -203,12 +205,12 @@ RegisterNetEvent('qbx_vehicleshop:server:financePayment', function(paymentAmount if not removeMoney(src, paymentAmount) then return end - UpdateVehicleFinance({ + require 'server.finance'.updateVehicleFinance({ balance = newBalance, payment = newPayment, paymentsLeft = newPaymentsLeft, timer = timer - }, plate) + }, vehId) end) @@ -225,7 +227,7 @@ RegisterNetEvent('qbx_vehicleshop:server:financePaymentFull', function(data) if not removeMoney(src, vehBalance) then return end - UpdateVehicleFinance({ + require 'server.finance'.updateVehicleFinance({ balance = 0, payment = 0, paymentsLeft = 0, @@ -287,7 +289,7 @@ RegisterNetEvent('qbx_vehicleshop:server:financeVehicle', function(downPayment, local cid = player.PlayerData.citizenid local timer = (config.finance.paymentInterval * 60) - local vehicleId = InsertVehicleEntityWithFinance({ + local vehicleId = require 'server.finance'.insertVehicleEntityWithFinance({ insertVehicleEntityRequest = { citizenId = cid, model = vehicle, @@ -395,7 +397,7 @@ RegisterNetEvent('qbx_vehicleshop:server:sellfinanceVehicle', function(downPayme if not sellShowroomVehicleTransact(src, target, vehiclePrice, downPayment) then return end - local vehicleId = InsertVehicleEntityWithFinance({ + local vehicleId = require 'server.finance'.insertVehicleEntityWithFinance({ insertVehicleEntityRequest = { citizenId = cid, model = vehicle, @@ -416,13 +418,16 @@ end) RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() local src = source local player = exports.qbx_core:GetPlayer(src) - local result = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) + local finance = require 'server.finance' + local result = finance.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) if not result[1] then return end exports.qbx_core:Notify(src, locale('general.paymentduein', config.finance.paymentWarning)) Wait(config.finance.paymentWarning * 60000) local vehicles = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) for _, v in pairs(vehicles) do + local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) + for _, v in ipairs(vehicles) do local plate = v.plate if config.deleteUnpaidFinancedVehicle then exports.qbx_vehicles:DeletePlayerVehicles('vehicleId', v.id) @@ -471,7 +476,7 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl local target = exports.qbx_core:GetPlayer(buyerId) local row = FetchVehicleEntityByPlate(plate) if config.finance.preventSelling then - local financeRow = FetchFinancedVehicleEntityById(row.id) + local financeRow = require 'server.finance'.fetchFinancedVehicleEntityById(row.id) if financeRow and financeRow.balance > 0 then return exports.qbx_core:Notify(src, locale('error.financed'), 'error') end @@ -519,7 +524,7 @@ end) ---@param vehicleId integer ---@return boolean local function isFinanced(vehicleId) - FetchIsFinanced(vehicleId) + return require 'server.finance'.fetchIsFinanced(vehicleId) end exports('IsFinanced', isFinanced) \ No newline at end of file From 6f8cef3f68159099c45d7ced88b4fa78a6bdae0e Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:35:45 +0100 Subject: [PATCH 03/23] perf: code improvements --- client/main.lua | 43 +++++++++++++++++++++++++++---------------- server/main.lua | 15 ++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/client/main.lua b/client/main.lua index 390d59b..99a08ca 100644 --- a/client/main.lua +++ b/client/main.lua @@ -11,6 +11,9 @@ local insideShop = nil ---@field balance number ---@field paymentsLeft integer ---@field paymentAmount number +---@field brand string +---@field name string +---@field vehId number ---@param data VehicleFinanceClient local function financePayment(data) @@ -24,7 +27,12 @@ local function financePayment(data) if not dialog then return end local paymentAmount = tonumber(dialog[1]) - TriggerServerEvent('qbx_vehicleshop:server:financePayment', paymentAmount, data) + TriggerServerEvent('qbx_vehicleshop:server:financePayment', paymentAmount, { + vehId = data.vehId, + paymentAmount = data.paymentAmount, + balance = data.balance, + paymentsLeft = data.paymentsLeft + }) end local function confirmationCheck() @@ -43,7 +51,7 @@ end ---@param data VehicleFinanceClient local function showVehicleFinanceMenu(data) - local vehLabel = VEHICLES[data.vehicle].brand..' '..VEHICLES[data.vehicle].name + local vehLabel = data.brand..' '..data.name local vehFinance = { { title = 'Finance Information', @@ -62,7 +70,7 @@ local function showVehicleFinanceMenu(data) onSelect = function() local check = confirmationCheck() if check == 'confirm' then - TriggerServerEvent('qbx_vehicleshop:server:financePaymentFull', {vehBalance = data.balance, vehPlate = data.vehiclePlate}) + TriggerServerEvent('qbx_vehicleshop:server:financePaymentFull', {vehBalance = data.balance, vehId = data.vehId}) else lib.showContext('vehicleFinance') end @@ -88,16 +96,18 @@ local function showFinancedVehiclesMenu() if vehicles == nil or #vehicles == 0 then return exports.qbx_core:Notify(locale('error.nofinanced'), 'error') end for _, v in pairs(vehicles) do if v.balance and v.balance > 0 then - local name = VEHICLES[v.vehicle].name + local vehicle = VEHICLES[v.modelName] local plate = v.plate:upper() ownedVehicles[#ownedVehicles + 1] = { - title = name, + title = vehicle.name, description = locale('menus.veh_platetxt')..plate, icon = 'fa-solid fa-car-side', arrow = true, onSelect = function() showVehicleFinanceMenu({ - vehicle = v.vehicle, + vehId = v.id, + name = vehicle.name, + brand = vehicle.brand, vehiclePlate = plate, balance = v.balance, paymentsLeft = v.paymentsleft, @@ -523,12 +533,6 @@ end local shopVehs = {} local function init() - CreateThread(function() - for name, shop in pairs(config.shops) do - createShop(shop.zone.shape, name) - end - end) - CreateThread(function() if config.finance.enable then lib.zones.box({ @@ -552,12 +556,14 @@ local function init() end) CreateThread(function() - for shopName in pairs(config.shops) do + for shopName, shop in pairs(config.shops) do + createShop(shop.zone.shape, shopName) + local showroomVehicles = config.shops[shopName].showroomVehicles for i = 1, #showroomVehicles do local showroomVehicle = showroomVehicles[i] local veh = createShowroomVehicle(showroomVehicle.vehicle, showroomVehicle.coords) - shopVehs[#shopVehs + 1] = veh + shopVehs[i] = veh if config.useTarget then createVehicleTarget(shopName, veh, i) else @@ -634,7 +640,12 @@ end) ---@param plate string RegisterNetEvent('qbx_vehicleshop:client:buyShowroomVehicle', function(vehicle, plate, vehicleId) local tempShop = insideShop -- temp hacky way of setting the shop because it changes after the callback has returned since you are outside the zone - local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, vehicle, config.shops[tempShop].vehicleSpawn, plate, vehicleId) + local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, { + model = vehicle, + coords = config.shops[tempShop].vehicleSpawn, + plate = plate, + vehicleId = vehicleId + }) local veh = NetToVeh(netId) local props = lib.getVehicleProperties(veh) props.plate = plate @@ -695,6 +706,6 @@ end) AddEventHandler('onResourceStart', function(resource) if GetCurrentResourceName() == resource then - if LocalPlayer.state.isLoggedIn then init() end + init() end end) diff --git a/server/main.lua b/server/main.lua index 6110d49..c209a90 100644 --- a/server/main.lua +++ b/server/main.lua @@ -36,7 +36,7 @@ AddEventHandler('playerDropped', function() if not license then return end local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(license) if not vehicles then return end - for _, v in pairs(vehicles) do + for _, v in ipairs(vehicles) do local playTime = financeTimer[v.citizenid] if v.balance >= 1 and playTime then local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60)) @@ -63,7 +63,6 @@ local function calculateFinance(vehiclePrice, downPayment, paymentamount) end ---@class FinancedVehicle ----@field vehiclePlate string ---@field paymentAmount number ---@field balance number ---@field paymentsLeft integer @@ -82,15 +81,15 @@ local function calculateNewFinance(paymentAmount, vehData) end local function generateUniquePlate() - while true do - local plate = qbx.generateRandomPlate('111AA11A') - if not DoesVehicleEntityExist(plate) and not exports.qbx_vehicles:DoesPlayerVehiclePlateExist(plate) then return plate end + local plate + repeat + plate = qbx.generateRandomPlate('111AA11A') Wait(0) - end + until not exports.qbx_vehicles:DoesPlayerVehiclePlateExist(plate) + return plate end -- Callbacks - lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(source) local src = source local player = exports.qbx_core:GetPlayer(src) @@ -424,8 +423,6 @@ RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() exports.qbx_core:Notify(src, locale('general.paymentduein', config.finance.paymentWarning)) Wait(config.finance.paymentWarning * 60000) - local vehicles = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) - for _, v in pairs(vehicles) do local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) for _, v in ipairs(vehicles) do local plate = v.plate From 828ef4484239b35fb9ba66a1eaa65691bfdd52e6 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:36:55 +0100 Subject: [PATCH 04/23] feat: use qbx_vehicles API --- server/main.lua | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/server/main.lua b/server/main.lua index c209a90..29ad219 100644 --- a/server/main.lua +++ b/server/main.lua @@ -94,22 +94,28 @@ lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(sourc local src = source local player = exports.qbx_core:GetPlayer(src) if not player then return end - local vehicles = FetchVehicleEntitiesByCitizenId(player.PlayerData.citizenid) - local financeVehicles = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) - for _, v in pairs(financeVehicles) do - vehicles[v.vehicleId].balance = v.balance - vehicles[v.vehicleId].paymentamount = v.paymentamount - vehicles[v.vehicleId].paymentsleft = v.paymentsleft - vehicles[v.vehicleId].financetime = v.financetime - end - if vehicles[1] then - return vehicles + + local vehicles = exports.qbx_vehicles:GetPlayerVehicles({ + citizenid = player.PlayerData.citizenid + }) + + local financeVehicles = require 'server.finance'.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) + for _, v in ipairs(financeVehicles) do + local vehicle = vehicles[v.vehicleId] + vehicle.balance = v.balance + vehicle.paymentamount = v.paymentamount + vehicle.paymentsleft = v.paymentsleft + vehicle.financetime = v.financetime end + return vehicles[1] and vehicles end) -lib.callback.register('qbx_vehicleshop:server:spawnVehicle', function(source, model, coords, plate, vehicleId) +lib.callback.register('qbx_vehicleshop:server:spawnVehicle', function(source, data) + local model, coords, plate, vehicleId = data.model, data.coords, data.plate, data.vehicleId local netId, veh = qbx.spawnVehicle({model = model, spawnSource = coords, warp = GetPlayerPed(source)}) + if not netId or netId == 0 then return end + if not veh or veh == 0 then return end if vehicleId then Entity(veh).state:set('vehicleid', vehicleId, false) end @@ -186,7 +192,7 @@ end -- Make a finance payment RegisterNetEvent('qbx_vehicleshop:server:financePayment', function(paymentAmount, vehData) local src = source - local plate = vehData.vehiclePlate + local vehId = vehData.vehId paymentAmount = tonumber(paymentAmount) --[[@as number]] local minPayment = tonumber(vehData.paymentAmount) --[[@as number]] local timer = (config.finance.paymentInterval * 60) @@ -217,7 +223,7 @@ end) RegisterNetEvent('qbx_vehicleshop:server:financePaymentFull', function(data) local src = source local vehBalance = data.vehBalance - local vehPlate = data.vehPlate + local vehId = data.vehId if vehBalance == 0 then exports.qbx_core:Notify(src, locale('error.alreadypaid'), 'error') @@ -231,7 +237,7 @@ RegisterNetEvent('qbx_vehicleshop:server:financePaymentFull', function(data) payment = 0, paymentsLeft = 0, timer = 0, - }, vehPlate) + }, vehId) end) -- Buy public vehicle outright @@ -471,7 +477,12 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl local player = exports.qbx_core:GetPlayer(src) local target = exports.qbx_core:GetPlayer(buyerId) - local row = FetchVehicleEntityByPlate(plate) + local row = exports.qbx_vehicles:GetPlayerVehicles({ + plate = plate + }) + if not row then return end + row = row[1] + if config.finance.preventSelling then local financeRow = require 'server.finance'.fetchFinancedVehicleEntityById(row.id) if financeRow and financeRow.balance > 0 then @@ -486,7 +497,6 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl return exports.qbx_core:Notify(src, locale('error.playertoofar'), 'error') end local targetcid = target.PlayerData.citizenid - local targetlicense = GetPlayerIdentifierByType(target.PlayerData.source, 'license') if not target then return exports.qbx_core:Notify(src, locale('error.buyerinfo'), 'error') end @@ -509,7 +519,7 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl player.Functions.AddMoney(currencyType, sellAmount) target.Functions.RemoveMoney(currencyType, sellAmount) end - UpdateVehicleEntityOwner(targetcid, targetlicense, row.id) + exports.qbx_vehicles:SetPlayerVehicleOwner(row.id, targetcid) TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, plate) local sellerMessage = sellAmount > 0 and locale('success.soldfor') .. lib.math.groupdigits(sellAmount) or locale('success.gifted') local buyerMessage = sellAmount > 0 and locale('success.boughtfor') .. lib.math.groupdigits(sellAmount) or locale('success.received_gift') From 9f6f261eae65edc9828c15cef0969e9e5eadb7c0 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:39:11 +0100 Subject: [PATCH 05/23] fix(test drive): wait netid to exist --- client/main.lua | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/client/main.lua b/client/main.lua index 99a08ca..c1fa134 100644 --- a/client/main.lua +++ b/client/main.lua @@ -94,6 +94,7 @@ local function showFinancedVehiclesMenu() local ownedVehicles = {} if vehicles == nil or #vehicles == 0 then return exports.qbx_core:Notify(locale('error.nofinanced'), 'error') end + for _, v in pairs(vehicles) do if v.balance and v.balance > 0 then local vehicle = VEHICLES[v.modelName] @@ -428,6 +429,16 @@ local function openVehicleSellMenu(targetVehicle) lib.showContext('vehicleMenu') end +--- End test drive +local function endTestDrive() + TriggerServerEvent('qbx_vehicleshop:server:deleteVehicle', testDriveVeh) + testDriveVeh = 0 + inTestDrive = false + LocalPlayer.state:set('isInTestDrive', false, true) + exports.qbx_core:Notify(locale('general.testdrive_complete'), 'success') +end + + --- Starts the test drive timer based on time and shop ---@param time number local function startTestDriveTimer(time) @@ -439,10 +450,7 @@ local function startTestDriveTimer(time) local currentGameTime = GetGameTimer() local secondsLeft = currentGameTime - gameTimer if currentGameTime < gameTimer + timeMs and secondsLeft >= timeMs - 50 then - TriggerServerEvent('qbx_vehicleshop:server:deleteVehicle', testDriveVeh) - testDriveVeh = 0 - inTestDrive = false - exports.qbx_core:Notify(locale('general.testdrive_complete'), 'success') + endTestDrive() end qbx.drawText2d({ text = locale('general.testdrive_timer')..math.ceil(time - secondsLeft / 1000), coords = vec2(1.0, 1.38), scale = 0.5}) Wait(0) @@ -600,9 +608,21 @@ RegisterNetEvent('qbx_vehicleshop:client:testDrive', function(args) if not args then return end inTestDrive = true + LocalPlayer.state:set('isInTestDrive', true, true) local testDrive = config.shops[insideShop].testDrive local plate = 'TEST'..lib.string.random('1111') - local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, args.vehicle, testDrive.spawn, plate) + local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, { + model = args.vehicle, + coords = testDrive.spawn, + plate = plate + }) + + lib.waitFor(function() + if NetworkDoesEntityExistWithNetworkId(netId) then + return true + end + end, 'netId not exist') + testDriveVeh = netId exports.qbx_core:Notify(locale('general.testdrive_timenoti', testDrive.limit), 'inform') startTestDriveTimer(testDrive.limit * 60) From 40ac21e1ccd1085ea0f3b07db2e73b70c3cf52c2 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:39:28 +0100 Subject: [PATCH 06/23] feat: command to end test drive manually --- client/main.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/main.lua b/client/main.lua index c1fa134..31fffc5 100644 --- a/client/main.lua +++ b/client/main.lua @@ -438,6 +438,11 @@ local function endTestDrive() exports.qbx_core:Notify(locale('general.testdrive_complete'), 'success') end +RegisterCommand('endtestdrive', function() + if not inTestDrive then return end + + endTestDrive() +end, false) --- Starts the test drive timer based on time and shop ---@param time number From d8c10f30650a98a9b0d612038d6aff35fca9673b Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:40:28 +0100 Subject: [PATCH 07/23] perf(fxmanifest): remove finance module auto loading --- fxmanifest.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 4073aed..b7d7674 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -20,7 +20,6 @@ client_scripts { server_scripts { '@oxmysql/lib/MySQL.lua', 'server/main.lua', - 'server/storage.lua', } files { From dd33a708ed4adaf03c3eec4ae6564df4f9f29bad Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:31:52 +0100 Subject: [PATCH 08/23] fix: use vehicle id instead of plate --- server/main.lua | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/server/main.lua b/server/main.lua index 29ad219..085af68 100644 --- a/server/main.lua +++ b/server/main.lua @@ -470,16 +470,15 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl return exports.qbx_core:Notify(src, locale('error.notinveh'), 'error') end - local plate = qbx.string.trim(GetVehicleNumberPlateText(vehicle)) - if not plate then - return exports.qbx_core:Notify(src, locale('error.vehinfo'), 'error') - end + local vehicleId = Entity(vehicle).state.vehicleid + if not vehicleId then return end local player = exports.qbx_core:GetPlayer(src) local target = exports.qbx_core:GetPlayer(buyerId) local row = exports.qbx_vehicles:GetPlayerVehicles({ - plate = plate + vehicleId = vehicleId }) + if not row then return end row = row[1] @@ -520,7 +519,7 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl target.Functions.RemoveMoney(currencyType, sellAmount) end exports.qbx_vehicles:SetPlayerVehicleOwner(row.id, targetcid) - TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, plate) + TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, row.plate) local sellerMessage = sellAmount > 0 and locale('success.soldfor') .. lib.math.groupdigits(sellAmount) or locale('success.gifted') local buyerMessage = sellAmount > 0 and locale('success.boughtfor') .. lib.math.groupdigits(sellAmount) or locale('success.received_gift') exports.qbx_core:Notify(src, sellerMessage, 'success') From 2cc21b54858a89c24ca9d19c2317af8d1d772891 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:49:06 +0100 Subject: [PATCH 09/23] fix: using best API --- server/main.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server/main.lua b/server/main.lua index 085af68..23cb2d1 100644 --- a/server/main.lua +++ b/server/main.lua @@ -475,12 +475,9 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl local player = exports.qbx_core:GetPlayer(src) local target = exports.qbx_core:GetPlayer(buyerId) - local row = exports.qbx_vehicles:GetPlayerVehicles({ - vehicleId = vehicleId - }) + local row = exports.qbx_vehicles:GetPlayerVehicle(vehicleId) if not row then return end - row = row[1] if config.finance.preventSelling then local financeRow = require 'server.finance'.fetchFinancedVehicleEntityById(row.id) From aeabae7c9a3c79c2db62a1dd0d9a11db2622b955 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:53:49 +0100 Subject: [PATCH 10/23] perf: code improvements --- server/main.lua | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/server/main.lua b/server/main.lua index 23cb2d1..6115021 100644 --- a/server/main.lua +++ b/server/main.lua @@ -365,6 +365,7 @@ RegisterNetEvent('qbx_vehicleshop:server:sellShowroomVehicle', function(data, pl }) TriggerClientEvent('qbx_vehicleshop:client:buyShowroomVehicle', target.PlayerData.source, vehicle, plate, vehicleId) + local shop = sharedConfig.shops[shopId] end) -- Finance vehicle to customer @@ -446,55 +447,58 @@ end) lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicle'), params = { {name = 'id', type = 'playerId', help = locale('general.command_transfervehicle_help')}, {name = 'amount', type = 'number', help = locale('general.command_transfervehicle_amount'), optional = true}}}, function(source, args) + local qbx_core = exports.qbx_core + local qbx_vehicles = exports.qbx_vehicles local src = source local buyerId = args.id local sellAmount = args.amount or 0 + if src == buyerId then - return exports.qbx_core:Notify(src, locale('error.selftransfer'), 'error') + return qbx_core:Notify(src, locale('error.selftransfer'), 'error') end if saleTimeout[src] then - return exports.qbx_core:Notify(src, locale('error.sale_timeout'), 'error') + return qbx_core:Notify(src, locale('error.sale_timeout'), 'error') end if buyerId == 0 then - return exports.qbx_core:Notify(src, locale('error.Invalid_ID'), 'error') + return qbx_core:Notify(src, locale('error.Invalid_ID'), 'error') end local ped = GetPlayerPed(src) local targetPed = GetPlayerPed(buyerId) if targetPed == 0 then - return exports.qbx_core:Notify(src, locale('error.buyerinfo'), 'error') + return qbx_core:Notify(src, locale('error.buyerinfo'), 'error') end local vehicle = GetVehiclePedIsIn(ped, false) if vehicle == 0 then - return exports.qbx_core:Notify(src, locale('error.notinveh'), 'error') + return qbx_core:Notify(src, locale('error.notinveh'), 'error') end - local vehicleId = Entity(vehicle).state.vehicleid + local vehicleId = Entity(vehicle).state.vehicleid or qbx_vehicles:GetVehicleIdByPlate(GetVehicleNumberPlateText(vehicle)) if not vehicleId then return end - local player = exports.qbx_core:GetPlayer(src) - local target = exports.qbx_core:GetPlayer(buyerId) - local row = exports.qbx_vehicles:GetPlayerVehicle(vehicleId) + local player = qbx_core:GetPlayer(src) + local target = qbx_core:GetPlayer(buyerId) + local row = qbx_vehicles:GetPlayerVehicle(vehicleId) if not row then return end if config.finance.preventSelling then local financeRow = require 'server.finance'.fetchFinancedVehicleEntityById(row.id) if financeRow and financeRow.balance > 0 then - return exports.qbx_core:Notify(src, locale('error.financed'), 'error') + return qbx_core:Notify(src, locale('error.financed'), 'error') end end if row.citizenid ~= player.PlayerData.citizenid then - return exports.qbx_core:Notify(src, locale('error.notown'), 'error') + return qbx_core:Notify(src, locale('error.notown'), 'error') end if #(GetEntityCoords(ped) - GetEntityCoords(targetPed)) > 5.0 then - return exports.qbx_core:Notify(src, locale('error.playertoofar'), 'error') + return qbx_core:Notify(src, locale('error.playertoofar'), 'error') end local targetcid = target.PlayerData.citizenid if not target then - return exports.qbx_core:Notify(src, locale('error.buyerinfo'), 'error') + return qbx_core:Notify(src, locale('error.buyerinfo'), 'error') end saleTimeout[src] = true @@ -504,23 +508,23 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl lib.callback('qbx_vehicleshop:client:confirmTrade', buyerId, function(approved) if not approved then - exports.qbx_core:Notify(src, locale('error.buyerdeclined'), 'error') + qbx_core:Notify(src, locale('error.buyerdeclined'), 'error') return end if sellAmount > 0 then local currencyType = findChargeableCurrencyType(sellAmount, target.PlayerData.money.cash, target.PlayerData.money.bank) if not currencyType then - return exports.qbx_core:Notify(src, locale('error.buyertoopoor'), 'error') + return qbx_core:Notify(src, locale('error.buyertoopoor'), 'error') end player.Functions.AddMoney(currencyType, sellAmount) target.Functions.RemoveMoney(currencyType, sellAmount) end - exports.qbx_vehicles:SetPlayerVehicleOwner(row.id, targetcid) + qbx_vehicles:SetPlayerVehicleOwner(row.id, targetcid) TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, row.plate) local sellerMessage = sellAmount > 0 and locale('success.soldfor') .. lib.math.groupdigits(sellAmount) or locale('success.gifted') local buyerMessage = sellAmount > 0 and locale('success.boughtfor') .. lib.math.groupdigits(sellAmount) or locale('success.received_gift') - exports.qbx_core:Notify(src, sellerMessage, 'success') - exports.qbx_core:Notify(buyerId, buyerMessage, 'success') + qbx_core:Notify(src, sellerMessage, 'success') + qbx_core:Notify(buyerId, buyerMessage, 'success') end, GetEntityModel(vehicle), sellAmount) end) From 3e02f9d47d269846152ece156d8b622020e275da Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:55:11 +0100 Subject: [PATCH 11/23] chore: switch shops config to shared config --- client/main.lua | 38 ++++---- config/client.lua | 218 +--------------------------------------------- config/shared.lua | 217 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 237 insertions(+), 236 deletions(-) diff --git a/client/main.lua b/client/main.lua index 31fffc5..c2f36e2 100644 --- a/client/main.lua +++ b/client/main.lua @@ -94,7 +94,7 @@ local function showFinancedVehiclesMenu() local ownedVehicles = {} if vehicles == nil or #vehicles == 0 then return exports.qbx_core:Notify(locale('error.nofinanced'), 'error') end - + for _, v in pairs(vehicles) do if v.balance and v.balance > 0 then local vehicle = VEHICLES[v.modelName] @@ -140,7 +140,7 @@ end) ---@param closestVehicle integer ---@return string local function getVehName(closestVehicle) - local vehicle = config.shops[insideShop].showroomVehicles[closestVehicle].vehicle + local vehicle = sharedConfig.shops[insideShop].showroomVehicles[closestVehicle].vehicle return VEHICLES[vehicle].name end @@ -148,7 +148,7 @@ end ---@param closestVehicle integer ---@return string local function getVehPrice(closestVehicle) - local vehicle = config.shops[insideShop].showroomVehicles[closestVehicle].vehicle + local vehicle = sharedConfig.shops[insideShop].showroomVehicles[closestVehicle].vehicle return lib.math.groupdigits(VEHICLES[vehicle].price) end @@ -156,7 +156,7 @@ end ---@param closestVehicle integer ---@return string local function getVehBrand(closestVehicle) - local vehicle = config.shops[insideShop].showroomVehicles[closestVehicle].vehicle + local vehicle = sharedConfig.shops[insideShop].showroomVehicles[closestVehicle].vehicle return VEHICLES[vehicle].brand end @@ -235,7 +235,7 @@ local function openVehCatsMenu(category, targetVehicle) lib.registerContext({ id = 'openVehCats', - title = config.shops[insideShop].categories[category], + title = sharedConfig.shops[insideShop].categories[category], menu = 'vehicleCategories', options = vehMenu }) @@ -248,7 +248,7 @@ end local function openVehicleCategoryMenu(args) local categoryMenu = {} local sortedCategories = {} - local categories = config.shops[insideShop].categories + local categories = sharedConfig.shops[insideShop].categories for k, v in pairs(categories) do sortedCategories[#sortedCategories + 1] = { @@ -283,7 +283,7 @@ end ---@param targetVehicle integer local function openCustomFinance(targetVehicle) - local vehicle = config.shops[insideShop].showroomVehicles[targetVehicle].vehicle + local vehicle = sharedConfig.shops[insideShop].showroomVehicles[targetVehicle].vehicle local dialog = lib.inputDialog(getVehBrand(targetVehicle):upper()..' '..vehicle:upper()..' - $'..getVehPrice(targetVehicle), { { type = 'number', @@ -344,7 +344,7 @@ end ---@param targetVehicle number local function openVehicleSellMenu(targetVehicle) local options = {} - local vehicle = config.shops[insideShop].showroomVehicles[targetVehicle].vehicle + local vehicle = sharedConfig.shops[insideShop].showroomVehicles[targetVehicle].vehicle local swapOption = { title = locale('menus.swap_header'), description = locale('menus.swap_txt'), @@ -355,7 +355,7 @@ local function openVehicleSellMenu(targetVehicle) arrow = true } - if config.shops[insideShop].type == 'free-use' then + if sharedConfig.shops[insideShop].type == 'free-use' then if config.enableTestDrive then options[#options + 1] = { title = locale('menus.test_header'), @@ -467,7 +467,7 @@ end ---@param entity number vehicle ---@param targetVehicle number local function createVehicleTarget(shopName, entity, targetVehicle) - local shop = config.shops[shopName] + local shop = sharedConfig.shops[shopName] exports.ox_target:addLocalEntity(entity, { { name = 'vehicleshop:showVehicleOptions', @@ -486,19 +486,21 @@ end ---@param coords vector4 ---@param targetVehicle number local function createVehicleZone(shopName, coords, targetVehicle) - local shop = config.shops[shopName] + local shop = sharedConfig.shops[shopName] lib.zones.box({ coords = coords.xyz, size = shop.zone.size, rotation = coords.w, debug = config.debugPoly, onEnter = function() - local job = config.shops[insideShop].job + if not insideShop then return end + local job = sharedConfig.shops[insideShop].job if job and QBX.PlayerData.job.name ~= job then return end lib.showTextUI(locale('menus.keypress_vehicleViewMenu')) end, inside = function() - local job = config.shops[insideShop].job + if not insideShop then return end + local job = sharedConfig.shops[insideShop].job if not IsControlJustPressed(0, 38) or job and QBX.PlayerData.job.name ~= job then return end openVehicleSellMenu(targetVehicle) end, @@ -569,10 +571,10 @@ local function init() end) CreateThread(function() - for shopName, shop in pairs(config.shops) do + for shopName, shop in pairs(sharedConfig.shops) do createShop(shop.zone.shape, shopName) - local showroomVehicles = config.shops[shopName].showroomVehicles + local showroomVehicles = sharedConfig.shops[shopName].showroomVehicles for i = 1, #showroomVehicles do local showroomVehicle = showroomVehicles[i] local veh = createShowroomVehicle(showroomVehicle.vehicle, showroomVehicle.coords) @@ -614,7 +616,7 @@ RegisterNetEvent('qbx_vehicleshop:client:testDrive', function(args) inTestDrive = true LocalPlayer.state:set('isInTestDrive', true, true) - local testDrive = config.shops[insideShop].testDrive + local testDrive = sharedConfig.shops[insideShop].testDrive local plate = 'TEST'..lib.string.random('1111') local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, { model = args.vehicle, @@ -637,7 +639,7 @@ end) ---@param data {toVehicle: string, targetVehicle: integer, ClosestShop: string} RegisterNetEvent('qbx_vehicleshop:client:swapVehicle', function(data) local shopName = data.ClosestShop - local dataTargetVehicle = config.shops[shopName].showroomVehicles[data.targetVehicle] + local dataTargetVehicle = sharedConfig.shops[shopName].showroomVehicles[data.targetVehicle] if dataTargetVehicle.vehicle == data.toVehicle then return end local closestVehicle = lib.getClosestVehicle(dataTargetVehicle.coords.xyz, 5, false) @@ -714,7 +716,7 @@ end) --- Thread to create blips CreateThread(function() - for _, v in pairs(config.shops) do + for _, v in pairs(sharedConfig.shops) do if v.blip.show then local dealer = AddBlipForCoord(v.blip.coords.x, v.blip.coords.y, v.blip.coords.z) SetBlipSprite(dealer, v.blip.sprite) diff --git a/config/client.lua b/config/client.lua index 2431e2d..325c6bf 100644 --- a/config/client.lua +++ b/config/client.lua @@ -4,229 +4,13 @@ return { enableFreeUseBuy = true, -- Allows players to buy from NPC shops requestModelTimeout = 5000, -- load model timeout for oxlib enableTestDrive = true, - + finance = { enable = true, -- Enables the financing system. Turning this off does not affect already financed vehicles commissionRate = 0.05, -- Percent that goes to sales person from a finance sale 5% zone = vec3(-29.53, -1103.67, 26.42), -- Where the finance menu is located }, - shops = { - --[[shop = { -- Needs to be unique - type = '', -- If 'free-use', no player-to-player interaction required to purchase. If 'managed', caresalesman required for purchase - job = '', -- If shop is 'free-use', remove this option. If shop is 'managed', put required job - zone = { - shape = { -- Polygon that surrounds the shop - vec3(0.0, 0.0, 0.0), - vec3(0.0, 0.0, 0.0), - vec3(0.0, 0.0, 0.0), - vec3(0.0, 0.0, 0.0), - }, - size = vec3(0.0, 0.0, 0.0), -- Size of the vehicles zones (x, y, z) - targetDistance = 1, -- Defines targeting distance. Only works if useTarget is enabled - }, - blip = { - label = '', -- Blip label - coords = vec3(0.0, 0.0, 0.0), -- Blip coordinates - show = true, -- Enables/disables the blip being shown - sprite = 0, -- Blip sprite - color = 0, -- Blip color - }, - categories = { -- Categories available to browse - sedans = 'Sedans', - coupes = 'Coupes', - suvs = 'SUVs', - offroad = 'Offroad', - }, - testDrive = { - limit = 5.0, -- Time in minutes allotted for the test drive - spawn = vec4(0.0, 0.0, 0.0, 0.0), -- Spawn location for the test drive - }, - returnLocation = vec3(0.0, -1082.58, 26.68), -- Location to return vehicle only if the vehicleshop is managed - vehicleSpawn = vec4(0.0, 0.0, 0.0, 0.0), -- Spawn location when vehicle is purchased - showroomVehicles = { - [1] = { - coords = vec4(0.0, 0.0, 0.0, 0.0), -- where the vehicle will spawn on display - vehicle = '', -- Model name of display vehicle. Is dynamically changed when swapping vehicles - }, - [2] = { - coords = vec4(0.0, 0.0, 0.0, 0.0), -- where the vehicle will spawn on display - vehicle = '', -- Model name of display vehicle. Is dynamically changed when swapping vehicles - }, - }, - },]]-- - pdm = { - type = 'free-use', - zone = { - shape = { - vec3(-56.727394104004, -1086.2325439453, 26.0), - vec3(-60.612808227539, -1096.7795410156, 26.0), - vec3(-58.26834487915, -1100.572265625, 26.0), - vec3(-35.927803039551, -1109.0034179688, 26.0), - vec3(-34.427627563477, -1108.5111083984, 26.0), - vec3(-32.02657699585, -1101.5877685547, 26.0), - vec3(-33.342102050781, -1101.0377197266, 26.0), - vec3(-31.292987823486, -1095.3717041016, 26.0) - }, - size = vec3(3, 3, 4), - targetDistance = 1, - }, - blip = { - label = 'Premium Deluxe Motorsport', - coords = vec3(-45.67, -1098.34, 26.42), - show = true, - sprite = 326, - color = 3, - }, - categories = { - sportsclassics = 'Sports Classics', - sedans = 'Sedans', - coupes = 'Coupes', - suvs = 'SUVs', - offroad = 'Offroad', - muscle = 'Muscle', - compacts = 'Compacts', - motorcycles = 'Motorcycles', - vans = 'Vans', - cycles = 'Bicycles' - }, - testDrive = { - limit = 5.0, - spawn = vec4(-7.84, -1081.35, 26.67, 121.83), - }, - returnLocation = vec3(-44.74, -1082.58, 26.68), - vehicleSpawn = vec4(-31.69, -1090.78, 26.42, 328.79), - showroomVehicles = { - [1] = {coords = vec4(-45.65, -1093.66, 25.44, 69.5), vehicle = 'adder'}, - [2] = {coords = vec4(-48.27, -1101.86, 25.44, 294.5), vehicle = 'schafter2'}, - [3] = {coords = vec4(-39.6, -1096.01, 25.44, 66.5), vehicle = 'comet2'}, - [4] = {coords = vec4(-51.21, -1096.77, 25.44, 254.5), vehicle = 'vigero'}, - [5] = {coords = vec4(-40.18, -1104.13, 25.44, 338.5), vehicle = 't20'}, - [6] = {coords = vec4(-43.31, -1099.02, 25.44, 52.5), vehicle = 'bati'}, - [7] = {coords = vec4(-50.66, -1093.05, 25.44, 222.5), vehicle = 'bati'}, - [8] = {coords = vec4(-44.28, -1102.47, 25.44, 298.5), vehicle = 'bati'} - }, - }, - - luxury = { - type = 'managed', - job = 'cardealer', - zone = { - shape = { - vec3(-1260.6973876953, -349.21334838867, 36.91), - vec3(-1268.6248779297, -352.87365722656, 36.91), - vec3(-1274.1533203125, -358.29794311523, 36.91), - vec3(-1273.8425292969, -362.73715209961, 36.91), - vec3(-1270.5701904297, -368.6716003418, 36.91), - vec3(-1266.0561523438, -375.14080810547, 36.91), - vec3(-1244.3684082031, -362.70278930664, 36.91), - vec3(-1249.8704833984, -352.03326416016, 36.91), - vec3(-1252.9503173828, -345.85726928711, 36.91) - }, - size = vec3(3, 3, 4), - targetDistance = 1, - }, - blip = { - label = 'Luxury Vehicle Shop', - coords = vec3(-1255.6, -361.16, 36.91), - show = true, - sprite = 326, - color = 3, - }, - categories = { - super = 'Super', - sports = 'Sports' - }, - testDrive = { - limit = 5.0, - spawn = vec4(-1232.81, -347.99, 37.33, 23.28), - }, - returnLocation = vec3(-1231.46, -349.86, 37.33), - vehicleSpawn = vec4(-1231.46, -349.86, 37.33, 26.61), - showroomVehicles = { - [1] = {coords = vec4(-1265.31, -354.44, 35.91, 205.08), vehicle = 'italirsx'}, - [2] = {coords = vec4(-1270.06, -358.55, 35.91, 247.08), vehicle = 'italigtb'}, - [3] = {coords = vec4(-1269.21, -365.03, 35.91, 297.12), vehicle = 'nero'}, - [4] = {coords = vec4(-1252.07, -364.2, 35.91, 56.44), vehicle = 'bati'}, - [5] = {coords = vec4(-1255.49, -365.91, 35.91, 55.63), vehicle = 'carbonrs'}, - [6] = {coords = vec4(-1249.21, -362.97, 35.91, 53.24), vehicle = 'hexer'}, - } - }, - - boats = { - type = 'free-use', - zone = { - shape = { - vec3(-729.39, -1315.84, 0), - vec3(-766.81, -1360.11, 0), - vec3(-754.21, -1371.49, 0), - vec3(-716.94, -1326.88, 0) - }, - size = vec3(8, 8, 6), - targetDistance = 10, - }, - blip = { - label = 'Marina Shop', - coords = vec3(-738.25, -1334.38, 1.6), - show = true, - sprite = 410, - color = 3, - }, - categories = { - boats = 'Boats' - }, - testDrive = { - limit = 5.0, - spawn = vec4(-722.23, -1351.98, 0.14, 135.33), - }, - returnLocation = vec3(-714.34, -1343.31, 0.0), - vehicleSpawn = vec4(-727.87, -1353.1, -0.17, 137.09), - showroomVehicles = { - [1] = {coords = vec4(-727.05, -1326.59, -0.50, 229.5), vehicle = 'seashark'}, - [2] = {coords = vec4(-732.84, -1333.5, -0.50, 229.5), vehicle = 'dinghy'}, - [3] = {coords = vec4(-737.84, -1340.83, -0.50, 229.5), vehicle = 'speeder'}, - [4] = {coords = vec4(-741.53, -1349.7, -0.50, 229.5), vehicle = 'marquis'}, - }, - }, - - air = { - type = 'free-use', - zone = { - shape = { - vec3(-1607.58, -3141.7, 12.99), - vec3(-1672.54, -3103.87, 12.99), - vec3(-1703.49, -3158.02, 12.99), - vec3(-1646.03, -3190.84, 12.99) - }, - size = vec3(10, 10, 8), - targetDistance = 5, - }, - blip = { - label = 'Air Shop', - coords = vec3(-1652.76, -3143.4, 13.99), - show = true, - sprite = 251, - color = 3, - }, - categories = { - helicopters = 'Helicopters', - planes = 'Planes' - }, - testDrive = { - limit = 5.0, - spawn = vec4(-1625.19, -3103.47, 13.94, 330.28), - }, - returnLocation = vec3(-1628.44, -3104.7, 13.94), - vehicleSpawn = vec4(-1617.49, -3086.17, 13.94, 329.2), - showroomVehicles = { - [1] = {coords = vec4(-1651.36, -3162.66, 12.99, 346.89), vehicle = 'volatus'}, - [2] = {coords = vec4(-1668.53, -3152.56, 12.99, 303.22), vehicle = 'luxor2'}, - [3] = {coords = vec4(-1632.02, -3144.48, 12.99, 31.08), vehicle = 'nimbus'}, - [4] = {coords = vec4(-1663.74, -3126.32, 12.99, 275.03), vehicle = 'frogger'}, - }, - }, - }, - vehicles = { asbo = { shop = 'pdm', diff --git a/config/shared.lua b/config/shared.lua index d7e60b4..e8354b4 100644 --- a/config/shared.lua +++ b/config/shared.lua @@ -2,5 +2,220 @@ return { finance = { minimumDown = 10, -- minimum percentage allowed down maximumPayments = 24, -- maximum payments allowed - } + }, + shops = { + --[[shop = { -- Needs to be unique + type = '', -- If 'free-use', no player-to-player interaction required to purchase. If 'managed', caresalesman required for purchase + job = '', -- If shop is 'free-use', remove this option. If shop is 'managed', put required job + zone = { + shape = { -- Polygon that surrounds the shop + vec3(0.0, 0.0, 0.0), + vec3(0.0, 0.0, 0.0), + vec3(0.0, 0.0, 0.0), + vec3(0.0, 0.0, 0.0), + }, + size = vec3(0.0, 0.0, 0.0), -- Size of the vehicles zones (x, y, z) + targetDistance = 1, -- Defines targeting distance. Only works if useTarget is enabled + }, + blip = { + label = '', -- Blip label + coords = vec3(0.0, 0.0, 0.0), -- Blip coordinates + show = true, -- Enables/disables the blip being shown + sprite = 0, -- Blip sprite + color = 0, -- Blip color + }, + categories = { -- Categories available to browse + sedans = 'Sedans', + coupes = 'Coupes', + suvs = 'SUVs', + offroad = 'Offroad', + }, + testDrive = { + limit = 5.0, -- Time in minutes allotted for the test drive + spawn = vec4(0.0, 0.0, 0.0, 0.0), -- Spawn location for the test drive + }, + returnLocation = vec3(0.0, -1082.58, 26.68), -- Location to return vehicle only if the vehicleshop is managed + vehicleSpawn = vec4(0.0, 0.0, 0.0, 0.0), -- Spawn location when vehicle is purchased + showroomVehicles = { + [1] = { + coords = vec4(0.0, 0.0, 0.0, 0.0), -- where the vehicle will spawn on display + vehicle = '', -- Model name of display vehicle. Is dynamically changed when swapping vehicles + }, + [2] = { + coords = vec4(0.0, 0.0, 0.0, 0.0), -- where the vehicle will spawn on display + vehicle = '', -- Model name of display vehicle. Is dynamically changed when swapping vehicles + }, + }, + },]]-- + pdm = { + type = 'free-use', + zone = { + shape = { + vec3(-56.727394104004, -1086.2325439453, 26.0), + vec3(-60.612808227539, -1096.7795410156, 26.0), + vec3(-58.26834487915, -1100.572265625, 26.0), + vec3(-35.927803039551, -1109.0034179688, 26.0), + vec3(-34.427627563477, -1108.5111083984, 26.0), + vec3(-32.02657699585, -1101.5877685547, 26.0), + vec3(-33.342102050781, -1101.0377197266, 26.0), + vec3(-31.292987823486, -1095.3717041016, 26.0) + }, + size = vec3(3, 3, 4), + targetDistance = 1, + }, + blip = { + label = 'Premium Deluxe Motorsport', + coords = vec3(-45.67, -1098.34, 26.42), + show = true, + sprite = 326, + color = 3, + }, + categories = { + sportsclassics = 'Sports Classics', + sedans = 'Sedans', + coupes = 'Coupes', + suvs = 'SUVs', + offroad = 'Offroad', + muscle = 'Muscle', + compacts = 'Compacts', + motorcycles = 'Motorcycles', + vans = 'Vans', + cycles = 'Bicycles' + }, + testDrive = { + limit = 5.0, + spawn = vec4(-7.84, -1081.35, 26.67, 121.83), + }, + returnLocation = vec3(-44.74, -1082.58, 26.68), + vehicleSpawn = vec4(-31.69, -1090.78, 26.42, 328.79), + showroomVehicles = { + [1] = {coords = vec4(-45.65, -1093.66, 25.44, 69.5), vehicle = 'adder'}, + [2] = {coords = vec4(-48.27, -1101.86, 25.44, 294.5), vehicle = 'schafter2'}, + [3] = {coords = vec4(-39.6, -1096.01, 25.44, 66.5), vehicle = 'comet2'}, + [4] = {coords = vec4(-51.21, -1096.77, 25.44, 254.5), vehicle = 'vigero'}, + [5] = {coords = vec4(-40.18, -1104.13, 25.44, 338.5), vehicle = 't20'}, + [6] = {coords = vec4(-43.31, -1099.02, 25.44, 52.5), vehicle = 'bati'}, + [7] = {coords = vec4(-50.66, -1093.05, 25.44, 222.5), vehicle = 'bati'}, + [8] = {coords = vec4(-44.28, -1102.47, 25.44, 298.5), vehicle = 'bati'} + }, + }, + + luxury = { + type = 'managed', + job = 'cardealer', + zone = { + shape = { + vec3(-1260.6973876953, -349.21334838867, 36.91), + vec3(-1268.6248779297, -352.87365722656, 36.91), + vec3(-1274.1533203125, -358.29794311523, 36.91), + vec3(-1273.8425292969, -362.73715209961, 36.91), + vec3(-1270.5701904297, -368.6716003418, 36.91), + vec3(-1266.0561523438, -375.14080810547, 36.91), + vec3(-1244.3684082031, -362.70278930664, 36.91), + vec3(-1249.8704833984, -352.03326416016, 36.91), + vec3(-1252.9503173828, -345.85726928711, 36.91) + }, + size = vec3(3, 3, 4), + targetDistance = 1, + }, + blip = { + label = 'Luxury Vehicle Shop', + coords = vec3(-1255.6, -361.16, 36.91), + show = true, + sprite = 326, + color = 3, + }, + categories = { + super = 'Super', + sports = 'Sports' + }, + testDrive = { + limit = 5.0, + spawn = vec4(-1232.81, -347.99, 37.33, 23.28), + }, + returnLocation = vec3(-1231.46, -349.86, 37.33), + vehicleSpawn = vec4(-1231.46, -349.86, 37.33, 26.61), + showroomVehicles = { + [1] = {coords = vec4(-1265.31, -354.44, 35.91, 205.08), vehicle = 'italirsx'}, + [2] = {coords = vec4(-1270.06, -358.55, 35.91, 247.08), vehicle = 'italigtb'}, + [3] = {coords = vec4(-1269.21, -365.03, 35.91, 297.12), vehicle = 'nero'}, + [4] = {coords = vec4(-1252.07, -364.2, 35.91, 56.44), vehicle = 'bati'}, + [5] = {coords = vec4(-1255.49, -365.91, 35.91, 55.63), vehicle = 'carbonrs'}, + [6] = {coords = vec4(-1249.21, -362.97, 35.91, 53.24), vehicle = 'hexer'}, + } + }, + + boats = { + type = 'free-use', + zone = { + shape = { + vec3(-729.39, -1315.84, 0), + vec3(-766.81, -1360.11, 0), + vec3(-754.21, -1371.49, 0), + vec3(-716.94, -1326.88, 0) + }, + size = vec3(8, 8, 6), + targetDistance = 10, + }, + blip = { + label = 'Marina Shop', + coords = vec3(-738.25, -1334.38, 1.6), + show = true, + sprite = 410, + color = 3, + }, + categories = { + boats = 'Boats' + }, + testDrive = { + limit = 5.0, + spawn = vec4(-722.23, -1351.98, 0.14, 135.33), + }, + returnLocation = vec3(-714.34, -1343.31, 0.0), + vehicleSpawn = vec4(-727.87, -1353.1, -0.17, 137.09), + showroomVehicles = { + [1] = {coords = vec4(-727.05, -1326.59, -0.50, 229.5), vehicle = 'seashark'}, + [2] = {coords = vec4(-732.84, -1333.5, -0.50, 229.5), vehicle = 'dinghy'}, + [3] = {coords = vec4(-737.84, -1340.83, -0.50, 229.5), vehicle = 'speeder'}, + [4] = {coords = vec4(-741.53, -1349.7, -0.50, 229.5), vehicle = 'marquis'}, + }, + }, + + air = { + type = 'free-use', + zone = { + shape = { + vec3(-1607.58, -3141.7, 12.99), + vec3(-1672.54, -3103.87, 12.99), + vec3(-1703.49, -3158.02, 12.99), + vec3(-1646.03, -3190.84, 12.99) + }, + size = vec3(10, 10, 8), + targetDistance = 5, + }, + blip = { + label = 'Air Shop', + coords = vec3(-1652.76, -3143.4, 13.99), + show = true, + sprite = 251, + color = 3, + }, + categories = { + helicopters = 'Helicopters', + planes = 'Planes' + }, + testDrive = { + limit = 5.0, + spawn = vec4(-1625.19, -3103.47, 13.94, 330.28), + }, + returnLocation = vec3(-1628.44, -3104.7, 13.94), + vehicleSpawn = vec4(-1617.49, -3086.17, 13.94, 329.2), + showroomVehicles = { + [1] = {coords = vec4(-1651.36, -3162.66, 12.99, 346.89), vehicle = 'volatus'}, + [2] = {coords = vec4(-1668.53, -3152.56, 12.99, 303.22), vehicle = 'luxor2'}, + [3] = {coords = vec4(-1632.02, -3144.48, 12.99, 31.08), vehicle = 'nimbus'}, + [4] = {coords = vec4(-1663.74, -3126.32, 12.99, 275.03), vehicle = 'frogger'}, + }, + }, + }, } \ No newline at end of file From 556ce13e3d4087515b6dd0fe873babe12b374be9 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:59:17 +0100 Subject: [PATCH 12/23] chore: code cleanup --- client/main.lua | 21 ++++----------------- server/finance.lua | 4 ---- server/main.lua | 21 --------------------- 3 files changed, 4 insertions(+), 42 deletions(-) diff --git a/client/main.lua b/client/main.lua index c2f36e2..848c393 100644 --- a/client/main.lua +++ b/client/main.lua @@ -97,8 +97,10 @@ local function showFinancedVehiclesMenu() for _, v in pairs(vehicles) do if v.balance and v.balance > 0 then + local plate = v.props.plate + plate = plate and plate:upper() + local vehicle = VEHICLES[v.modelName] - local plate = v.plate:upper() ownedVehicles[#ownedVehicles + 1] = { title = vehicle.name, description = locale('menus.veh_platetxt')..plate, @@ -619,7 +621,7 @@ RegisterNetEvent('qbx_vehicleshop:client:testDrive', function(args) local testDrive = sharedConfig.shops[insideShop].testDrive local plate = 'TEST'..lib.string.random('1111') local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, { - model = args.vehicle, + modelName = args.vehicle, coords = testDrive.spawn, plate = plate }) @@ -662,21 +664,6 @@ RegisterNetEvent('qbx_vehicleshop:client:swapVehicle', function(data) if config.useTarget then createVehicleTarget(shopName, veh, data.targetVehicle) end end) ---- Buys the selected vehicle ----@param vehicle number ----@param plate string -RegisterNetEvent('qbx_vehicleshop:client:buyShowroomVehicle', function(vehicle, plate, vehicleId) - local tempShop = insideShop -- temp hacky way of setting the shop because it changes after the callback has returned since you are outside the zone - local netId = lib.callback.await('qbx_vehicleshop:server:spawnVehicle', false, { - model = vehicle, - coords = config.shops[tempShop].vehicleSpawn, - plate = plate, - vehicleId = vehicleId - }) - local veh = NetToVeh(netId) - local props = lib.getVehicleProperties(veh) - props.plate = plate - TriggerServerEvent('qb-vehicletuning:server:SaveVehicleProps', props) end) local function confirmTrade(confirmationText) diff --git a/server/finance.lua b/server/finance.lua index 92af642..fe3462d 100644 --- a/server/finance.lua +++ b/server/finance.lua @@ -1,7 +1,6 @@ ---@class InsertVehicleEntityRequest ---@field citizenId string ---@field model string ----@field plate string ---@class VehicleFinanceServer ---@field balance number @@ -28,9 +27,6 @@ function finance.insertVehicleEntityWithFinance(request) local vehicleId = exports.qbx_vehicles:CreatePlayerVehicle({ model = insertVehicleEntityRequest.model, citizenid = insertVehicleEntityRequest.citizenId, - props = { - plate = insertVehicleEntityRequest.plate - } }) local vehicleFinance = request.vehicleFinance diff --git a/server/main.lua b/server/main.lua index 6115021..c035297 100644 --- a/server/main.lua +++ b/server/main.lua @@ -80,15 +80,6 @@ local function calculateNewFinance(paymentAmount, vehData) return qbx.math.round(newBalance), qbx.math.round(newPayment), newPaymentsLeft end -local function generateUniquePlate() - local plate - repeat - plate = qbx.generateRandomPlate('111AA11A') - Wait(0) - until not exports.qbx_vehicles:DoesPlayerVehiclePlateExist(plate) - return plate -end - -- Callbacks lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(source) local src = source @@ -251,13 +242,9 @@ RegisterNetEvent('qbx_vehicleshop:server:buyShowroomVehicle', function(vehicle) return exports.qbx_core:Notify(src, locale('error.notenoughmoney'), 'error') end - local plate = generateUniquePlate() local vehicleId = exports.qbx_vehicles:CreatePlayerVehicle({ model = vehicle, citizenid = player.PlayerData.citizenid, - props = { - plate = plate - } }) exports.qbx_core:Notify(src, locale('success.purchased'), 'success') TriggerClientEvent('qbx_vehicleshop:client:buyShowroomVehicle', src, vehicle, plate, vehicleId) @@ -289,7 +276,6 @@ RegisterNetEvent('qbx_vehicleshop:server:financeVehicle', function(downPayment, return exports.qbx_core:Notify(src, locale('error.notenoughmoney'), 'error') end - local plate = generateUniquePlate() local balance, vehPaymentAmount = calculateFinance(vehiclePrice, downPayment, paymentAmount) local cid = player.PlayerData.citizenid local timer = (config.finance.paymentInterval * 60) @@ -298,7 +284,6 @@ RegisterNetEvent('qbx_vehicleshop:server:financeVehicle', function(downPayment, insertVehicleEntityRequest = { citizenId = cid, model = vehicle, - plate = plate, }, vehicleFinance = { balance = balance, @@ -308,7 +293,6 @@ RegisterNetEvent('qbx_vehicleshop:server:financeVehicle', function(downPayment, } }) exports.qbx_core:Notify(src, locale('success.purchased'), 'success') - TriggerClientEvent('qbx_vehicleshop:client:buyShowroomVehicle', src, vehicle, plate, vehicleId) player.Functions.RemoveMoney(currencyType, downPayment, 'vehicle-bought-in-showroom') end) @@ -352,7 +336,6 @@ RegisterNetEvent('qbx_vehicleshop:server:sellShowroomVehicle', function(data, pl local vehicle = data local vehiclePrice = coreVehicles[vehicle].price local cid = target.PlayerData.citizenid - local plate = generateUniquePlate() if not sellShowroomVehicleTransact(src, target, vehiclePrice, vehiclePrice) then return end @@ -364,7 +347,6 @@ RegisterNetEvent('qbx_vehicleshop:server:sellShowroomVehicle', function(data, pl } }) - TriggerClientEvent('qbx_vehicleshop:client:buyShowroomVehicle', target.PlayerData.source, vehicle, plate, vehicleId) local shop = sharedConfig.shops[shopId] end) @@ -398,7 +380,6 @@ RegisterNetEvent('qbx_vehicleshop:server:sellfinanceVehicle', function(downPayme local cid = target.PlayerData.citizenid local timer = (config.finance.paymentInterval * 60) - local plate = generateUniquePlate() local balance, vehPaymentAmount = calculateFinance(vehiclePrice, downPayment, paymentAmount) if not sellShowroomVehicleTransact(src, target, vehiclePrice, downPayment) then return end @@ -407,7 +388,6 @@ RegisterNetEvent('qbx_vehicleshop:server:sellfinanceVehicle', function(downPayme insertVehicleEntityRequest = { citizenId = cid, model = vehicle, - plate = plate, }, vehicleFinance = { balance = balance, @@ -417,7 +397,6 @@ RegisterNetEvent('qbx_vehicleshop:server:sellfinanceVehicle', function(downPayme } }) - TriggerClientEvent('qbx_vehicleshop:client:buyShowroomVehicle', target.PlayerData.source, vehicle, plate, vehicleId) end) -- Check if payment is due From 409e83cd18a7ec37668c6c5254937e1aad4a153e Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:59:59 +0100 Subject: [PATCH 13/23] feat: get player current shop id callback --- client/main.lua | 2 ++ server/main.lua | 73 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/client/main.lua b/client/main.lua index 848c393..a44af22 100644 --- a/client/main.lua +++ b/client/main.lua @@ -664,6 +664,8 @@ RegisterNetEvent('qbx_vehicleshop:client:swapVehicle', function(data) if config.useTarget then createVehicleTarget(shopName, veh, data.targetVehicle) end end) +lib.callback.register('qbx_vehicleshop:client:getPlayerCurrentShop', function() + return insideShop end) local function confirmTrade(confirmationText) diff --git a/server/main.lua b/server/main.lua index c035297..cdadfa2 100644 --- a/server/main.lua +++ b/server/main.lua @@ -101,20 +101,6 @@ lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(sourc return vehicles[1] and vehicles end) -lib.callback.register('qbx_vehicleshop:server:spawnVehicle', function(source, data) - local model, coords, plate, vehicleId = data.model, data.coords, data.plate, data.vehicleId - local netId, veh = qbx.spawnVehicle({model = model, spawnSource = coords, warp = GetPlayerPed(source)}) - - if not netId or netId == 0 then return end - - if not veh or veh == 0 then return end - - if vehicleId then Entity(veh).state:set('vehicleid', vehicleId, false) end - - SetVehicleNumberPlateText(veh, plate) - TriggerClientEvent('vehiclekeys:client:SetOwner', source, plate) - return netId -end) -- Events @@ -231,6 +217,26 @@ RegisterNetEvent('qbx_vehicleshop:server:financePaymentFull', function(data) }, vehId) end) +local function spawnVehicle(src, data) + local coords, vehicleId = data.coords, data.vehicleId + local vehicle = vehicleId and exports.qbx_vehicles:GetPlayerVehicle(vehicleId) or data + if not vehicle then return end + + local netId, veh = qbx.spawnVehicle({model = vehicle.modelName, spawnSource = coords, warp = GetPlayerPed(src)}) + + if not netId or netId == 0 then return end + + if not veh or veh == 0 then return end + + if vehicleId then Entity(veh).state:set('vehicleid', vehicleId, false) end + + local plate = vehicle.plate or vehicle.props.plate + SetVehicleNumberPlateText(veh, plate) + TriggerClientEvent('vehiclekeys:client:SetOwner', src, plate) + return netId +end +lib.callback.register('qbx_vehicleshop:server:spawnVehicle', spawnVehicle) + -- Buy public vehicle outright RegisterNetEvent('qbx_vehicleshop:server:buyShowroomVehicle', function(vehicle) local src = source @@ -247,7 +253,15 @@ RegisterNetEvent('qbx_vehicleshop:server:buyShowroomVehicle', function(vehicle) citizenid = player.PlayerData.citizenid, }) exports.qbx_core:Notify(src, locale('success.purchased'), 'success') - TriggerClientEvent('qbx_vehicleshop:client:buyShowroomVehicle', src, vehicle, plate, vehicleId) + + local shopId = lib.callback.await('qbx_vehicleshop:client:getPlayerCurrentShop', src) + local shop = sharedConfig.shops[shopId] + if not shop then return end + + spawnVehicle(src, { + coords = shop.vehicleSpawn, + vehicleId = vehicleId + }) player.Functions.RemoveMoney(currencyType, vehiclePrice, 'vehicle-bought-in-showroom') end) @@ -293,6 +307,17 @@ RegisterNetEvent('qbx_vehicleshop:server:financeVehicle', function(downPayment, } }) exports.qbx_core:Notify(src, locale('success.purchased'), 'success') + + local shopId = lib.callback.await('qbx_vehicleshop:client:getPlayerCurrentShop', src) + + local shop = sharedConfig.shops[shopId] + if not shop then return end + + spawnVehicle(src, { + coords = shop.vehicleSpawn, + vehicleId = vehicleId + }) + player.Functions.RemoveMoney(currencyType, downPayment, 'vehicle-bought-in-showroom') end) @@ -342,12 +367,16 @@ RegisterNetEvent('qbx_vehicleshop:server:sellShowroomVehicle', function(data, pl local vehicleId = exports.qbx_vehicles:CreatePlayerVehicle({ model = vehicle, citizenid = cid, - props = { - plate = plate - } }) + local shopId = lib.callback.await('qbx_vehicleshop:client:getPlayerCurrentShop', target.PlayerData.source) local shop = sharedConfig.shops[shopId] + if not shop then return end + + spawnVehicle(src, { + coords = shop.vehicleSpawn, + vehicleId = vehicleId + }) end) -- Finance vehicle to customer @@ -397,6 +426,14 @@ RegisterNetEvent('qbx_vehicleshop:server:sellfinanceVehicle', function(downPayme } }) + local shopId = lib.callback.await('qbx_vehicleshop:client:getPlayerCurrentShop', target.PlayerData.source) + local shop = sharedConfig.shops[shopId] + if not shop then return end + + spawnVehicle(src, { + coords = shop.vehicleSpawn, + vehicleId = vehicleId + }) end) -- Check if payment is due From 4ca5c1ca7847624eff12f916de6958120ba83b92 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:07:48 +0100 Subject: [PATCH 14/23] type: spawnVehicle typing --- server/main.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/main.lua b/server/main.lua index cdadfa2..427fd71 100644 --- a/server/main.lua +++ b/server/main.lua @@ -100,8 +100,6 @@ lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(sourc end return vehicles[1] and vehicles end) - - -- Events -- Brute force vehicle deletion @@ -217,6 +215,9 @@ RegisterNetEvent('qbx_vehicleshop:server:financePaymentFull', function(data) }, vehId) end) +---@param src number +---@param data {coords: vector4, vehicleId: number, modelName: string, plate?: string} +---@return number|nil local function spawnVehicle(src, data) local coords, vehicleId = data.coords, data.vehicleId local vehicle = vehicleId and exports.qbx_vehicles:GetPlayerVehicle(vehicleId) or data From 3d31fe8c171b0c25da12caa8cc84e18ec7d0180f Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:40:39 +0100 Subject: [PATCH 15/23] perf: numerical for loop --- server/main.lua | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/server/main.lua b/server/main.lua index 427fd71..baa18d5 100644 --- a/server/main.lua +++ b/server/main.lua @@ -18,7 +18,8 @@ RegisterNetEvent('qbx_vehicleshop:server:removePlayer', function(citizenid) local playTime = financeTimer[citizenid] local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(citizenid) - for _, v in ipairs(vehicles) do + for i = 1, #vehicles do + local v = vehicles[i] if v.balance >= 1 then local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60)) if newTime < 0 then newTime = 0 end @@ -36,7 +37,8 @@ AddEventHandler('playerDropped', function() if not license then return end local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(license) if not vehicles then return end - for _, v in ipairs(vehicles) do + for i = 1, #vehicles do + local v = vehicles[i] local playTime = financeTimer[v.citizenid] if v.balance >= 1 and playTime then local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60)) @@ -91,7 +93,8 @@ lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(sourc }) local financeVehicles = require 'server.finance'.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) - for _, v in ipairs(financeVehicles) do + for i = 1, #financeVehicles do + local v = financeVehicles[i] local vehicle = vehicles[v.vehicleId] vehicle.balance = v.balance vehicle.paymentamount = v.paymentamount @@ -441,14 +444,13 @@ end) RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() local src = source local player = exports.qbx_core:GetPlayer(src) - local finance = require 'server.finance' - local result = finance.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) - if not result[1] then return end exports.qbx_core:Notify(src, locale('general.paymentduein', config.finance.paymentWarning)) Wait(config.finance.paymentWarning * 60000) - local vehicles = finance.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) - for _, v in ipairs(vehicles) do + + local vehicles = require 'server.finance'.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) + for i = 1, #vehicles do + local v = vehicles[i] local plate = v.plate if config.deleteUnpaidFinancedVehicle then exports.qbx_vehicles:DeletePlayerVehicles('vehicleId', v.id) From fdd5475809d8acbf4168a484737a5157252c0e15 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:42:54 +0100 Subject: [PATCH 16/23] fix: remove local var and use statebag --- client/main.lua | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/client/main.lua b/client/main.lua index a44af22..625494e 100644 --- a/client/main.lua +++ b/client/main.lua @@ -3,7 +3,6 @@ local sharedConfig = require 'config.shared' local VEHICLES = exports.qbx_core:GetVehiclesByName() local VEHICLES_HASH = exports.qbx_core:GetVehiclesByHash() local testDriveVeh = 0 -local inTestDrive = false local insideShop = nil ---@class VehicleFinanceClient @@ -435,17 +434,9 @@ end local function endTestDrive() TriggerServerEvent('qbx_vehicleshop:server:deleteVehicle', testDriveVeh) testDriveVeh = 0 - inTestDrive = false LocalPlayer.state:set('isInTestDrive', false, true) exports.qbx_core:Notify(locale('general.testdrive_complete'), 'success') end - -RegisterCommand('endtestdrive', function() - if not inTestDrive then return end - - endTestDrive() -end, false) - --- Starts the test drive timer based on time and shop ---@param time number local function startTestDriveTimer(time) @@ -453,7 +444,8 @@ local function startTestDriveTimer(time) local timeMs = time * 1000 CreateThread(function() - while inTestDrive do + local playerState = LocalPlayer.state + while playerState.isInTestDrive do local currentGameTime = GetGameTimer() local secondsLeft = currentGameTime - gameTimer if currentGameTime < gameTimer + timeMs and secondsLeft >= timeMs - 50 then @@ -609,14 +601,13 @@ end) --- Starts the test drive. If vehicle parameter is not provided then the test drive will start with the closest vehicle to the player. --- @param args table RegisterNetEvent('qbx_vehicleshop:client:testDrive', function(args) - if inTestDrive then + if LocalPlayer.state.isInTestDrive then exports.qbx_core:Notify(locale('error.testdrive_alreadyin'), 'error') return end if not args then return end - inTestDrive = true LocalPlayer.state:set('isInTestDrive', true, true) local testDrive = sharedConfig.shops[insideShop].testDrive local plate = 'TEST'..lib.string.random('1111') From 37fec6daab9e43e137ea4309b8caa7ddb908573e Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:43:25 +0100 Subject: [PATCH 17/23] fix: set plate in core API instead --- server/main.lua | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/server/main.lua b/server/main.lua index baa18d5..a74b965 100644 --- a/server/main.lua +++ b/server/main.lua @@ -226,7 +226,16 @@ local function spawnVehicle(src, data) local vehicle = vehicleId and exports.qbx_vehicles:GetPlayerVehicle(vehicleId) or data if not vehicle then return end - local netId, veh = qbx.spawnVehicle({model = vehicle.modelName, spawnSource = coords, warp = GetPlayerPed(src)}) + local plate = vehicle.plate or vehicle.props.plate + + local netId, veh = qbx.spawnVehicle({ + model = vehicle.modelName, + spawnSource = coords, + warp = GetPlayerPed(src), + props = { + plate + } + }) if not netId or netId == 0 then return end @@ -234,8 +243,6 @@ local function spawnVehicle(src, data) if vehicleId then Entity(veh).state:set('vehicleid', vehicleId, false) end - local plate = vehicle.plate or vehicle.props.plate - SetVehicleNumberPlateText(veh, plate) TriggerClientEvent('vehiclekeys:client:SetOwner', src, plate) return netId end From b5384e05c2bf125e505efb647fad347476213cdf Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:49:27 +0100 Subject: [PATCH 18/23] fix: right plate variable --- server/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/main.lua b/server/main.lua index a74b965..7ecae7a 100644 --- a/server/main.lua +++ b/server/main.lua @@ -546,7 +546,7 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl target.Functions.RemoveMoney(currencyType, sellAmount) end qbx_vehicles:SetPlayerVehicleOwner(row.id, targetcid) - TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, row.plate) + TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, row.props.plate) local sellerMessage = sellAmount > 0 and locale('success.soldfor') .. lib.math.groupdigits(sellAmount) or locale('success.gifted') local buyerMessage = sellAmount > 0 and locale('success.boughtfor') .. lib.math.groupdigits(sellAmount) or locale('success.received_gift') qbx_core:Notify(src, sellerMessage, 'success') From 9fbc52e022dfa748a0c249cf94025881414b3fca Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:00:19 +0100 Subject: [PATCH 19/23] fix: typing --- server/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/main.lua b/server/main.lua index 7ecae7a..95819a7 100644 --- a/server/main.lua +++ b/server/main.lua @@ -219,7 +219,7 @@ RegisterNetEvent('qbx_vehicleshop:server:financePaymentFull', function(data) end) ---@param src number ----@param data {coords: vector4, vehicleId: number, modelName: string, plate?: string} +---@param data {coords: vector4, vehicleId?: number, modelName: string, plate?: string, props?: {plate: string}} ---@return number|nil local function spawnVehicle(src, data) local coords, vehicleId = data.coords, data.vehicleId From c5a2ee9b83398cde6b820b4b069116e5d8ee5137 Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:01:14 +0100 Subject: [PATCH 20/23] fix: use qbx_vehicles API / localize --- server/main.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/main.lua b/server/main.lua index 95819a7..16f4ddd 100644 --- a/server/main.lua +++ b/server/main.lua @@ -450,9 +450,10 @@ end) -- Check if payment is due RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() local src = source - local player = exports.qbx_core:GetPlayer(src) + local qbx_core = exports.qbx_core + local player = qbx_core:GetPlayer(src) - exports.qbx_core:Notify(src, locale('general.paymentduein', config.finance.paymentWarning)) + qbx_core:Notify(src, locale('general.paymentduein', config.finance.paymentWarning)) Wait(config.finance.paymentWarning * 60000) local vehicles = require 'server.finance'.fetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid) @@ -462,10 +463,10 @@ RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() if config.deleteUnpaidFinancedVehicle then exports.qbx_vehicles:DeletePlayerVehicles('vehicleId', v.id) else - MySQL.update('UPDATE player_vehicles SET citizenid = ? WHERE id = ?', {'REPO-'..v.citizenid, v.id}) -- Use this if you don't want them to be deleted + exports.qbx_vehicles:SetPlayerVehicleOwner(v.id, 'REPO-'..v.citizenid) end - exports.qbx_core:Notify(src, locale('error.repossessed', plate), 'error') + qbx_core:Notify(src, locale('error.repossessed', plate), 'error') end end) From 432ff56f9710667fc392c9740e70df3ab9e567fb Mon Sep 17 00:00:00 2001 From: Frowmza <66181451+Frowmza@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:01:49 +0100 Subject: [PATCH 21/23] feat: locale for not owned vehicle --- locales/cs.json | 1 + locales/de.json | 1 + locales/en.json | 167 ++++++++++++++++++++++++------------------------ locales/es.json | 1 + locales/fr.json | 1 + locales/hu.json | 1 + locales/nl.json | 1 + locales/ro.json | 1 + server/main.lua | 4 +- 9 files changed, 94 insertions(+), 84 deletions(-) diff --git a/locales/cs.json b/locales/cs.json index 07931a8..75d679d 100644 --- a/locales/cs.json +++ b/locales/cs.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "Vozidlo nevlastní!", "testdrive_alreadyin": "Uz jsi v testovaci jizde!", "testdrive_return": "Toto neni vozidlo, ktere jsi testoval", "Invalid_ID": "Spatne ID", diff --git a/locales/de.json b/locales/de.json index fa7ec34..343c2fd 100644 --- a/locales/de.json +++ b/locales/de.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "Fahrzeug nicht im Besitz!", "testdrive_alreadyin": "Bereits in der Probefahrt", "testdrive_return": "Dies ist kein Fahrzeug für eine Probefahrt", "Invalid_ID": "Ungültige Bürger-ID angegeben", diff --git a/locales/en.json b/locales/en.json index b321a96..38f4175 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1,83 +1,84 @@ -{ - "error": { - "testdrive_alreadyin": "Already in test drive", - "testdrive_return": "This is not your test drive vehicle", - "Invalid_ID": "Invalid Player Id Supplied", - "playertoofar": "This player is not close enough", - "notenoughmoney": "Not enough money", - "minimumallowed": "Minimum payment allowed is $", - "overpaid": "You overpaid", - "alreadypaid": "Vehicle is already paid off", - "notworth": "Vehicle is not worth that much", - "downtoosmall": "Down payment too small", - "exceededmax": "Exceeded maximum payment amount", - "repossessed": "Your vehicle with plate %s has been repossessed", - "buyerinfo": "Couldn't get buyer info", - "notinveh": "You must be in the vehicle you want to transfer", - "vehinfo": "Couldn't get vehicle info", - "notown": "You don't own this vehicle", - "buyertoopoor": "The buyer doesn't have enough money", - "nofinanced": "You don't have any financed vehicles", - "financed": "This vehicle is financed", - "buyerdeclined": "The player declined the transaction", - "selftransfer": "You can't transfer to yourself", - "sale_timeout": "Wait a while before trading your vehicle" - }, - "success": { - "purchased": "Congratulations on your purchase!", - "earned_commission": "You earned $ %s in commission", - "gifted": "You gifted your vehicle", - "received_gift": "You were gifted a vehicle", - "soldfor": "You sold your vehicle for $", - "boughtfor": "You bought a vehicle for $" - }, - "menus": { - "vehHeader_header": "Vehicle Options", - "vehHeader_txt": "Interact with the current vehicle", - "financed_header": "Financed Vehicles", - "finance_txt": "Browse your owned vehicles", - "returnTestDrive_header": "Finish Test Drive", - "categories_header": "Categories", - "goback_header": "Go Back", - "veh_price": "Price: $", - "veh_platetxt": "Plate: ", - "veh_finance": "Vehicle Payment", - "veh_finance_balance": "Total Balance Remaining", - "veh_finance_currency": "$", - "veh_finance_total": "Total Payments Remaining", - "veh_finance_reccuring": "Recurring Payment Amount", - "veh_finance_pay": "Make a payment", - "veh_finance_payoff": "Payoff vehicle", - "veh_finance_payment": "Payment Amount ($)", - "submit_text": "Submit", - "test_header": "Test Drive", - "finance_header": "Finance Vehicle", - "owned_vehicles_header": "Owned Vehicles", - "swap_header": "Swap Vehicle", - "swap_txt": "Change currently selected vehicle", - "financesubmit_downpayment": "Down Payment Amount - Min ", - "financesubmit_totalpayment": "Total Payments - Max ", - "freeuse_test_txt": "Test drive currently selected vehicle", - "freeuse_buy_header": "Buy Vehicle", - "freeuse_buy_txt": "Purchase currently selected vehicle", - "freeuse_finance_txt": "Finance currently selected vehicle", - "managed_test_txt": "Allow player for test drive", - "managed_sell_header": "Sell Vehicle", - "managed_sell_txt": "Sell vehicle to Player", - "managed_finance_txt": "Finance vehicle to Player", - "submit_ID": "Server ID (#)", - "keypress_showFinanceMenu": "[E] Open Finance Menu", - "keypress_vehicleViewMenu": "[E] View Vehicle" - }, - "general": { - "testdrive_timer": "Test Drive Time Remaining: ", - "vehinteraction": "Vehicle Interaction", - "testdrive_timenoti": "You have %s minutes remaining", - "testdrive_complete": "Vehicle test drive complete", - "paymentduein": "Your vehicle payment is due within %s minutes", - "command_transfervehicle": "Gift or sell your vehicle", - "command_transfervehicle_help": "ID of buyer", - "command_transfervehicle_amount": "Sell amount (optional)", - "transfervehicle_confirm": "Confirm trade of %s %s for $ %s" - } -} +{ + "error": { + "notowned": "Vehicle not owned", + "testdrive_alreadyin": "Already in test drive", + "testdrive_return": "This is not your test drive vehicle", + "Invalid_ID": "Invalid Player Id Supplied", + "playertoofar": "This player is not close enough", + "notenoughmoney": "Not enough money", + "minimumallowed": "Minimum payment allowed is $", + "overpaid": "You overpaid", + "alreadypaid": "Vehicle is already paid off", + "notworth": "Vehicle is not worth that much", + "downtoosmall": "Down payment too small", + "exceededmax": "Exceeded maximum payment amount", + "repossessed": "Your vehicle with plate %s has been repossessed", + "buyerinfo": "Couldn't get buyer info", + "notinveh": "You must be in the vehicle you want to transfer", + "vehinfo": "Couldn't get vehicle info", + "notown": "You don't own this vehicle", + "buyertoopoor": "The buyer doesn't have enough money", + "nofinanced": "You don't have any financed vehicles", + "financed": "This vehicle is financed", + "buyerdeclined": "The player declined the transaction", + "selftransfer": "You can't transfer to yourself", + "sale_timeout": "Wait a while before trading your vehicle" + }, + "success": { + "purchased": "Congratulations on your purchase!", + "earned_commission": "You earned $ %s in commission", + "gifted": "You gifted your vehicle", + "received_gift": "You were gifted a vehicle", + "soldfor": "You sold your vehicle for $", + "boughtfor": "You bought a vehicle for $" + }, + "menus": { + "vehHeader_header": "Vehicle Options", + "vehHeader_txt": "Interact with the current vehicle", + "financed_header": "Financed Vehicles", + "finance_txt": "Browse your owned vehicles", + "returnTestDrive_header": "Finish Test Drive", + "categories_header": "Categories", + "goback_header": "Go Back", + "veh_price": "Price: $", + "veh_platetxt": "Plate: ", + "veh_finance": "Vehicle Payment", + "veh_finance_balance": "Total Balance Remaining", + "veh_finance_currency": "$", + "veh_finance_total": "Total Payments Remaining", + "veh_finance_reccuring": "Recurring Payment Amount", + "veh_finance_pay": "Make a payment", + "veh_finance_payoff": "Payoff vehicle", + "veh_finance_payment": "Payment Amount ($)", + "submit_text": "Submit", + "test_header": "Test Drive", + "finance_header": "Finance Vehicle", + "owned_vehicles_header": "Owned Vehicles", + "swap_header": "Swap Vehicle", + "swap_txt": "Change currently selected vehicle", + "financesubmit_downpayment": "Down Payment Amount - Min ", + "financesubmit_totalpayment": "Total Payments - Max ", + "freeuse_test_txt": "Test drive currently selected vehicle", + "freeuse_buy_header": "Buy Vehicle", + "freeuse_buy_txt": "Purchase currently selected vehicle", + "freeuse_finance_txt": "Finance currently selected vehicle", + "managed_test_txt": "Allow player for test drive", + "managed_sell_header": "Sell Vehicle", + "managed_sell_txt": "Sell vehicle to Player", + "managed_finance_txt": "Finance vehicle to Player", + "submit_ID": "Server ID (#)", + "keypress_showFinanceMenu": "[E] Open Finance Menu", + "keypress_vehicleViewMenu": "[E] View Vehicle" + }, + "general": { + "testdrive_timer": "Test Drive Time Remaining: ", + "vehinteraction": "Vehicle Interaction", + "testdrive_timenoti": "You have %s minutes remaining", + "testdrive_complete": "Vehicle test drive complete", + "paymentduein": "Your vehicle payment is due within %s minutes", + "command_transfervehicle": "Gift or sell your vehicle", + "command_transfervehicle_help": "ID of buyer", + "command_transfervehicle_amount": "Sell amount (optional)", + "transfervehicle_confirm": "Confirm trade of %s %s for $ %s" + } +} diff --git a/locales/es.json b/locales/es.json index 48bb89a..094ce6a 100644 --- a/locales/es.json +++ b/locales/es.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "¡Vehículo no propio!", "testdrive_alreadyin": "Ya se encuentra en prueba de manejo", "testdrive_return": "Este no es tu vehículo para prueba de manejo", "Invalid_ID": "ID de jugador inválida", diff --git a/locales/fr.json b/locales/fr.json index ed9db9b..79278b6 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "Véhicule non possédé !", "testdrive_alreadyin": "Déjà dans le test", "testdrive_return": "Ce n'est pas votre véhicule de test", "Invalid_ID": "ID invalide", diff --git a/locales/hu.json b/locales/hu.json index 7640176..36d1abb 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "A jármű nincs a tulajdonában!", "testdrive_alreadyin": "Már próbaút alatt van", "testdrive_return": "Ez nem a te próbajárműved", "Invalid_ID": "Érvénytelen Játékos ID", diff --git a/locales/nl.json b/locales/nl.json index cd4ec04..6b89930 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "Voertuig is geen eigendom!", "testdrive_alreadyin": "Je bent al bezig met een testrit", "testdrive_return": "Dit is niet jouw testrit voertuig", "Invalid_ID": "Ongeldige speler ID", diff --git a/locales/ro.json b/locales/ro.json index 6f3501f..590b7e9 100644 --- a/locales/ro.json +++ b/locales/ro.json @@ -1,5 +1,6 @@ { "error": { + "notowned": "Vehicul nu este deținut!", "testdrive_alreadyin": "Testezi deja un vehicul", "testdrive_return": "Acesta nu este vehiculul tau de test", "Invalid_ID": "S-a furnizat un ID invalid de jucator", diff --git a/server/main.lua b/server/main.lua index 16f4ddd..bb00b01 100644 --- a/server/main.lua +++ b/server/main.lua @@ -502,7 +502,9 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl end local vehicleId = Entity(vehicle).state.vehicleid or qbx_vehicles:GetVehicleIdByPlate(GetVehicleNumberPlateText(vehicle)) - if not vehicleId then return end + if not vehicleId then + return qbx_core:Notify(src, locale('error.notowned'), 'error') + end local player = qbx_core:GetPlayer(src) local target = qbx_core:GetPlayer(buyerId) From f66fd6fd87764bae8066b01a57603912cc9fe5df Mon Sep 17 00:00:00 2001 From: Manason Date: Fri, 30 Aug 2024 05:59:30 -0700 Subject: [PATCH 22/23] set vehicle owner to nil when soft deleting --- server/main.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/main.lua b/server/main.lua index bb00b01..969eea4 100644 --- a/server/main.lua +++ b/server/main.lua @@ -463,7 +463,7 @@ RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function() if config.deleteUnpaidFinancedVehicle then exports.qbx_vehicles:DeletePlayerVehicles('vehicleId', v.id) else - exports.qbx_vehicles:SetPlayerVehicleOwner(v.id, 'REPO-'..v.citizenid) + exports.qbx_vehicles:SetPlayerVehicleOwner(v.id, nil) end qbx_core:Notify(src, locale('error.repossessed', plate), 'error') @@ -563,4 +563,4 @@ local function isFinanced(vehicleId) return require 'server.finance'.fetchIsFinanced(vehicleId) end -exports('IsFinanced', isFinanced) \ No newline at end of file +exports('IsFinanced', isFinanced) From a500b28047242cc16daa33a9fcc26a5e64a7fe19 Mon Sep 17 00:00:00 2001 From: Manason Date: Fri, 30 Aug 2024 06:00:04 -0700 Subject: [PATCH 23/23] fix passing plate prop to spawn vehicle function --- server/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/main.lua b/server/main.lua index 969eea4..7acb705 100644 --- a/server/main.lua +++ b/server/main.lua @@ -233,7 +233,7 @@ local function spawnVehicle(src, data) spawnSource = coords, warp = GetPlayerPed(src), props = { - plate + plate = plate } })