diff --git a/LICENSE.md b/LICENSE.md index f288702..e5e53f9 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -631,9 +631,9 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) - + luke_garages + Copyright (C) 2022 Luke + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -647,25 +647,6 @@ the "copyright" line and a pointer to where the full notice is found. You should have received a copy of the GNU General Public License along with this program. If not, see . -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with diff --git a/README.md b/README.md index 8b30302..106c090 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # luke_garages -This resource now only supports ESX Legacy, other versions of the framework **will not** work without modifying the resource. +This resource only supports ESX Legacy, other versions of the framework **will not** work without modifying the resource. Alongside cars, aircrafts and boats are also fully supported with them having their own separate garages and impounds. @@ -8,16 +8,16 @@ The impound has checks in place to prevent vehicle duping. I used esx_vehicleshop, but the resource should work with anything that follows that databse structure in `owned_vehicles` table. -[Updated Video Showcase](https://www.youtube.com/watch?v=GT2u5uoz7Tc) +[Video Showcase](https://www.youtube.com/watch?v=GT2u5uoz7Tc) (From 2.0.0 version) ### Dependencies - [PolyZone](https://github.com/mkafrin/PolyZone) -- [qtarget](https://github.com/QuantusRP/qtarget) -- [zf_context](https://github.com/zf-development/zf_context) +- [qtarget](https://github.com/overextended/qtarget) +- [ox_lib](https://github.com/overextended/ox_lib) - Server game build 1868 or newer\* -Make sure to follow the well detailed installation instructions on qtarget. +Make sure to download the release zip for [ox_lib](https://github.com/overextended/ox_lib/releases/latest) (ox_lib.zip). ### Installation @@ -29,7 +29,7 @@ Make sure to follow the well detailed installation instructions on qtarget. If you wish to add more garages or impounds make sure to follow the provided template and examples in the config.lua file. -Custom vehicles are now fully supported, for each custom vehicle you have to add a text entry of it's model and make name (if there isn't one already) into the vehicle_names.lua file which is located in the client folder. I provided an example of this that I used on the GTR in the video. +Custom vehicles are fully supported, for each custom vehicle you have to add a text entry of it's model and make name (if there isn't one already) into the vehicle_names.lua file which is located in the client folder. I provided an example of this that I used on the GTR in the video. For any issues or bugs that may occur please open an Issue in the repository. Make sure to describe the issue in detail and how to reproduce it. @@ -57,3 +57,20 @@ Depending on the game build number you choose is the GTA DLC your server is goin 2373 - Tuners update 2545 - The Contract update ``` +## License + + luke_garages + Copyright (C) 2022 Luke + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . \ No newline at end of file diff --git a/client/client.lua b/client/client.lua index 5482a78..9a29c4d 100644 --- a/client/client.lua +++ b/client/client.lua @@ -7,25 +7,45 @@ local jobBlips = {} local ped = nil - -local function GetGarageLabel(name) - for _, garage in pairs(Config.Garages) do +local function getGarageLabel(name) + for i = 1, #Config.Garages do + local garage = Config.Garages[i] if garage.zone.name == name then return garage.label end end end -function VehicleSpawn(data, spawn, price) - ESX.Streaming.RequestModel(data.vehicle.model) +local function isVehicleInGarage(garage, stored) + if Config.SplitGarages then + if (stored == true or stored == 1) and currentGarage.zone.name == garage then + return Locale('in_garage') + else + if (stored == false or stored == 0) then + return Locale('not_in_garage') + else + return getGarageLabel(garage) + end + end + else + if (stored == true or stored == 1) then + return Locale('in_garage') + else + return Locale('not_in_garage') + end + end +end + +local function spawnVehicle(data, spawn, price) + lib.requestModel(data.vehicle.model) TriggerServerEvent('luke_garages:SpawnVehicle', data.vehicle.model, data.vehicle.plate, vector3(spawn.x, spawn.y, spawn.z-1), type(spawn) == 'vector4' and spawn.w or spawn.h, price) end -function IsInsideZone(type, entity) +local function isInsideZone(type, entity) local entityCoords = GetEntityCoords(entity) if type == 'impound' then for k, v in pairs(impounds) do if impounds[k]:isPointInside(entityCoords) then currentImpound = Config.Impounds[k] - return true + return true end if k == #impounds then return false end end @@ -40,7 +60,7 @@ function IsInsideZone(type, entity) end end -function ImpoundBlips(coords, type, label, blipOptions) +local function ImpoundBlips(coords, type, label, blipOptions) local blip = AddBlipForCoord(coords) SetBlipSprite(blip, blipOptions?.sprite or 285) SetBlipScale(blip, blipOptions?.scale or 0.8) @@ -51,7 +71,7 @@ function ImpoundBlips(coords, type, label, blipOptions) EndTextCommandSetBlipName(blip) end -function GarageBlips(coords, type, label, job, blipOptions) +local function GarageBlips(coords, type, label, job, blipOptions) if job then return end local blip = AddBlipForCoord(coords) SetBlipSprite(blip, blipOptions?.sprite or 357) @@ -84,7 +104,7 @@ exports['qtarget']:Vehicle({ icon = 'fas fa-parking', canInteract = function(entity) hasChecked = false - if IsInsideZone('garage', entity) and not hasChecked then + if isInsideZone('garage', entity) and not hasChecked then hasChecked = true return true end @@ -121,7 +141,7 @@ for k, v in pairs(Config.Garages) do job = v.job or nil, canInteract = function(entity) hasChecked = false - if IsInsideZone('garage', entity) and not hasChecked then + if isInsideZone('garage', entity) and not hasChecked then hasChecked = true return true end @@ -136,7 +156,7 @@ for k, v in pairs(Config.Garages) do local heading = type(v.pedCoords) == 'vector4' and v.pedCoords.w or v.pedCoords.h if isPointInside then - ESX.Streaming.RequestModel(model) + lib.requestModel(model) ped = CreatePed(0, model, v.pedCoords.x, v.pedCoords.y, v.pedCoords.z, heading, false, true) SetEntityAlpha(ped, 0, false) @@ -174,14 +194,14 @@ for k, v in pairs(Config.Impounds) do impounds[k].type = v.type - table.insert(impoundPeds, v.ped) + impoundPeds[#impoundPeds+1] = v.ped impounds[k]:onPlayerInOut(function(isPointInside, point) local model = v.ped or Config.DefaultImpoundPed local heading = type(v.pedCoords) == 'vector4' and v.pedCoords.w or v.pedCoords.h if isPointInside then - ESX.Streaming.RequestModel(model) + lib.requestModel(model) ped = CreatePed(0, model, v.pedCoords.x, v.pedCoords.y, v.pedCoords.z, heading, false, true) SetEntityAlpha(ped, 0, false) @@ -209,7 +229,7 @@ exports['qtarget']:AddTargetModel(impoundPeds, { label = Locale('access_impound'), canInteract = function(entity) hasChecked = false - if IsInsideZone('impound', entity) and not hasChecked then + if isInsideZone('impound', entity) and not hasChecked then hasChecked = true return true end @@ -222,212 +242,156 @@ exports['qtarget']:AddTargetModel(impoundPeds, { AddStateBagChangeHandler('vehicleData', nil, function(bagName, key, value, _unused, replicated) if not value then return end local entNet = bagName:gsub('entity:', '') - while not NetworkDoesEntityExistWithNetworkId(tonumber(entNet)) do Wait(0) end + local timer = GetGameTimer() + while not NetworkDoesEntityExistWithNetworkId(tonumber(entNet)) do + Wait(0) + if GetGameTimer() - timer > 10000 then + return + end + end local vehicle = NetToVeh(tonumber(entNet)) - if NetworkGetEntityOwner(vehicle) ~= PlayerId() then return end - SetVehProperties(vehicle, json.decode(value.vehicle), json.decode(value.health)) - TriggerServerEvent('luke_garages:ChangeStored', value.plate, false, nil) + local timer = GetGameTimer() + while NetworkGetEntityOwner(vehicle) ~= PlayerId() do + Wait(0) + if GetGameTimer() - timer > 10000 then + return + end + end + lib.setVehicleProperties(vehicle, json.decode(value.vehicle)) + TriggerServerEvent('luke_garages:ChangeStored', value.plate) + Entity(vehicle).state:set('vehicleData', nil, true) end) -RegisterNetEvent('luke_garages:GetImpoundedVehicles') -AddEventHandler('luke_garages:GetImpoundedVehicles', function() - ESX.TriggerServerCallback('luke_garages:GetImpound', function(vehicles) - local menu = {} +RegisterNetEvent('luke_garages:GetImpoundedVehicles', function() + local vehicles = lib.callback.await('luke_garages:GetImpound', false, currentImpound.type) + local options = {} - TriggerEvent('nh-context:sendMenu', { - { - id = 0, - header = currentImpound.label or Locale(currentImpound.type) .. ' ' .. Locale('impound'), - txt = '' - }, + if not vehicles or #vehicles == 0 then + lib.registerContext({ + id = 'luke_garages:ImpoundMenu', + title = currentImpound.label or Locale(currentImpound.type) .. ' ' .. Locale('impound'), + options = { + [Locale('no_vehicles_impound')] = {} + } }) - if vehicles ~= nil then - for k, v in pairs(vehicles) do - local vehModel = v.vehicle.model - local vehMake = GetLabelText(GetMakeNameFromVehicleModel(vehModel)) - local vehName = GetLabelText(GetDisplayNameFromVehicleModel(vehModel)) - local vehTitle = vehMake .. ' ' .. vehName - - local impoundPrice = Config.ImpoundPrices['' .. GetVehicleClassFromName(vehModel)] - - table.insert(menu, { - id = k, - header = vehTitle, - txt = Locale('plate') .. ': ' .. v.plate, - params = { - event = 'luke_garages:ImpoundVehicleMenu', - args = {name = vehTitle, plate = v.plate, model = vehModel, vehicle = v.vehicle, health = v.health, price = impoundPrice} - } - }) - end - if #menu ~= 0 then - TriggerEvent('nh-context:sendMenu', menu) - else - TriggerEvent('nh-context:sendMenu', { - { - id = 1, - header = Locale('no_vehicles_impound'), - txt = '' - } - }) - end - else - TriggerEvent('nh-context:sendMenu', { - { - id = 1, - header = Locale('no_vehicles_impound'), - txt = '' - } - }) - end - end, currentImpound.type) + return lib.showContext('luke_garages:ImpoundMenu') + end + + for i = 1, #vehicles do + local data = vehicles[i] + local vehicleMake = GetLabelText(GetMakeNameFromVehicleModel(data.vehicle.model)) + local vehicleModel = GetLabelText(GetDisplayNameFromVehicleModel(data.vehicle.model)) + local vehicleTitle = vehicleMake .. ' ' .. vehicleModel + + options[vehicleTitle] = { + event = 'luke_garages:ImpoundVehicleMenu', + arrow = true, + description = Locale('plate') .. ': ' .. data.plate, -- Single item so no need to use metadata + args = { + name = vehicleTitle, + plate = data.plate, + model = vehicleModel, + vehicle = data.vehicle, + price = Config.ImpoundPrices[GetVehicleClassFromName(vehicleModel)] + } + } + end + + lib.registerContext({ + id = 'luke_garages:ImpoundMenu', + title = currentImpound.label or Locale(currentImpound.type) .. ' ' .. Locale('impound'), + options = options + }) + + lib.showContext('luke_garages:ImpoundMenu') end) ---todo: Refactor *everything* -RegisterNetEvent('luke_garages:GetOwnedVehicles') -AddEventHandler('luke_garages:GetOwnedVehicles', function() - ESX.TriggerServerCallback('luke_garages:GetVehicles', function(vehicles) - local menu = {} +RegisterNetEvent('luke_garages:GetOwnedVehicles', function() + local vehicles = lib.callback.await('luke_garages:GetVehicles', false, currentGarage.type, currentGarage.job) + local options = {} - TriggerEvent('nh-context:sendMenu', { - { - id = 0, - header = Config.SplitGarages == true and currentGarage.label or Locale(currentGarage.type) .. ' ' .. Locale('garage'), - txt = '' - }, + if not vehicles then + lib.registerContext({ + id = 'luke_garages:GarageMenu', + title = Config.SplitGarages == true and currentGarage.label or Locale(currentGarage.type) .. ' ' .. Locale('garage'), + options = { + [Locale('no_vehicles_garage')] = {} + } }) - if vehicles ~= nil then - for k, v in pairs(vehicles) do - local vehModel = v.vehicle.model - local vehMake = GetLabelText(GetMakeNameFromVehicleModel(vehModel)) - local vehName = GetLabelText(GetDisplayNameFromVehicleModel(vehModel)) - local vehTitle = vehMake .. ' ' .. vehName - if Config.SplitGarages then - if (v.stored == 1 or v.stored == true) and (v.garage == (currentGarage.zone.name or currentGarage.label) or not v.garage) then - table.insert(menu, { - id = k, - header = vehTitle, - txt = Locale('plate') .. ': ' .. v.plate .. '
' .. Locale('in_garage'), - params = { - event = 'luke_garages:VehicleMenu', - args = {name = vehTitle, plate = v.plate, model = vehModel, vehicle = v.vehicle, health = v.health} - } - }) - elseif (v.stored == 1 or v.stored == true) and v.garage ~= currentGarage.zone.name then - table.insert(menu, { - id = k, - header = vehTitle, - txt = Locale('plate') .. ': ' .. v.plate .. '
' .. Locale('garage') .. ': ' .. GetGarageLabel(v.garage), - }) - else - table.insert(menu, { - id = k, - header = vehTitle, - txt = Locale('plate') .. ': ' .. v.plate .. '
' .. Locale('not_in_garage'), - }) - end - else - if v.stored == 1 or v.stored == true then - table.insert(menu, { - id = k, - header = vehTitle, - txt = Locale('plate') .. ': ' .. v.plate .. '
' .. Locale('in_garage'), - params = { - event = 'luke_garages:VehicleMenu', - args = {name = vehTitle, plate = v.plate, model = vehModel, vehicle = v.vehicle, health = v.health} - } - }) - else - table.insert(menu, { - id = k, - header = vehTitle, - txt = Locale('plate') .. ': ' .. v.plate .. '
' .. Locale('not_in_garage'), - }) - end - end - end - if #menu ~= 0 then - TriggerEvent('nh-context:sendMenu', menu) - else - TriggerEvent('nh-context:sendMenu', { - { - id = 1, - header = Locale('no_vehicles_garage'), - txt = '' - } - }) - end - else - TriggerEvent('nh-context:sendMenu', { - { - id = 1, - header = Locale('no_vehicles_garage'), - txt = '', - } - }) - end - end, currentGarage.type, currentGarage.job) -end) + return lib.showContext('luke_garages:GarageMenu') + end -RegisterNetEvent('luke_garages:ImpoundVehicleMenu') -AddEventHandler('luke_garages:ImpoundVehicleMenu', function(data) - TriggerEvent('nh-context:sendMenu', { - { - id = 0, - header = Locale('menu_go_back'), - txt = '', - params = { - event = 'luke_garages:GetImpoundedVehicles', + for i = 1, #vehicles do + local data = vehicles[i] + local vehicleMake = GetLabelText(GetMakeNameFromVehicleModel(data.vehicle.model)) + local vehicleModel = GetLabelText(GetDisplayNameFromVehicleModel(data.vehicle.model)) + local vehicleTitle = vehicleMake .. ' ' .. vehicleModel + options[vehicleTitle] = { + event = (data.stored == 1 or data.stored == true) and 'luke_garages:VehicleMenu' or nil, + arrow = (data.stored == 1 or data.stored == true) and 'luke_garages:VehicleMenu' or false, + args = {name = vehicleTitle, plate = data.plate, model = vehicleModel, vehicle = data.vehicle}, + metadata = { + [Locale('plate')] = data.plate, + [Locale("status")] = isVehicleInGarage(data.garage, data.stored) } - }, - { - id = 1, - header = Locale('take_out_vehicle_impound'), - txt = Locale('car') .. ': ' .. data.name .. '
' .. Locale('plate') .. ': ' .. data.plate .. '
' .. Locale('price') .. ': ' .. Locale('$') .. data.price, - params = { + } + end + + lib.registerContext({ + id = 'luke_garages:GarageMenu', + title = Config.SplitGarages == true and currentGarage.label or Locale(currentGarage.type) .. ' ' .. Locale('garage'), + options = options + }) + + lib.showContext('luke_garages:GarageMenu') +end) + +RegisterNetEvent('luke_garages:ImpoundVehicleMenu', function(data) + lib.registerContext({ + id = 'luke_garages:ImpoundVehicleMenu', + title = data.name, + menu = 'luke_garages:ImpoundMenu', + options = { + [Locale('take_out_vehicle_impound')] = { + metadata = { + [Locale('plate')] = data.plate, + [Locale('price')] = Locale('$') .. data.price + }, event = 'luke_garages:RequestVehicle', args = { vehicle = data.vehicle, - health = data.health, price = data.price, type = 'impound' } } } }) + + lib.showContext('luke_garages:ImpoundVehicleMenu') end) -RegisterNetEvent('luke_garages:VehicleMenu') -AddEventHandler('luke_garages:VehicleMenu', function(data) - TriggerEvent('nh-context:sendMenu', { - { - id = 0, - header = Locale('menu_go_back'), - txt = '', - params = { - event = 'luke_garages:GetOwnedVehicles' - } - }, - { - id = 1, - header = Locale('take_out_vehicle'), - txt = Locale('car') .. ': ' .. data.name .. ' | ' .. Locale('plate') .. ': ' .. data.plate, - params = { +RegisterNetEvent('luke_garages:VehicleMenu', function(data) + lib.registerContext({ + id = 'luke_garages:VehicleMenu', + title = data.name, + menu = 'luke_garages:GarageMenu', + options = { + [Locale('take_out_vehicle')] = { event = 'luke_garages:RequestVehicle', args = { vehicle = data.vehicle, - health = data.health, type = 'garage' } } } }) + + lib.showContext('luke_garages:VehicleMenu') end) -RegisterNetEvent('luke_garages:RequestVehicle') -AddEventHandler('luke_garages:RequestVehicle', function(data) +RegisterNetEvent('luke_garages:RequestVehicle', function(data) local spawn = nil if data.type == 'garage' then @@ -438,63 +402,26 @@ AddEventHandler('luke_garages:RequestVehicle', function(data) for i = 1, #spawn do if ESX.Game.IsSpawnPointClear(vector3(spawn[i].x, spawn[i].y, spawn[i].z), 1.0) then - return VehicleSpawn(data, spawn[i], data.type == 'impound' and data.price or nil) + return spawnVehicle(data, spawn[i], data.type == 'impound' and data.price or nil) end if i == #spawn then ESX.ShowNotification(Locale('no_spawn_spots')) end end end) -RegisterNetEvent('luke_garages:StoreVehicle') -AddEventHandler('luke_garages:StoreVehicle', function(target) - local health = {} - local brokenParts = { - windows = {}, - tires = {}, - doors = {} - } - +RegisterNetEvent('luke_garages:StoreVehicle', function(target) local vehicle = target.entity local vehPlate = GetVehicleNumberPlateText(vehicle) + local vehProps = lib.getVehicleProperties(vehicle) - for window = 0, 7 do - if not IsVehicleWindowIntact(vehicle, window) then - table.insert(brokenParts.windows, window) - end - end + local doesOwn = lib.callback.await('luke_garages:CheckOwnership', false, vehPlate, vehProps.model, currentGarage.job) - for index = 0, 5 do - if IsVehicleTyreBurst(vehicle, index, false) then - table.insert(brokenParts.tires, index) - end - if IsVehicleDoorDamaged(vehicle, index) then - table.insert(brokenParts.doors, index) - end - end - - health.body = ESX.Math.Round(GetVehicleBodyHealth(vehicle), 2) - health.engine = ESX.Math.Round(GetVehicleEngineHealth(vehicle), 2) - health.parts = brokenParts - health.fuel = ESX.Math.Round(GetVehicleFuelLevel(vehicle), 2) - - local ent = Entity(vehicle) - if ent.state.fuel ~= nil then - health.fuel = ESX.Math.Round(ent.state.fuel, 2) + if doesOwn then + if type(doesOwn) == 'table' then return ESX.ShowNotification(Locale('garage_cant_store')) end + TriggerServerEvent('luke_garages:SaveVehicle', vehProps, vehPlate, VehToNet(vehicle), currentGarage.zone.name) + else + ESX.ShowNotification(Locale('no_ownership')) end - local vehProps = getVehProperties(vehicle) - - ESX.TriggerServerCallback('luke_garages:CheckOwnership', function(doesOwn) - if doesOwn then - if type(doesOwn) == 'table' then return ESX.ShowNotification(Locale('garage_cant_store')) end - - TriggerServerEvent('luke_garages:ChangeStored', vehPlate, true, currentGarage.zone.name) - - TriggerServerEvent('luke_garages:SaveVehicle', vehProps, health, vehPlate, VehToNet(vehicle)) - else - ESX.ShowNotification(Locale('no_ownership')) - end - end, vehPlate, vehProps.model, currentGarage.job) - end) RegisterNetEvent('esx:setJob', function(job) diff --git a/client/vehicle_functions.lua b/client/vehicle_functions.lua deleted file mode 100644 index dc8af6c..0000000 --- a/client/vehicle_functions.lua +++ /dev/null @@ -1,453 +0,0 @@ -function getVehProperties(vehicle) - if DoesEntityExist(vehicle) then - local ent = Entity(vehicle) - local colorPrimary, colorSecondary = GetVehicleColours(vehicle) - local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) - local customPrimaryColor, customSecondaryColor = nil, nil - - if GetIsVehiclePrimaryColourCustom(vehicle) then - local r, g, b = GetVehicleCustomPrimaryColour(vehicle) - customPrimaryColor = { r, g, b } - end - - if GetIsVehicleSecondaryColourCustom(vehicle) then - local r, g, b = GetVehicleCustomSecondaryColour(vehicle) - customSecondaryColor = { r, g, b } - end - - local extras = {} - - for i = 0, 14 do - if DoesExtraExist(vehicle, i) then - -- [0=on, 1=off] - if IsVehicleExtraTurnedOn(vehicle, i) then - extras[i] = false - else - extras[i] = true - end - end - end - - if GetVehicleMod(vehicle, 48) == -1 and GetVehicleLivery(vehicle) ~= -1 then - modLivery = GetVehicleLivery(vehicle) - else - modLivery = GetVehicleMod(vehicle, 48) - end - - local neons = {} - local neonCount = 0 - - for i = 0, 3 do - if IsVehicleNeonLightEnabled(vehicle, i) then - neonCount += 1 - neons[neonCount] = i - end - end - - return { - model = GetEntityModel(vehicle), - plate = GetVehicleNumberPlateText(vehicle), - plateIndex = GetVehicleNumberPlateTextIndex(vehicle), - bodyHealth = math.floor(GetVehicleBodyHealth(vehicle) + 0.5), - engineHealth = math.floor(GetVehicleEngineHealth(vehicle) + 0.5), - tankHealth = math.floor(GetVehiclePetrolTankHealth(vehicle) + 0.5), - fuelLevel = math.floor(GetVehicleFuelLevel(vehicle) + 0.5), - dirtLevel = math.floor(GetVehicleDirtLevel(vehicle) + 0.5), - color1 = colorPrimary, - color2 = colorSecondary, - customPrimaryColor = customPrimaryColor, - customSecondaryColor = customSecondaryColor, - pearlescentColor = pearlescentColor, - interiorColor = GetVehicleInteriorColor(vehicle), - dashboardColor = GetVehicleDashboardColour(vehicle), - wheelColor = wheelColor, - wheels = GetVehicleWheelType(vehicle), - windowTint = GetVehicleWindowTint(vehicle), - xenonColor = GetVehicleXenonLightsColour(vehicle), - neonEnabled = neons, - neonColor = {GetVehicleNeonLightsColour(vehicle)}, - extras = extras, - tyreSmokeColor = {GetVehicleTyreSmokeColor(vehicle)}, - modSpoilers = GetVehicleMod(vehicle, 0), - modFrontBumper = GetVehicleMod(vehicle, 1), - modRearBumper = GetVehicleMod(vehicle, 2), - modSideSkirt = GetVehicleMod(vehicle, 3), - modExhaust = GetVehicleMod(vehicle, 4), - modFrame = GetVehicleMod(vehicle, 5), - modGrille = GetVehicleMod(vehicle, 6), - modHood = GetVehicleMod(vehicle, 7), - modFender = GetVehicleMod(vehicle, 8), - modRightFender = GetVehicleMod(vehicle, 9), - modRoof = GetVehicleMod(vehicle, 10), - modEngine = GetVehicleMod(vehicle, 11), - modBrakes = GetVehicleMod(vehicle, 12), - modTransmission = GetVehicleMod(vehicle, 13), - modHorns = GetVehicleMod(vehicle, 14), - modSuspension = GetVehicleMod(vehicle, 15), - modArmor = GetVehicleMod(vehicle, 16), - modNitrous = GetVehicleMod(vehicle, 17), - modTurbo = IsToggleModOn(vehicle, 18), - modSubwoofer = GetVehicleMod(vehicle, 19), - modSmokeEnabled = IsToggleModOn(vehicle, 20), - modHydraulics = IsToggleModOn(vehicle, 21), - modXenon = IsToggleModOn(vehicle, 22), - modFrontWheels = GetVehicleMod(vehicle, 23), - modBackWheels = GetVehicleMod(vehicle, 24), - modCustomTiresF = GetVehicleModVariation(vehicle, 23), - modCustomTiresR = GetVehicleModVariation(vehicle, 24), - modPlateHolder = GetVehicleMod(vehicle, 25), - modVanityPlate = GetVehicleMod(vehicle, 26), - modTrimA = GetVehicleMod(vehicle, 27), - modOrnaments = GetVehicleMod(vehicle, 28), - modDashboard = GetVehicleMod(vehicle, 29), - modDial = GetVehicleMod(vehicle, 30), - modDoorSpeaker = GetVehicleMod(vehicle, 31), - modSeats = GetVehicleMod(vehicle, 32), - modSteeringWheel = GetVehicleMod(vehicle, 33), - modShifterLeavers = GetVehicleMod(vehicle, 34), - modAPlate = GetVehicleMod(vehicle, 35), - modSpeakers = GetVehicleMod(vehicle, 36), - modTrunk = GetVehicleMod(vehicle, 37), - modHydrolic = GetVehicleMod(vehicle, 38), - modEngineBlock = GetVehicleMod(vehicle, 39), - modAirFilter = GetVehicleMod(vehicle, 40), - modStruts = GetVehicleMod(vehicle, 41), - modArchCover = GetVehicleMod(vehicle, 42), - modAerials = GetVehicleMod(vehicle, 43), - modTrimB = GetVehicleMod(vehicle, 44), - modTank = GetVehicleMod(vehicle, 45), - modWindows = GetVehicleMod(vehicle, 46), - modDoorR = GetVehicleMod(vehicle, 47), - modLivery = modLivery, - modLightbar = GetVehicleMod(vehicle, 49) - } - end -end - -function SetVehProperties(vehicle, props, health) - if DoesEntityExist(vehicle) then - local ent = Entity(vehicle) - local colorPrimary, colorSecondary = GetVehicleColours(vehicle) - local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) - if Config.LockDoors then SetVehicleDoorsLocked(vehicle, 2) end - SetVehicleModKit(vehicle, 0) - SetVehicleAutoRepairDisabled(vehicle, true) - - if props.plate then - SetVehicleNumberPlateText(vehicle, props.plate) - end - - if props.plateIndex then - SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex) - end - - if props.tankHealth then - SetVehiclePetrolTankHealth(vehicle, 1000.0) - end - - if props.dirtLevel then - SetVehicleDirtLevel(vehicle, props.dirtLevel + 0.0) - end - - if props.customPrimaryColor then - SetVehicleCustomPrimaryColour(vehicle, props.customPrimaryColor[1], props.customPrimaryColor[2], props.customPrimaryColor[3]) - end - - if props.customSecondaryColor then - SetVehicleCustomSecondaryColour(vehicle, props.customSecondaryColor[1], props.customSecondaryColor[2], props.customSecondaryColor[3]) - end - - if props.color1 then - SetVehicleColours(vehicle, props.color1, colorSecondary) - end - - if props.color2 then - SetVehicleColours(vehicle, props.color1 or colorPrimary, props.color2) - end - - if props.pearlescentColor then - SetVehicleExtraColours(vehicle, props.pearlescentColor, wheelColor) - end - - if props.interiorColor then - SetVehicleInteriorColor(vehicle, props.interiorColor) - end - - if props.dashboardColor then - SetVehicleDashboardColour(vehicle, props.dashboardColor) - end - - if props.wheelColor then - SetVehicleExtraColours(vehicle, props.pearlescentColor or pearlescentColor, props.wheelColor) - end - - if props.wheels then - SetVehicleWheelType(vehicle, props.wheels) - end - - if props.windowTint then - SetVehicleWindowTint(vehicle, props.windowTint) - end - - if props.neonEnabled then - SetVehicleNeonLightEnabled(vehicle, 0, props.neonEnabled[1]) - SetVehicleNeonLightEnabled(vehicle, 1, props.neonEnabled[2]) - SetVehicleNeonLightEnabled(vehicle, 2, props.neonEnabled[3]) - SetVehicleNeonLightEnabled(vehicle, 3, props.neonEnabled[4]) - end - - if props.extras then - for k, v in pairs(props.extras) do - SetVehicleExtra(vehicle, k, props.extras[k]) - end - end - - if props.neonColor then - SetVehicleNeonLightsColour(vehicle, props.neonColor[1], props.neonColor[2], props.neonColor[3]) - end - - if props.xenonColor then - SetVehicleXenonLightsColour(vehicle, props.xenonColor) - end - - if props.modSmokeEnabled then - ToggleVehicleMod(vehicle, 20, true) - end - - if props.tyreSmokeColor then - SetVehicleTyreSmokeColor(vehicle, props.tyreSmokeColor[1], props.tyreSmokeColor[2], props.tyreSmokeColor[3]) - end - - if props.modSpoilers then - SetVehicleMod(vehicle, 0, props.modSpoilers, false) - end - - if props.modFrontBumper then - SetVehicleMod(vehicle, 1, props.modFrontBumper, false) - end - - if props.modRearBumper then - SetVehicleMod(vehicle, 2, props.modRearBumper, false) - end - - if props.modSideSkirt then - SetVehicleMod(vehicle, 3, props.modSideSkirt, false) - end - - if props.modExhaust then - SetVehicleMod(vehicle, 4, props.modExhaust, false) - end - - if props.modFrame then - SetVehicleMod(vehicle, 5, props.modFrame, false) - end - - if props.modGrille then - SetVehicleMod(vehicle, 6, props.modGrille, false) - end - - if props.modHood then - SetVehicleMod(vehicle, 7, props.modHood, false) - end - - if props.modFender then - SetVehicleMod(vehicle, 8, props.modFender, false) - end - - if props.modRightFender then - SetVehicleMod(vehicle, 9, props.modRightFender, false) - end - - if props.modRoof then - SetVehicleMod(vehicle, 10, props.modRoof, false) - end - - if props.modEngine then - SetVehicleMod(vehicle, 11, props.modEngine, false) - end - - if props.modBrakes then - SetVehicleMod(vehicle, 12, props.modBrakes, false) - end - - if props.modTransmission then - SetVehicleMod(vehicle, 13, props.modTransmission, false) - end - - if props.modHorns then - SetVehicleMod(vehicle, 14, props.modHorns, false) - end - - if props.modSuspension then - SetVehicleMod(vehicle, 15, props.modSuspension, false) - end - - if props.modArmor then - SetVehicleMod(vehicle, 16, props.modArmor, false) - end - - if props.modTurbo then - ToggleVehicleMod(vehicle, 18, props.modTurbo) - end - - if props.modSubwoofer then - ToggleVehicleMod(vehicle, 19, props.modSubwoofer) - end - - if props.modHydraulics then - ToggleVehicleMod(vehicle, 21, props.modHydraulics) - end - - if props.modXenon then - ToggleVehicleMod(vehicle, 22, props.modXenon) - end - - if props.xenonColor then - SetVehicleXenonLightsColor(vehicle, props.xenonColor) - end - - if props.modFrontWheels then - SetVehicleMod(vehicle, 23, props.modFrontWheels, props.modCustomTiresF) - end - - if props.modBackWheels then - SetVehicleMod(vehicle, 24, props.modBackWheels, props.modCustomTiresR) - end - - if props.modPlateHolder then - SetVehicleMod(vehicle, 25, props.modPlateHolder, false) - end - - if props.modVanityPlate then - SetVehicleMod(vehicle, 26, props.modVanityPlate, false) - end - - if props.modTrimA then - SetVehicleMod(vehicle, 27, props.modTrimA, false) - end - - if props.modOrnaments then - SetVehicleMod(vehicle, 28, props.modOrnaments, false) - end - - if props.modDashboard then - SetVehicleMod(vehicle, 29, props.modDashboard, false) - end - - if props.modDial then - SetVehicleMod(vehicle, 30, props.modDial, false) - end - - if props.modDoorSpeaker then - SetVehicleMod(vehicle, 31, props.modDoorSpeaker, false) - end - - if props.modSeats then - SetVehicleMod(vehicle, 32, props.modSeats, false) - end - - if props.modSteeringWheel then - SetVehicleMod(vehicle, 33, props.modSteeringWheel, false) - end - - if props.modShifterLeavers then - SetVehicleMod(vehicle, 34, props.modShifterLeavers, false) - end - - if props.modAPlate then - SetVehicleMod(vehicle, 35, props.modAPlate, false) - end - - if props.modSpeakers then - SetVehicleMod(vehicle, 36, props.modSpeakers, false) - end - - if props.modTrunk then - SetVehicleMod(vehicle, 37, props.modTrunk, false) - end - - if props.modHydrolic then - SetVehicleMod(vehicle, 38, props.modHydrolic, false) - end - - if props.modEngineBlock then - SetVehicleMod(vehicle, 39, props.modEngineBlock, false) - end - - if props.modAirFilter then - SetVehicleMod(vehicle, 40, props.modAirFilter, false) - end - - if props.modStruts then - SetVehicleMod(vehicle, 41, props.modStruts, false) - end - - if props.modArchCover then - SetVehicleMod(vehicle, 42, props.modArchCover, false) - end - - if props.modAerials then - SetVehicleMod(vehicle, 43, props.modAerials, false) - end - - if props.modTrimB then - SetVehicleMod(vehicle, 44, props.modTrimB, false) - end - - if props.modTank then - SetVehicleMod(vehicle, 45, props.modTank, false) - end - - if props.modWindows then - SetVehicleMod(vehicle, 46, props.modWindows, false) - end - - if props.modDoorR then - SetVehicleMod(vehicle, 47, props.modDoorR, false) - end - - if props.modLivery then - SetVehicleMod(vehicle, 48, props.modLivery, false) - SetVehicleLivery(vehicle, props.modLivery) - end - - if props.modLightbar then - SetVehicleMod(vehicle, 49, props.modLightbar, false) - end - if health ~= nil then - health.engine = ESX.Math.Round(health.engine, 2) - health.body = ESX.Math.Round(health.body, 2) - - -- Making the vehicle still drivable if it's completely totaled - if health.engine < 200.0 then - health.engine = 200.0 - end - - if health.body < 150.0 then - health.body = 150.0 - end - - for _, window in pairs(health.parts.windows) do - SmashVehicleWindow(vehicle, window) - end - - for _, tyre in pairs(health.parts.tires) do - SetVehicleTyreBurst(vehicle, tyre, true, 1000.0) - end - - for _, door in pairs(health.parts.doors) do - SetVehicleDoorBroken(vehicle, door, false) - end - - SetVehicleBodyHealth(vehicle, health.body) - SetVehicleEngineHealth(vehicle, health.engine) - if health.fuel ~= nil then - health.fuel = ESX.Math.Round(health.fuel, 2) - SetVehicleFuelLevel(vehicle, health.fuel) - ent.state:set('fuel', health.fuel, true) - end - else - return - end - end -end \ No newline at end of file diff --git a/config.lua b/config.lua index 4d0bcca..9b03263 100644 --- a/config.lua +++ b/config.lua @@ -3,11 +3,12 @@ Config = {} Config.Locale = 'en' Config.EnableVersionCheck = true -- If set to true you'll get a print in server console when your resource is out of date -Config.VersionCheckInterval = 60 -- in minutes -- If using split garages on first start all vehicles will default to legion garage. after that they will restore at the last garage you put it in. Config.RestoreVehicles = false +Config.TeleportToVehicle = false -- enable this if you have issues with vehicle mods not setting properly. + -- Default garage zone name the vehicles will be restored to -- Ignore if not using split garages Config.DefaultGarage = 'legion' @@ -15,10 +16,8 @@ Config.DefaultGarage = 'legion' -- Setting to true will only allow you take out the vehicle from a garage you put it in Config.SplitGarages = false --- Locks vehicles doors on spawn -Config.LockDoors = false - Config.DefaultGaragePed = `s_m_y_airworker` + Config.DefaultImpoundPed = `s_m_y_construct_01` Config.BlipColors = { @@ -29,28 +28,28 @@ Config.BlipColors = { Config.ImpoundPrices = { -- These are vehicle classes - ['0'] = 300, -- Compacts - ['1'] = 500, -- Sedans - ['2'] = 500, -- SUVs - ['3'] = 800, -- Coupes - ['4'] = 1200, -- Muscle - ['5'] = 800, -- Sports Classics - ['6'] = 1500, -- Sports - ['7'] = 2500, -- Super - ['8'] = 300, -- Motorcycles - ['9'] = 500, -- Off-road - ['10'] = 1000, -- Industrial - ['11'] = 500, -- Utility - ['12'] = 600, -- Vans - ['13'] = 100, -- Cylces - ['14'] = 2800, -- Boats - ['15'] = 3500, -- Helicopters - ['16'] = 3800, -- Planes - ['17'] = 500, -- Service - ['18'] = 0, -- Emergency - ['19'] = 100, -- Military - ['20'] = 1500, -- Commercial - ['21'] = 0 -- Trains (lol) + [0] = 300, -- Compacts + [1] = 500, -- Sedans + [2] = 500, -- SUVs + [3] = 800, -- Coupes + [4] = 1200, -- Muscle + [5] = 800, -- Sports Classics + [6] = 1500, -- Sports + [7] = 2500, -- Super + [8] = 300, -- Motorcycles + [9] = 500, -- Off-road + [10] = 1000, -- Industrial + [11] = 500, -- Utility + [12] = 600, -- Vans + [13] = 100, -- Cylces + [14] = 2800, -- Boats + [15] = 3500, -- Helicopters + [16] = 3800, -- Planes + [17] = 500, -- Service + [18] = 0, -- Emergency + [19] = 100, -- Military + [20] = 1500, -- Commercial + [21] = 0 -- Trains (lol) } Config.PayInCash = true -- whether you want to pay impound price in cash, otherwise uses bank @@ -198,7 +197,7 @@ Config.Garages = { { label = 'MRPD Police Garage', type = 'car', - job = 'police', + job = {['police'] = 0}, ped = `s_m_y_cop_01`, pedCoords = vector4(450.6633, -1027.3324, 27.5732, 5.1321), zone = {name = 'mrpd', x = 439.36, y= -1021.04, z = 28.83, l = 20, w = 40, h = 0, minZ = 27.03, maxZ = 31.03}, @@ -232,6 +231,7 @@ Config.Garages = { label = '', -- name that will be displayed in menus type = 'car', -- can be 'car', 'boat' or 'aircraft', job = 'jobName', -- Set garage to be only accessed and stored into by a job (Optional) + -- If you want multiple jobs and grades you can do job = {['police'] = 0, ['mechanic'] = 3} ped = `ped_model_name`, -- Define the model model you want to use for the garage (Optional) pedCoords = vector4(x, y, z, h), -- Ped MUST be inside the create zone zone = {name = 'somename', x = X, y = X, z = X, l = X, w = X, h = X, minZ = X, maxZ = x}, -- l is length of the box zone, w is width, h is heading, take all walues from generated zone from /pzcreate diff --git a/fxmanifest.lua b/fxmanifest.lua index 7d81e81..6044f0e 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -16,6 +16,7 @@ dependencies { shared_scripts { '@es_extended/imports.lua', + '@ox_lib/init.lua', 'locale.lua', 'locales/*.lua', 'config.lua' diff --git a/locales/br.lua b/locales/br.lua index a5e9525..2d6688b 100644 --- a/locales/br.lua +++ b/locales/br.lua @@ -21,6 +21,6 @@ Locales['br'] = { ['no_ownership'] = "Você não possui este veículo", ['no_money_cash'] = "Você não tem dinheiro suficiente com você", ['no_money_bank'] = "Você não tem dinheiro suficiente em sua conta bancária", - ['menu_go_back'] = "< Voltar", - ['vehicle_already_exists'] = "Vehicle already exists" + ['vehicle_already_exists'] = "Vehicle already exists", + ["status"] = "Status" } diff --git a/locales/cs.lua b/locales/cs.lua index 74671d6..415068f 100644 --- a/locales/cs.lua +++ b/locales/cs.lua @@ -21,6 +21,6 @@ Locales['cs'] = { ['no_ownership'] = "Toto vozidlo nevlastníte", ['no_money_cash'] = "Nemáte u sebe dost peněz", ['no_money_bank'] = "Na svém bankovním účtu nemáte dostatek peněz", - ['menu_go_back'] = "< Jít zpět", - ['vehicle_already_exists'] = "Vehicle already exists" + ['vehicle_already_exists'] = "Vehicle already exists", + ["status"] = "Status" } diff --git a/locales/de.lua b/locales/de.lua new file mode 100644 index 0000000..ac417ff --- /dev/null +++ b/locales/de.lua @@ -0,0 +1,26 @@ +Locales['de'] = { + ['$'] = '$', + ['car'] = 'Auto', + ['boat'] = 'Boot', + ['aircraft'] = 'Flugzeug', + ['plate'] = "Kennzeichen", + ['price'] = "Preis", + ['impound'] = "Abschlepphof", + ['impound_lot'] = "Abschlepphof", + ['access_impound'] = "Auf Abschlepphof zugreifen", + ['take_out_vehicle_impound'] = "Fahrzeug aus Abschlepphof holen", + ['no_vehicles_impound'] = "Kein Fahrzeug im Abschlepphof", + ['garage'] = "Garage", + ['garage_cant_store'] = "Du kannst dieses Fahrzeug hier nicht einparken", + ['take_out_vehicle'] = "Fahrzeug ausparken", + ['store_vehicle'] = "Fahrzeug einparken", + ['in_garage'] = "In der Garage", + ['not_in_garage'] = "Nicht in der Garage", + ['no_vehicles_garage'] = "Keine Fahrzeuge in der Garage", + ['no_spawn_spots'] = "Es sind keine freien Parkflächen vorhanden", + ['no_ownership'] = "Dir gehört dieses Fahrzeug nicht", + ['no_money_cash'] = "Du hast nicht genug Geld dabei", + ['no_money_bank'] = "Du hast nicht genug Geld auf deinem Bank-Konto", + ['vehicle_already_exists'] = "Fahrzeug existiert bereits", + ["status"] = "Status" +} diff --git a/locales/en.lua b/locales/en.lua index bef4086..af1502e 100644 --- a/locales/en.lua +++ b/locales/en.lua @@ -21,6 +21,6 @@ Locales['en'] = { ['no_ownership'] = "You do not own this vehicle", ['no_money_cash'] = "You do not have enough money on you", ['no_money_bank'] = "You do not have enough money in your bank account", - ['menu_go_back'] = "< Go back", - ['vehicle_already_exists'] = "Vehicle already exists" + ['vehicle_already_exists'] = "Vehicle already exists", + ["status"] = "Status" } \ No newline at end of file diff --git a/locales/fr.lua b/locales/fr.lua index c8be3ad..2c6a99b 100644 --- a/locales/fr.lua +++ b/locales/fr.lua @@ -21,6 +21,6 @@ Locales['fr'] = { ['no_ownership'] = "Tu ne possède pas ce Véhicule", ['no_money_cash'] = "Tu n'a pas assez d'argent sur toi", ['no_money_bank'] = "Tu n'a pas assez d'argent en banque", - ['menu_go_back'] = "< Revenir", - ['vehicle_already_exists'] = "Vehicle already exists" + ['vehicle_already_exists'] = "Vehicle already exists", + ["status"] = "Status" } diff --git a/locales/it.lua b/locales/it.lua index 3af22c8..f0a247a 100644 --- a/locales/it.lua +++ b/locales/it.lua @@ -21,6 +21,6 @@ Locales['it'] = { ['no_ownership'] = "Questo veicolo non ti appartiene", ['no_money_cash'] = "Non hai abbastanza soldi con te", ['no_money_bank'] = "Non hai abbastanza soldi in banca", - ['menu_go_back'] = "< Torna Indietro", - ['vehicle_already_exists'] = "Il veicolo è già fuori dal garage" + ['vehicle_already_exists'] = "Il veicolo è già fuori dal garage", + ["status"] = "Status" } diff --git a/locales/sr.lua b/locales/sr.lua index 7089095..ae5ef51 100644 --- a/locales/sr.lua +++ b/locales/sr.lua @@ -22,5 +22,6 @@ Locales['sr'] = { ['no_money_cash'] = "Nemaš dovoljno novca kod sebe", ['no_money_bank'] = "Nemaš dovoljno novca na bankovnom računu", ['menu_go_back'] = "< Vrati se", - ['vehicle_already_exists'] = "Vozilo već postoji" + ['vehicle_already_exists'] = "Vozilo već postoji", + ["status"] = "Status" } \ No newline at end of file diff --git a/luke_garages.sql b/luke_garages.sql index 8717c34..e4dd171 100644 --- a/luke_garages.sql +++ b/luke_garages.sql @@ -9,6 +9,5 @@ CREATE TABLE IF NOT EXISTS `owned_vehicles` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ALTER TABLE `owned_vehicles` - ADD COLUMN `health` TEXT(255) DEFAULT NULL, ADD COLUMN `last_garage` VARCHAR(40) DEFAULT 'legion', ADD COLUMN `garage` VARCHAR(40) DEFAULT NULL; diff --git a/server/server.lua b/server/server.lua index ea66ef8..cc4fac3 100644 --- a/server/server.lua +++ b/server/server.lua @@ -2,156 +2,154 @@ RegisterNetEvent('luke_garages:ThrowError', function(text) error(text) end) +if Config.EnableVersionCheck then lib.versionCheck('lukewastakenn/luke_garages') end + if Config.RestoreVehicles then MySQL.ready(function() - MySQL.Async.execute("UPDATE `owned_vehicles` SET `stored` = 1, `garage` = `last_garage` WHERE `stored` = 0", {}) + MySQL.Async.execute("UPDATE `owned_vehicles` SET `stored` = 1, `garage` = `last_garage` WHERE `stored` = 0") end) end -ESX.RegisterServerCallback('luke_garages:GetVehicles', function(source, callback, type, job) +lib.callback.register('luke_garages:GetVehicles', function(source, garageType, job) local xPlayer = ESX.GetPlayerFromId(source) local identifier = xPlayer.getIdentifier() local vehicles = {} if not job then - MySQL.Async.fetchAll("SELECT `plate`, `vehicle`, `stored`, `health`, `garage`, `job` FROM `owned_vehicles` WHERE `owner` = @identifier AND `type` = @type", { + local results = MySQL.Sync.fetchAll("SELECT `plate`, `vehicle`, `stored`, `health`, `garage`, `job` FROM `owned_vehicles` WHERE `owner` = @identifier AND `type` = @type", { ['@identifier'] = identifier, - ['@type'] = type - }, function(result) - if result[1] ~= nil then - for k, v in pairs(result) do - if not v.job or v.job == 'civ' then - local veh = json.decode(v.vehicle) - local health = json.decode(v.health) - table.insert(vehicles, {plate = v.plate, vehicle = veh, stored = v.stored, health = health, garage = v.garage}) - end + ['@type'] = garageType + }) + if results[1] ~= nil then + for i = 1, #results do + local result = results[i] + if not result.job or result.job == 'civ' then + local veh = json.decode(result.vehicle) + local health = json.decode(result.health) + vehicles[#vehicles+1] = {plate = result.plate, vehicle = veh, stored = result.stored, health = health, garage = result.garage} end - callback(vehicles) - else - callback(nil) end - end) + + return vehicles + end else - MySQL.Async.fetchAll('SELECT `plate`, `vehicle`, `stored`, `health`, `garage` FROM `owned_vehicles` WHERE (`owner` = @identifier OR `owner` = @job) AND `type` = @type AND `job` = @job', { + local jobs = {} + if type(job) == 'table' then for k, _ in pairs(job) do jobs[#jobs+1] = k end else jobs = job end + local results = MySQL.Sync.fetchAll('SELECT `plate`, `vehicle`, `stored`, `health`, `garage` FROM `owned_vehicles` WHERE (`owner` = @identifier OR `owner` IN (@jobs)) AND `type` = @type AND `job` IN (@jobs)', { ['@identifier'] = identifier, - ['@type'] = type, - ['@job'] = job - }, function(result) - if result[1] ~= nil then - for k, v in pairs(result) do - local veh = json.decode(v.vehicle) - local health = json.decode(v.health) - table.insert(vehicles, {plate = v.plate, vehicle = veh, stored = v.stored, health = health, garage = v.garage}) - end - callback(vehicles) - else - callback(nil) + ['@type'] = garageType, + ['@jobs'] = jobs + }) + if results[1] ~= nil then + for i = 1, #results do + local result = results[i] + local veh = json.decode(result.vehicle) + local health = json.decode(result.health) + vehicles[#vehicles+1] = {plate = result.plate, vehicle = veh, stored = result.stored, health = health, garage = result.garage} end - end) + + return vehicles + end end end) -ESX.RegisterServerCallback('luke_garages:GetImpound', function(source, callback, type) +lib.callback.register('luke_garages:GetImpound', function(source, type) local xPlayer = ESX.GetPlayerFromId(source) local identifier = xPlayer.getIdentifier() local vehicles = {} local worldVehicles = GetAllVehicles() - MySQL.Async.fetchAll('SELECT `plate`, `vehicle`, `health`, `job` FROM owned_vehicles WHERE (`owner` = @identifier OR `owner` = @job) AND `type` = @type AND `stored` = 0', { + local results = MySQL.Sync.fetchAll('SELECT `plate`, `vehicle`, `health`, `job` FROM owned_vehicles WHERE (`owner` = @identifier OR `owner` = @job) AND `type` = @type AND `stored` = 0', { ['@identifier'] = identifier, ['@type'] = type, ['@job'] = xPlayer.job.name - }, function(results) - if results[1] ~= nil then - for k, v in pairs(results) do - local veh = json.decode(v.vehicle) - local health = json.decode(v.health) - for index, vehicle in pairs(worldVehicles) do - if ESX.Math.Trim(v.plate) == ESX.Math.Trim(GetVehicleNumberPlateText(vehicle)) then - if GetVehiclePetrolTankHealth(vehicle) > 0 and GetVehicleBodyHealth(vehicle) > 0 then - break - end - if GetVehiclePetrolTankHealth(vehicle) <= 0 and GetVehicleBodyHealth(vehicle) <= 0 then - DeleteEntity(vehicle) - end - break - elseif index == #worldVehicles then - -- Allows players to only get their job vehicle from impound while having the job - if (v.job == 'civ' or v.job == nil) or v.job == xPlayer.job.name then - table.insert(vehicles, {plate = v.plate, vehicle = veh, health = health}) - end + }) + if results[1] ~= nil then + for i = 1, #results do + local result = results[i] + local veh = json.decode(result.vehicle) + local health = json.decode(result.health) + for index = 1, #worldVehicles do + local vehicle = worldVehicles[index] + if ESX.Math.Trim(result.plate) == ESX.Math.Trim(GetVehicleNumberPlateText(vehicle)) then + if GetVehiclePetrolTankHealth(vehicle) > 0 and GetVehicleBodyHealth(vehicle) > 0 then break end + if GetVehiclePetrolTankHealth(vehicle) <= 0 and GetVehicleBodyHealth(vehicle) <= 0 then DeleteEntity(vehicle) end + break + elseif index == #worldVehicles then + -- Allows players to only get their job vehicle from impound while having the job + if (result.job == 'civ' or result.job == nil) or result.job == xPlayer.job.name then + vehicles[#vehicles+1] = {plate = result.plate, vehicle = veh, health = health} end end end - callback(vehicles) - else - callback(nil) end - end) + + return vehicles + end end) -ESX.RegisterServerCallback('luke_garages:CheckOwnership', function(source, callback, plate, model, job) +lib.callback.register('luke_garages:CheckOwnership', function(source, plate, model, job) local xPlayer = ESX.GetPlayerFromId(source) local identifier = xPlayer.getIdentifier() plate = ESX.Math.Trim(plate) - MySQL.Async.fetchAll('SELECT `vehicle`, `job` FROM owned_vehicles WHERE (`owner` = @owner OR `job` = @job) AND `plate` = @plate', { + local jobs = {} + if type(job) == 'table' then for k, _ in pairs(job) do jobs[#jobs+1] = k end else jobs = job end + local result = MySQL.Sync.fetchAll("SELECT `vehicle`, `job` FROM owned_vehicles WHERE (`owner` = @owner OR `job` IN ('police')) AND `plate` = @plate", { ['@owner'] = identifier, - ['@plate'] = plate, - ['@job'] = xPlayer.job.name - }, function(result) - if result[1] then - local vehicle = json.decode(result[1].vehicle) - local vehicleJob = result[1].job - if ESX.Math.Trim(vehicle.plate) == plate and vehicle.model == model then - if not job and not vehicleJob or vehicleJob == 'civ' then return callback(true) end - if job and job == vehicleJob then return callback(true) - else return callback({true, false}) end - else - -- Player tried to cheat - callback(false) - end + ['@plate'] = ESX.Math.Trim(plate), + ['@jobs'] = jobs + }) + + if result[1] then + local vehicle = json.decode(result[1].vehicle) + local vehicleJob = result[1].job + if ESX.Math.Trim(vehicle.plate) == plate and vehicle.model == model then + if not job and not vehicleJob or vehicleJob == 'civ' then return true end + if job then + if type(jobs) == 'table' then + for i = 1, #jobs do + if jobs[i] == vehicleJob then return true end + if i == #jobs then return {true, false} end + end + else + if job == vehicleJob then + return true + else + return {true, false} + end + end + else if vehicleJob ~= 'civ' then return {true,false} end end else - callback(false) + -- Player tried to cheat + return false end - end) + end end) -RegisterNetEvent('luke_garages:ChangeStored') -AddEventHandler('luke_garages:ChangeStored', function(plate, stored, garage) +RegisterNetEvent('luke_garages:ChangeStored', function(plate) local plate = ESX.Math.Trim(plate) - if stored then - stored = 1 - MySQL.Async.execute('UPDATE `owned_vehicles` SET `stored` = @stored, `garage` = @garage, `last_garage` = @garage WHERE `plate` = @plate', { - ['@garage'] = garage, - ['@stored'] = stored, - ['@plate'] = plate - }, function(rowsChanged) - end) - else - stored = 0 - garage = 'none' - MySQL.Async.execute('UPDATE `owned_vehicles` SET `stored` = @stored, `garage` = @garage WHERE `plate` = @plate', { - ['@garage'] = garage, - ['@stored'] = stored, - ['@plate'] = plate - }, function(rowsChanged) - end) - end + MySQL.Async.execute('UPDATE `owned_vehicles` SET `stored` = @stored, `garage` = @garage WHERE `plate` = @plate', { + ['@garage'] = 'none', + ['@stored'] = 0, + ['@plate'] = plate + }) end) -RegisterNetEvent('luke_garages:SaveVehicle') -AddEventHandler('luke_garages:SaveVehicle', function(vehicle, health, plate, ent) - DeleteEntity(NetworkGetEntityFromNetworkId(ent)) - MySQL.Async.execute('UPDATE `owned_vehicles` SET `vehicle` = @vehicle, `health` = @health WHERE `plate` = @plate', { - ['@health'] = json.encode(health), +RegisterNetEvent('luke_garages:SaveVehicle', function(vehicle, plate, ent, garage) + MySQL.Async.execute('UPDATE `owned_vehicles` SET `vehicle` = @vehicle, `garage` = @garage, `last_garage` = @garage, `stored` = @stored WHERE `plate` = @plate', { ['@vehicle'] = json.encode(vehicle), - ['@plate'] = ESX.Math.Trim(plate) + ['@plate'] = ESX.Math.Trim(plate), + ['@stored'] = 1, + ['@garage'] = garage }) + local ent = NetworkGetEntityFromNetworkId(ent) + DeleteEntity(ent) end) + local function canAfford(src, price) local xPlayer = ESX.GetPlayerFromId(src) if xPlayer then @@ -189,7 +187,7 @@ RegisterNetEvent('luke_garages:SpawnVehicle', function(model, plate, coords, hea end MySQL.Async.fetchAll('SELECT vehicle, plate, health, garage FROM `owned_vehicles` WHERE plate = @plate', {['@plate'] = ESX.Math.Trim(plate)}, function(result) if result[1] then - Citizen.CreateThread(function() + CreateThread(function() local entity = Citizen.InvokeNative(`CREATE_AUTOMOBILE`, model, coords.x, coords.y, coords.z, heading) local ped = GetPedInVehicleSeat(entity, -1) if ped > 0 then @@ -201,6 +199,17 @@ RegisterNetEvent('luke_garages:SpawnVehicle', function(model, plate, coords, hea end end end + if Config.TeleportToVehicle then + local playerPed = GetPlayerPed(xPlayer.source) + local timer = GetGameTimer() + while GetVehiclePedIsIn(playerPed) ~= entity do + Wait(0) + SetPedIntoVehicle(playerPed, entity, -1) + if timer - GetGameTimer() > 15000 then + break + end + end + end local ent = Entity(entity) ent.state.vehicleData = result[1] end) diff --git a/server/version_check.lua b/server/version_check.lua deleted file mode 100644 index 782d76f..0000000 --- a/server/version_check.lua +++ /dev/null @@ -1,26 +0,0 @@ -if Config.EnableVersionCheck == true then - local resource = GetCurrentResourceName() - local versionData = GetResourceMetadata(resource, 'version') - local gitRepo = 'https://raw.githubusercontent.com/lukewastakenn/luke_garages/master/fxmanifest.lua' - - function versionCheck(error, response, headers) - local response = tostring(response) - for line in response:gmatch("([^\n]*)\n?") do - if line:find('^version ') then - repoVersion = line:sub(10, (line:len(line) - 1)) - break - end - end - - if versionData < repoVersion then - print(string.format("New version is available: ^1%s^7, current version: ^3%s^0", repoVersion, versionData)) - end - end - - Citizen.CreateThread(function() - while true do - PerformHttpRequest(gitRepo, versionCheck, "GET") - Citizen.Wait(60000 * Config.VersionCheckInterval) - end - end) -end