Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 48 additions & 80 deletions [esx_addons]/esx_garage/client/init.lua
Original file line number Diff line number Diff line change
@@ -1,127 +1,95 @@
local created_peds = {}
local return_vehicle = false
local return_vehicle_locale = (TranslateCap('park-vehicle', Keybinds.GetName()))

---@type false | integer
PLAYER_VEHICLE = false
GARAGE_POINT = nil

local function openGarage()
if not GARAGE_POINT then
return
-- ~INPUT_94A9125A~ - 0x94A9125A
-- https://tools.povers.fr/hashgenerator/ If you ever change the openGarage name
ESX.RegisterInput('openGarage', 'Opens Garage Menu', 'keyboard', 'E', function()
if GARAGE_POINT then
NUI.OpenGarage()
elseif return_vehicle and PLAYER_VEHICLE then
Actions.HideVehicle()
end
end)

local garage = Config.Garages[GARAGE_POINT]
AddEventHandler('esx:enteredVehicle', function(vehicle, plate, seat, displayName, netId)
PLAYER_VEHICLE = vehicle
Mileage.StartLoop()

if not garage then
ESX.ShowNotification('Couldn\'t open garage menu', 'error')
return
if return_vehicle then
exports['esx_textui']:TextUI(return_vehicle_locale)
end
end)

---@type GarageVehicleDB[]
local owned_vehicles = ESX.AwaitServerCallback('esx_garages/getOwnedVehicles')

---@type GarageVehicle[]
local wrapped_vehicles = {}

for i = 1, #owned_vehicles do
local vehicle = owned_vehicles[i]
---@type ESXVehicleProperties
local properties = json.decode(vehicle.vehicle)

if not properties then
ESX.ShowNotification('One of your vehicles, have invalid properties. Contact server owner', 'error')
return
end
AddEventHandler('esx:exitedVehicle', function()
PLAYER_VEHICLE = false

local display_name = GetDisplayNameFromVehicleModel(properties.model):lower()

wrapped_vehicles[i] = {
id = vehicle.plate,
plate = vehicle.plate,
model = vehicle.model or display_name:lower(),
name = display_name,
type = vehicle.type,
garageId = vehicle.parking,
impouned = Config.GarageState.IMPOUNDED == vehicle.stored,
impoundFee = Config.ImpoundFee,
mileage = 0,
fuel = properties.fuelLevel,
engine = properties.engineHealth / 10,
body = properties.bodyHealth / 10,
stored = Config.GarageState.STORED == vehicle.stored,
isFavorite = false,
customName = nil,
lastUsed = 0,
props = properties,
}
if return_vehicle then
exports['esx_textui']:HideUI()
end
end)

SendNUIMessage({
type = 'openGarage',
payload = {
garage = {
id = garage.id,
name = garage.id,
type = 'public',
label = garage.label,
},
vehicles = wrapped_vehicles
}
})

SetNuiFocus(true, true)
end

ESX.RegisterInput('openGarage', 'Opens Garage Menu', 'keyboard', 'E', openGarage)

Citizen.CreateThread(function()
for i = 1, #Config.Garages do
local garage = Config.Garages[i]
local blip = garage.blip

Utils.CreateBlip(garage.entryPoint, blip.sprite, blip.scale, blip.color, TranslateCap('parking_blip_name'))
Utils.CreateBlip(garage.entryPoint, blip.sprite, blip.scale, blip.color, TranslateCap('parking-blip'))

created_peds[#created_peds + 1] = Utils.SpawnFrozenPed(garage.ped.model, garage.ped.coords)


local access_parking = (TranslateCap('access-parking', Keybinds.GetName()))


ESX.Point:new({
coords = garage.entryPoint,
distance = 3,
enter = function()
GARAGE_POINT = i
exports['esx_textui']:TextUI('Press [E] to open Garage Menu')
exports['esx_textui']:TextUI(access_parking)
end,
leave = function()
GARAGE_POINT = nil
exports['esx_textui']:HideUI()
end
})

local vec3_spawn_point = vec3(garage.spawnPoint.x, garage.spawnPoint.y, garage.spawnPoint.z)

ESX.Point:new({
coords = vec3_spawn_point,
distance = 50,
enter = function()
return_vehicle = true
if PLAYER_VEHICLE then
exports['esx_textui']:TextUI(return_vehicle_locale)
end
end,
leave = function()
return_vehicle = false
exports['esx_textui']:HideUI()
end
})
end
end)


AddEventHandler('onResourceStop', function(resource_name)
if resource_name ~= GetCurrentResourceName() then
return
end

exports['esx_textui']:HideUI()

for i = 1, #created_peds do
local ped = created_peds[i]
if DoesEntityExist(ped) then
DeleteEntity(ped)
end
end
end)

---@param body { vehicleId: string, isFavorite: boolean }
---@param cb function
RegisterNUICallback('garage:toggleFavorite', function(body, cb)
local result = ESX.AwaitServerCallback('esx_garages/toggleFavorite', body)
cb(result)
end)

---@param body { hasFocus: boolean, hasCursor: boolean }
---@param cb function
RegisterNUICallback('SetNuiFocus', function(body, cb)
SetNuiFocus(body.hasFocus, body.hasCursor)

cb({
success = true
})
end)
182 changes: 182 additions & 0 deletions [esx_addons]/esx_garage/client/modules/actions.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
Actions = {}

---@return nil | GaragePayload
function Actions.GaragePayload()
if not GARAGE_POINT then
return
end

local garage = Config.Garages[GARAGE_POINT]

if not garage then
ESX.ShowNotification(TranslateCap('cant-open'), 'error')
return
end

---@type GarageVehicleDB[] | { success: false, error: string}
local owned_vehicles = ESX.AwaitServerCallback('esx_garages/getOwnedVehicles')

if owned_vehicles?.error then
return ESX.ShowNotification(owned_vehicles.error, 'error')
end

---@type GarageVehicle[]
local wrapped_vehicles = {}

for i = 1, #owned_vehicles do
local vehicle = owned_vehicles[i]
---@type ESXVehicleProperties
local properties = json.decode(vehicle.vehicle)

if not properties then
ESX.ShowNotification(TranslateCap('invalid-vehicle'), 'error')
return
end

local display_name = GetDisplayNameFromVehicleModel(properties.model):lower()

wrapped_vehicles[i] = {
id = vehicle.plate,
plate = vehicle.plate,
model = vehicle.model or display_name:lower(),
name = display_name,
type = vehicle.type,
garageId = vehicle.parking,
impouned = Config.GarageState.IMPOUNDED == vehicle.stored,
impoundFee = Config.ImpoundFee,
mileage = vehicle.mileage or 0,
fuel = properties.fuelLevel,
engine = properties.engineHealth / 10,
body = properties.bodyHealth / 10,
stored = Config.GarageState.STORED == vehicle.stored,
isFavorite = (vehicle.second_favorite or vehicle.favorite) == 1,
customName = (vehicle.second_nickname or vehicle.nickname),
lastUsed = vehicle.last_used,
props = properties,
secondOwners = vehicle.second_owners
}
end

return {
garage = {
id = garage.id,
name = garage.id,
type = 'public',
label = garage.label,
},
vehicles = wrapped_vehicles
}
end

---@param data { vehicleId: string, isFavorite: boolean }
---@return CallbackResult
function Actions.ToggleFavorite(data)
local result = ESX.AwaitServerCallback('esx_garages/toggleFavorite', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end

---@param data { vehicleId: string, newName: string }
---@return CallbackResult
function Actions.RenameVehicle(data)
local result = ESX.AwaitServerCallback('esx_garages/renameVehicle', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end

---@param data { vehicleId: string, targetId: string}
---@return CallbackResult
function Actions.TransferVehicle(data)
local result = ESX.AwaitServerCallback('esx_garages/transferVehicle', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end

---@param data { vehicleId: string }
---@return CallbackResult
function Actions.RetrieveVehicle(data)
if not ESX.Game.IsSpawnPointClear(Config.Garages[GARAGE_POINT].spawnPoint, 8) then
ESX.ShowNotification(TranslateCap('no-empty-space'), 'error')
return {
success = false,
error = TranslateCap('no-empty-space')
}
end

local result = ESX.AwaitServerCallback('esx_garages/retrieveVehicle', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end

---@return CallbackResult | nil
function Actions.HideVehicle()
if not PLAYER_VEHICLE then
return
end

local properties = ESX.Game.GetVehicleProperties(PLAYER_VEHICLE)

local result = ESX.AwaitServerCallback('esx_garages/hideVehicle', {
properties = properties
})

if result.error then
ESX.ShowNotification(result.error, 'error')
else
PLAYER_VEHICLE = false
end

return result
end

---@param data { vehicleId: string, targetId: string }
---@return CallbackResult
function Actions.AddSecondOwner(data)
local result = ESX.AwaitServerCallback('esx_garages/addSecondOwner', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end

---@param data { vehicleId: string, targetId: string }
---@return CallbackResult
function Actions.RemoveSecondOwner(data)
local result = ESX.AwaitServerCallback('esx_garages/removeSecondOwner', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end

---@param data { type: 'impound' | 'find', vehicleId: string }
---@return CallbackResult
function Actions.ImpoundVehicle(data)
local result = ESX.AwaitServerCallback('esx_garages/impoundVehicle', data)

if result.error then
ESX.ShowNotification(result.error, 'error')
end

return result
end
Loading