structura foldere

mutat kq- folders in un singur folder [kq]
This commit is contained in:
2026-03-30 01:55:03 +03:00
parent af1286d583
commit c291b81f26
2319 changed files with 0 additions and 14 deletions

View File

@@ -0,0 +1,352 @@
if Config.UseTarget ~= 'ox_target' then
return
end
local function storeVehicleZone2()
local id = exports.ox_target:addGlobalVehicle({
{
name = 'garages:storeVehicle',
icon = 'fas fa-car',
label = 'Store Vehicle',
-- bones = { 'door_dside_f', 'seat_dside_f' },
canInteract = function(entity, distance, coords, name)
if IsNearbyJobGarage() then return true end
if CurrentShellGarage then return false end
local _garage = ClosestGarage
if not _garage then
return false
end
local garage = Config.Garages[_garage]
if not CheckGarageAuthorization(garage.jobs, garage.gangs) then return end
if not garage then
return false
end
local distance = #(coords - vec3(garage.coords.spawnCoords.x, garage.coords.spawnCoords.y, garage.coords.spawnCoords.z))
if distance > 50.0 then
return false
end
return true
end,
onSelect = function(data)
local jobGarage = IsNearbyJobGarage()
if jobGarage then
StoreVehicle(jobGarage, true, data.entity)
return
end
if CurrentShellGarage and existKey then
nearbyGarageType = 'vehicle'
StoreVehicle(CurrentShellGarage, false, data.entity)
return
end
StoreVehicle(ClosestGarage, false, data.entity)
end
}
})
return id
end
storeVehicleZone2()
local function storeVehicleZone(garage, garageName, isJob)
local options = {
{
onSelect = function()
if isJob then
StoreVehicle(garage, isJob)
return
end
StoreVehicle(ClosestGarage or garageName, isJob)
end,
canInteract = function()
return (isJob and CheckGarageAuthorization(garage.jobs, garage.gangs) and cache.vehicle) or (not garage.isImpound and (IsGarageOwner or garage.available or IsKeyHolder) and cache.vehicle)
end,
distance = 150.0,
icon = 'fas fa-car',
label = 'Store Vehicle'
}
}
local id = exports.ox_target:addBoxZone({
coords = garage.coords.spawnCoords,
distance = 150.0,
rotation = 180.0,
options = options,
debug = Config.ZoneDebug
})
return id
end
local boxZones = {}
function InitZones()
if #boxZones > 0 then
for k, v in pairs(boxZones) do
exports.ox_target:removeZone(v)
end
boxZones = {}
end
Wait(100)
for k, garage in pairs(Config.Garages) do
local options = {}
if garage.type ~= 'plane' or garage.isImpound then
table.insert(options, {
onSelect = function()
OpenGarageMenu(k, garage.isImpound, nil, garage.type == 'boat')
end,
canInteract = function()
local job = CheckGarageAuthorization(garage.jobs, garage.gangs)
return (IsGarageOwner or garage.available or IsKeyHolder) and job
end,
distance = 5.0,
icon = 'fas fa-car',
label = 'Open Garage'
})
end
if not garage.isImpound then
local garageType = garage.type
if garageType == 'vehicle' or garageType == 'plane' then
if garageType == 'plane' or (garageType == 'vehicle' and (Config.EnablePublicInteriors or not garage.available)) then
table.insert(options, {
onSelect = function()
GotoShellGarage(k, garage.coords.spawnCoords, garage.shell)
end,
canInteract = function()
local job = CheckGarageAuthorization(garage.jobs, garage.gangs)
return (IsGarageOwner or garage.available or IsKeyHolder) and job
end,
icon = 'fas fa-warehouse',
label = 'Enter the Garage',
distance = 5.0
})
end
end
end
if not garage.owner or garage.owner == '' and not garage.isImpound then
table.insert(options, {
onSelect = function()
local price = garage.price
TriggerServerEvent('advancedgarages:buyGarage', k, price)
end,
canInteract = function()
local job = CheckGarageAuthorization(garage.jobs, garage.gangs)
return job
end,
distance = 5.0,
icon = 'fas fa-store',
label = 'Buy Garage',
debug = true
})
end
local id = exports.ox_target:addBoxZone({
coords = garage.coords.menuCoords,
distance = 5.5,
rotation = 180.0,
name = 'garage:' .. k,
id = k,
index = k,
options = options,
debug = Config.ZoneDebug,
})
table.insert(boxZones, id)
local otherId = storeVehicleZone(garage, k, false)
table.insert(boxZones, otherId)
end
end
local shellBoxes = {}
function InitShellGarages()
for k, v in pairs(shellBoxes) do
exports.ox_target:removeZone(v)
shellBoxes = {}
end
for k, garage in pairs(ShellGarages) do
if not garage.takeVehicle or not garage.takeVehicle.x then goto continue end
local options = {}
table.insert(options, {
onSelect = function()
local shell = garage?.shell
nearbyGarageType = 'vehicle'
GotoGarage(CurrentShellGarage, vec4(garage.takeVehicle.x, garage.takeVehicle.y, garage.takeVehicle.z, garage.takeVehicle.h), shell)
end,
distance = 5.0,
canInteract = function()
return CurrentShellGarage == k and existKey
end,
icon = 'fas fa-warehouse',
label = 'Enter the garage'
})
table.insert(options, {
onSelect = function()
local shell = garage?.shell
nearbyGarageType = 'vehicle'
SaveVehicle(k, true)
-- GotoGarage(k, vec4(garage.takeVehicle.x, garage.takeVehicle.y, garage.takeVehicle.z, garage.takeVehicle.h), shell?.shell)
end,
distance = 5.0,
icon = 'fas fa-car',
label = 'Store Vehicle',
canInteract = function()
return CurrentShellGarage == k and existKey and cache.vehicle
end,
})
local id = exports.ox_target:addBoxZone({
coords = vec3(garage.takeVehicle.x, garage.takeVehicle.y, garage.takeVehicle.z),
distance = 5.5,
rotation = 180.0,
name = 'shell-garage:' .. k,
id = 'shell-' .. k,
index = k,
options = options,
debug = Config.ZoneDebug,
})
shellBoxes[k] = id
::continue::
end
end
CreateThread(function()
for k, garage in pairs(Config.JobGarages) do
local job = garage.job or garage.gang
local options = {}
table.insert(options, {
onSelect = function()
local serverVehicles = lib.callback.await('advancedgarages:getJobVehicles', false, garage.name, job)
local vehicleList = serverVehicles
local garageIsAvailable = lib.callback.await('advancedgarages:isGarageAvailable', false, k)
if not garageIsAvailable then return Notification(i18n.t('garage_not_available'), 'error') end
for _, veh in pairs(vehicleList) do
veh.vehicle = json.encode(veh.vehicle)
end
for a, model in ipairs(garage.vehicles) do
local plate = tostring(job .. math.random(111, 999))
table.insert(vehicleList, {
id = #vehicleList + 1,
vehicle = json.encode({
model = model,
plate = plate
}),
plate = plate,
})
end
TriggerServerEvent('advancedgarages:setInJobGarage', k, true)
OpenGarageMenu(k, garage.isImpound, vehicleList)
end,
canInteract = function()
return CheckJob(garage.job, garage.grade)
end,
distance = 5.0,
icon = 'fas fa-car',
label = 'Open Garage'
})
exports.ox_target:addBoxZone({
coords = garage.coords.menuCoords,
distance = 5.5,
rotation = 180.0,
name = 'job-garage:' .. k,
id = k,
index = k,
options = options,
debug = Config.ZoneDebug,
})
storeVehicleZone(garage, k, true)
end
end)
CreateThread(function()
for k, types in pairs(Config.VehicleShowRooms) do
for a, v in pairs(types) do
local options = {}
table.insert(options, {
onSelect = function()
ExitGarage()
end,
distance = 5.0,
icon = 'fas fa-warehouse',
label = 'Exit Garage'
})
exports.ox_target:addBoxZone({
coords = vec3(v.entry.x, v.entry.y, v.entry.z),
distance = 5.5,
rotation = 180.0,
name = 'exit-garage:' .. k,
id = k,
index = k,
options = options,
debug = Config.ZoneDebug,
})
end
end
end)
---@param coords vector4
function InitShellExit(coords)
exports.ox_target:addBoxZone({
coords = coords,
distance = 5.5,
rotation = 180.0,
name = 'exit-shell-garage',
id = 'exit-shell-garage',
options = {
{
onSelect = function()
ExitGarage()
end,
distance = 5.0,
icon = 'fas fa-warehouse',
label = 'Exit Garage'
}
},
})
end
function RemoveShellExit()
exports.ox_target:removeZone('exit-shell-garage')
end
CreateThread(function()
for k, v in pairs(Config.Recovery.coords) do
local options = {}
table.insert(options, {
onSelect = function()
local vehicleList = lib.callback.await('advancedgarages:getRecoveryVehicles', false)
if #vehicleList == 0 then
return Notification(i18n.t('keyholders.empty_out'), 'info')
end
OpenRecoveryMenu(vehicleList)
end,
distance = 5.0,
icon = 'fas fa-car-on',
label = 'Recover vehicle $' .. Config.Recovery.price
})
exports.ox_target:addBoxZone({
coords = v,
size = vec3(2.0, 2.0, 2.0),
rotation = 180.0,
name = 'recovery-garage:' .. k,
id = k,
index = k,
options = options,
debug = Config.ZoneDebug,
})
end
end)
CreateThread(function()
local function checkMenu()
local sleep = 500
if not ClosestGarage then return sleep end
local garage = Config.Garages[ClosestGarage]
if not IsGarageOwner and not garage.available and not IsKeyHolder then return sleep end
if not CheckGarageAuthorization(garage.jobs, garage.gangs) then return sleep end
if garage.isImpound then return sleep end
if cache.vehicle then
sleep = 0
DrawMarkerZone(garage.coords.spawnCoords.x, garage.coords.spawnCoords.y, garage.coords.spawnCoords.z)
-- DrawMarker(1, garage.coords.spawnCoords.x, garage.coords.spawnCoords.y, garage.coords.spawnCoords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 4.0, 0.8, 255, 255, 255, 150, false, false, false, true, false, false, false)
end
return sleep
end
while true do
local sleep = checkMenu()
Wait(sleep)
end
end)

View File

@@ -0,0 +1,181 @@
if Config.UseTarget ~= 'qb-radialmenu' then
return
end
local menuItems = {}
local function AddRadialOption()
RemoveRadialOptions()
local garage, garageJobName
if ClosestGarage then
garage = Config.Garages[ClosestGarage]
end
if garage then
if not cache.vehicle and (garage.available or IsGarageOwner or IsKeyHolder) then
if not CheckGarageAuthorization(garage.jobs, garage.gangs) then goto continue end
if garage.type ~= 'plane' and not cache.vehicle then
table.insert(menuItems, {
id = 'radialOpenMenu',
title = 'Open Garage',
icon = 'car',
type = 'client',
event = 'advancedgarages:client:radialOpenMenu',
shouldClose = true
})
end
if garage.type == 'plane' or ((Config.EnablePublicInteriors or not garage.available) and garage.type ~= 'boat' and not garage.isImpound and not cache.vehicle) then
table.insert(menuItems, {
id = 'radialEnterShell',
title = 'Enter Garage',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialEnterShell',
shouldClose = true
})
end
end
::continue::
end
if cache.vehicle and ClosestGarage and not garage.isImpound then
if not CheckGarageAuthorization(garage.jobs, garage.gangs) then goto continue end
table.insert(menuItems, {
id = 'radialSaveVehicle',
title = 'Store Vehicle',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialSaveVehicle',
garage = ClosestGarage,
shouldClose = true
})
::continue::
end
local nearbyElevator = nearbyElevator()
if nearbyElevator and nearbyElevator == 0 then
table.insert(menuItems, {
id = 'radialExitShell',
title = 'Exit',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialExitShell',
shouldClose = true
})
end
local recover = checkMenu()
if recover == 0 then
table.insert(menuItems, {
id = 'radialRecoverVehicle',
title = 'Recover',
icon = 'car',
type = 'client',
event = 'advancedgarages:client:radialRecoverVehicle',
shouldClose = true
})
end
if IsGarageOwner and not cache.vehicle then
table.insert(menuItems, {
id = 'radialGarageManagement',
title = 'Management',
icon = 'bars-progress',
type = 'client',
event = 'advancedgarages:client:radialGarageManagement',
shouldClose = true
})
end
local nearbyHouseGarage = CheckNearbyGarage()
if nearbyHouseGarage and nearbyHouseGarage == 0 and cache.vehicle then
table.insert(menuItems, {
id = 'save_vehicle',
title = 'Store Vehicle',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialSaveHousingGarage',
shouldClose = true
})
end
if nearbyHouseGarage and nearbyHouseGarage == 0 and not cache.vehicle then
table.insert(menuItems, {
id = 'enter_garage_shell',
title = 'Enter Garage',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialEnterHousingGarage',
shouldClose = true
})
end
local job = GetJobName()
if IsJobAllowed(job, 'impound') and not cache.vehicle then
table.insert(menuItems, {
id = 'radialImpoundVehicle',
title = 'Impound vehicle',
icon = 'car-side',
type = 'client',
event = 'advancedgarages:client:radialImpoundVehicle',
shouldClose = true
})
end
local playerCoords = GetEntityCoords(cache.ped)
for k, garage in pairs(Config.JobGarages) do
local access = CheckJob(garage.job, garage.grade)
if access then
local dst = #(playerCoords - vec3(garage.coords.menuCoords.x, garage.coords.menuCoords.y, garage.coords.menuCoords.z))
if dst < 15.0 and not cache.vehicle then
table.insert(menuItems, {
id = 'radialOpenJobGarage',
title = 'Open Garage',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialOpenJobGarage',
garage = k,
shouldClose = true
})
end
if dst < 15.0 and cache.vehicle then
table.insert(menuItems, {
id = 'radialSaveVehicle',
title = 'Save Vehicle',
icon = 'warehouse',
type = 'client',
event = 'advancedgarages:client:radialSaveVehicle',
garage = k,
isJob = true,
shouldClose = true
})
end
end
end
for _, item in ipairs(menuItems) do
item.id = exports['qb-radialmenu']:AddOption(item)
end
end
function RemoveRadialOptions()
for _, item in ipairs(menuItems) do
exports['qb-radialmenu']:RemoveOption(item.id)
end
menuItems = {}
Debug('The qb-radialmenu table has been cleaned!')
end
RegisterNetEvent('qb-radialmenu:client:onRadialmenuOpen', function()
AddRadialOption()
end)
AddEventHandler('onResourceStop', function(resourceName)
if (resourceName == 'qs-advancedgarages') then
RemoveRadialOptions()
end
end)

View File

@@ -0,0 +1,483 @@
if Config.UseTarget ~= 'qs-radialmenu' then
return
end
-- ============================================================
-- State
-- ============================================================
local shellExitCoords = nil
local nearestGarage = nil
-- ============================================================
-- Self-contained proximity detection
-- Maintains nearestGarage independently of the escrowed code,
-- so garage items appear even when ClosestGarage is not set.
-- ============================================================
CreateThread(function()
while true do
local playerCoords = GetEntityCoords(cache.ped)
local closest, closestDist = nil, 10.0
for k, g in pairs(Config.Garages) do
if g.coords and g.coords.menuCoords then
local mc = g.coords.menuCoords
local d = #(playerCoords - vec3(mc.x, mc.y, mc.z))
if d < closestDist then
closest = k
closestDist = d
end
end
end
nearestGarage = closest
Wait(closest and 250 or 1000)
end
end)
local function getClosestGarage()
return ClosestGarage or nearestGarage
end
-- ============================================================
-- Lifecycle hooks (same interface as ox_target.lua)
-- The escrowed code calls these at key moments.
-- ============================================================
function InitZones() end
function InitShellGarages() end
---@param coords vector4
function InitShellExit(coords)
shellExitCoords = coords
end
function RemoveShellExit()
shellExitCoords = nil
end
-- ============================================================
-- Provider: getRadialItems export
-- Called synchronously by qs-radialmenu before building menu.
-- Returns a plain table of items — no cross-resource closures.
-- ============================================================
exports('getRadialItems', function()
local items = {}
local playerCoords = GetEntityCoords(cache.ped)
local garageName = getClosestGarage()
local garage = garageName and Config.Garages[garageName] or nil
local authorized = false
if garage then
local jobOk = type(CheckGarageAuthorization) ~= 'function' or CheckGarageAuthorization(garage.jobs, garage.gangs)
authorized = jobOk and (IsGarageOwner or garage.available or IsKeyHolder)
end
-- ── 1. Open Garage (on foot, authorized)
if garage and not cache.vehicle and authorized then
if garage.type ~= 'plane' or garage.isImpound then
table.insert(items, {
id = 'radialOpenMenu',
title = 'Open Garage',
icon = 'Car',
type = 'client',
event = 'qs-radialmenu:garages:openGarage',
shouldClose = true
})
end
end
-- ── 2. Enter Garage interior (on foot, authorized)
if garage and not cache.vehicle and authorized and not garage.isImpound then
local gt = garage.type
if gt == 'plane' or (gt == 'vehicle' and (Config.EnablePublicInteriors or not garage.available)) then
table.insert(items, {
id = 'radialEnterShell',
title = 'Enter Garage',
icon = 'Warehouse',
type = 'client',
event = 'qs-radialmenu:garages:enterShell',
shouldClose = true
})
end
end
-- ── 3. Buy Garage (no owner, authorized)
if garage and not garage.isImpound and (not garage.owner or garage.owner == '') then
local jobOk = type(CheckGarageAuthorization) ~= 'function' or CheckGarageAuthorization(garage.jobs, garage.gangs)
if jobOk then
table.insert(items, {
id = 'radialBuyGarage',
title = 'Buy Garage',
icon = 'Store',
type = 'client',
event = 'qs-radialmenu:garages:buyGarage',
shouldClose = true
})
end
end
-- ── 4. Store Vehicle regular garage (in vehicle)
if cache.vehicle and not CurrentShellGarage then
local canStore = false
if type(IsNearbyJobGarage) == 'function' and IsNearbyJobGarage() then
canStore = true
elseif garage and not garage.isImpound and authorized then
local sp = garage.coords.spawnCoords
local dst = #(playerCoords - vec3(sp.x, sp.y, sp.z))
if dst <= 50.0 then
canStore = true
end
end
if canStore then
table.insert(items, {
id = 'radialStoreVehicle',
title = 'Store Vehicle',
icon = 'Car',
type = 'client',
event = 'qs-radialmenu:garages:storeVehicle',
shouldClose = true
})
end
end
-- ── 5. Shell garage options
if CurrentShellGarage and existKey then
local shellData = type(ShellGarages) == 'table' and ShellGarages[CurrentShellGarage] or nil
if shellData and shellData.takeVehicle and shellData.takeVehicle.x then
if not cache.vehicle then
table.insert(items, {
id = 'radialEnterShellGarage',
title = 'Enter Garage',
icon = 'Warehouse',
type = 'client',
event = 'qs-radialmenu:garages:enterShellGarage',
shouldClose = true
})
else
table.insert(items, {
id = 'radialStoreShellVehicle',
title = 'Store Vehicle',
icon = 'Car',
type = 'client',
event = 'qs-radialmenu:garages:storeShellVehicle',
shouldClose = true
})
end
end
end
-- ── 6. Exit Garage (shell exit or VehicleShowRooms)
local showExit = false
if shellExitCoords then
showExit = true
end
if not showExit and Config.VehicleShowRooms then
for _, types in pairs(Config.VehicleShowRooms) do
for _, v in pairs(types) do
if v.entry and v.entry.x then
local dst = #(playerCoords - vec3(v.entry.x, v.entry.y, v.entry.z))
if dst <= 5.5 then
showExit = true
break
end
end
end
if showExit then break end
end
end
if showExit then
table.insert(items, {
id = 'radialExitGarage',
title = 'Exit',
icon = 'DoorOpen',
type = 'client',
event = 'qs-radialmenu:garages:exitGarage',
shouldClose = true
})
end
-- ── 7. Recover Vehicle
if Config.Recovery and Config.Recovery.coords then
for _, v in pairs(Config.Recovery.coords) do
local dst = #(playerCoords - vec3(v.x, v.y, v.z))
if dst <= 5.0 then
table.insert(items, {
id = 'radialRecoverVehicle',
title = 'Recover $' .. (Config.Recovery.price or 0),
icon = 'Car',
type = 'client',
event = 'qs-radialmenu:garages:recoverVehicle',
shouldClose = true
})
break
end
end
end
-- ── 8. Garage Management (owner only, on foot)
if IsGarageOwner and not cache.vehicle then
table.insert(items, {
id = 'radialGarageManagement',
title = 'Management',
icon = 'Settings',
type = 'client',
event = 'qs-radialmenu:garages:management',
shouldClose = true
})
end
-- ── 9. Impound Vehicle (allowed job, on foot)
if not cache.vehicle then
local job = type(GetJobName) == 'function' and GetJobName() or nil
if job and type(IsJobAllowed) == 'function' and IsJobAllowed(job, 'impound') then
table.insert(items, {
id = 'radialImpoundVehicle',
title = 'Impound Vehicle',
icon = 'Car',
type = 'client',
event = 'qs-radialmenu:garages:impoundVehicle',
shouldClose = true
})
end
end
-- ── 10. Job Garages
if Config.JobGarages then
for k, jGarage in pairs(Config.JobGarages) do
local access = type(CheckJob) == 'function' and CheckJob(jGarage.job, jGarage.grade) or false
if access then
local mc = jGarage.coords.menuCoords
local dst = #(playerCoords - vec3(mc.x, mc.y, mc.z))
if dst <= 15.0 then
if not cache.vehicle then
table.insert(items, {
id = 'radialOpenJobGarage_' .. k,
title = 'Open Garage',
icon = 'Warehouse',
type = 'client',
event = 'qs-radialmenu:garages:openJobGarage',
shouldClose = true
})
else
table.insert(items, {
id = 'radialStoreJobVehicle_' .. k,
title = 'Store Vehicle',
icon = 'Warehouse',
type = 'client',
event = 'qs-radialmenu:garages:storeJobVehicle',
shouldClose = true
})
end
end
end
end
end
return items
end)
-- ============================================================
-- Register as an item provider once qs-radialmenu is ready
-- ============================================================
CreateThread(function()
local attempts = 0
while attempts < 60 do
local ok = pcall(function()
exports['qs-radialmenu']:RegisterItemProvider(GetCurrentResourceName())
end)
if ok then return end
attempts = attempts + 1
Wait(500)
end
end)
-- ============================================================
-- Bridge events — call escrowed functions directly
-- (mirrors ox_target onSelect callbacks)
-- Use getClosestGarage() so bridge events also benefit from
-- the self-contained proximity fallback.
-- ============================================================
RegisterNetEvent('qs-radialmenu:garages:openGarage', function()
local gName = getClosestGarage()
if not gName then return end
local garage = Config.Garages[gName]
if not garage then return end
if type(OpenGarageMenu) == 'function' then
OpenGarageMenu(gName, garage.isImpound, nil, garage.type == 'boat')
end
end)
RegisterNetEvent('qs-radialmenu:garages:enterShell', function()
local gName = getClosestGarage()
if not gName then return end
local garage = Config.Garages[gName]
if not garage then return end
if type(GotoShellGarage) == 'function' then
GotoShellGarage(gName, garage.coords.spawnCoords, garage.shell)
end
end)
RegisterNetEvent('qs-radialmenu:garages:buyGarage', function()
local gName = getClosestGarage()
if not gName then return end
local garage = Config.Garages[gName]
if not garage then return end
TriggerServerEvent('advancedgarages:buyGarage', gName, garage.price)
end)
RegisterNetEvent('qs-radialmenu:garages:storeVehicle', function()
if type(StoreVehicle) ~= 'function' then return end
local jobGarage = type(IsNearbyJobGarage) == 'function' and IsNearbyJobGarage() or nil
if jobGarage then
StoreVehicle(jobGarage, true, cache.vehicle)
return
end
local gName = getClosestGarage()
StoreVehicle(gName, false, cache.vehicle)
end)
RegisterNetEvent('qs-radialmenu:garages:enterShellGarage', function()
if not CurrentShellGarage or not existKey then return end
local shellData = type(ShellGarages) == 'table' and ShellGarages[CurrentShellGarage] or nil
if not shellData or not shellData.takeVehicle then return end
nearbyGarageType = 'vehicle'
if type(GotoGarage) == 'function' then
GotoGarage(CurrentShellGarage, vec4(shellData.takeVehicle.x, shellData.takeVehicle.y, shellData.takeVehicle.z, shellData.takeVehicle.h), shellData.shell)
end
end)
RegisterNetEvent('qs-radialmenu:garages:storeShellVehicle', function()
if not CurrentShellGarage or not existKey then return end
nearbyGarageType = 'vehicle'
if type(SaveVehicle) == 'function' then
SaveVehicle(CurrentShellGarage, true)
end
end)
RegisterNetEvent('qs-radialmenu:garages:exitGarage', function()
if type(ExitGarage) == 'function' then
ExitGarage()
end
end)
RegisterNetEvent('qs-radialmenu:garages:recoverVehicle', function()
local vehicleList = lib.callback.await('advancedgarages:getRecoveryVehicles', false)
if not vehicleList or #vehicleList == 0 then
if type(Notification) == 'function' then
Notification(i18n.t('keyholders.empty_out'), 'info')
end
return
end
if type(OpenRecoveryMenu) == 'function' then
OpenRecoveryMenu(vehicleList)
end
end)
RegisterNetEvent('qs-radialmenu:garages:management', function()
TriggerEvent('advancedgarages:client:radialGarageManagement')
end)
RegisterNetEvent('qs-radialmenu:garages:impoundVehicle', function()
TriggerEvent('advancedgarages:client:radialImpoundVehicle')
end)
RegisterNetEvent('qs-radialmenu:garages:openJobGarage', function()
if not Config.JobGarages then return end
local playerCoords = GetEntityCoords(cache.ped)
for k, jGarage in pairs(Config.JobGarages) do
local access = type(CheckJob) == 'function' and CheckJob(jGarage.job, jGarage.grade) or false
if access then
local mc = jGarage.coords.menuCoords
local dst = #(playerCoords - vec3(mc.x, mc.y, mc.z))
if dst <= 15.0 then
local job = jGarage.job or jGarage.gang
local serverVehicles = lib.callback.await('advancedgarages:getJobVehicles', false, jGarage.name, job)
local vehicleList = serverVehicles or {}
local garageIsAvailable = lib.callback.await('advancedgarages:isGarageAvailable', false, k)
if not garageIsAvailable then
if type(Notification) == 'function' then Notification(i18n.t('garage_not_available'), 'error') end
return
end
for _, veh in pairs(vehicleList) do
veh.vehicle = json.encode(veh.vehicle)
end
if jGarage.vehicles then
for _, model in ipairs(jGarage.vehicles) do
local plate = tostring(job .. math.random(111, 999))
table.insert(vehicleList, {
id = #vehicleList + 1,
vehicle = json.encode({ model = model, plate = plate }),
plate = plate,
})
end
end
TriggerServerEvent('advancedgarages:setInJobGarage', k, true)
if type(OpenGarageMenu) == 'function' then
OpenGarageMenu(k, jGarage.isImpound, vehicleList)
end
return
end
end
end
end)
RegisterNetEvent('qs-radialmenu:garages:storeJobVehicle', function()
if not Config.JobGarages or type(StoreVehicle) ~= 'function' then return end
local playerCoords = GetEntityCoords(cache.ped)
for k, jGarage in pairs(Config.JobGarages) do
local access = type(CheckJob) == 'function' and CheckJob(jGarage.job, jGarage.grade) or false
if access then
local mc = jGarage.coords.menuCoords
local dst = #(playerCoords - vec3(mc.x, mc.y, mc.z))
if dst <= 15.0 then
StoreVehicle(jGarage, true)
return
end
end
end
end)
-- ============================================================
-- Cleanup
-- ============================================================
AddEventHandler('onResourceStop', function(resourceName)
if resourceName == 'qs-advancedgarages' then
pcall(function()
exports['qs-radialmenu']:UnregisterItemProvider(GetCurrentResourceName())
end)
end
end)
-- ============================================================
-- Marker thread (mirrors ox_target lines 333-352)
-- Uses getClosestGarage() for proximity fallback.
-- ============================================================
CreateThread(function()
local function checkStoreMarker()
local sleep = 500
local gName = getClosestGarage()
if not gName then return sleep end
local garage = Config.Garages[gName]
if not garage then return sleep end
if not IsGarageOwner and not garage.available and not IsKeyHolder then return sleep end
if type(CheckGarageAuthorization) == 'function' and not CheckGarageAuthorization(garage.jobs, garage.gangs) then return sleep end
if garage.isImpound then return sleep end
if cache.vehicle then
sleep = 0
if type(DrawMarkerZone) == 'function' then
DrawMarkerZone(garage.coords.spawnCoords.x, garage.coords.spawnCoords.y, garage.coords.spawnCoords.z)
end
end
return sleep
end
while true do
Wait(checkStoreMarker())
end
end)