From 6b6667b4c5a20e96d3711e37e6bcfcd46b7efee0 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 14 Dec 2024 22:33:47 +0100 Subject: [PATCH 01/23] Merge pull request #1539 from Kenshiin13/spawn-vehicle feat(es_extended): add promise support for vehicle spawn functions --- [core]/es_extended/client/functions.lua | 25 +++++++-- [core]/es_extended/server/modules/onesync.lua | 54 +++++++++++++------ 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/[core]/es_extended/client/functions.lua b/[core]/es_extended/client/functions.lua index 8c35eae6a..8a577e7e1 100644 --- a/[core]/es_extended/client/functions.lua +++ b/[core]/es_extended/client/functions.lua @@ -530,10 +530,14 @@ end ---@param vehicleModel integer | string The vehicle to spawn ---@param coords table | vector3 The coords to spawn the vehicle at ---@param heading number The heading of the vehicle ----@param cb? function The callback function +---@param cb? fun(vehicle: number) The callback function ---@param networked? boolean Whether the vehicle should be networked ----@return nil +---@return number? vehicle function ESX.Game.SpawnVehicle(vehicleModel, coords, heading, cb, networked) + if cb and not ESX.IsFunctionReference(cb) then + error("Invalid callback function") + end + local model = type(vehicleModel) == "number" and vehicleModel or joaat(vehicleModel) local vector = type(coords) == "vector3" and coords or vec(coords.x, coords.y, coords.z) local isNetworked = networked == nil or networked @@ -549,8 +553,15 @@ function ESX.Game.SpawnVehicle(vehicleModel, coords, heading, cb, networked) return error(("Resource ^5%s^1 Tried to spawn vehicle on the client but the position is too far away (Out of onesync range)."):format(executingResource)) end + local promise = not cb and promise.new() CreateThread(function() - ESX.Streaming.RequestModel(model) + local modelHash = ESX.Streaming.RequestModel(model) + if not modelHash then + if promise then + return promise:reject(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) + end + error(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) + end local vehicle = CreateVehicle(model, vector.x, vector.y, vector.z, heading, isNetworked, true) @@ -569,10 +580,16 @@ function ESX.Game.SpawnVehicle(vehicleModel, coords, heading, cb, networked) Wait(0) end - if cb then + if promise then + promise:resolve(vehicle) + elseif cb then cb(vehicle) end end) + + if promise then + return Citizen.Await(promise) + end end ---@param vehicle integer The vehicle to spawn diff --git a/[core]/es_extended/server/modules/onesync.lua b/[core]/es_extended/server/modules/onesync.lua index 87c5f7f0d..cb914a17a 100644 --- a/[core]/es_extended/server/modules/onesync.lua +++ b/[core]/es_extended/server/modules/onesync.lua @@ -82,35 +82,57 @@ end ---@param coords vector3|table ---@param heading number ---@param properties table ----@param cb function +---@param cb? fun(netId: number) +---@return number? netId function ESX.OneSync.SpawnVehicle(model, coords, heading, properties, cb) + if cb and not ESX.IsFunctionReference(cb) then + error("Invalid callback function") + end + + local vehicleModel = joaat(model) local vehicleProperties = properties + local promise = not cb and promise.new() CreateThread(function() local xPlayer = ESX.OneSync.GetClosestPlayer(coords, 300) ESX.GetVehicleType(vehicleModel, xPlayer.id, function(vehicleType) - if vehicleType then - local createdVehicle = CreateVehicleServerSetter(vehicleModel, vehicleType, coords.x, coords.y, coords.z, heading) - local tries = 0 - - while not createdVehicle or createdVehicle == 0 or not GetEntityCoords(createdVehicle) do - Wait(200) - tries = tries + 1 - if tries > 20 then - return error(("Could not spawn vehicle - ^5%s^7!"):format(model)) + if not vehicleType then + if (promise) then + return promise:reject(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) + end + error(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) + end + + local createdVehicle = CreateVehicleServerSetter(vehicleModel, vehicleType, coords.x, coords.y, coords.z, heading) + local tries = 0 + + while not createdVehicle or createdVehicle == 0 or not GetEntityCoords(createdVehicle) do + Wait(200) + tries = tries + 1 + if tries > 20 then + if promise then + return promise:reject(("Could not spawn vehicle - ^5%s^7!"):format(model)) end + error(("Could not spawn vehicle - ^5%s^7!"):format(model)) end - -- luacheck: ignore - SetEntityOrphanMode(createdVehicle, 2) - local networkId = NetworkGetNetworkIdFromEntity(createdVehicle) - Entity(createdVehicle).state:set("VehicleProperties", vehicleProperties, true) + end + + -- luacheck: ignore + SetEntityOrphanMode(createdVehicle, 2) + local networkId = NetworkGetNetworkIdFromEntity(createdVehicle) + Entity(createdVehicle).state:set("VehicleProperties", vehicleProperties, true) + if promise then + promise:resolve(networkId) + elseif cb then cb(networkId) - else - error(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) end end) end) + + if promise then + return Citizen.Await(promise) + end end ---@param model number|string From 8ea8b4a69f8347b974560e7c6b98c52eecff29c7 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:02:19 +0100 Subject: [PATCH 02/23] feat(es_extended/server/classes/vehicle): add vehicle class --- [core]/es_extended/fxmanifest.lua | 1 + [core]/es_extended/server/classes/vehicle.lua | 209 ++++++++++++++++++ [core]/es_extended/server/common.lua | 2 + 3 files changed, 212 insertions(+) create mode 100644 [core]/es_extended/server/classes/vehicle.lua diff --git a/[core]/es_extended/fxmanifest.lua b/[core]/es_extended/fxmanifest.lua index 848289bf8..ffc8aa8c5 100644 --- a/[core]/es_extended/fxmanifest.lua +++ b/[core]/es_extended/fxmanifest.lua @@ -25,6 +25,7 @@ server_scripts { 'server/common.lua', 'server/modules/callback.lua', 'server/classes/player.lua', + 'server/classes/vehicle.lua', 'server/classes/overrides/*.lua', 'server/functions.lua', 'server/modules/onesync.lua', diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua new file mode 100644 index 000000000..2f5d87f3f --- /dev/null +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -0,0 +1,209 @@ +---@class DbVehicle +---@field owner string +---@field plate string +---@field vehicle string +---@field type string +---@field job? string +---@field stored boolean +---@field parking? string +---@field pound? string + +---@class VehicleData +---@field plate string +---@field netId number +---@field entity number +---@field modelHash number +---@field owner string + +---@class VehicleClass +---@field plate string +---@field isValid fun(self:VehicleClass):boolean +---@field new fun(owner:string, plate:string, coords:vector4): VehicleClass? +---@field getPlate fun(self:VehicleClass):string? +---@field getNetId fun(self:VehicleClass):number? +---@field getEntity fun(self:VehicleClass):number? +---@field getModelHash fun(self:VehicleClass):number? +---@field getProps fun(self:VehicleClass):table? +---@field getOwner fun(self:VehicleClass):string? +---@field setPlate fun(self:VehicleClass, plate:string):boolean +---@field setProps fun(self:VehicleClass, props:table):boolean +---@field setOwner fun(self:VehicleClass, owner:string):boolean +---@field delete fun(self:VehicleClass):nil +Core.vehicleClass = { + plate = "", + new = function(owner, plate, coords) + assert(type(owner) == "string", "Expected 'owner' to be a string") + assert(type(plate) == "string", "Expected 'plate' to be a string") + assert(type(coords) == "vector4", "Expected 'coords' to be a vector4") + + if Core.vehicles[plate] then + local obj = table.clone(Core.vehicleClass) + obj.plate = plate + + if obj:isValid() then + return obj + end + end + + local dbVehicle = MySQL.single.await("SELECT * FROM `owned_vehicles` WHERE `stored` = true AND `owner` = ? AND `plate` = ?", { owner, plate }) --[[@as DbVehicle]] + if not dbVehicle then + return + end + + local vehicleProps = json.decode(dbVehicle.vehicle) + if type(vehicleProps.model) ~= "number" then + model = joaat(model) + end + + local netId = ESX.OneSync.SpawnVehicle(model, coords.xyz, coords.w, vehicleProps) + if not netId then + return + end + + local entity = NetworkGetEntityFromNetworkId(netId) + if entity <= 0 then + return + end + + Entity(entity).state:set("owner", owner, false) + + local vehicle = { + plate = plate, + entity = entity, + netId = netId, + modelHash = model, + owner = owner, + } + Core.vehicles[plate] = vehicle + + MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 0 WHERE `owner` = ? AND `plate` = ?", { owner, plate }) + + local obj = table.clone(Core.vehicleClass) + obj.plate = plate + TriggerEvent("esx:createdExtendedVehicle", obj) + + return obj + end, + isValid = function(self) + local xVehicle = Core.vehicles[self.plate] + if not xVehicle then + return false + end + + local entity = NetworkGetEntityFromNetworkId(xVehicle.netId) + if entity <= 0 or Entity(entity).state.owner ~= xVehicle.owner then + self:delete() + return false + end + + local plate = ESX.Math.Trim(GetVehicleNumberPlateText(entity)) + if plate ~= xVehicle.plate then + self:delete() + return false + end + + xVehicle.entity = entity + + return true + end, + getNetId = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].netId + end, + getEntity = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].entity + end, + getPlate = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].plate + end, + getModelHash = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].modelHash + end, + getProps = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].props + end, + getOwner = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].owner + end, + setPlate = function(self, plate) + if not self:isValid() then + return false + end + assert(type(plate) == "string", "Expected 'plate' to be a string") + + local xVehicle = Core.vehicles[self.plate] + SetVehicleNumberPlateText(xVehicle.entity, plate) + xVehicle.plate = plate + MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) + + return true + end, + setProps = function(self, props) + if not self:isValid() then + return false + end + assert(type(props) == "table", "Expected 'props' to be a table") + + local xVehicle = Core.vehicles[self.plate] + Entity(xVehicle.entity).state:set("VehicleProperties", props, true) + MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(props), xVehicle.plate, xVehicle.owner) + + return true + end, + setOwner = function(self, owner) + if not self:isValid() then + return false + end + assert(type(owner) == "string", "Expected 'owner' to be a string") + + local xVehicle = Core.vehicles[self.plate] + if xVehicle.owner == owner then + return true + end + + Entity(xVehicle.entity).state:set("owner", owner, false) + xVehicle.owner = owner + MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE `plate` = ?", { owner, xVehicle.plate }) + + return true + end, + delete = function(self) + local xVehicle = Core.vehicles[self.plate] + if not xVehicle then + return + end + + local entity = NetworkGetEntityFromNetworkId(xVehicle.netId) + if entity >= 0 and Entity(entity).state.owner == xVehicle.owner then + DeleteEntity(xVehicle.entity) + end + + MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 1 WHERE `plate` = ?", { xVehicle.plate }) + TriggerEvent("esx:deletedExtendedVehicle", self) + + Core.vehicles[self.plate] = nil + end, +} diff --git a/[core]/es_extended/server/common.lua b/[core]/es_extended/server/common.lua index edbc39529..2e6845c4a 100644 --- a/[core]/es_extended/server/common.lua +++ b/[core]/es_extended/server/common.lua @@ -11,6 +11,8 @@ Core.PlayerFunctionOverrides = {} Core.DatabaseConnected = false Core.playersByIdentifier = {} +---@type table +Core.vehicles = {} Core.vehicleTypesByModel = {} RegisterNetEvent("esx:onPlayerSpawn", function() From 3d16c4fecdeb811e6ebab9846cbadb406c3a4543 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:02:45 +0100 Subject: [PATCH 03/23] feat(es_extended/server/functions): add exposed vehicle class functions --- [core]/es_extended/server/functions.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index 884ef4a57..4d61617ff 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -615,3 +615,23 @@ function Core.IsPlayerAdmin(playerId) local xPlayer = ESX.Players[playerId] return (xPlayer and Config.AdminGroups[xPlayer.group] and true) or false end + +---@param owner string +---@param plate string +---@param coords vector4 +---@return VehicleClass? +function ESX.CreateExtendedVehicle(owner, plate, coords) + return Core.vehicleClass.new(owner, plate, coords) +end + +---@param plate string +---@return VehicleClass? +function ESX.GetExtendedVehicleFromPlate(plate) + assert(type(plate) == "string", "Expected 'plate' to be a string") + + if Core.vehicles[plate] then + local obj = table.clone(Core.vehicleClass) + obj.plate = plate + return obj + end +end \ No newline at end of file From 5c44b5c8551c578e3da08c3da5350219ebcded4e Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:25:38 +0100 Subject: [PATCH 04/23] refactor(es_extended/server/functions): move ESX.GetExtendedVehicleFromPlate logic into vehicle class --- [core]/es_extended/server/classes/vehicle.lua | 21 ++++++++++++------- [core]/es_extended/server/functions.lua | 6 +----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 2f5d87f3f..469cedb61 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -19,6 +19,7 @@ ---@field plate string ---@field isValid fun(self:VehicleClass):boolean ---@field new fun(owner:string, plate:string, coords:vector4): VehicleClass? +---@field getFromPlate fun(plate:string):VehicleClass? ---@field getPlate fun(self:VehicleClass):string? ---@field getNetId fun(self:VehicleClass):number? ---@field getEntity fun(self:VehicleClass):number? @@ -36,13 +37,9 @@ Core.vehicleClass = { assert(type(plate) == "string", "Expected 'plate' to be a string") assert(type(coords) == "vector4", "Expected 'coords' to be a vector4") - if Core.vehicles[plate] then - local obj = table.clone(Core.vehicleClass) - obj.plate = plate - - if obj:isValid() then - return obj - end + local xVehicle = Core.vehicleClass.getFromPlate(plate) + if xVehicle then + return xVehicle end local dbVehicle = MySQL.single.await("SELECT * FROM `owned_vehicles` WHERE `stored` = true AND `owner` = ? AND `plate` = ?", { owner, plate }) --[[@as DbVehicle]] @@ -84,6 +81,16 @@ Core.vehicleClass = { return obj end, + getFromPlate = function(plate) + if Core.vehicles[plate] then + local obj = table.clone(Core.vehicleClass) + obj.plate = plate + + if obj:isValid() then + return obj + end + end + end, isValid = function(self) local xVehicle = Core.vehicles[self.plate] if not xVehicle then diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index 4d61617ff..90c5bc4fc 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -629,9 +629,5 @@ end function ESX.GetExtendedVehicleFromPlate(plate) assert(type(plate) == "string", "Expected 'plate' to be a string") - if Core.vehicles[plate] then - local obj = table.clone(Core.vehicleClass) - obj.plate = plate - return obj - end + return Core.vehicleClass.getFromPlate(plate) end \ No newline at end of file From 520446a6acfeec1635a2784c0017e5390cc33c48 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:33:30 +0100 Subject: [PATCH 05/23] refactor(es_extended/server/classes/vehicle): only select relevant data from db --- [core]/es_extended/server/classes/vehicle.lua | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 469cedb61..e23084cce 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -1,13 +1,3 @@ ----@class DbVehicle ----@field owner string ----@field plate string ----@field vehicle string ----@field type string ----@field job? string ----@field stored boolean ----@field parking? string ----@field pound? string - ---@class VehicleData ---@field plate string ---@field netId number @@ -42,12 +32,12 @@ Core.vehicleClass = { return xVehicle end - local dbVehicle = MySQL.single.await("SELECT * FROM `owned_vehicles` WHERE `stored` = true AND `owner` = ? AND `plate` = ?", { owner, plate }) --[[@as DbVehicle]] - if not dbVehicle then + local vehicleProps = MySQL.scalar.await("SELECT `vehicle` FROM `owned_vehicles` WHERE `stored` = true AND `owner` = ? AND `plate` = ? LIMIT 1", { owner, plate }) + if not vehicleProps then return end + vehicleProps = json.decode(vehicleProps.vehicle) - local vehicleProps = json.decode(dbVehicle.vehicle) if type(vehicleProps.model) ~= "number" then model = joaat(model) end From 68508b96f0cf83c5fdb9bfbf156f1deb70fd3d65 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:38:15 +0100 Subject: [PATCH 06/23] fix(es_extended/server/classes/vehicle): remove unused function getProps --- [core]/es_extended/server/classes/vehicle.lua | 9 --------- 1 file changed, 9 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index e23084cce..c71723bdd 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -14,7 +14,6 @@ ---@field getNetId fun(self:VehicleClass):number? ---@field getEntity fun(self:VehicleClass):number? ---@field getModelHash fun(self:VehicleClass):number? ----@field getProps fun(self:VehicleClass):table? ---@field getOwner fun(self:VehicleClass):string? ---@field setPlate fun(self:VehicleClass, plate:string):boolean ---@field setProps fun(self:VehicleClass, props:table):boolean @@ -51,7 +50,6 @@ Core.vehicleClass = { if entity <= 0 then return end - Entity(entity).state:set("owner", owner, false) local vehicle = { @@ -131,13 +129,6 @@ Core.vehicleClass = { return Core.vehicles[self.plate].modelHash end, - getProps = function(self) - if not self:isValid() then - return - end - - return Core.vehicles[self.plate].props - end, getOwner = function(self) if not self:isValid() then return From 04ef04e2078f425f9a8000e1a3c15e1f5253be4c Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 01:20:28 +0100 Subject: [PATCH 07/23] fix(es_extended/server/classes/vehicle): properly parse vehicleProps --- [core]/es_extended/server/classes/vehicle.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index c71723bdd..b4f0240df 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -35,7 +35,7 @@ Core.vehicleClass = { if not vehicleProps then return end - vehicleProps = json.decode(vehicleProps.vehicle) + vehicleProps = json.decode(vehicleProps) if type(vehicleProps.model) ~= "number" then model = joaat(model) From 4e6e37e7089658c63d425cff81acfb9b447917e6 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 01:25:18 +0100 Subject: [PATCH 08/23] fix(es_extended/server/classes/vehicle): fix vehicle model extraction --- [core]/es_extended/server/classes/vehicle.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index b4f0240df..edc1c2402 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -38,10 +38,10 @@ Core.vehicleClass = { vehicleProps = json.decode(vehicleProps) if type(vehicleProps.model) ~= "number" then - model = joaat(model) + vehicleProps.model = joaat(vehicleProps.model) end - local netId = ESX.OneSync.SpawnVehicle(model, coords.xyz, coords.w, vehicleProps) + local netId = ESX.OneSync.SpawnVehicle(vehicleProps.model, coords.xyz, coords.w, vehicleProps) if not netId then return end @@ -56,7 +56,7 @@ Core.vehicleClass = { plate = plate, entity = entity, netId = netId, - modelHash = model, + modelHash = vehicleProps.model, owner = owner, } Core.vehicles[plate] = vehicle From 9d7c2edac040666b62af5ed9c1d67b0b9ef3d973 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Mon, 16 Dec 2024 23:00:46 +0100 Subject: [PATCH 09/23] Merge pull request #1553 from Mycroft-Studios/better-vehicle-spawning fix(es_extended/server/onesync): better vehicle spawning method --- [core]/es_extended/server/modules/onesync.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/[core]/es_extended/server/modules/onesync.lua b/[core]/es_extended/server/modules/onesync.lua index cb914a17a..de4f4eb8d 100644 --- a/[core]/es_extended/server/modules/onesync.lua +++ b/[core]/es_extended/server/modules/onesync.lua @@ -107,10 +107,10 @@ function ESX.OneSync.SpawnVehicle(model, coords, heading, properties, cb) local createdVehicle = CreateVehicleServerSetter(vehicleModel, vehicleType, coords.x, coords.y, coords.z, heading) local tries = 0 - while not createdVehicle or createdVehicle == 0 or not GetEntityCoords(createdVehicle) do + while not createdVehicle or createdVehicle == 0 or NetworkGetEntityOwner(createdVehicle) == -1 do Wait(200) tries = tries + 1 - if tries > 20 then + if tries > 40 then if promise then return promise:reject(("Could not spawn vehicle - ^5%s^7!"):format(model)) end @@ -122,6 +122,7 @@ function ESX.OneSync.SpawnVehicle(model, coords, heading, properties, cb) SetEntityOrphanMode(createdVehicle, 2) local networkId = NetworkGetNetworkIdFromEntity(createdVehicle) Entity(createdVehicle).state:set("VehicleProperties", vehicleProperties, true) + if promise then promise:resolve(networkId) elseif cb then From 7341b37850f5756369f05b5df4ce4d6aa3435b77 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 02:01:01 +0100 Subject: [PATCH 10/23] fix(es_extended/server/classes/vehicle): fix plate race condition It takes a while until the vehicle plate is actually set. To combat this, we will store the plate in the entity statebag instead. --- [core]/es_extended/server/classes/vehicle.lua | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index edc1c2402..cbc9daa69 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -51,6 +51,7 @@ Core.vehicleClass = { return end Entity(entity).state:set("owner", owner, false) + Entity(entity).state:set("plate", plate, false) local vehicle = { plate = plate, @@ -86,13 +87,7 @@ Core.vehicleClass = { end local entity = NetworkGetEntityFromNetworkId(xVehicle.netId) - if entity <= 0 or Entity(entity).state.owner ~= xVehicle.owner then - self:delete() - return false - end - - local plate = ESX.Math.Trim(GetVehicleNumberPlateText(entity)) - if plate ~= xVehicle.plate then + if entity <= 0 or Entity(entity).state.owner ~= xVehicle.owner or Entity(entity).state.plate ~= xVehicle.plate then self:delete() return false end @@ -143,6 +138,7 @@ Core.vehicleClass = { assert(type(plate) == "string", "Expected 'plate' to be a string") local xVehicle = Core.vehicles[self.plate] + Entity(xVehicle.entity).state:set("plate", plate, false) SetVehicleNumberPlateText(xVehicle.entity, plate) xVehicle.plate = plate MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) From 2babbdda687690aeb9922958218f3410ab61cefc Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 02:15:39 +0100 Subject: [PATCH 11/23] fix(es_extended/server/classes/vehicle): fix plate not updating in db --- [core]/es_extended/server/classes/vehicle.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index cbc9daa69..68ee4f28a 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -140,8 +140,8 @@ Core.vehicleClass = { local xVehicle = Core.vehicles[self.plate] Entity(xVehicle.entity).state:set("plate", plate, false) SetVehicleNumberPlateText(xVehicle.entity, plate) - xVehicle.plate = plate MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) + xVehicle.plate = plate return true end, From 734c5ec3d558669b3baa5d0d2f7cb46ca062499b Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 02:21:17 +0100 Subject: [PATCH 12/23] fix(es_extended/server/classes/vehicle): confirm updates to db before reflecting changes in veh obj --- [core]/es_extended/server/classes/vehicle.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 68ee4f28a..f12c23666 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -138,9 +138,12 @@ Core.vehicleClass = { assert(type(plate) == "string", "Expected 'plate' to be a string") local xVehicle = Core.vehicles[self.plate] + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) + if affectedRows <= 0 then + return false + end Entity(xVehicle.entity).state:set("plate", plate, false) SetVehicleNumberPlateText(xVehicle.entity, plate) - MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) xVehicle.plate = plate return true @@ -152,8 +155,11 @@ Core.vehicleClass = { assert(type(props) == "table", "Expected 'props' to be a table") local xVehicle = Core.vehicles[self.plate] + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(props), xVehicle.plate, xVehicle.owner) + if affectedRows <= 0 then + return false + end Entity(xVehicle.entity).state:set("VehicleProperties", props, true) - MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(props), xVehicle.plate, xVehicle.owner) return true end, @@ -168,9 +174,12 @@ Core.vehicleClass = { return true end + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { owner, xVehicle.owner, xVehicle.plate }) + if affectedRows <= 0 then + return false + end Entity(xVehicle.entity).state:set("owner", owner, false) xVehicle.owner = owner - MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE `plate` = ?", { owner, xVehicle.plate }) return true end, From 88ad28775fef06ba26a0e12d8be5ee2d0347a5dd Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 02:25:53 +0100 Subject: [PATCH 13/23] refactor(es_extended/server/classes/vehicle): better variable name & added spacing --- [core]/es_extended/server/classes/vehicle.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index f12c23666..486c096ed 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -53,14 +53,14 @@ Core.vehicleClass = { Entity(entity).state:set("owner", owner, false) Entity(entity).state:set("plate", plate, false) - local vehicle = { + local vehicleData = { plate = plate, entity = entity, netId = netId, modelHash = vehicleProps.model, owner = owner, } - Core.vehicles[plate] = vehicle + Core.vehicles[plate] = vehicleData MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 0 WHERE `owner` = ? AND `plate` = ?", { owner, plate }) @@ -142,6 +142,7 @@ Core.vehicleClass = { if affectedRows <= 0 then return false end + Entity(xVehicle.entity).state:set("plate", plate, false) SetVehicleNumberPlateText(xVehicle.entity, plate) xVehicle.plate = plate @@ -159,6 +160,7 @@ Core.vehicleClass = { if affectedRows <= 0 then return false end + Entity(xVehicle.entity).state:set("VehicleProperties", props, true) return true @@ -178,6 +180,7 @@ Core.vehicleClass = { if affectedRows <= 0 then return false end + Entity(xVehicle.entity).state:set("owner", owner, false) xVehicle.owner = owner From 5656505e006bd2529ae28f51d2326b1c7c7ea6bb Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:48:39 +0100 Subject: [PATCH 14/23] refactor(es_extended/server/functions): move GetExtendedVehicleFromPlate plate validation to vehicle class --- [core]/es_extended/server/classes/vehicle.lua | 2 ++ [core]/es_extended/server/functions.lua | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 486c096ed..3cd8562d5 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -71,6 +71,8 @@ Core.vehicleClass = { return obj end, getFromPlate = function(plate) + assert(type(plate) == "string", "Expected 'plate' to be a string") + if Core.vehicles[plate] then local obj = table.clone(Core.vehicleClass) obj.plate = plate diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index 90c5bc4fc..f4894ff7e 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -627,7 +627,5 @@ end ---@param plate string ---@return VehicleClass? function ESX.GetExtendedVehicleFromPlate(plate) - assert(type(plate) == "string", "Expected 'plate' to be a string") - return Core.vehicleClass.getFromPlate(plate) end \ No newline at end of file From ea668afb3ab94ea7d091f393f786b259274d6bb7 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:15:38 +0100 Subject: [PATCH 15/23] fix(es_extended/server/classes/vehicle): properly object to new vehicle plate --- [core]/es_extended/server/classes/vehicle.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 3cd8562d5..221476637 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -147,7 +147,14 @@ Core.vehicleClass = { Entity(xVehicle.entity).state:set("plate", plate, false) SetVehicleNumberPlateText(xVehicle.entity, plate) + + local oldPlate = xVehicle.plate xVehicle.plate = plate + Core.vehicles[plate] = table.clone(xVehicle) + Core.vehicles[self.plate] = nil + + TriggerEvent("esx:changedExtendedVehiclePlate", xVehicle.plate, oldPlate) + Wait(0) return true end, From 203dc9af0252dbd961f059c72edb9a6256458e7a Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:33:56 +0100 Subject: [PATCH 16/23] fix(es_extended/server/classes/vehicle): invalidate vehicle on failed db update --- [core]/es_extended/server/classes/vehicle.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 221476637..fea762d34 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -142,6 +142,7 @@ Core.vehicleClass = { local xVehicle = Core.vehicles[self.plate] local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) if affectedRows <= 0 then + self:delete() return false end @@ -167,6 +168,7 @@ Core.vehicleClass = { local xVehicle = Core.vehicles[self.plate] local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(props), xVehicle.plate, xVehicle.owner) if affectedRows <= 0 then + self:delete() return false end @@ -187,6 +189,7 @@ Core.vehicleClass = { local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { owner, xVehicle.owner, xVehicle.plate }) if affectedRows <= 0 then + self:delete() return false end From 0fe26d2455fbb897185e01763275ddae54ba76e9 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:35:41 +0100 Subject: [PATCH 17/23] fix(es_extended/server/classes/vehicle): add owner check in db query --- [core]/es_extended/server/classes/vehicle.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index fea762d34..6c676971f 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -209,7 +209,7 @@ Core.vehicleClass = { DeleteEntity(xVehicle.entity) end - MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 1 WHERE `plate` = ?", { xVehicle.plate }) + MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 1 WHERE `plate` = ? AND `owner` = ?", { xVehicle.plate, xVehicle.owner }) TriggerEvent("esx:deletedExtendedVehicle", self) Core.vehicles[self.plate] = nil From efc91176401739d7ce3ac9f9c16137a74a5e60c2 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:38:06 +0100 Subject: [PATCH 18/23] feat(es_extended/server/classes/vehicle): add support for setting garage/impound on delete --- [core]/es_extended/server/classes/vehicle.lua | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 6c676971f..7222bf9f1 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -18,7 +18,7 @@ ---@field setPlate fun(self:VehicleClass, plate:string):boolean ---@field setProps fun(self:VehicleClass, props:table):boolean ---@field setOwner fun(self:VehicleClass, owner:string):boolean ----@field delete fun(self:VehicleClass):nil +---@field delete fun(self:VehicleClass, garageName:string?, impound:boolean?):nil Core.vehicleClass = { plate = "", new = function(owner, plate, coords) @@ -198,7 +198,14 @@ Core.vehicleClass = { return true end, - delete = function(self) + delete = function(self, garageName, impound) + if type(garageName) ~= "string" then + garageName = nil + end + if type(impound) ~= "boolean" then + impound = false + end + local xVehicle = Core.vehicles[self.plate] if not xVehicle then return @@ -209,7 +216,19 @@ Core.vehicleClass = { DeleteEntity(xVehicle.entity) end - MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 1 WHERE `plate` = ? AND `owner` = ?", { xVehicle.plate, xVehicle.owner }) + local query = "UPDATE `owned_vehicles` SET `stored` = true WHERE `plate` = ? AND `owner` = ?" + local queryParams = { xVehicle.plate, xVehicle.owner } + if garageName then + if impound then + query = "UPDATE `owned_vehicles` SET `stored` = true, `parking` = NULL, `pound` = ? WHERE `plate` = ? AND `owner` = ?" + else + query = "UPDATE `owned_vehicles` SET `stored` = true, `pound` = NULL, `parking` = ? WHERE `plate` = ? AND `owner` = ?" + end + + queryParams = { garageName, xVehicle.plate, xVehicle.owner } + end + + MySQL.update.await(query, queryParams) TriggerEvent("esx:deletedExtendedVehicle", self) Core.vehicles[self.plate] = nil From 9c7d7ea26c7a756bd70ec499c466789a2de1384d Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:46:36 +0100 Subject: [PATCH 19/23] refactor(es_extended/server/classes/vehicle): better variable naming --- [core]/es_extended/server/classes/vehicle.lua | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 7222bf9f1..f900d4d8e 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -15,10 +15,10 @@ ---@field getEntity fun(self:VehicleClass):number? ---@field getModelHash fun(self:VehicleClass):number? ---@field getOwner fun(self:VehicleClass):string? ----@field setPlate fun(self:VehicleClass, plate:string):boolean +---@field setPlate fun(self:VehicleClass, newPlate:string):boolean ---@field setProps fun(self:VehicleClass, props:table):boolean ----@field setOwner fun(self:VehicleClass, owner:string):boolean ----@field delete fun(self:VehicleClass, garageName:string?, impound:boolean?):nil +---@field setOwner fun(self:VehicleClass, newOwner:string):boolean +---@field delete fun(self:VehicleClass, garageName:string?, isImpound:boolean?):nil Core.vehicleClass = { plate = "", new = function(owner, plate, coords) @@ -133,26 +133,26 @@ Core.vehicleClass = { return Core.vehicles[self.plate].owner end, - setPlate = function(self, plate) + setPlate = function(self, newPlate) if not self:isValid() then return false end - assert(type(plate) == "string", "Expected 'plate' to be a string") + assert(type(newPlate) == "string", "Expected 'plate' to be a string") local xVehicle = Core.vehicles[self.plate] - local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { plate, xVehicle.plate, xVehicle.owner }) + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { newPlate, xVehicle.plate, xVehicle.owner }) if affectedRows <= 0 then self:delete() return false end - Entity(xVehicle.entity).state:set("plate", plate, false) - SetVehicleNumberPlateText(xVehicle.entity, plate) + Entity(xVehicle.entity).state:set("plate", newPlate, false) + SetVehicleNumberPlateText(xVehicle.entity, newPlate) local oldPlate = xVehicle.plate - xVehicle.plate = plate - Core.vehicles[plate] = table.clone(xVehicle) - Core.vehicles[self.plate] = nil + xVehicle.plate = newPlate + Core.vehicles[newPlate] = table.clone(xVehicle) + Core.vehicles[oldPlate] = nil TriggerEvent("esx:changedExtendedVehiclePlate", xVehicle.plate, oldPlate) Wait(0) @@ -176,34 +176,34 @@ Core.vehicleClass = { return true end, - setOwner = function(self, owner) + setOwner = function(self, newOwner) if not self:isValid() then return false end - assert(type(owner) == "string", "Expected 'owner' to be a string") + assert(type(newOwner) == "string", "Expected 'owner' to be a string") local xVehicle = Core.vehicles[self.plate] - if xVehicle.owner == owner then + if xVehicle.owner == newOwner then return true end - local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { owner, xVehicle.owner, xVehicle.plate }) + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { newOwner, xVehicle.owner, xVehicle.plate }) if affectedRows <= 0 then self:delete() return false end - Entity(xVehicle.entity).state:set("owner", owner, false) - xVehicle.owner = owner + Entity(xVehicle.entity).state:set("owner", newOwner, false) + xVehicle.owner = newOwner return true end, - delete = function(self, garageName, impound) + delete = function(self, garageName, isImpound) if type(garageName) ~= "string" then garageName = nil end - if type(impound) ~= "boolean" then - impound = false + if type(isImpound) ~= "boolean" then + isImpound = false end local xVehicle = Core.vehicles[self.plate] @@ -219,7 +219,7 @@ Core.vehicleClass = { local query = "UPDATE `owned_vehicles` SET `stored` = true WHERE `plate` = ? AND `owner` = ?" local queryParams = { xVehicle.plate, xVehicle.owner } if garageName then - if impound then + if isImpound then query = "UPDATE `owned_vehicles` SET `stored` = true, `parking` = NULL, `pound` = ? WHERE `plate` = ? AND `owner` = ?" else query = "UPDATE `owned_vehicles` SET `stored` = true, `pound` = NULL, `parking` = ? WHERE `plate` = ? AND `owner` = ?" From ac7aa3f0b18669b95332b241c37f4f1619c5bbaa Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:01:02 +0100 Subject: [PATCH 20/23] refactor(es_extended/server/classes/vehicle): rename classes --- [core]/es_extended/server/classes/vehicle.lua | 36 +++++++++---------- [core]/es_extended/server/common.lua | 2 +- [core]/es_extended/server/functions.lua | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index f900d4d8e..025b86da5 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -1,24 +1,24 @@ ----@class VehicleData +---@class CVehicleData ---@field plate string ---@field netId number ---@field entity number ---@field modelHash number ---@field owner string ----@class VehicleClass +---@class CExtendedVehicle ---@field plate string ----@field isValid fun(self:VehicleClass):boolean ----@field new fun(owner:string, plate:string, coords:vector4): VehicleClass? ----@field getFromPlate fun(plate:string):VehicleClass? ----@field getPlate fun(self:VehicleClass):string? ----@field getNetId fun(self:VehicleClass):number? ----@field getEntity fun(self:VehicleClass):number? ----@field getModelHash fun(self:VehicleClass):number? ----@field getOwner fun(self:VehicleClass):string? ----@field setPlate fun(self:VehicleClass, newPlate:string):boolean ----@field setProps fun(self:VehicleClass, props:table):boolean ----@field setOwner fun(self:VehicleClass, newOwner:string):boolean ----@field delete fun(self:VehicleClass, garageName:string?, isImpound:boolean?):nil +---@field isValid fun(self:CExtendedVehicle):boolean +---@field new fun(owner:string, plate:string, coords:vector4): CExtendedVehicle? +---@field getFromPlate fun(plate:string):CExtendedVehicle? +---@field getPlate fun(self:CExtendedVehicle):string? +---@field getNetId fun(self:CExtendedVehicle):number? +---@field getEntity fun(self:CExtendedVehicle):number? +---@field getModelHash fun(self:CExtendedVehicle):number? +---@field getOwner fun(self:CExtendedVehicle):string? +---@field setPlate fun(self:CExtendedVehicle, newPlate:string):boolean +---@field setProps fun(self:CExtendedVehicle, newProps:table):boolean +---@field setOwner fun(self:CExtendedVehicle, newOwner:string):boolean +---@field delete fun(self:CExtendedVehicle, garageName:string?, isImpound:boolean?):nil Core.vehicleClass = { plate = "", new = function(owner, plate, coords) @@ -159,20 +159,20 @@ Core.vehicleClass = { return true end, - setProps = function(self, props) + setProps = function(self, newProps) if not self:isValid() then return false end - assert(type(props) == "table", "Expected 'props' to be a table") + assert(type(newProps) == "table", "Expected 'props' to be a table") local xVehicle = Core.vehicles[self.plate] - local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(props), xVehicle.plate, xVehicle.owner) + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(newProps), xVehicle.plate, xVehicle.owner) if affectedRows <= 0 then self:delete() return false end - Entity(xVehicle.entity).state:set("VehicleProperties", props, true) + Entity(xVehicle.entity).state:set("VehicleProperties", newProps, true) return true end, diff --git a/[core]/es_extended/server/common.lua b/[core]/es_extended/server/common.lua index 2e6845c4a..9c95c5713 100644 --- a/[core]/es_extended/server/common.lua +++ b/[core]/es_extended/server/common.lua @@ -11,7 +11,7 @@ Core.PlayerFunctionOverrides = {} Core.DatabaseConnected = false Core.playersByIdentifier = {} ----@type table +---@type table Core.vehicles = {} Core.vehicleTypesByModel = {} diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index f4894ff7e..ae052f728 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -619,13 +619,13 @@ end ---@param owner string ---@param plate string ---@param coords vector4 ----@return VehicleClass? +---@return CExtendedVehicle? function ESX.CreateExtendedVehicle(owner, plate, coords) return Core.vehicleClass.new(owner, plate, coords) end ---@param plate string ----@return VehicleClass? +---@return CExtendedVehicle? function ESX.GetExtendedVehicleFromPlate(plate) return Core.vehicleClass.getFromPlate(plate) end \ No newline at end of file From 9635d4774782bff0688f46cf3481fb3846cb37d9 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:13:39 +0100 Subject: [PATCH 21/23] fix(es_extended/server/classes/vehicle): properly annotate vehicleData type --- [core]/es_extended/server/classes/vehicle.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 025b86da5..1d498cd71 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -53,6 +53,7 @@ Core.vehicleClass = { Entity(entity).state:set("owner", owner, false) Entity(entity).state:set("plate", plate, false) + ---@type CVehicleData local vehicleData = { plate = plate, entity = entity, From 738e0ea0fe59d378c42ddad0690b26901d990456 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:17:41 +0100 Subject: [PATCH 22/23] refactor(es_extended/server/classes/vehicle): rename xVehicle to vehicleData where appropriate Avoids confusion. --- [core]/es_extended/server/classes/vehicle.lua | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index 1d498cd71..ac9feca81 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -84,18 +84,18 @@ Core.vehicleClass = { end end, isValid = function(self) - local xVehicle = Core.vehicles[self.plate] - if not xVehicle then + local vehicleData = Core.vehicles[self.plate] + if not vehicleData then return false end - local entity = NetworkGetEntityFromNetworkId(xVehicle.netId) - if entity <= 0 or Entity(entity).state.owner ~= xVehicle.owner or Entity(entity).state.plate ~= xVehicle.plate then + local entity = NetworkGetEntityFromNetworkId(vehicleData.netId) + if entity <= 0 or Entity(entity).state.owner ~= vehicleData.owner or Entity(entity).state.plate ~= vehicleData.plate then self:delete() return false end - xVehicle.entity = entity + vehicleData.entity = entity return true end, @@ -140,22 +140,22 @@ Core.vehicleClass = { end assert(type(newPlate) == "string", "Expected 'plate' to be a string") - local xVehicle = Core.vehicles[self.plate] - local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { newPlate, xVehicle.plate, xVehicle.owner }) + local vehicleData = Core.vehicles[self.plate] + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { newPlate, vehicleData.plate, vehicleData.owner }) if affectedRows <= 0 then self:delete() return false end - Entity(xVehicle.entity).state:set("plate", newPlate, false) - SetVehicleNumberPlateText(xVehicle.entity, newPlate) + Entity(vehicleData.entity).state:set("plate", newPlate, false) + SetVehicleNumberPlateText(vehicleData.entity, newPlate) - local oldPlate = xVehicle.plate - xVehicle.plate = newPlate - Core.vehicles[newPlate] = table.clone(xVehicle) + local oldPlate = vehicleData.plate + vehicleData.plate = newPlate + Core.vehicles[newPlate] = table.clone(vehicleData) Core.vehicles[oldPlate] = nil - TriggerEvent("esx:changedExtendedVehiclePlate", xVehicle.plate, oldPlate) + TriggerEvent("esx:changedExtendedVehiclePlate", vehicleData.plate, oldPlate) Wait(0) return true @@ -166,14 +166,14 @@ Core.vehicleClass = { end assert(type(newProps) == "table", "Expected 'props' to be a table") - local xVehicle = Core.vehicles[self.plate] - local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(newProps), xVehicle.plate, xVehicle.owner) + local vehicleData = Core.vehicles[self.plate] + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(newProps), vehicleData.plate, vehicleData.owner) if affectedRows <= 0 then self:delete() return false end - Entity(xVehicle.entity).state:set("VehicleProperties", newProps, true) + Entity(vehicleData.entity).state:set("VehicleProperties", newProps, true) return true end, @@ -183,19 +183,19 @@ Core.vehicleClass = { end assert(type(newOwner) == "string", "Expected 'owner' to be a string") - local xVehicle = Core.vehicles[self.plate] - if xVehicle.owner == newOwner then + local vehicleData = Core.vehicles[self.plate] + if vehicleData.owner == newOwner then return true end - local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { newOwner, xVehicle.owner, xVehicle.plate }) + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { newOwner, vehicleData.owner, vehicleData.plate }) if affectedRows <= 0 then self:delete() return false end - Entity(xVehicle.entity).state:set("owner", newOwner, false) - xVehicle.owner = newOwner + Entity(vehicleData.entity).state:set("owner", newOwner, false) + vehicleData.owner = newOwner return true end, @@ -207,18 +207,18 @@ Core.vehicleClass = { isImpound = false end - local xVehicle = Core.vehicles[self.plate] - if not xVehicle then + local vehicleData = Core.vehicles[self.plate] + if not vehicleData then return end - local entity = NetworkGetEntityFromNetworkId(xVehicle.netId) - if entity >= 0 and Entity(entity).state.owner == xVehicle.owner then - DeleteEntity(xVehicle.entity) + local entity = NetworkGetEntityFromNetworkId(vehicleData.netId) + if entity >= 0 and Entity(entity).state.owner == vehicleData.owner then + DeleteEntity(vehicleData.entity) end local query = "UPDATE `owned_vehicles` SET `stored` = true WHERE `plate` = ? AND `owner` = ?" - local queryParams = { xVehicle.plate, xVehicle.owner } + local queryParams = { vehicleData.plate, vehicleData.owner } if garageName then if isImpound then query = "UPDATE `owned_vehicles` SET `stored` = true, `parking` = NULL, `pound` = ? WHERE `plate` = ? AND `owner` = ?" @@ -226,7 +226,7 @@ Core.vehicleClass = { query = "UPDATE `owned_vehicles` SET `stored` = true, `pound` = NULL, `parking` = ? WHERE `plate` = ? AND `owner` = ?" end - queryParams = { garageName, xVehicle.plate, xVehicle.owner } + queryParams = { garageName, vehicleData.plate, vehicleData.owner } end MySQL.update.await(query, queryParams) From a812285e3c251f7e0865186d73cb1b32726e9c37 Mon Sep 17 00:00:00 2001 From: Kenshin13 <63159154+Kenshiin13@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:39:16 +0100 Subject: [PATCH 23/23] refactor(es_extended/server/classes/vehicle): refactory query --- [core]/es_extended/server/classes/vehicle.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/[core]/es_extended/server/classes/vehicle.lua b/[core]/es_extended/server/classes/vehicle.lua index ac9feca81..b85c8f655 100644 --- a/[core]/es_extended/server/classes/vehicle.lua +++ b/[core]/es_extended/server/classes/vehicle.lua @@ -63,7 +63,7 @@ Core.vehicleClass = { } Core.vehicles[plate] = vehicleData - MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = 0 WHERE `owner` = ? AND `plate` = ?", { owner, plate }) + MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = false WHERE `owner` = ? AND `plate` = ?", { owner, plate }) local obj = table.clone(Core.vehicleClass) obj.plate = plate