diff --git a/__resource.lua b/__resource.lua new file mode 100644 index 00000000..40b44860 --- /dev/null +++ b/__resource.lua @@ -0,0 +1,14 @@ +resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937' + +description 'ESX Garage' + +server_scripts { + '@mysql-async/lib/MySQL.lua', + 'config.lua', + 'server/main.lua' +} + +client_scripts { + 'config.lua', + 'client/main.lua' +} diff --git a/client/main.lua b/client/main.lua new file mode 100644 index 00000000..84625a50 --- /dev/null +++ b/client/main.lua @@ -0,0 +1,369 @@ +ESX = nil +local LastGarage = nil +local LastPart = nil +local LastParking = nil + +Citizen.CreateThread(function() + while ESX == nil do + TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + Citizen.Wait(0) + end +end) + +AddEventHandler('esx_property:hasEnteredMarker', function(name, part, parking) + + if part == 'ExteriorEntryPoint' then + + local playerPed = GetPlayerPed(-1) + local coords = GetEntityCoords(playerPed) + local garage = Config.Garages[name] + + if IsPedInAnyVehicle(playerPed, false) then + + local vehicle, distance = ESX.Game.GetClosestVehicle({ + x = coords.x, + y = coords.y, + z = coords.z + }) + + if distance <= 2.0 then + + local vehicleProps = ESX.Game.GetVehicleProperties(vehicle) + + local spawnCoords = { + x = garage.InteriorSpawnPoint.Pos.x, + y = garage.InteriorSpawnPoint.Pos.y, + z = garage.InteriorSpawnPoint.Pos.z + } + + DeleteVehicle(vehicle) + + ESX.Game.Teleport(playerPed, spawnCoords, function() + + TriggerEvent('instance:create') + + ESX.Game.SpawnLocalVehicle(vehicleProps.model, spawnCoords, garage.InteriorSpawnPoint.Heading, function(vehicle) + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + ESX.Game.SetVehicleProperties(vehicle, vehicleProps) + end) + + ESX.TriggerServerCallback('esx_vehicleshop:getVehiclesInGarage', function(vehicles) + + Citizen.CreateThread(function() + + for i=1, #garage.Parkings, 1 do + for j=1, #vehicles, 1 do + + if i == vehicles[j].zone then + + local vehicleLoaded = false + + ESX.Game.SpawnLocalVehicle(vehicles[j].vehicle.model, { + x = garage.Parkings[i].Pos.x, + y = garage.Parkings[i].Pos.y, + z = garage.Parkings[i].Pos.z + }, garage.Parkings[i].Heading, function(vehicle) + ESX.Game.SetVehicleProperties(vehicle, vehicles[j].vehicle) + vehicleLoaded = true + end) + + while not vehicleLoaded do + Citizen.Wait(0) + end + + end + + end + end + + end) + + end, name) + + end) + + end + + else + + ESX.Game.Teleport(playerPed, { + x = garage.InteriorSpawnPoint.Pos.x, + y = garage.InteriorSpawnPoint.Pos.y, + z = garage.InteriorSpawnPoint.Pos.z + }, function() + + TriggerEvent('instance:create') + + ESX.TriggerServerCallback('esx_vehicleshop:getVehiclesInGarage', function(vehicles) + + Citizen.CreateThread(function() + + for i=1, #garage.Parkings, 1 do + for j=1, #vehicles, 1 do + + if i == vehicles[j].zone then + + local vehicleLoaded = false + + ESX.Game.SpawnLocalVehicle(vehicles[j].vehicle.model, { + x = garage.Parkings[i].Pos.x, + y = garage.Parkings[i].Pos.y, + z = garage.Parkings[i].Pos.z + }, garage.Parkings[i].Heading, function(vehicle) + ESX.Game.SetVehicleProperties(vehicle, vehicles[j].vehicle) + vehicleLoaded = true + end) + + while not vehicleLoaded do + Citizen.Wait(0) + end + + end + + end + end + + end) + + end, name) + + end) + + end + + end + + if part == 'InteriorExitPoint' then + + local playerPed = GetPlayerPed(-1) + local coords = GetEntityCoords(playerPed) + local garage = Config.Garages[name] + + if IsPedInAnyVehicle(playerPed, false) then + + local vehicle, distance = ESX.Game.GetClosestVehicle({ + x = coords.x, + y = coords.y, + z = coords.z + }) + + if distance <= 2.0 then + + local vehicleProps = ESX.Game.GetVehicleProperties(vehicle) + + local spawnCoords = { + x = garage.ExteriorSpawnPoint.Pos.x, + y = garage.ExteriorSpawnPoint.Pos.y, + z = garage.ExteriorSpawnPoint.Pos.z + } + + DeleteVehicle(vehicle) + + ESX.Game.Teleport(playerPed, spawnCoords, function() + + TriggerEvent('instance:close') + + ESX.Game.SpawnVehicle(vehicleProps.model, spawnCoords, garage.ExteriorSpawnPoint.Heading, function(vehicle) + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + ESX.Game.SetVehicleProperties(vehicle, vehicleProps) + end) + + end) + + end + + else + + ESX.Game.Teleport(playerPed, { + x = garage.ExteriorSpawnPoint.Pos.x, + y = garage.ExteriorSpawnPoint.Pos.y, + z = garage.ExteriorSpawnPoint.Pos.z + }, function() + TriggerEvent('instance:close') + end) + + end + + for i=1, #garage.Parkings, 1 do + + local vehicle, distance = ESX.Game.GetClosestVehicle({ + x = garage.Parkings[i].Pos.x, + y = garage.Parkings[i].Pos.y, + z = garage.Parkings[i].Pos.z + }) + + if distance <= 2.0 then + DeleteVehicle(vehicle) + end + + end + + end + + if part == 'Parking' then + + local playerPed = GetPlayerPed(-1) + local garage = Config.Garages[name] + + if IsPedInAnyVehicle(playerPed, false) then + + local vehicle, distance = ESX.Game.GetClosestVehicle() + local vehicleProps = ESX.Game.GetVehicleProperties(vehicle) + + if distance <= 2.0 then + TriggerServerEvent('esx_garage:setParking', name, parking, vehicleProps) + end + + end + + end + +end) + +AddEventHandler('esx_property:hasExitedMarker', function(name, part, parking) + + if part == 'Parking' then + + local playerPed = GetPlayerPed(-1) + local garage = Config.Garages[name] + + if IsPedInAnyVehicle(playerPed, false) then + TriggerServerEvent('esx_garage:setParking', name, parking, false) + end + + end + +end) + +-- Create Blips +Citizen.CreateThread(function() + + for k,v in pairs(Config.Garages) do + + if v.IsClosed then + + local blip = AddBlipForCoord(v.ExteriorEntryPoint.Pos.x, v.ExteriorEntryPoint.Pos.y, v.ExteriorEntryPoint.Pos.z) + + SetBlipSprite (blip, 357) + SetBlipDisplay(blip, 4) + SetBlipScale (blip, 1.2) + SetBlipColour (blip, 3) + SetBlipAsShortRange(blip, true) + + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("Garage") + EndTextCommandSetBlipName(blip) + + end + + end + +end) + +-- Display markers +Citizen.CreateThread(function() + while true do + + Wait(0) + + local playerPed = GetPlayerPed(-1) + local coords = GetEntityCoords(playerPed) + + for k,v in pairs(Config.Garages) do + + if v.IsClosed then + + if(GetDistanceBetweenCoords(coords, v.ExteriorEntryPoint.Pos.x, v.ExteriorEntryPoint.Pos.y, v.ExteriorEntryPoint.Pos.z, true) < Config.DrawDistance) then + DrawMarker(Config.MarkerType, v.ExteriorEntryPoint.Pos.x, v.ExteriorEntryPoint.Pos.y, v.ExteriorEntryPoint.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.MarkerSize.x, Config.MarkerSize.y, Config.MarkerSize.z, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, false, false, false, false) + end + + if(GetDistanceBetweenCoords(coords, v.InteriorExitPoint.Pos.x, v.InteriorExitPoint.Pos.y, v.InteriorExitPoint.Pos.z, true) < Config.DrawDistance) then + DrawMarker(Config.MarkerType, v.InteriorExitPoint.Pos.x, v.InteriorExitPoint.Pos.y, v.InteriorExitPoint.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.MarkerSize.x, Config.MarkerSize.y, Config.MarkerSize.z, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, false, false, false, false) + end + + end + + if IsPedInAnyVehicle(playerPed, false) then + + for i=1, #v.Parkings, 1 do + + local parking = v.Parkings[i] + + if(GetDistanceBetweenCoords(coords, parking.Pos.x, parking.Pos.y, parking.Pos.z, true) < Config.DrawDistance) then + DrawMarker(Config.MarkerType, parking.Pos.x, parking.Pos.y, parking.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.ParkingMarkerSize.x, Config.ParkingMarkerSize.y, Config.ParkingMarkerSize.z, Config.ParkingMarkerColor.r, Config.ParkingMarkerColor.g, Config.ParkingMarkerColor.b, 100, false, true, 2, false, false, false, false) + end + + end + + end + + end + + end +end) + +-- Enter / Exit marker events +Citizen.CreateThread(function() + while true do + + Wait(0) + + local playerPed = GetPlayerPed(-1) + local coords = GetEntityCoords(playerPed) + local isInMarker = false + local currentGarage = nil + local currentPart = nil + local currentParking = nil + + for k,v in pairs(Config.Garages) do + + if v.IsClosed then + + if GetDistanceBetweenCoords(coords, v.ExteriorEntryPoint.Pos.x, v.ExteriorEntryPoint.Pos.y, v.ExteriorEntryPoint.Pos.z, true) < Config.MarkerSize.x then + isInMarker = true + currentGarage = k + currentPart = 'ExteriorEntryPoint' + end + + if GetDistanceBetweenCoords(coords, v.InteriorExitPoint.Pos.x, v.InteriorExitPoint.Pos.y, v.InteriorExitPoint.Pos.z, true) < Config.MarkerSize.x then + isInMarker = true + currentGarage = k + currentPart = 'InteriorExitPoint' + end + + for i=1, #v.Parkings, 1 do + + local parking = v.Parkings[i] + + if GetDistanceBetweenCoords(coords, parking.Pos.x, parking.Pos.y, parking.Pos.z, true) < Config.ParkingMarkerSize.x then + isInMarker = true + currentGarage = k + currentPart = 'Parking' + currentParking = i + end + + end + + end + + end + + if isInMarker and not HasAlreadyEnteredMarker or (isInMarker and (LastGarage ~= currentGarage or LastPart ~= currentPart) ) then + + HasAlreadyEnteredMarker = true + LastGarage = currentGarage + LastPart = currentPart + LastParking = currentParking + + TriggerEvent('esx_property:hasEnteredMarker', currentGarage, currentPart, currentParking) + end + + if not isInMarker and HasAlreadyEnteredMarker then + + HasAlreadyEnteredMarker = false + + TriggerEvent('esx_property:hasExitedMarker', LastGarage, LastPart, LastParking) + end + + end +end) \ No newline at end of file diff --git a/config.lua b/config.lua new file mode 100644 index 00000000..234498f1 --- /dev/null +++ b/config.lua @@ -0,0 +1,80 @@ +Config = {} +Config.DrawDistance = 100.0 +Config.MarkerType = 1 +Config.MarkerSize = {x = 2.0, y = 2.0, z = 1.0} +Config.MarkerColor = {r = 204, g = 204, b = 0} +Config.ParkingMarkerSize = {x = 3.0, y = 3.0, z = 2.0} +Config.ParkingMarkerColor = {r = 102, g = 102, b = 204} + +Config.Zones = {} + +Config.Garages = { + + MiltonDrive = { + + IsClosed = true, + + ExteriorEntryPoint = { + Pos = {x= -796.542, y = 318.137, z = 84.673}, + }, + + ExteriorSpawnPoint = { + Pos = {x = -796.501, y = 302.271, z = 85.000}, + Heading = 180.0 + }, + + InteriorSpawnPoint = { + Pos = {x = 228.930, y = -1000.698, z = -100.000}, + Heading = 0.0 + }, + + InteriorExitPoint = { + Pos = {x = 224.613, y = -1004.769, z = -100.000}, + }, + + Parkings = { + { + Pos = {x = 224.500, y = -998.695, z = -100.000}, + Heading = 225.0 + }, + { + Pos = {x = 224.500, y = -994.630, z = -100.000}, + Heading = 225.0 + }, + { + Pos = {x = 224.500, y = -990.255, z = -100.000}, + Heading = 225.0 + }, + { + Pos = {x = 224.500, y = -986.628, z = -100.000}, + Heading = 225.0 + }, + { + Pos = {x = 224.500, y = -982.496, z = -100.000}, + Heading = 225.0 + }, + { + Pos = {x = 232.500, y = -982.496, z = -100.000}, + Heading = 135.0 + }, + { + Pos = {x = 232.500, y = -986.628, z = -100.000}, + Heading = 135.0 + }, + { + Pos = {x = 232.500, y = -990.255, z = -100.000}, + Heading = 135.0 + }, + { + Pos = {x = 232.500, y = -994.630, z = -100.000}, + Heading = 135.0 + }, + { + Pos = {x = 232.500, y = -998.695, z = -100.000}, + Heading = 135.0 + }, + } + + } + +} diff --git a/server/main.lua b/server/main.lua new file mode 100644 index 00000000..b4d1f90c --- /dev/null +++ b/server/main.lua @@ -0,0 +1,67 @@ +ESX = nil + +TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + +RegisterServerEvent('esx_garage:setParking') +AddEventHandler('esx_garage:setParking', function(garage, zone, vehicleProps) + + local xPlayer = ESX.GetPlayerFromId(source) + + if vehicleProps == false then + + MySQL.Async.execute( + 'DELETE FROM `user_parkings` WHERE `identifier` = @identifier AND `garage` = @garage AND zone = @zone', + { + ['@identifier'] = xPlayer.identifier, + ['@garage'] = garage; + ['@zone'] = zone + }, function(rowsChanged) + TriggerClientEvent('esx:showNotification', xPlayer.source, 'Véhicule ~g~sorti') + end + ) + + else + + MySQL.Async.execute( + 'INSERT INTO `user_parkings` (`identifier`, `garage`, `zone`, `vehicle`) VALUES (@identifier, @garage, @zone, @vehicle)', + { + ['@identifier'] = xPlayer.identifier, + ['@garage'] = garage; + ['@zone'] = zone, + ['vehicle'] = json.encode(vehicleProps) + }, function(rowsChanged) + TriggerClientEvent('esx:showNotification', xPlayer.source, 'Véhicule ~g~rangé') + end + ) + + end + +end) + +ESX.RegisterServerCallback('esx_vehicleshop:getVehiclesInGarage', function(source, cb, garage) + + local xPlayer = ESX.GetPlayerFromId(source) + + MySQL.Async.fetchAll( + 'SELECT * FROM `user_parkings` WHERE `identifier` = @identifier AND garage = @garage', + { + ['@identifier'] = xPlayer.identifier, + ['@garage'] = garage + }, + function(result) + + local vehicles = {} + + for i=1, #result, 1 do + table.insert(vehicles, { + zone = result[i].zone, + vehicle = json.decode(result[i].vehicle) + }) + end + + cb(vehicles) + + end + ) + +end) \ No newline at end of file