From 6ff461839de949b5c974b32a2383fbcc704f4efb Mon Sep 17 00:00:00 2001 From: Andyyy7666 <86536434+Andyyy7666@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:24:07 +0200 Subject: [PATCH] feat(vehicle): garages --- client/vehicle/data.lua | 243 +++++++++++++++++++++ client/vehicle/garages.lua | 265 +++++++++++++++++++++++ client/{vehicle.lua => vehicle/main.lua} | 17 +- fxmanifest.lua | 8 +- server/vehicle.lua | 88 ++++++-- 5 files changed, 594 insertions(+), 27 deletions(-) create mode 100644 client/vehicle/data.lua create mode 100644 client/vehicle/garages.lua rename client/{vehicle.lua => vehicle/main.lua} (97%) diff --git a/client/vehicle/data.lua b/client/vehicle/data.lua new file mode 100644 index 0000000..d16bc8a --- /dev/null +++ b/client/vehicle/data.lua @@ -0,0 +1,243 @@ +return { + { + garageType = "land", + groups = {"sahp", "lspd", "bcso"}, + ped = vector4(452.83, -1027.79, 28.54, 2.49), + vehicleSpawns = { + vector4(446.19, -1025.47, 28.24, 185.96), + vector4(438.75, -1026.09, 28.38, 184.29), + vector4(434.98, -1026.61, 28.46, 185.99), + vector4(431.26, -1027.31, 28.53, 185.59), + vector4(427.52, -1026.84, 28.58, 184.25) + } + }, + { + garageType = "land", + impound = true, + ped = vector4(407.99, -1624.74, 29.29, 229.93), + vehicleSpawns = { + vector4(396.34, -1644.28, 28.86, 319.10), + vector4(398.56, -1646.42, 28.8616, 319.18), + vector4(400.68, -1648.86, 28.86, 140.78), + vector4(403.32, -1650.54, 28.86, 319.92), + vector4(403.21, -1650.68, 28.86, 139.40) + } + }, + { + garageType = "plane", + ped = vector4(-941.05, -2966.04, 13.95, 136.06), + vehicleSpawns = { + vector4(-974.98, -2977.90, 14.55, 59.91) + } + }, + { + garageType = "heli", + ped = vector4(-731.00, -1394.54, 5.00, 245.52), + vehicleSpawns = { + vector4(-746.01, -1469.39, 5.68, 139.27), + vector4(-725.26, -1444.72, 5.68, 139.58) + } + }, + { + garageType = "plane", + ped = vector4(1742.77, 3298.25, 41.22, 132.91), + vehicleSpawns = { + vector4(1734.26, 3250.98, 41.96, 81.11), + vector4(1729.32, 3270.69, 41.74, 145.39) + } + }, + { + garageType = "plane", + ped = vector4(-1241.26, -3391.48, 13.94, 35.03), + vehicleSpawns = { + vector4(-1254.71, -3388.15, 14.54, 330.04), + vector4(-1270.36, -3378.80, 14.54, 330.20), + vector4(-1286.05, -3369.44, 14.54, 329.99) + } + }, + { + garageType = "plane", + ped = vector4(-1621.10, -3151.63, 13.99, 41.26), + vehicleSpawns = { + vector4(-1634.04, -3147.84, 14.60, 330.28), + vector4(-1649.75, -3138.34, 14.60, 329.20), + vector4(-1665.42, -3129.26, 14.60, 330.10) + } + }, + { + garageType = "heli", + ped = vector4(-1121.87, -2839.88, 13.95, 150.58), + vehicleSpawns = { + vector4(-1178.71, -2846.51, 14.62, 150.16), + vector4(-1146.40, -2865.22, 14.62, 151.08), + vector4(-1112.85, -2884.66, 14.62, 149.70) + } + }, + { + garageType = "water", + ped = vector4(-831.03, -1359.53, 5.00, 299.80), + vehicleSpawns = { + vector4(-846.16, -1362.07, 0.39, 110.54), + vector4(-842.53, -1372.00, 0.39, 111.54), + vector4(-849.29, -1353.26, 0.38, 109.53), + vector4(-852.26, -1345.09, 0.41, 110.52), + vector4(-855.49, -1336.60, 0.40, 107.43), + vector4(-858.63, -1328.30, 0.40, 109.82), + vector4(-839.35, -1380.30, 0.39, 109.27), + vector4(-836.38, -1388.93, 0.41, 110.11), + vector4(-833.29, -1397.32, 0.40, 110.80), + vector4(-830.34, -1405.65, 0.37, 110.16) + } + }, + { + garageType = "land", + ped = vector4(-280.32, -888.42, 31.32, 250.68), + vehicleSpawns = { + vector4(-282.36, -915.11, 30.38, 68.81), + vector4(-284.27, -918.37, 30.38, 70.58), + vector4(-285.44, -921.82, 30.38, 250.22), + vector4(-285.70, -887.62, 30.38, 167.04), + vector4(-292.70, -885.93, 30.38, 167.09), + vector4(-285.76, -887.47, 30.38, 169.59), + vector4(-300.44, -885.14, 30.38, 347.05), + vector4(-303.59, -883.71, 30.38, 167.69), + vector4(-309.38, -896.88, 30.38, 167.15), + vector4(-312.98, -896.30, 30.38, 166.46), + vector4(-316.68, -896.26, 30.37, 347.94), + vector4(-311.06, -881.94, 30.38, 168.21), + vector4(-314.78, -881.86, 30.37, 348.45) + } + }, + { + garageType = "land", + ped = vector4(597.53, 91.08, 93.13, 250.54), + vehicleSpawns = { + vector4(598.53, 98.37, 92.27, 69.47), + vector4(599.79, 102.00, 92.27, 249.38), + vector4(608.21, 103.90, 92.18, 248.98), + vector4(600.60, 111.38, 92.27, 73.07), + vector4(609.91, 107.59, 92.23, 68.77), + vector4(601.36, 114.99, 92.27, 250.19), + vector4(611.07, 111.39, 92.29, 249.69), + vector4(603.52, 118.52, 92.26, 67.62), + vector4(612.74, 114.94, 92.28, 69.01), + vector4(604.00, 122.58, 92.27, 249.76), + vector4(613.78, 118.83, 92.29, 248.82), + vector4(622.43, 115.48, 91.99, 70.39), + vector4(628.56, 110.25, 91.47, 249.30), + vector4(620.67, 111.89, 92.03, 250.24), + vector4(618.41, 104.51, 91.97, 72.22), + vector4(624.87, 99.25, 91.36, 63.32), + vector4(616.59, 100.82, 91.97, 249.00) + } + }, + { + garageType = "land", + ped = vector4(100.64, -1072.88, 29.37, 341.55), + vehicleSpawns = { + vector4(106.13, -1063.24, 28.51, 66.86), + vector4(107.82, -1059.73, 28.51, 66.99), + vector4(112.39, -1049.71, 28.52, 67.40), + vector4(110.76, -1053.09, 28.51, 68.13), + vector4(109.06, -1056.38, 28.51, 66.45), + vector4(117.53, -1081.03, 28.50, 181.40), + vector4(119.09, -1069.44, 28.50, 181.12), + vector4(121.22, -1081.42, 28.50, 0.57), + vector4(122.32, -1070.46, 28.50, 0.67), + vector4(125.62, -1069.54, 28.50, 179.25), + vector4(124.83, -1081.17, 28.50, 180.37), + vector4(128.62, -1081.71, 28.50, 1.36), + vector4(128.93, -1070.62, 28.50, 359.89), + vector4(132.24, -1069.35, 28.50, 181.54), + vector4(132.31, -1081.45, 28.50, 180.86), + vector4(135.93, -1081.35, 28.50, 358.82), + vector4(135.64, -1070.75, 28.50, 0.43), + vector4(139.75, -1081.91, 28.50, 182.18), + vector4(138.86, -1070.37, 28.50, 181.90), + vector4(143.55, -1081.41, 28.50, 0.89), + vector4(147.13, -1081.48, 28.50, 179.02), + vector4(150.95, -1081.49, 28.50, 358.79), + vector4(154.64, -1081.32, 28.50, 179.51), + vector4(158.38, -1082.03, 28.50, 1.57), + vector4(162.10, -1081.32, 28.50, 179.88) + } + }, + { + garageType = "land", + ped = vector4(214.84, -806.24, 30.81, 342.23), + vehicleSpawns = { + vector4(251.26, -774.63, 29.98, 67.34), + vector4(245.36, -772.34, 30.02, 66.81), + vector4(219.19, -765.93, 30.14, 249.78), + vector4(228.11, -768.94, 30.10, 249.66), + vector4(233.68, -771.18, 30.07, 249.82), + vector4(244.01, -775.06, 29.99, 249.41), + vector4(249.53, -777.07, 29.95, 251.09), + vector4(248.74, -779.52, 29.92, 69.14), + vector4(243.64, -777.63, 29.96, 69.23), + vector4(233.47, -773.91, 30.05, 69.88), + vector4(218.62, -768.58, 30.14, 69.81), + vector4(217.02, -770.83, 30.16, 248.11), + vector4(226.09, -773.95, 30.09, 249.30), + vector4(231.82, -776.14, 30.04, 249.17), + vector4(242.05, -779.91, 29.93, 246.99), + vector4(247.72, -782.02, 29.88, 251.04), + vector4(216.19, -773.65, 30.16, 67.90), + vector4(225.82, -776.85, 30.08, 65.64), + vector4(230.77, -778.89, 30.03, 69.40), + vector4(241.72, -782.84, 29.90, 69.13), + vector4(247.12, -784.93, 29.84, 67.56), + vector4(246.23, -787.13, 29.82, 247.56), + vector4(239.40, -784.68, 29.90, 248.06), + vector4(230.42, -781.41, 30.01, 247.48), + vector4(224.14, -779.01, 30.07, 247.39), + vector4(215.32, -775.95, 30.17, 248.99), + vector4(243.81, -792.19, 29.77, 246.23), + vector4(238.08, -789.95, 29.85, 250.62), + vector4(228.14, -786.30, 30.01, 249.07), + vector4(221.98, -783.92, 30.08, 248.25), + vector4(213.41, -781.01, 30.19, 249.21), + vector4(214.77, -778.70, 30.17, 67.86), + vector4(224.02, -781.91, 30.07, 68.82), + vector4(229.34, -784.05, 30.01, 66.57), + vector4(239.87, -787.83, 29.86, 69.37), + vector4(245.18, -789.87, 29.79, 68.00), + vector4(241.85, -797.20, 29.72, 245.51), + vector4(236.57, -795.07, 29.82, 247.54), + vector4(226.12, -791.34, 29.99, 247.84), + vector4(220.61, -789.19, 30.08, 248.09), + vector4(212.00, -786.22, 30.21, 248.93), + vector4(212.91, -783.71, 30.19, 68.61), + vector4(222.11, -786.89, 30.07, 70.10), + vector4(227.84, -789.16, 29.99, 67.55), + vector4(237.73, -792.73, 29.82, 69.40), + vector4(243.54, -794.88, 29.73, 68.74), + vector4(237.03, -812.64, 29.59, 243.63), + vector4(207.66, -798.70, 30.29, 70.06), + vector4(216.56, -801.92, 30.10, 70.31), + vector4(222.28, -804.17, 29.98, 69.97), + vector4(232.41, -807.95, 29.74, 69.42), + vector4(238.16, -810.17, 29.60, 68.95), + vector4(238.32, -807.43, 29.63, 248.28), + vector4(233.32, -805.44, 29.75, 248.13), + vector4(222.46, -801.41, 29.98, 248.50), + vector4(216.85, -799.11, 30.10, 248.54), + vector4(207.60, -795.90, 30.29, 248.64), + vector4(209.28, -793.74, 30.25, 69.82), + vector4(218.31, -796.92, 30.08, 68.55), + vector4(224.50, -799.34, 29.96, 68.63), + vector4(234.40, -803.02, 29.76, 66.67), + vector4(240.09, -805.27, 29.64, 69.02), + vector4(240.53, -802.44, 29.67, 248.95), + vector4(234.46, -800.13, 29.79, 249.40), + vector4(224.30, -796.51, 29.98, 248.31), + vector4(218.23, -794.00, 30.09, 249.09), + vector4(209.84, -791.10, 30.24, 251.56), + vector4(211.09, -788.68, 30.22, 69.53), + vector4(220.17, -791.73, 30.06, 70.56), + vector4(225.84, -794.12, 29.98, 67.53), + vector4(236.38, -797.85, 29.79, 69.39), + vector4(216.56, -801.90, 30.79, 69.39) + } + }, +} \ No newline at end of file diff --git a/client/vehicle/garages.lua b/client/vehicle/garages.lua new file mode 100644 index 0000000..68e9616 --- /dev/null +++ b/client/vehicle/garages.lua @@ -0,0 +1,265 @@ +local locations = require "client.vehicle.data" +local sprite = { + ["water"] = 356, + ["heli"] = 360, + ["plane"] = 359, + ["land"] = 357 +} +local garageTypes = { + ["water"] = 14, + ["heli"] = 15, + ["plane"] = 16 +} + +local clothing = { + { + face = { + drawable = 1, + texture = 1 + }, + undershirt = { + drawable = 0, + texture = 0 + }, + torso = { + drawable = 1, + texture = 1 + }, + leg = { + drawable = 0, + texture = 0 + }, + glasses = { + drawable = 1, + texture = 0 + }, + hat = { + drawable = -1, + texture = -1 + }, + }, + { + leg = { + drawable = 0, + texture = 1 + }, + undershirt = { + drawable = 0, + texture = 0 + }, + face = { + drawable = 0, + texture = 0 + }, + torso = { + drawable = 0, + texture = 2 + }, + glasses = { + drawable = -1, + texture = -1 + }, + hat = { + drawable = 0, + texture = 0 + }, + }, + { + face = { + drawable = 0, + texture = 2 + }, + undershirt = { + drawable = 0, + texture = 0 + }, + torso = { + drawable = 1, + texture = 2 + }, + leg = { + drawable = 0, + texture = 0 + }, + hat = { + drawable = -1, + texture = -1 + }, + glasses = { + drawable = -1, + texture = -1 + }, + } +} + +local function getClosestOwnedVehicle() + local coords = GetEntityCoords(cache.ped) + local vehicles = lib.getNearbyVehicles(coords, 50.0, true) + local nearestVeh = {} + + local function setNearestVehicle(veh) + local state = Entity(veh.vehicle).state + if not state.owner or state.owner ~= NDCore.player?.id then return end + + local nearestDist = nearestVeh.dist + local dist = #(coords-veh.coords) + if not nearestDist or dist < nearestDist then + nearestVeh.dist = dist + nearestVeh.coords = veh.coords + nearestVeh.entity = veh.vehicle + end + end + + for i=1, #vehicles do + setNearestVehicle(vehicles[i]) + end + return nearestVeh.entity, nearestVeh.coords, nearestVeh.dist +end + +local function parkVehicle(veh) + if not veh or not DoesEntityExist(veh) then + return NDCore.notify({ + title = "Garage", + description = "No owned vehicle found nearby.", + type = "error", + position = "bottom", + duration = 3000 + }) + end + if GetPedInVehicleSeat(veh, -1) ~= 0 then + NDCore.notify({ + title = "Garage", + description = "Player in vehicle!", + type = "error", + position = "bottom", + duration = 3000 + }) + return + end + + local properties = lib.getVehicleProperties(veh) + properties.class = GetVehicleClass(veh) + TriggerServerEvent("ND_Vehicles:storeVehicle", VehToNet(veh)) +end + +local function isVehicleClassForGarage(class, garageType) + if not class then return true end + for garType, garClass in pairs(garageTypes) do + print(garType, garageType, garClass, class) + if garType == garageType and garClass == class then + return true + end + end +end + +local function getEngineStatus(health) + if health > 950 then + return "Perfect" + elseif health > 750 then + return "Good" + elseif health > 500 then + return "Bad" + end + return "Very bad" +end + +local function createMenuOptions(vehicle, vehicleSpawns) + local props = vehicle.properties + local makeName = GetLabelText(GetMakeNameFromVehicleModel(props.model)) + local modelName = GetLabelText(GetDisplayNameFromVehicleModel(props.model)) + + local metadata = { + {label = "Plate", value = vehicle.properties.plate}, + {label = "Fuel", value = ("%d%s"):format(vehicle.properties.fuelLevel, "%")}, + {label = "Engine status", value = getEngineStatus(vehicle.properties.engineHealth)} + } + + if not makeName or makeName == "NULL" then + makeName = "" + else + metadata[#metadata+1] = {label = "Make", value = makeName} + makeName = makeName .. " " + end + if not modelName or modelName == "NULL" then + modelName = "" + else + metadata[#metadata+1] = {label = "Model", value = modelName} + end + + return { + title = ("%s%s"):format(makeName, modelName), + metadata = metadata, + onSelect = function(args) + TriggerServerEvent("ND_Vehicles:takeVehicle", vehicle.id, vehicleSpawns) + end, + } +end + +local function createMenu(vehicles, garageType, vehicleSpawns) + local options = { + { + title = "Park vehicle", + onSelect = function(args) + local veh = getClosestOwnedVehicle() + parkVehicle(veh) + end + } + } + for _, vehicle in ipairs(vehicles) do + if vehicle.available and isVehicleClassForGarage(vehicle.properties.class, garageType) then + options[#options+1] = createMenuOptions(vehicle, vehicleSpawns) + end + end + return { + id = ("garage_%s"):format(garageType), + title = "Parking garage", + options = options, + onExit = function() + garageOpen = false + end + } +end + +for i=1, #locations do + local location = locations[i] + NDCore.createAiPed({ + model = `s_m_y_airworker`, + coords = location.ped, + distance = 45.0, + clothing = clothing[math.random(1, #clothing)], + blip = { + label = ("Parking garage (%s)"):format(location.garageType), + sprite = sprite[location.garageType], + scale = 0.7, + color = 3 + }, + anim = { + dict = "anim@amb@casino@valet_scenario@pose_d@", + clip = "base_a_m_y_vinewood_01" + }, + options = { + { + name = "nd_core:garagePed", + icon = "fa-solid fa-warehouse", + label = "View garage", + distance = 2.0, + canInteract = function(entity, distance, coords, name, bone) + if not location.groups then return true end + local groups = location.groups + local playerGroups = NDCore.player?.groups + for i=1, #groups do + if playerGroups?[groups[i]] then + return true + end + end + end, + onSelect = function(data) + local vehicles = lib.callback.await("ND_Vehicles:getOwnedVehicles") or {} + local menu = createMenu(vehicles, location.garageType, location.vehicleSpawns) + lib.registerContext(menu) + lib.showContext(menu.id) + end + } + }, + }) +end diff --git a/client/vehicle.lua b/client/vehicle/main.lua similarity index 97% rename from client/vehicle.lua rename to client/vehicle/main.lua index f42c6de..b66d37a 100644 --- a/client/vehicle.lua +++ b/client/vehicle/main.lua @@ -241,14 +241,20 @@ local function getVehicleBlipSprite(entity) return typeBlip[model] or classBlip[class] or 225 -- 255 is default car blip end -RegisterNetEvent("ND_Vehicles:blip", function(netid, status) - local veh = NetToVeh(netid) +RegisterNetEvent("ND_Vehicles:blip", function(netId, status) + local time = GetCloudTimeAsInt() + while not NetworkDoesNetworkIdExist(netId) or not NetworkDoesEntityExistWithNetworkId(netId) and time-GetCloudTimeAsInt() < 5 do + Wait(100) + end + + local veh = NetToVeh(netId) if not veh then return end if not status then local blip = GetBlipFromEntity(veh) if not blip or not DoesBlipExist(blip) then return end return RemoveBlip(blip) end + local blip = AddBlipForEntity(veh) SetBlipSprite(blip, getVehicleBlipSprite(veh)) SetBlipColour(blip, 0) @@ -723,6 +729,13 @@ lib.onCache("ped", function(value) SetPedConfigFlag(value, 184, true) end) +lib.onCache("vehicle", function(value) + local veh = value or cache.vehicle + local blip = GetBlipFromEntity(veh) + if not blip or not DoesBlipExist(blip) then return end + SetBlipAlpha(blip, value and 0 or 255) +end) + SetTimeout(500, function() SetPedConfigFlag(cache.ped, 184, true) end) diff --git a/fxmanifest.lua b/fxmanifest.lua index e14996a..35cd0a8 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -12,8 +12,9 @@ shared_script "@ox_lib/init.lua" client_scripts { "client/main.lua", "shared/functions.lua", - "client/vehicle.lua", "client/peds.lua", + "client/vehicle/main.lua", + "client/vehicle/garages.lua", "client/functions.lua", "client/events.lua", "client/death.lua", @@ -30,6 +31,9 @@ server_scripts { "server/commands.lua" } -file "init.lua" +files { + "init.lua", + "client/vehicle/data.lua" +} dependency "oxmysql" diff --git a/server/vehicle.lua b/server/vehicle.lua index 57aa52b..861e7bc 100644 --- a/server/vehicle.lua +++ b/server/vehicle.lua @@ -52,7 +52,7 @@ local function getVehicleDatabaseInfo(vehicle) stored = stored, impounded = impounded, stolen = vehicle.stolen == 1, - available = not impounded and not stored + available = not impounded and stored } end @@ -84,8 +84,12 @@ function NDCore.getVehicle(entity) } --- delete the vehicle - function self.delete() + function self.delete(saveProperties) if not DoesEntityExist(entity) then return end + if saveProperties and self.id and self.owner then + local properties = lib.callback.await("ND_Vehicles:getProps", NetworkGetEntityOwner(entity)) + MySQL.query("UPDATE nd_vehicles SET properties = ? WHERE id = ?", {json.encode(properties), self.id}) + end DeleteEntity(entity) end @@ -107,7 +111,7 @@ function NDCore.getVehicle(entity) function self.setLocked(status) if not DoesEntityExist(entity) then return end local state = Entity(entity).state - status.locked = status + state.locked = status self.locked = status end @@ -132,10 +136,11 @@ function NDCore.getVehicle(entity) ---@param status boolean function self.setStatus(statusType, status) if not lib.table.contains({"stored", "impounded", "stolen"}, statusType) then return end - if statusType ~= "stolen" then self.delete() end + if statusType ~= "stolen" then self.delete(true) end if not self.id or not self.owner then return end - local query = ("UPDATE nd_vehicles %s = ? WHERE id = ?"):format(statusType) + local query = ("UPDATE nd_vehicles SET %s = ? WHERE id = ?"):format(statusType) MySQL.query(query, {status and 1 or 0, self.id}) + return true end if self.id and self.owner then @@ -228,16 +233,22 @@ function NDCore.createVehicle(info) if coordType == "vector3" or coordType == "table" then spawnCoords = vector4(coords.x, coords.y, coords.z, coords.w or coords.h or info.heading or 0.0) end - if not spawnCoords then return end + if not spawnCoords then + return Citizen.Trace("NDCore.createVehicle", "spawnCoords not found") + end local model = info.model or properties.model local vehType = getVehicleType(model) - if not vehType then return end + if not vehType then + return Citizen.Trace("NDCore.createVehicle", "vehType not found") + end local veh = CreateVehicleServerSetter(model, vehType, spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w) local time = os.time() while not DoesEntityExist(veh) and time-os.time() < 5 do Wait(5) end - if not veh or not DoesEntityExist(veh) then return end + if not veh or not DoesEntityExist(veh) then + return Citizen.Trace("NDCore.createVehicle", "vehicle entity doesn't exist") + end local netId = NetworkGetNetworkIdFromEntity(veh) local state = Entity(veh).state @@ -279,7 +290,7 @@ function NDCore.createVehicle(info) end end - return NDCore.getVehicle(entity) + return NDCore.getVehicle(veh) end --- transfer ownership of a vehicle between players @@ -381,12 +392,12 @@ end ---@param coords vector4 ---@return table function NDCore.spawnOwnedVehicle(source, vehicleId, coords, heading) - local player = NDCore.getPlayer(src) + local player = NDCore.getPlayer(source) if not player then return end local vehicle = NDCore.getVehicleById(vehicleId) if not vehicle or not vehicle.available or vehicle.owner ~= player.id then return end - + MySQL.query.await("UPDATE nd_vehicles SET stored = ? WHERE id = ?", {0, vehicleId}) return NDCore.createVehicle({ owner = player.id, @@ -604,16 +615,47 @@ RegisterNetEvent("ND_Vehicles:hotwire", function(netId) state.hotwired = true end) --- lib.callback.await("ND_Vehicles:getProps", src) - -RegisterCommand("test", function(src, args, rawCommand) - local ped = GetPlayerPed(src) - local coords = GetEntityCoords(ped) - NDCore.spawnOwnedVehicle(src, 35, vec4(coords.x, coords.y, coords.z, GetEntityHeading(ped))) -end, false) - -RegisterCommand("test2", function(source, args, rawCommand) +RegisterNetEvent("ND_Vehicles:storeVehicle", function(netId) local src = source - local properties = lib.callback.await("ND_Vehicles:getProps", src) - NDCore.setVehicleOwned(src, properties, true) -end, false) + local vehicle = NDCore.getVehicle(NetworkGetEntityFromNetworkId(netId)) + if not vehicle then return end + + local player = NDCore.getPlayer(src) + if not vehicle.setStatus("stored", true) or not player or player.id ~= vehicle.owner then + return player.notify({ + title = "Garage", + description = "No owned vehicle found nearby.", + type = "error", + position = "bottom", + duration = 3000 + }) + end + player.notify({ + title = "Garage", + description = "Vehicle stored in garage.", + type = "success", + position = "bottom", + duration = 3000 + }) +end) + +local function isParkingAvailable(locations) + for i=1, #locations do + local loc = locations[math.random(1, #locations)] + if #getNearbyVehicles(vec3(loc.x, loc.y, loc.z), 2.0) == 0 then + return loc + end + end +end + +RegisterNetEvent("ND_Vehicles:takeVehicle", function(vehId, locations) + local src = source + local info = NDCore.spawnOwnedVehicle(src, vehId, isParkingAvailable(locations)) + TriggerClientEvent("ND_Vehicles:blip", src, info.netId, true) +end) + +lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src) + local player = NDCore.getPlayer(src) + if not player then return end + return NDCore.getVehicles(player.id) +end)