2026-04-14 17:41:39 +02:00

238 lines
6.7 KiB
Lua

---@class CVehicleData
---@field plate string
---@field netId number
---@field entity number
---@field modelHash number
---@field owner string
---@class CExtendedVehicle
---@field plate string
---@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)
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")
local xVehicle = Core.vehicleClass.getFromPlate(plate)
if xVehicle then
return xVehicle
end
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)
if type(vehicleProps.model) ~= "number" then
vehicleProps.model = joaat(vehicleProps.model)
end
local netId = ESX.OneSync.SpawnVehicle(vehicleProps.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)
Entity(entity).state:set("plate", plate, false)
---@type CVehicleData
local vehicleData = {
plate = plate,
entity = entity,
netId = netId,
modelHash = vehicleProps.model,
owner = owner,
}
Core.vehicles[plate] = vehicleData
MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = false WHERE `owner` = ? AND `plate` = ?", { owner, plate })
local obj = table.clone(Core.vehicleClass)
obj.plate = plate
TriggerEvent("esx:createdExtendedVehicle", obj)
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
if obj:isValid() then
return obj
end
end
end,
isValid = function(self)
local vehicleData = Core.vehicles[self.plate]
if not vehicleData then
return false
end
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
vehicleData.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,
getOwner = function(self)
if not self:isValid() then
return
end
return Core.vehicles[self.plate].owner
end,
setPlate = function(self, newPlate)
if not self:isValid() then
return false
end
assert(type(newPlate) == "string", "Expected 'plate' to be a string")
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(vehicleData.entity).state:set("plate", newPlate, false)
SetVehicleNumberPlateText(vehicleData.entity, newPlate)
local oldPlate = vehicleData.plate
vehicleData.plate = newPlate
Core.vehicles[newPlate] = table.clone(vehicleData)
Core.vehicles[oldPlate] = nil
TriggerEvent("esx:changedExtendedVehiclePlate", vehicleData.plate, oldPlate)
Wait(0)
return true
end,
setProps = function(self, newProps)
if not self:isValid() then
return false
end
assert(type(newProps) == "table", "Expected 'props' to be a table")
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(vehicleData.entity).state:set("VehicleProperties", newProps, true)
return true
end,
setOwner = function(self, newOwner)
if not self:isValid() then
return false
end
assert(type(newOwner) == "string", "Expected 'owner' to be a string")
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, vehicleData.owner, vehicleData.plate })
if affectedRows <= 0 then
self:delete()
return false
end
Entity(vehicleData.entity).state:set("owner", newOwner, false)
vehicleData.owner = newOwner
return true
end,
delete = function(self, garageName, isImpound)
if type(garageName) ~= "string" then
garageName = nil
end
if type(isImpound) ~= "boolean" then
isImpound = false
end
local vehicleData = Core.vehicles[self.plate]
if not vehicleData then
return
end
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 = { vehicleData.plate, vehicleData.owner }
if garageName 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` = ?"
end
queryParams = { garageName, vehicleData.plate, vehicleData.owner }
end
MySQL.update.await(query, queryParams)
TriggerEvent("esx:deletedExtendedVehicle", self)
Core.vehicles[self.plate] = nil
end,
}