mirror of
https://github.com/ND-Framework/ND_Core.git
synced 2026-08-17 05:56:01 +01:00
feat: vehicle stuff
This commit is contained in:
130
client/vehicle.lua
Normal file
130
client/vehicle.lua
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
local function getVehicleBlipSprite(entity)
|
||||||
|
if not IsEntityAVehicle(entity) then
|
||||||
|
return 148 -- circle blip
|
||||||
|
end
|
||||||
|
|
||||||
|
local class = GetVehicleClass(entity)
|
||||||
|
local model = GetEntityModel(entity)
|
||||||
|
local classBlip = {
|
||||||
|
[16] = 423, -- plane
|
||||||
|
[8] = 226, -- motorcycle
|
||||||
|
[15] = 64, -- helicopter
|
||||||
|
[14] = 427, -- boat
|
||||||
|
[6] = 825, -- sports
|
||||||
|
[7] = 523, -- super
|
||||||
|
[2] = 821, -- SUV
|
||||||
|
[4] = 663 -- muscle
|
||||||
|
}
|
||||||
|
local typeBlip = {
|
||||||
|
[`seashark`] = 471,
|
||||||
|
[`marquis`] = 410,
|
||||||
|
[`rhino`] = 421,
|
||||||
|
[`hydra`] = 424,
|
||||||
|
[`lazer`] = 424,
|
||||||
|
[`taxi`] = 198,
|
||||||
|
[`trash`] = 318,
|
||||||
|
[`trash2`] = 318
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
SetBlipScale(blip, 0.8)
|
||||||
|
SetBlipAsShortRange(blip, true)
|
||||||
|
BeginTextCommandSetBlipName("STRING")
|
||||||
|
AddTextComponentSubstringPlayerName("Personal vehicle")
|
||||||
|
EndTextCommandSetBlipName(blip)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent("ND_Vehicles:syncAlarm", function(netid, success, action)
|
||||||
|
local veh = NetToVeh(netid)
|
||||||
|
if not veh then return end
|
||||||
|
SetVehicleAlarmTimeLeft(veh, 1)
|
||||||
|
SetVehicleAlarm(veh, true)
|
||||||
|
StartVehicleAlarm(veh)
|
||||||
|
if success and action == "lockpick" then
|
||||||
|
setVehicleLocked(veh, false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent("ND_VehicleSystem:setOwnedIfNot", function(netid)
|
||||||
|
local veh = NetToVeh(netid)
|
||||||
|
if not veh then return end
|
||||||
|
setVehicleOwned(veh, true)
|
||||||
|
setVehicleLocked(veh, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
AddStateBagChangeHandler("props", nil, function(bagName, key, value, reserved, replicated)
|
||||||
|
local entity = GetEntityFromStateBagName(bagName)
|
||||||
|
if entity == 0 or not value then return end
|
||||||
|
lib.setVehicleProperties(entity, value)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function playKeyFob(veh)
|
||||||
|
local keyFob
|
||||||
|
local ped = cache.ped
|
||||||
|
if GetVehiclePedIsIn(ped) == 0 then
|
||||||
|
ClearPedTasks(ped)
|
||||||
|
lib.requestAnimDict("anim@mp_player_intmenu@key_fob@")
|
||||||
|
TaskPlayAnim(ped, "anim@mp_player_intmenu@key_fob@", "fob_click_fp", 8.0, 8.0, -1, 48, 1, false, false, false)
|
||||||
|
keyFob = CreateObject(`lr_prop_carkey_fob`, 0, 0, 0, true, true, true)
|
||||||
|
AttachEntityToEntity(keyFob, ped, GetPedBoneIndex(ped, 0xDEAD), 0.12, 0.04, -0.025, -100.0, 100.0, 0.0, true, true, false, true, 1, true)
|
||||||
|
Wait(700)
|
||||||
|
end
|
||||||
|
|
||||||
|
PlaySoundFromEntity(-1, "Remote_Control_Fob", ped, "PI_Menu_Sounds", true, 0)
|
||||||
|
SetVehicleLights(veh, 2)
|
||||||
|
Wait(100)
|
||||||
|
SetVehicleLights(veh, 0)
|
||||||
|
Wait(200)
|
||||||
|
SetVehicleLights(veh, 2)
|
||||||
|
Wait(100)
|
||||||
|
SetVehicleLights(veh, 0)
|
||||||
|
return keyFob and DeleteEntity(keyFob)
|
||||||
|
end
|
||||||
|
|
||||||
|
AddStateBagChangeHandler("locked", nil, function(bagName, key, value, reserved, replicated)
|
||||||
|
local entity = GetEntityFromStateBagName(bagName)
|
||||||
|
if entity == 0 then return end
|
||||||
|
|
||||||
|
CreateThread(function()
|
||||||
|
playKeyFob(entity)
|
||||||
|
end)
|
||||||
|
|
||||||
|
if value then
|
||||||
|
SetVehicleDoorsLocked(entity, 4)
|
||||||
|
return SetVehicleDoorsLocked(entity, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
CreateThread(function()
|
||||||
|
while GetVehiclePedIsEntering(cache.ped) ~= 0 do Wait(10) end
|
||||||
|
SetVehicleDoorsLocked(entity, 1)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
lib.callback.register("ND_Vehicles:getProps", function()
|
||||||
|
return lib.getVehicleProperties(GetVehiclePedIsIn(cache.ped))
|
||||||
|
end)
|
||||||
|
|
||||||
|
lib.callback.register("ND_Vehicles:getNearbyVehicleById", function(vehId)
|
||||||
|
local coords = GetEntityCoords(cache.ped)
|
||||||
|
local vehicles = lib.getNearbyVehicles(coords, 25.0, true)
|
||||||
|
for i=1, #vehicles do
|
||||||
|
local veh = vehicles[i]
|
||||||
|
local state = Entity(veh).state
|
||||||
|
if state and state.id == vehId then
|
||||||
|
return VehToNet(veh)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
local playerOwnedVehicles = {}
|
local playerOwnedVehicles = {}
|
||||||
|
|
||||||
local function isPlateAvailable(plate)
|
local function isPlateAvailable(plate)
|
||||||
return not MySQL.scalar.await("SELECT 1 FROM vehicles WHERE plate = ?", {plate})
|
return not MySQL.scalar.await("SELECT 1 FROM nd_vehicles WHERE plate = ?", {plate})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function generatePlate()
|
local function generatePlate()
|
||||||
@@ -21,7 +21,7 @@ local function generatePlateWait()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function getVehicles(characterId)
|
local function getVehicles(characterId)
|
||||||
local result = MySQL.query.await("SELECT * FROM vehicles WHERE owner = ?", {characterId})
|
local result = MySQL.query.await("SELECT * FROM nd_vehicles WHERE owner = ?", {characterId})
|
||||||
if not result then return {} end
|
if not result then return {} end
|
||||||
local vehicles = {}
|
local vehicles = {}
|
||||||
for _, vehicle in pairs(result) do
|
for _, vehicle in pairs(result) do
|
||||||
@@ -89,7 +89,7 @@ function NDCore.setVehicleOwned(src, properties, stored)
|
|||||||
local player = NDCore.getPlayer(src)
|
local player = NDCore.getPlayer(src)
|
||||||
local plate = generatePlateWait()
|
local plate = generatePlateWait()
|
||||||
properties.plate = plate
|
properties.plate = plate
|
||||||
local id = MySQL.insert.await("INSERT INTO vehicles (owner, plate, properties, stored) VALUES (?, ?, ?, ?)", {player.id, properties.plate, json.encode(properties), stored and 1 or 0})
|
local id = MySQL.insert.await("INSERT INTO nd_vehicles (owner, plate, properties, stored) VALUES (?, ?, ?, ?)", {player.id, properties.plate, json.encode(properties), stored and 1 or 0})
|
||||||
local vehicles = getVehicles(player.id)
|
local vehicles = getVehicles(player.id)
|
||||||
player.triggerEvent("ND_Vehicles:returnVehicles", vehicles)
|
player.triggerEvent("ND_Vehicles:returnVehicles", vehicles)
|
||||||
return id
|
return id
|
||||||
@@ -146,63 +146,37 @@ function NDCore.giveVehicleAccess(source, vehicle, access)
|
|||||||
player.triggerEvent("ND_Vehicles:setOwnedIfNot", NetworkGetNetworkIdFromEntity(vehicle))
|
player.triggerEvent("ND_Vehicles:setOwnedIfNot", NetworkGetNetworkIdFromEntity(vehicle))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function isParkingAvailable(source, coords)
|
|
||||||
local tries = 1
|
|
||||||
while tries < #coords do
|
|
||||||
Wait(300)
|
|
||||||
local coord = coords[math.random(1, #coords)]
|
|
||||||
local available = lib.callback.await("ND_Vehicles:getParkedVehicle", source, vector3(coord.x, coord.y, coord.z))
|
|
||||||
if available then
|
|
||||||
return coord
|
|
||||||
end
|
|
||||||
tries += 1
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getVehicleType(model)
|
local function getVehicleType(model)
|
||||||
local tempVehicle = CreateVehicle(model, 0, 0, 0, 0, false, false)
|
local tempVehicle = CreateVehicle(model, 0, 0, 0, 0, true, true)
|
||||||
while not DoesEntityExist(tempVehicle) do Wait(0) end
|
while not DoesEntityExist(tempVehicle) do Wait(0) end
|
||||||
local entityType = GetVehicleType(tempVehicle)
|
local entityType = GetVehicleType(tempVehicle)
|
||||||
DeleteEntity(tempVehicle)
|
DeleteEntity(tempVehicle)
|
||||||
return entityType
|
return entityType
|
||||||
end
|
end
|
||||||
|
|
||||||
function NDCore.spawnOwnedVehicle(source, vehicleID, coords)
|
function NDCore.spawnOwnedVehicle(source, vehicleID, coords, heading)
|
||||||
local player = NDCore.getPlayer(source)
|
local player = NDCore.getPlayer(source)
|
||||||
local spawnCoords = coords
|
|
||||||
|
|
||||||
if type(coords) == "table" then
|
|
||||||
spawnCoords = isParkingAvailable(source, coords)
|
|
||||||
if not spawnCoords then
|
|
||||||
player.notify({
|
|
||||||
title = "Can't bring out vehicle",
|
|
||||||
description = "No parking spot available for your vehicle. It's still in your garage.",
|
|
||||||
type = "error",
|
|
||||||
position = "bottom",
|
|
||||||
duration = 4000
|
|
||||||
})
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local vehicles = getVehicles(player.id)
|
local vehicles = getVehicles(player.id)
|
||||||
for _, vehicle in pairs(vehicles) do
|
for _, vehicle in pairs(vehicles) do
|
||||||
if vehicle.owner == player.id and vehicle.id == vehicleID then
|
if vehicle.id == vehicleID and vehicle.owner == player.id then
|
||||||
MySQL.query.await("UPDATE vehicles SET stored = ? WHERE id = ?", {0, vehicleID})
|
MySQL.query.await("UPDATE nd_vehicles SET stored = ? WHERE id = ?", {0, vehicleID})
|
||||||
player.triggerEvent("ND_VehicleSystem:returnVehicles", getVehicles(player.id))
|
vehicle.available = false
|
||||||
|
player.triggerEvent("ND_Vehicles:returnVehicles", vehicles)
|
||||||
|
|
||||||
local veh = CreateVehicleServerSetter(vehicle.properties.model, getVehicleType(vehicle.properties.model), spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w)
|
local model = vehicle.properties.model
|
||||||
|
local veh = CreateVehicleServerSetter(model, getVehicleType(model), coords.x, coords.y, coords.z, coords.w or heading)
|
||||||
while not DoesEntityExist(veh) do Wait(0) end
|
while not DoesEntityExist(veh) do Wait(0) end
|
||||||
|
|
||||||
playerOwnedVehicles[vehicle.id] = {
|
playerOwnedVehicles[vehicle.id] = {
|
||||||
netid = NetworkGetNetworkIdFromEntity(veh)
|
netid = NetworkGetNetworkIdFromEntity(veh),
|
||||||
|
entity = veh
|
||||||
}
|
}
|
||||||
|
|
||||||
local state = Entity(veh).state
|
local state = Entity(veh).state
|
||||||
state.owner = vehicle.owner
|
state.owner = vehicle.owner
|
||||||
state.id = vehicle.id
|
state.id = vehicle.id
|
||||||
state.props = vehicle.properties
|
state.props = vehicle.properties
|
||||||
|
state.locked = true
|
||||||
|
|
||||||
if Config.useInventoryForKeys then
|
if Config.useInventoryForKeys then
|
||||||
exports.ox_inventory:AddItem(source, "keys", 1, {
|
exports.ox_inventory:AddItem(source, "keys", 1, {
|
||||||
@@ -231,7 +205,7 @@ function NDCore.returnVehicleToGarage(source, veh, properties)
|
|||||||
|
|
||||||
for _, vehicle in pairs(vehicles) do
|
for _, vehicle in pairs(vehicles) do
|
||||||
if vehicle.owner == player.id and vehicle.id == vehID then
|
if vehicle.owner == player.id and vehicle.id == vehID then
|
||||||
MySQL.query.await("UPDATE vehicles SET properties = ?, stored = ? WHERE id = ?", {json.encode(properties), 1, vehID})
|
MySQL.query.await("UPDATE nd_vehicles SET properties = ?, stored = ? WHERE id = ?", {json.encode(properties), 1, vehID})
|
||||||
player.triggerEvent("ND_Vehicles:returnVehicles", getVehicles(player.id))
|
player.triggerEvent("ND_Vehicles:returnVehicles", getVehicles(player.id))
|
||||||
DeleteEntity(veh)
|
DeleteEntity(veh)
|
||||||
return true
|
return true
|
||||||
@@ -248,7 +222,7 @@ function NDCore.saveVehicleProperties(source, veh, properties)
|
|||||||
|
|
||||||
for _, vehicle in pairs(vehicles) do
|
for _, vehicle in pairs(vehicles) do
|
||||||
if vehicle.owner == player.id and vehicle.id == vehID then
|
if vehicle.owner == player.id and vehicle.id == vehID then
|
||||||
MySQL.query.await("UPDATE vehicles SET properties = ? WHERE id = ?", {json.encode(properties), vehID})
|
MySQL.query.await("UPDATE nd_vehicles SET properties = ? WHERE id = ?", {json.encode(properties), vehID})
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -261,6 +235,73 @@ RegisterNetEvent("ND_Vehicles:syncAlarm", function(netid, success, action)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
if Config.useInventoryForKeys then
|
if Config.useInventoryForKeys then
|
||||||
|
local function toggleVehicleLock(id, veh, nearby)
|
||||||
|
local player = NDCore.getPlayer(id)
|
||||||
|
if nearby then
|
||||||
|
local state = Entity(veh).state
|
||||||
|
local locked = not state.locked
|
||||||
|
state.locked = locked
|
||||||
|
if locked then
|
||||||
|
player.notify({
|
||||||
|
title = "LOCKED",
|
||||||
|
description = "Your vehicle has now been locked.",
|
||||||
|
type = "success",
|
||||||
|
position = "bottom-right",
|
||||||
|
duration = 3000
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
player.notify({
|
||||||
|
title = "UNLOCKED",
|
||||||
|
description = "Your vehicle has now been unlocked.",
|
||||||
|
type = "inform",
|
||||||
|
position = "bottom-right",
|
||||||
|
duration = 3000
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
player.notify({
|
||||||
|
title = "No signal",
|
||||||
|
description = "Vehicle to far away.",
|
||||||
|
type = "error",
|
||||||
|
position = "bottom-right",
|
||||||
|
duration = 3000
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
exports("keys", function(event, item, inventory, slot, data)
|
||||||
|
if event ~= "usingItem" then return end
|
||||||
|
local metadata
|
||||||
|
for i=1, #inventory.items do
|
||||||
|
local item = inventory.items[i]
|
||||||
|
if item.slot == slot then
|
||||||
|
metadata = item.metadata
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not metadata then return false end
|
||||||
|
local veh = playerOwnedVehicles[metadata.vehId] and playerOwnedVehicles[metadata.vehId].entity
|
||||||
|
if veh and DoesEntityExist(veh) then
|
||||||
|
local ped = GetPlayerPed(inventory.id)
|
||||||
|
local pedCoords = GetEntityCoords(ped)
|
||||||
|
local vehCoords = GetEntityCoords(veh)
|
||||||
|
if not pedCoords or not vehCoords then return end
|
||||||
|
toggleVehicleLock(inventory.id, veh, #(pedCoords-vehCoords) < 25.0)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
lib.callback("ND_Vehicles:getNearbyVehicleById", inventory.id, function(netId)
|
||||||
|
if not netId then return end
|
||||||
|
local veh = NetworkGetEntityFromNetworkId(netId)
|
||||||
|
if veh then
|
||||||
|
toggleVehicleLock(inventory.id, veh, true)
|
||||||
|
end
|
||||||
|
end, metadata.vehId)
|
||||||
|
return false
|
||||||
|
end)
|
||||||
|
|
||||||
RegisterCommand("getkeys", function(source, args, rawCommand)
|
RegisterCommand("getkeys", function(source, args, rawCommand)
|
||||||
local veh = GetVehiclePedIsIn(GetPlayerPed(source))
|
local veh = GetVehiclePedIsIn(GetPlayerPed(source))
|
||||||
if not veh or veh == 0 then return end
|
if not veh or veh == 0 then return end
|
||||||
|
|||||||
Reference in New Issue
Block a user