forked from Simnation/Main
769 lines
31 KiB
Lua
769 lines
31 KiB
Lua
![]() |
local vehicles = {}
|
||
|
local DB_vehicles = {}
|
||
|
|
||
|
-- Command to delete ALL vehicles from the database table. Needs to be executed twice for security reason.
|
||
|
local deleteSavedVehicles = false
|
||
|
RegisterCommand("deleteSavedVehicles", function(source, args, raw)
|
||
|
if (deleteSavedVehicles) then
|
||
|
MySQL.query("DELETE FROM vehicle_parking", { })
|
||
|
|
||
|
vehicles = {}
|
||
|
|
||
|
Log("Deleted all vehicles from the vehicle_parking table.")
|
||
|
else
|
||
|
Log("Are you sure that you want to delete all vehicles from the parking list?\nIf yes, type the command a second time!")
|
||
|
end
|
||
|
|
||
|
deleteSavedVehicles = not deleteSavedVehicles
|
||
|
end, true)
|
||
|
|
||
|
-- read all vehicles from the database on startup and do a cleanup check
|
||
|
MySQL.ready(function()
|
||
|
-- fetch all database results
|
||
|
MySQL.query("SELECT plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate FROM vehicle_parking", {}, function(results)
|
||
|
Log("Found " .. #results .. " saved vehicles in vehicle_parking.")
|
||
|
|
||
|
for i = 1, #results do
|
||
|
vehicles[results[i].plate] = {
|
||
|
handle = nil,
|
||
|
position = vector3(results[i].posX, results[i].posY, results[i].posZ),
|
||
|
rotation = vector3(results[i].rotX, results[i].rotY, results[i].rotZ),
|
||
|
modifications = json.decode(results[i].modifications),
|
||
|
lastUpdate = results[i].lastUpdate,
|
||
|
spawning = false,
|
||
|
spawningPlayer = nil,
|
||
|
faultyModel = false
|
||
|
}
|
||
|
end
|
||
|
|
||
|
--CleanUp()
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
-- Default CleanUp function. Deletes vehicles from the database after a specific amount of time has passed (configurable in config)
|
||
|
function CleanUp()
|
||
|
local currentTime = os.time()
|
||
|
local threshold = 60 * 60 * Config.cleanUpThresholdTime
|
||
|
|
||
|
local toDelete = {}
|
||
|
|
||
|
for plate, vehicle in pairs(vehicles) do
|
||
|
if (vehicle.lastUpdate < os.difftime(currentTime, threshold)) then
|
||
|
|
||
|
MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate",
|
||
|
{
|
||
|
["@plate"] = plate
|
||
|
})
|
||
|
|
||
|
table.insert(toDelete, plate)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
for i = 1, #toDelete, 1 do
|
||
|
local plate = toDelete[i]
|
||
|
vehicles[plate] = nil
|
||
|
end
|
||
|
|
||
|
Log("CleanUp complete. Deleted " .. #toDelete .. " entries.")
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- loop to spawn vehicles near players
|
||
|
Citizen.CreateThread(function()
|
||
|
while (true) do
|
||
|
Citizen.Wait(5000)
|
||
|
|
||
|
if (GetActivePlayerCount() > 0) then
|
||
|
TrySpawnVehicles()
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
Citizen.CreateThread(function()
|
||
|
while (true) do
|
||
|
CallDB_Vehicles()
|
||
|
Citizen.Wait(60000 * 5)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- loop to delete vehicles
|
||
|
Citizen.CreateThread(function()
|
||
|
if (Config.deleteTimer <= 0) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
while (true) do
|
||
|
Citizen.Wait(60000 * (Config.deleteTimer - Config.deleteNotificationTimes[1]))
|
||
|
|
||
|
TriggerClientEvent("mh_Parking:notification", -1, string.format(Config.timeLeftNotification, Config.deleteNotificationTimes[1]))
|
||
|
for i = 2, #Config.deleteNotificationTimes, 1 do
|
||
|
Citizen.Wait(60000 * (Config.deleteNotificationTimes[i - 1] - Config.deleteNotificationTimes[i]))
|
||
|
TriggerClientEvent("mh_Parking:notification", -1, string.format(Config.timeLeftNotification, Config.deleteNotificationTimes[i]))
|
||
|
end
|
||
|
Citizen.Wait(60000 * Config.deleteNotificationTimes[#Config.deleteNotificationTimes])
|
||
|
|
||
|
DeleteAllVehicles()
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
|
||
|
|
||
|
-- sync player position
|
||
|
RegisterServerEvent("mh_Parking:syncPlayerPosition")
|
||
|
AddEventHandler("mh_Parking:syncPlayerPosition", function(position)
|
||
|
activePlayerPositions[source] = position
|
||
|
end)
|
||
|
|
||
|
-- player disconnected
|
||
|
AddEventHandler("playerDropped", function(disconnectReason)
|
||
|
activePlayerPositions[source] = nil
|
||
|
end)
|
||
|
|
||
|
-- player entered a vehicle
|
||
|
RegisterServerEvent("mh_Parking:enteredVehicle")
|
||
|
AddEventHandler("mh_Parking:enteredVehicle", function(networkId, plate, modifications)
|
||
|
local vehicle = NetworkGetEntityFromNetworkId(networkId)
|
||
|
|
||
|
if (DoesEntityExist(vehicle)) then
|
||
|
local currentTime = os.time()
|
||
|
|
||
|
local position = GetEntityCoords(vehicle)
|
||
|
position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0)
|
||
|
local rotation = GetEntityRotation(vehicle)
|
||
|
rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0)
|
||
|
|
||
|
if (vehicles[plate]) then
|
||
|
-- already on server list
|
||
|
|
||
|
Log("Entered vehicle " .. plate .. ". Updating...")
|
||
|
|
||
|
if (vehicles[plate].handle ~= vehicle) then
|
||
|
if (DoesEntityExist(vehicles[plate].handle)) then
|
||
|
DeleteEntity(vehicles[plate].handle)
|
||
|
end
|
||
|
|
||
|
vehicles[plate].handle = vehicle
|
||
|
end
|
||
|
|
||
|
vehicles[plate].position = position
|
||
|
vehicles[plate].rotation = rotation
|
||
|
vehicles[plate].modifications = modifications
|
||
|
vehicles[plate].lastUpdate = currentTime
|
||
|
|
||
|
MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate", {
|
||
|
["@plate"] = plate,
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@lastUpdate"] = vehicles[plate].lastUpdate
|
||
|
})
|
||
|
else
|
||
|
-- insert in db
|
||
|
|
||
|
Log("Entered vehicle " .. plate .. ". Inserting new...")
|
||
|
|
||
|
vehicles[plate] = {
|
||
|
handle = vehicle,
|
||
|
position = position,
|
||
|
rotation = rotation,
|
||
|
modifications = modifications,
|
||
|
lastUpdate = currentTime,
|
||
|
spawning = false,
|
||
|
spawningPlayer = nil
|
||
|
}
|
||
|
|
||
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs)
|
||
|
Log(json.encode(rs))
|
||
|
if rs[1] then
|
||
|
Log("FOUND OWNER FROM VEHICLE")
|
||
|
|
||
|
MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)", {
|
||
|
["@plate"] = plate,
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@lastUpdate"] = vehicles[plate].lastUpdate
|
||
|
})
|
||
|
else
|
||
|
Log("1: NO VEHICLE FOUND")
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
else
|
||
|
Log("Vehicle does not exist. Might be a Onesync error.")
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- player left a vehicle
|
||
|
RegisterServerEvent("mh_Parking:leftVehicle")
|
||
|
AddEventHandler("mh_Parking:leftVehicle", function(networkId, modifications)
|
||
|
local vehicle = NetworkGetEntityFromNetworkId(networkId)
|
||
|
|
||
|
if (DoesEntityExist(vehicle)) then
|
||
|
local currentTime = os.time()
|
||
|
|
||
|
local plate = GetVehicleNumberPlateText(vehicle)
|
||
|
|
||
|
local position = GetEntityCoords(vehicle)
|
||
|
position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0)
|
||
|
local rotation = GetEntityRotation(vehicle)
|
||
|
rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0)
|
||
|
|
||
|
if (vehicles[plate]) then
|
||
|
-- already on server list
|
||
|
|
||
|
Log("Left vehicle " .. plate .. ". Updating...")
|
||
|
|
||
|
if (vehicles[plate].handle ~= vehicle) then
|
||
|
if (DoesEntityExist(vehicles[plate].handle)) then
|
||
|
DeleteEntity(vehicles[plate].handle)
|
||
|
end
|
||
|
|
||
|
vehicles[plate].handle = vehicle
|
||
|
end
|
||
|
|
||
|
vehicles[plate].position = position
|
||
|
vehicles[plate].rotation = rotation
|
||
|
vehicles[plate].modifications = modifications
|
||
|
vehicles[plate].lastUpdate = currentTime
|
||
|
|
||
|
MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate",{
|
||
|
["@plate"] = plate,
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@lastUpdate"] = currentTime
|
||
|
})
|
||
|
else
|
||
|
-- insert in db
|
||
|
|
||
|
Log("Left vehicle " .. plate .. ". Inserting new...")
|
||
|
|
||
|
vehicles[plate] = {
|
||
|
handle = vehicle,
|
||
|
position = position,
|
||
|
rotation = rotation,
|
||
|
modifications = modifications,
|
||
|
lastUpdate = currentTime,
|
||
|
spawning = false,
|
||
|
spawningPlayer = nil
|
||
|
}
|
||
|
|
||
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs)
|
||
|
if rs[1] then
|
||
|
Log("FOUND OWNER FROM VEHICLE")
|
||
|
|
||
|
MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)",{
|
||
|
["@plate"] = plate,
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@lastUpdate"] = vehicles[plate].lastUpdate
|
||
|
})
|
||
|
else
|
||
|
Log("2: NO VEHICLE FOUND")
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- update a vehicle with its modifications
|
||
|
RegisterServerEvent("mh_Parking:updateVehicle")
|
||
|
AddEventHandler("mh_Parking:updateVehicle", function(networkId, modifications)
|
||
|
local vehicle = NetworkGetEntityFromNetworkId(networkId)
|
||
|
|
||
|
if (DoesEntityExist(vehicle)) then
|
||
|
local currentTime = os.time()
|
||
|
|
||
|
local plate = GetVehicleNumberPlateText(vehicle)
|
||
|
|
||
|
local position = GetEntityCoords(vehicle)
|
||
|
position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0)
|
||
|
local rotation = GetEntityRotation(vehicle)
|
||
|
rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0)
|
||
|
|
||
|
if (vehicles[plate] ~= nil) then
|
||
|
-- already on server list
|
||
|
|
||
|
Log("Updating vehicle " .. plate)
|
||
|
|
||
|
if (vehicles[plate].handle ~= vehicle) then
|
||
|
if (DoesEntityExist(vehicles[plate].handle)) then
|
||
|
DeleteEntity(vehicles[plate].handle)
|
||
|
end
|
||
|
|
||
|
vehicles[plate].handle = vehicle
|
||
|
end
|
||
|
|
||
|
vehicles[plate].position = position
|
||
|
vehicles[plate].rotation = rotation
|
||
|
vehicles[plate].modifications = modifications
|
||
|
vehicles[plate].lastUpdate = currentTime
|
||
|
|
||
|
MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate",{
|
||
|
["@plate"] = plate,
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@lastUpdate"] = vehicles[plate].lastUpdate
|
||
|
})
|
||
|
else
|
||
|
-- insert in db
|
||
|
|
||
|
Log("Updating vehicle " .. plate .. ". Inserting new...")
|
||
|
|
||
|
vehicles[plate] = {
|
||
|
handle = vehicle,
|
||
|
position = position,
|
||
|
rotation = rotation,
|
||
|
modifications = modifications,
|
||
|
lastUpdate = currentTime,
|
||
|
spawning = false,
|
||
|
spawningPlayer = nil
|
||
|
}
|
||
|
|
||
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs)
|
||
|
if rs[1] then
|
||
|
Log("FOUND OWNER FROM VEHICLE")
|
||
|
|
||
|
MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)",{
|
||
|
["@plate"] = plate,
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@lastUpdate"] = vehicles[plate].lastUpdate
|
||
|
})
|
||
|
else
|
||
|
Log("3: NO VEHICLE FOUND")
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- delete a vehicle from the table (and world) with its plate
|
||
|
RegisterServerEvent("mh_Parking:deleteVehicle")
|
||
|
AddEventHandler("mh_Parking:deleteVehicle", function(plate, deleteEntity)
|
||
|
if (plate == nil) then
|
||
|
Log("^1mh_Parking: \"plate\" was nil while trying to delete vehicle!")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
Log("Trying to delete " .. tostring(plate))
|
||
|
|
||
|
if (vehicles[plate] ~= nil) then
|
||
|
if (deleteEntity and DoesEntityExist(vehicles[plate].handle)) then
|
||
|
DeleteEntity(vehicles[plate].handle)
|
||
|
end
|
||
|
|
||
|
vehicles[plate] = nil
|
||
|
|
||
|
MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate",
|
||
|
{
|
||
|
["@plate"] = plate
|
||
|
})
|
||
|
else
|
||
|
local loadedVehicles = GetAllVehicles()
|
||
|
local loadedVehicle = TryGetLoadedVehicle(plate, loadedVehicles)
|
||
|
|
||
|
if (loadedVehicle ~= nil) then
|
||
|
if (deleteEntity and DoesEntityExist(loadedVehicle)) then
|
||
|
DeleteEntity(loadedVehicle)
|
||
|
end
|
||
|
|
||
|
MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate",
|
||
|
{
|
||
|
["@plate"] = plate
|
||
|
})
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- checks if vehicles have to be spawned and spawns them if necessary
|
||
|
function TrySpawnVehicles()
|
||
|
local loadedVehicles = GetAllVehicles()
|
||
|
|
||
|
local playerVehiclePlates = {}
|
||
|
for id, position in pairs(activePlayerPositions) do
|
||
|
local ped = GetPlayerPed(id)
|
||
|
local veh = GetVehiclePedIsIn(ped, false)
|
||
|
|
||
|
if (DoesEntityExist(veh)) then
|
||
|
table.insert(playerVehiclePlates, GetVehicleNumberPlateText(veh))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- check, if vehicles need to be spawned
|
||
|
for plate, vehicleData in pairs(vehicles) do
|
||
|
local plateCheck = CheckPlate(plate)
|
||
|
if (plateCheck ~= false) then
|
||
|
|
||
|
if (not vehicleData.faultyModel) then
|
||
|
if (not vehicleData.spawning) then
|
||
|
local closestPlayer, dist = GetClosestPlayerId(vehicleData.position)
|
||
|
|
||
|
if (closestPlayer ~= nil and dist < Config.spawnDistance and not ContainsPlate(plate, playerVehiclePlates)) then
|
||
|
if (vehicleData.handle ~= nil and DoesEntityExist(vehicleData.handle)) then
|
||
|
-- vehicle found on server side
|
||
|
|
||
|
UpdateVehicle(plate)
|
||
|
else
|
||
|
-- vehicle not found on server side
|
||
|
-- check, if it is loaded differently
|
||
|
|
||
|
local loadedVehicle = TryGetLoadedVehicle(plate, loadedVehicles)
|
||
|
if (loadedVehicle ~= nil) then
|
||
|
-- vehicle found
|
||
|
|
||
|
vehicleData.handle = loadedVehicle
|
||
|
|
||
|
UpdateVehicle(plate)
|
||
|
else
|
||
|
-- vehicle not found
|
||
|
-- try and spawn it
|
||
|
|
||
|
local playerId, distance = GetClosestPlayerId(vehicleData.position)
|
||
|
if (playerId and distance < Config.spawnDistance) then
|
||
|
vehicleData.spawning = true
|
||
|
|
||
|
Citizen.CreateThread(function()
|
||
|
local vec4 = vector4(vehicleData.position.x, vehicleData.position.y, vehicleData.position.z, vehicleData.rotation.z)
|
||
|
local vehicle = Citizen.InvokeNative(GetHashKey("CREATE_AUTOMOBILE"), vehicleData.modifications[1], vec4.xyzw)
|
||
|
|
||
|
while (not DoesEntityExist(vehicle)) do
|
||
|
Citizen.Wait(0)
|
||
|
end
|
||
|
|
||
|
SetEntityCoords(vehicle, vehicleData.position.x, vehicleData.position.y, vehicleData.position.z)
|
||
|
SetEntityRotation(vehicle, vehicleData.rotation.x, vehicleData.rotation.y, vehicleData.rotation.z)
|
||
|
|
||
|
vehicleData.handle = vehicle
|
||
|
|
||
|
local networkOwner = -1
|
||
|
while (networkOwner == -1) do
|
||
|
Citizen.Wait(0)
|
||
|
networkOwner = NetworkGetEntityOwner(vehicleData.handle)
|
||
|
end
|
||
|
|
||
|
vehicleData.spawningPlayer = GetPlayerIdentifiersSorted(networkOwner)["license"]
|
||
|
|
||
|
Log("Creating vehicle " .. plate .. " at " .. tostring(vehicleData.position) .. " at entity owner " .. tostring(networkOwner))
|
||
|
|
||
|
TriggerClientEvent("mh_Parking:setVehicleMods", networkOwner, NetworkGetNetworkIdFromEntity(vehicleData.handle), plate, vehicleData.modifications)
|
||
|
end)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
elseif (vehicleData.spawningPlayer) then
|
||
|
-- if vehicle is currently spawning check if responsible player is still connected
|
||
|
if (not IsPlayerWithLicenseActive(vehicleData.spawningPlayer)) then
|
||
|
TriggerEvent("mh_Parking:setVehicleModsFailed", plate)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
RegisterServerEvent("mh_Parking:setVehicleModsSuccess")
|
||
|
AddEventHandler("mh_Parking:setVehicleModsSuccess", function(plate)
|
||
|
Log("Setting mods successful...")
|
||
|
|
||
|
if (vehicles[plate]) then
|
||
|
vehicles[plate].spawning = false
|
||
|
vehicles[plate].spawningPlayer = nil
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterServerEvent("mh_Parking:setVehicleModsFailed")
|
||
|
AddEventHandler("mh_Parking:setVehicleModsFailed", function(plate)
|
||
|
Log("Setting mods for " .. plate .. " failed... retrying...")
|
||
|
|
||
|
if (vehicles[plate] and vehicles[plate].handle and DoesEntityExist(vehicles[plate].handle)) then
|
||
|
local networkOwner = -1
|
||
|
while (networkOwner == -1) do
|
||
|
Citizen.Wait(0)
|
||
|
networkOwner = NetworkGetEntityOwner(vehicles[plate].handle)
|
||
|
end
|
||
|
|
||
|
local netOwnerLicense = GetPlayerIdentifiersSorted(networkOwner)["license"]
|
||
|
if (netOwnerLicense ~= nil) then
|
||
|
vehicles[plate].spawningPlayer = GetPlayerIdentifiersSorted(networkOwner)["license"]
|
||
|
|
||
|
TriggerClientEvent("mh_Parking:setVehicleMods", networkOwner, NetworkGetNetworkIdFromEntity(vehicles[plate].handle), plate, vehicles[plate].modifications)
|
||
|
else
|
||
|
Log("Something went wrong while trying to get player license for spawning vehicle " .. tostring(plate) .. ". Despawning vehicle")
|
||
|
|
||
|
DeleteEntity(vehicles[plate].handle)
|
||
|
|
||
|
vehicles[plate].handle = nil
|
||
|
vehicles[plate].spawningPlayer = nil
|
||
|
vehicles[plate].spawning = false
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterServerEvent("mh_Parking:modelDoesNotExist")
|
||
|
AddEventHandler("mh_Parking:modelDoesNotExist", function(plate)
|
||
|
if (vehicles[plate] == nil) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if (DoesEntityExist(vehicles[plate].handle)) then
|
||
|
DeleteEntity(vehicles[plate].handle)
|
||
|
end
|
||
|
vehicles[plate].handle = nil
|
||
|
vehicles[plate].spawningPlayer = nil
|
||
|
vehicles[plate].spawning = false
|
||
|
|
||
|
Log("The model for vehicle " .. tostring(plate) .. " does not exist. Removing from spawn pool...")
|
||
|
|
||
|
vehicles[plate].faultyModel = true
|
||
|
end)
|
||
|
|
||
|
RegisterServerEvent("mh_Parking:updatePlate")
|
||
|
AddEventHandler("mh_Parking:updatePlate", function(oldPlate, newPlate)
|
||
|
if (oldPlate == nil or newPlate == nil) then
|
||
|
Log("^1mh_Parking: \"oldPlate\" or \"newPlate\" was nil while trying to update a plate!")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if (vehicles[oldPlate]) then
|
||
|
if (vehicles[newPlate]) then
|
||
|
Log("Updating plate failed. New plate was already there!")
|
||
|
else
|
||
|
vehicles[newPlate] = vehicles[oldPlate]
|
||
|
vehicles[oldPlate] = nil
|
||
|
|
||
|
Log("Updating plate successful!")
|
||
|
|
||
|
MySQL.query("UPDATE vehicle_parking SET plate = @newPlate WHERE plate = @oldPlate",
|
||
|
{
|
||
|
["@newPlate"] = newPlate,
|
||
|
["@oldPlate"] = oldPlate
|
||
|
})
|
||
|
end
|
||
|
else
|
||
|
Log("Updating plate failed or unnecessary. Old plate was not found!")
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
function UpdateVehicle(plate)
|
||
|
local newPos = GetEntityCoords(vehicles[plate].handle)
|
||
|
local newRot = GetEntityRotation(vehicles[plate].handle)
|
||
|
newPos = vector3(math.floor(newPos.x * 100.0) * 0.01, math.floor(newPos.y * 100.0) * 0.01, math.floor(newPos.z * 100.0) * 0.01)
|
||
|
newRot = vector3(math.floor(newRot.x * 100.0) * 0.01, math.floor(newRot.y * 100.0) * 0.01, math.floor(newRot.z * 100.0) * 0.01)
|
||
|
|
||
|
local newLockStatus = GetVehicleDoorLockStatus(vehicles[plate].handle)
|
||
|
local newEngineHealth = math.floor(GetVehicleEngineHealth(vehicles[plate].handle) * 10.0) * 0.1
|
||
|
local newTankHealth = math.floor(GetVehiclePetrolTankHealth(vehicles[plate].handle) * 10.0) * 0.1
|
||
|
if (Vector3DistFast(vehicles[plate].position, newPos) > 1.0
|
||
|
or GetRotationDifference(vehicles[plate].rotation, newRot) > 15.0
|
||
|
or newLockStatus ~= vehicles[plate].modifications[2]
|
||
|
or math.abs(newEngineHealth - vehicles[plate].modifications[5]) > 5.0
|
||
|
or math.abs(newTankHealth - vehicles[plate].modifications[6]) > 5.0
|
||
|
) then
|
||
|
vehicles[plate].modifications[2] = newLockStatus
|
||
|
vehicles[plate].modifications[5] = newEngineHealth
|
||
|
vehicles[plate].modifications[6] = newTankHealth
|
||
|
|
||
|
Log("Updating vehicle " .. plate)
|
||
|
|
||
|
vehicles[plate].position = newPos
|
||
|
vehicles[plate].rotation = newRot
|
||
|
|
||
|
MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications WHERE plate = @plate",
|
||
|
{
|
||
|
["@posX"] = vehicles[plate].position.x,
|
||
|
["@posY"] = vehicles[plate].position.y,
|
||
|
["@posZ"] = vehicles[plate].position.z,
|
||
|
["@rotX"] = vehicles[plate].rotation.x,
|
||
|
["@rotY"] = vehicles[plate].rotation.y,
|
||
|
["@rotZ"] = vehicles[plate].rotation.z,
|
||
|
["@modifications"] = json.encode(vehicles[plate].modifications),
|
||
|
["@plate"] = plate
|
||
|
})
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function DeleteAllVehicles()
|
||
|
TriggerClientEvent("mh_Parking:notification", -1, Config.deleteNotification)
|
||
|
|
||
|
local peds = GetAllPeds()
|
||
|
local playerPeds = {}
|
||
|
for i = 1, #peds, 1 do
|
||
|
if (IsPedAPlayer(peds[i])) then
|
||
|
table.insert(playerPeds, peds[i])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if (#playerPeds == 0) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local time = GetGameTimer()
|
||
|
|
||
|
local vehs = GetAllVehicles()
|
||
|
local deleted = 0
|
||
|
for i = 1, #vehs, 1 do
|
||
|
if (not IsAnyPlayerInsideVehicle(vehs[i], playerPeds)) then
|
||
|
local closestPlayer, distance = GetClosestPlayerPed(GetEntityCoords(vehs[i]), playerPeds)
|
||
|
if (closestPlayer ~= nil and distance > Config.deleteDistance) then
|
||
|
local plate = GetVehicleNumberPlateText(vehs[i])
|
||
|
if (vehicles[plate] ~= nil) then
|
||
|
vehicles[plate] = nil
|
||
|
|
||
|
MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate",
|
||
|
{
|
||
|
["@plate"] = plate
|
||
|
})
|
||
|
end
|
||
|
|
||
|
DeleteEntity(vehs[i])
|
||
|
|
||
|
deleted = deleted + 1
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
Log("Deleted " .. tostring(deleted) .. "/" .. tostring(#vehs) .. " vehicles. Took " .. tostring((GetGameTimer() - time) / 1000.0) .. "sec")
|
||
|
end
|
||
|
|
||
|
AddEventHandler("onResourceStop", function(name)
|
||
|
if (name ~= GetCurrentResourceName()) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
-- delete vehicles that are still being spawned before actually stopping the resource
|
||
|
for plate, vehicleData in pairs(vehicles) do
|
||
|
if (vehicleData.spawning and DoesEntityExist(vehicleData.handle)) then
|
||
|
DeleteEntity(vehicleData.handle)
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- render entity scorched (trigger with netid of the vehicle and false when repairing)
|
||
|
RegisterServerEvent("mh_Parking:renderScorched")
|
||
|
AddEventHandler("mh_Parking:renderScorched", function(vehicleNetId, scorched)
|
||
|
local vehicleHandle = NetworkGetEntityFromNetworkId(vehicleNetId)
|
||
|
if (DoesEntityExist(vehicleHandle)) then
|
||
|
TriggerClientEvent("mh_Parking:renderScorched", -1, vehicleNetId, scorched)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
if (GetResourceState("kimi_callbacks") == "started") then
|
||
|
exports["kimi_callbacks"]:Register("AP:getVehiclePosition", function(source, plate)
|
||
|
local vehs = GetAllVehicles()
|
||
|
|
||
|
for i, veh in ipairs(vehs) do
|
||
|
local vehPlate = GetVehicleNumberPlateText(veh)
|
||
|
if (plate == vehPlate or plate == string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")) then
|
||
|
return GetEntityCoords(veh)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
for vehPlate, vehData in pairs(vehicles) do
|
||
|
if (plate == vehPlate or plate == string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")) then
|
||
|
return vehData.position
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return nil
|
||
|
end)
|
||
|
|
||
|
exports["kimi_callbacks"]:Register("AP:getVehiclePositions", function(source, plates)
|
||
|
local platePositions = {}
|
||
|
|
||
|
Log("Looking for plates:")
|
||
|
for i, plate in ipairs(plates) do
|
||
|
Log("\"" .. plate .. "\"")
|
||
|
end
|
||
|
|
||
|
local vehs = GetAllVehicles()
|
||
|
for i, veh in ipairs(vehs) do
|
||
|
local vehPlate = GetVehicleNumberPlateText(veh)
|
||
|
local trimmedVehPlate = string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")
|
||
|
|
||
|
for j, plate in ipairs(plates) do
|
||
|
if (plate == vehPlate or plate == trimmedVehPlate) then
|
||
|
platePositions[plate] = GetEntityCoords(veh)
|
||
|
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
for i, plate in ipairs(plates) do
|
||
|
if (platePositions[plate] == nil) then
|
||
|
for vehPlate, vehData in pairs(vehicles) do
|
||
|
local trimmedVehPlate = string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")
|
||
|
|
||
|
if (plate == vehPlate or plate == trimmedVehPlate) then
|
||
|
platePositions[plate] = vehData.position
|
||
|
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return platePositions
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
|
||
|
RegisterNetEvent('mh_Parking:removeVehicle')
|
||
|
AddEventHandler('mh_Parking:removeVehicle', function(plate)
|
||
|
vehicles[plate] = nil
|
||
|
end)
|
||
|
|
||
|
function CallDB_Vehicles()
|
||
|
DB_vehicles = {}
|
||
|
MySQL.query('SELECT * FROM player_vehicles', {}, function(rs)
|
||
|
for k, v in pairs(rs) do
|
||
|
table.insert(DB_vehicles, v)
|
||
|
end
|
||
|
end) --DB_vehicles
|
||
|
end
|
||
|
|
||
|
function CheckPlate(plate) -- DB_Players
|
||
|
for k, v in pairs(DB_vehicles) do
|
||
|
if Config.isDebug then
|
||
|
Log(json.encode(v))
|
||
|
Log(plate)
|
||
|
Log(v.plate)
|
||
|
end
|
||
|
|
||
|
if v.plate == plate then
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
return false
|
||
|
end
|