forked from Simnation/Main
ed
This commit is contained in:
parent
187f3ee8ff
commit
07aee0f73e
2 changed files with 377 additions and 120 deletions
|
@ -4,6 +4,7 @@ local lastKnownCoords = {}
|
||||||
local garagePending = {} -- Fahrzeuge, die gerade in die Garage gestellt werden
|
local garagePending = {} -- Fahrzeuge, die gerade in die Garage gestellt werden
|
||||||
local spawnedVehicles = {} -- Track recently spawned vehicles to prevent duplication
|
local spawnedVehicles = {} -- Track recently spawned vehicles to prevent duplication
|
||||||
local vehicleOwnership = {} -- Cache vehicle ownership status
|
local vehicleOwnership = {} -- Cache vehicle ownership status
|
||||||
|
local vehicleExistsCallbacks = {} -- Callbacks for vehicle existence checks
|
||||||
|
|
||||||
-- Helper function to count table entries
|
-- Helper function to count table entries
|
||||||
function tableLength(T)
|
function tableLength(T)
|
||||||
|
@ -19,6 +20,44 @@ local function Debug(msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Function to check if a vehicle is a temporary/special vehicle (like police cars, ambulances, etc.)
|
||||||
|
local function IsTemporaryVehicle(vehicle)
|
||||||
|
local plate = QBCore.Functions.GetPlate(vehicle)
|
||||||
|
|
||||||
|
-- Check for common temporary vehicle patterns
|
||||||
|
if not plate or plate == "" then return true end
|
||||||
|
|
||||||
|
-- Some servers use specific patterns for temporary vehicles
|
||||||
|
if string.match(plate, "^TEMP%d%d%d%d%d$") then return true end
|
||||||
|
if string.match(plate, "^[A-Z][A-Z][A-Z][A-Z]%d%d%d$") and GetEntityModel(vehicle) == GetHashKey("police") then return true end
|
||||||
|
|
||||||
|
-- Add more patterns as needed for your server
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Function to check if a vehicle might be a job vehicle
|
||||||
|
local function IsLikelyJobVehicle(vehicle)
|
||||||
|
local model = GetEntityModel(vehicle)
|
||||||
|
|
||||||
|
-- List of common job vehicle models
|
||||||
|
local jobVehicles = {
|
||||||
|
"police", "police2", "police3", "police4",
|
||||||
|
"ambulance", "firetruk",
|
||||||
|
"taxi",
|
||||||
|
"flatbed", "towtruck", "towtruck2",
|
||||||
|
-- Add more as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, jobVehicle in ipairs(jobVehicles) do
|
||||||
|
if model == GetHashKey(jobVehicle) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- Anti-Duplication: Check if a vehicle with this plate already exists in the world
|
-- Anti-Duplication: Check if a vehicle with this plate already exists in the world
|
||||||
local function DoesVehicleExistInWorld(plate)
|
local function DoesVehicleExistInWorld(plate)
|
||||||
local vehicles = GetGamePool('CVehicle')
|
local vehicles = GetGamePool('CVehicle')
|
||||||
|
@ -114,6 +153,28 @@ local function DoesPlayerOwnVehicle(plate)
|
||||||
return isOwned == true
|
return isOwned == true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Function to check if a vehicle exists in the database
|
||||||
|
local function CheckVehicleExists(plate, callback)
|
||||||
|
vehicleExistsCallbacks[plate] = callback
|
||||||
|
TriggerServerEvent('antidespawn:server:checkVehicleExists', plate)
|
||||||
|
|
||||||
|
-- Set a timeout to clean up the callback if no response is received
|
||||||
|
SetTimeout(5000, function()
|
||||||
|
if vehicleExistsCallbacks[plate] then
|
||||||
|
vehicleExistsCallbacks[plate](false) -- Assume it doesn't exist if no response
|
||||||
|
vehicleExistsCallbacks[plate] = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Register the event handler for vehicle existence check
|
||||||
|
RegisterNetEvent('antidespawn:client:vehicleExistsResult', function(exists, plate)
|
||||||
|
if vehicleExistsCallbacks[plate] then
|
||||||
|
vehicleExistsCallbacks[plate](exists)
|
||||||
|
vehicleExistsCallbacks[plate] = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
-- Funktion um zu prüfen ob Fahrzeugklasse erlaubt ist
|
-- Funktion um zu prüfen ob Fahrzeugklasse erlaubt ist
|
||||||
local function IsVehicleClassAllowed(vehicle)
|
local function IsVehicleClassAllowed(vehicle)
|
||||||
local vehicleClass = GetVehicleClass(vehicle)
|
local vehicleClass = GetVehicleClass(vehicle)
|
||||||
|
@ -388,6 +449,24 @@ CreateThread(function()
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Skip temporary vehicles
|
||||||
|
if IsTemporaryVehicle(currentVehicle) then
|
||||||
|
Debug("Skipping temporary vehicle")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skip likely job vehicles
|
||||||
|
if IsLikelyJobVehicle(currentVehicle) then
|
||||||
|
Debug("Skipping likely job vehicle")
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skip recently spawned vehicles
|
||||||
|
if WasVehicleRecentlySpawned(plate) then
|
||||||
|
Debug("Skipping recently spawned vehicle: " .. plate)
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
-- Anti-Duplication: Check if this plate already exists multiple times
|
-- Anti-Duplication: Check if this plate already exists multiple times
|
||||||
if DoesVehicleExistInWorld(plate) then
|
if DoesVehicleExistInWorld(plate) then
|
||||||
Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not tracking")
|
Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not tracking")
|
||||||
|
@ -397,7 +476,7 @@ CreateThread(function()
|
||||||
-- Check if this vehicle is already being tracked
|
-- Check if this vehicle is already being tracked
|
||||||
if not trackedVehicles[plate] and not garagePending[plate] then
|
if not trackedVehicles[plate] and not garagePending[plate] then
|
||||||
-- First verify this vehicle exists in the database
|
-- First verify this vehicle exists in the database
|
||||||
TriggerServerEvent('antidespawn:server:checkVehicleExists', plate, function(exists)
|
CheckVehicleExists(plate, function(exists)
|
||||||
if not exists then
|
if not exists then
|
||||||
Debug("Vehicle not in database, not tracking: " .. plate)
|
Debug("Vehicle not in database, not tracking: " .. plate)
|
||||||
return
|
return
|
||||||
|
@ -492,19 +571,29 @@ CreateThread(function()
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Versuche Fahrzeug wiederherzustellen, aber nur wenn es nicht in die Garage gestellt wird
|
-- Verify this vehicle still exists in the database before respawning
|
||||||
if lastKnownCoords[plate] and not garagePending[plate] then
|
CheckVehicleExists(plate, function(exists)
|
||||||
Debug("Versuche Fahrzeug wiederherzustellen: " .. plate)
|
if not exists then
|
||||||
TriggerServerEvent('antidespawn:server:respawnVehicle', plate)
|
Debug("Vehicle no longer in database, not respawning: " .. plate)
|
||||||
|
trackedVehicles[plate] = nil
|
||||||
|
lastKnownCoords[plate] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Entferne aus lokaler Tracking-Liste, wird nach Respawn wieder hinzugefügt
|
-- Versuche Fahrzeug wiederherzustellen, aber nur wenn es nicht in die Garage gestellt wird
|
||||||
trackedVehicles[plate] = nil
|
if lastKnownCoords[plate] and not garagePending[plate] then
|
||||||
lastKnownCoords[plate] = nil
|
Debug("Versuche Fahrzeug wiederherzustellen: " .. plate)
|
||||||
else
|
TriggerServerEvent('antidespawn:server:respawnVehicle', plate)
|
||||||
-- Entferne aus Tracking
|
|
||||||
trackedVehicles[plate] = nil
|
-- Entferne aus lokaler Tracking-Liste, wird nach Respawn wieder hinzugefügt
|
||||||
lastKnownCoords[plate] = nil
|
trackedVehicles[plate] = nil
|
||||||
end
|
lastKnownCoords[plate] = nil
|
||||||
|
else
|
||||||
|
-- Entferne aus Tracking
|
||||||
|
trackedVehicles[plate] = nil
|
||||||
|
lastKnownCoords[plate] = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
|
@ -548,6 +637,12 @@ end)
|
||||||
RegisterNetEvent('antidespawn:client:spawnVehicle', function(data)
|
RegisterNetEvent('antidespawn:client:spawnVehicle', function(data)
|
||||||
Debug("Spawne Fahrzeug: " .. data.plate)
|
Debug("Spawne Fahrzeug: " .. data.plate)
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not data.plate or data.plate == "" or string.len(data.plate) < 2 then
|
||||||
|
Debug("Skipping spawn of vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Anti-Duplication: Check if vehicle was recently spawned
|
-- Anti-Duplication: Check if vehicle was recently spawned
|
||||||
if WasVehicleRecentlySpawned(data.plate) then
|
if WasVehicleRecentlySpawned(data.plate) then
|
||||||
Debug("Anti-Dupe: Blocking respawn of recently spawned vehicle: " .. data.plate)
|
Debug("Anti-Dupe: Blocking respawn of recently spawned vehicle: " .. data.plate)
|
||||||
|
@ -570,100 +665,107 @@ RegisterNetEvent('antidespawn:client:spawnVehicle', function(data)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Allow spawning of all vehicles, not just owned ones
|
-- Verify this vehicle exists in the database before spawning
|
||||||
-- No ownership check here
|
CheckVehicleExists(data.plate, function(exists)
|
||||||
|
if not exists then
|
||||||
-- Konvertiere Modell zu Hash wenn nötig
|
Debug("Vehicle not in database, not spawning: " .. data.plate)
|
||||||
local modelHash = data.model
|
|
||||||
if type(modelHash) == "string" then
|
|
||||||
-- Versuche den String als Hash zu interpretieren
|
|
||||||
if tonumber(modelHash) then
|
|
||||||
modelHash = tonumber(modelHash)
|
|
||||||
else
|
|
||||||
-- Versuche den String als Modellnamen zu interpretieren
|
|
||||||
modelHash = GetHashKey(modelHash)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Debug("Versuche Modell zu laden: " .. tostring(modelHash))
|
|
||||||
|
|
||||||
-- Prüfe ob Modell existiert
|
|
||||||
if not IsModelInCdimage(modelHash) then
|
|
||||||
Debug("Modell existiert nicht in CD Image: " .. tostring(modelHash))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
RequestModel(modelHash)
|
|
||||||
local timeout = 0
|
|
||||||
while not HasModelLoaded(modelHash) and timeout < 100 do
|
|
||||||
Wait(100)
|
|
||||||
timeout = timeout + 1
|
|
||||||
Debug("Warte auf Modell: " .. tostring(timeout) .. "/100")
|
|
||||||
end
|
|
||||||
|
|
||||||
if HasModelLoaded(modelHash) then
|
|
||||||
Debug("Modell geladen, erstelle Fahrzeug...")
|
|
||||||
|
|
||||||
-- Anti-Duplication: Final check before spawning
|
|
||||||
if GetVehicleByPlate(data.plate) then
|
|
||||||
Debug("Anti-Dupe: Vehicle with plate " .. data.plate .. " appeared during model loading, aborting spawn")
|
|
||||||
SetModelAsNoLongerNeeded(modelHash)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Verwende CREATE_AUTOMOBILE für bessere Persistenz
|
-- Konvertiere Modell zu Hash wenn nötig
|
||||||
local vehicle
|
local modelHash = data.model
|
||||||
|
if type(modelHash) == "string" then
|
||||||
if Citizen and Citizen.InvokeNative then
|
-- Versuche den String als Hash zu interpretieren
|
||||||
-- OneSync Methode
|
if tonumber(modelHash) then
|
||||||
Debug("Verwende OneSync Methode")
|
modelHash = tonumber(modelHash)
|
||||||
vehicle = Citizen.InvokeNative(0xAF35D0D2583051B0, modelHash, data.coords.x, data.coords.y, data.coords.z, data.heading, true, true)
|
else
|
||||||
else
|
-- Versuche den String als Modellnamen zu interpretieren
|
||||||
-- Fallback
|
modelHash = GetHashKey(modelHash)
|
||||||
Debug("Verwende Fallback Methode")
|
end
|
||||||
vehicle = CreateVehicle(modelHash, data.coords.x, data.coords.y, data.coords.z, data.heading, true, false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if DoesEntityExist(vehicle) then
|
Debug("Versuche Modell zu laden: " .. tostring(modelHash))
|
||||||
-- Anti-Duplication: Mark as recently spawned
|
|
||||||
MarkVehicleAsSpawned(data.plate)
|
-- Prüfe ob Modell existiert
|
||||||
|
if not IsModelInCdimage(modelHash) then
|
||||||
-- Warte bis Fahrzeug vollständig geladen ist
|
Debug("Modell existiert nicht in CD Image: " .. tostring(modelHash))
|
||||||
Wait(500)
|
return
|
||||||
|
|
||||||
-- Setze Kennzeichen
|
|
||||||
SetVehicleNumberPlateText(vehicle, data.plate)
|
|
||||||
|
|
||||||
-- Setze Mods
|
|
||||||
if data.mods then
|
|
||||||
Debug("Setze Fahrzeugmods...")
|
|
||||||
SetVehicleMods(vehicle, data.mods)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Setze Fuel
|
|
||||||
if GetResourceState(Config.FuelSystem) == 'started' then
|
|
||||||
exports[Config.FuelSystem]:SetFuel(vehicle, data.fuel or 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Verhindere Despawn
|
|
||||||
PreventDespawn(vehicle)
|
|
||||||
|
|
||||||
-- Füge zu getrackten Fahrzeugen hinzu
|
|
||||||
trackedVehicles[data.plate] = vehicle
|
|
||||||
lastKnownCoords[data.plate] = GetEntityCoords(vehicle)
|
|
||||||
|
|
||||||
-- Registriere beim Server
|
|
||||||
TriggerServerEvent('antidespawn:server:registerVehicle', data.plate, modelHash, GetEntityCoords(vehicle), GetEntityHeading(vehicle), GetVehicleMods(vehicle))
|
|
||||||
|
|
||||||
Debug("Fahrzeug erfolgreich gespawnt: " .. data.plate)
|
|
||||||
else
|
|
||||||
Debug("Fehler beim Spawnen des Fahrzeugs: " .. data.plate)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
SetModelAsNoLongerNeeded(modelHash)
|
RequestModel(modelHash)
|
||||||
else
|
local timeout = 0
|
||||||
Debug("Modell konnte nicht geladen werden: " .. data.plate .. " (Hash: " .. tostring(modelHash) .. ")")
|
while not HasModelLoaded(modelHash) and timeout < 100 do
|
||||||
end
|
Wait(100)
|
||||||
|
timeout = timeout + 1
|
||||||
|
Debug("Warte auf Modell: " .. tostring(timeout) .. "/100")
|
||||||
|
end
|
||||||
|
|
||||||
|
if HasModelLoaded(modelHash) then
|
||||||
|
Debug("Modell geladen, erstelle Fahrzeug...")
|
||||||
|
|
||||||
|
-- Anti-Duplication: Final check before spawning
|
||||||
|
if GetVehicleByPlate(data.plate) then
|
||||||
|
Debug("Anti-Dupe: Vehicle with plate " .. data.plate .. " appeared during model loading, aborting spawn")
|
||||||
|
SetModelAsNoLongerNeeded(modelHash)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Verwende CREATE_AUTOMOBILE für bessere Persistenz
|
||||||
|
local vehicle
|
||||||
|
|
||||||
|
if Citizen and Citizen.InvokeNative then
|
||||||
|
-- OneSync Methode
|
||||||
|
Debug("Verwende OneSync Methode")
|
||||||
|
vehicle = Citizen.InvokeNative(0xAF35D0D2583051B0, modelHash, data.coords.x, data.coords.y, data.coords.z, data.heading, true, true)
|
||||||
|
else
|
||||||
|
-- Fallback
|
||||||
|
Debug("Verwende Fallback Methode")
|
||||||
|
vehicle = CreateVehicle(modelHash, data.coords.x, data.coords.y, data.coords.z, data.heading, true, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
if DoesEntityExist(vehicle) then
|
||||||
|
-- Anti-Duplication: Mark as recently spawned
|
||||||
|
MarkVehicleAsSpawned(data.plate)
|
||||||
|
|
||||||
|
-- Warte bis Fahrzeug vollständig geladen ist
|
||||||
|
Wait(500)
|
||||||
|
|
||||||
|
-- Setze Kennzeichen
|
||||||
|
SetVehicleNumberPlateText(vehicle, data.plate)
|
||||||
|
|
||||||
|
-- Setze Mods
|
||||||
|
if data.mods then
|
||||||
|
Debug("Setze Fahrzeugmods...")
|
||||||
|
SetVehicleMods(vehicle, data.mods)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setze Fuel
|
||||||
|
if GetResourceState(Config.FuelSystem) == 'started' then
|
||||||
|
exports[Config.FuelSystem]:SetFuel(vehicle, data.fuel or 100)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Verhindere Despawn
|
||||||
|
PreventDespawn(vehicle)
|
||||||
|
|
||||||
|
-- Füge zu getrackten Fahrzeugen hinzu
|
||||||
|
trackedVehicles[data.plate] = vehicle
|
||||||
|
lastKnownCoords[data.plate] = GetEntityCoords(vehicle)
|
||||||
|
|
||||||
|
-- Registriere beim Server
|
||||||
|
TriggerServerEvent('antidespawn:server:registerVehicle', data.plate, modelHash, GetEntityCoords(vehicle), GetEntityHeading(vehicle), GetVehicleMods(vehicle))
|
||||||
|
|
||||||
|
Debug("Fahrzeug erfolgreich gespawnt: " .. data.plate)
|
||||||
|
else
|
||||||
|
Debug("Fehler beim Spawnen des Fahrzeugs: " .. data.plate)
|
||||||
|
end
|
||||||
|
|
||||||
|
SetModelAsNoLongerNeeded(modelHash)
|
||||||
|
else
|
||||||
|
Debug("Modell konnte nicht geladen werden: " ..
|
||||||
|
else
|
||||||
|
Debug("Modell konnte nicht geladen werden: " .. data.plate .. " (Hash: " .. tostring(modelHash) .. ")")
|
||||||
|
end
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Event für Garage Store (wird ausgelöst, wenn der Spieler ein Fahrzeug in die Garage stellen will)
|
-- Event für Garage Store (wird ausgelöst, wenn der Spieler ein Fahrzeug in die Garage stellen will)
|
||||||
|
@ -674,6 +776,12 @@ RegisterNetEvent('jg-advancedgarages:client:store-vehicle', function(garageId, g
|
||||||
if vehicle ~= 0 then
|
if vehicle ~= 0 then
|
||||||
local plate = QBCore.Functions.GetPlate(vehicle)
|
local plate = QBCore.Functions.GetPlate(vehicle)
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Skipping garage storage for vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Markiere Fahrzeug als "wird in Garage gestellt"
|
-- Markiere Fahrzeug als "wird in Garage gestellt"
|
||||||
garagePending[plate] = true
|
garagePending[plate] = true
|
||||||
SetTimeout(10000, function()
|
SetTimeout(10000, function()
|
||||||
|
@ -695,6 +803,12 @@ end)
|
||||||
-- jg-advanced-garage Events
|
-- jg-advanced-garage Events
|
||||||
RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data)
|
RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data)
|
||||||
if data and data.plate then
|
if data and data.plate then
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not data.plate or data.plate == "" or string.len(data.plate) < 2 then
|
||||||
|
Debug("Skipping garage storage completion for vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Markiere Fahrzeug als "in Garage"
|
-- Markiere Fahrzeug als "in Garage"
|
||||||
garagePending[data.plate] = nil
|
garagePending[data.plate] = nil
|
||||||
|
|
||||||
|
@ -713,6 +827,12 @@ end)
|
||||||
|
|
||||||
RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data)
|
RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data)
|
||||||
if data and data.plate then
|
if data and data.plate then
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not data.plate or data.plate == "" or string.len(data.plate) < 2 then
|
||||||
|
Debug("Skipping garage spawn completion for vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Entferne Markierung "in Garage"
|
-- Entferne Markierung "in Garage"
|
||||||
garagePending[data.plate] = nil
|
garagePending[data.plate] = nil
|
||||||
|
|
||||||
|
@ -758,6 +878,24 @@ RegisterCommand('fixvehicle', function()
|
||||||
if vehicle ~= 0 then
|
if vehicle ~= 0 then
|
||||||
local plate = QBCore.Functions.GetPlate(vehicle)
|
local plate = QBCore.Functions.GetPlate(vehicle)
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Cannot fix vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skip temporary vehicles
|
||||||
|
if IsTemporaryVehicle(vehicle) then
|
||||||
|
Debug("Cannot fix temporary vehicle")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skip likely job vehicles
|
||||||
|
if IsLikelyJobVehicle(vehicle) then
|
||||||
|
Debug("Cannot fix likely job vehicle")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Anti-Duplication: Check if this plate already exists multiple times
|
-- Anti-Duplication: Check if this plate already exists multiple times
|
||||||
if DoesVehicleExistInWorld(plate) then
|
if DoesVehicleExistInWorld(plate) then
|
||||||
Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not fixing")
|
Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not fixing")
|
||||||
|
@ -766,20 +904,27 @@ RegisterCommand('fixvehicle', function()
|
||||||
|
|
||||||
-- Prüfe ob Fahrzeug gerade in die Garage gestellt wird
|
-- Prüfe ob Fahrzeug gerade in die Garage gestellt wird
|
||||||
if not garagePending[plate] then
|
if not garagePending[plate] then
|
||||||
-- Track all vehicles, regardless of ownership
|
-- Verify this vehicle exists in the database
|
||||||
PreventDespawn(vehicle)
|
CheckVehicleExists(plate, function(exists)
|
||||||
trackedVehicles[plate] = vehicle
|
if not exists then
|
||||||
lastKnownCoords[plate] = GetEntityCoords(vehicle)
|
Debug("Vehicle not in database, cannot fix: " .. plate)
|
||||||
|
return
|
||||||
-- Registriere Fahrzeug beim Server
|
end
|
||||||
local vehicleCoords = GetEntityCoords(vehicle)
|
|
||||||
local vehicleHeading = GetEntityHeading(vehicle)
|
PreventDespawn(vehicle)
|
||||||
local vehicleModel = GetEntityModel(vehicle)
|
trackedVehicles[plate] = vehicle
|
||||||
local vehicleMods = GetVehicleMods(vehicle)
|
lastKnownCoords[plate] = GetEntityCoords(vehicle)
|
||||||
|
|
||||||
TriggerServerEvent('antidespawn:server:registerVehicle', plate, vehicleModel, vehicleCoords, vehicleHeading, vehicleMods)
|
-- Registriere Fahrzeug beim Server
|
||||||
|
local vehicleCoords = GetEntityCoords(vehicle)
|
||||||
Debug("Anti-Despawn für Fahrzeug aktiviert: " .. plate)
|
local vehicleHeading = GetEntityHeading(vehicle)
|
||||||
|
local vehicleModel = GetEntityModel(vehicle)
|
||||||
|
local vehicleMods = GetVehicleMods(vehicle)
|
||||||
|
|
||||||
|
TriggerServerEvent('antidespawn:server:registerVehicle', plate, vehicleModel, vehicleCoords, vehicleHeading, vehicleMods)
|
||||||
|
|
||||||
|
Debug("Anti-Despawn für Fahrzeug aktiviert: " .. plate)
|
||||||
|
end)
|
||||||
else
|
else
|
||||||
Debug("Fahrzeug wird gerade in Garage gestellt, kann nicht fixiert werden: " .. plate)
|
Debug("Fahrzeug wird gerade in Garage gestellt, kann nicht fixiert werden: " .. plate)
|
||||||
end
|
end
|
||||||
|
@ -802,6 +947,7 @@ AddEventHandler('onResourceStop', function(resourceName)
|
||||||
garagePending = {}
|
garagePending = {}
|
||||||
spawnedVehicles = {}
|
spawnedVehicles = {}
|
||||||
vehicleOwnership = {}
|
vehicleOwnership = {}
|
||||||
|
vehicleExistsCallbacks = {}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -813,14 +959,16 @@ RegisterCommand('checkdupes', function()
|
||||||
|
|
||||||
for _, vehicle in pairs(vehicles) do
|
for _, vehicle in pairs(vehicles) do
|
||||||
local plate = QBCore.Functions.GetPlate(vehicle)
|
local plate = QBCore.Functions.GetPlate(vehicle)
|
||||||
if plates[plate] then
|
if plate and plate ~= "" then
|
||||||
if not dupes[plate] then
|
if plates[plate] then
|
||||||
dupes[plate] = 2
|
if not dupes[plate] then
|
||||||
|
dupes[plate] = 2
|
||||||
|
else
|
||||||
|
dupes[plate] = dupes[plate] + 1
|
||||||
|
end
|
||||||
else
|
else
|
||||||
dupes[plate] = dupes[plate] + 1
|
plates[plate] = true
|
||||||
end
|
end
|
||||||
else
|
|
||||||
plates[plate] = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -849,3 +997,35 @@ RegisterCommand('clearownership', function()
|
||||||
Debug("Cleared vehicle ownership cache")
|
Debug("Cleared vehicle ownership cache")
|
||||||
end, false)
|
end, false)
|
||||||
|
|
||||||
|
-- Debug command to list all tracked vehicles
|
||||||
|
RegisterCommand('listtracked', function()
|
||||||
|
local count = 0
|
||||||
|
Debug("Currently tracked vehicles:")
|
||||||
|
for plate, _ in pairs(trackedVehicles) do
|
||||||
|
Debug("- " .. plate)
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
Debug("Total tracked vehicles: " .. count)
|
||||||
|
end, false)
|
||||||
|
|
||||||
|
-- Debug command to delete duplicate vehicles
|
||||||
|
RegisterCommand('deletedupes', function()
|
||||||
|
local vehicles = GetGamePool('CVehicle')
|
||||||
|
local plates = {}
|
||||||
|
local deleted = 0
|
||||||
|
|
||||||
|
for _, vehicle in pairs(vehicles) do
|
||||||
|
local plate = QBCore.Functions.GetPlate(vehicle)
|
||||||
|
if plate and plate ~= "" then
|
||||||
|
if plates[plate] then
|
||||||
|
DeleteEntity(vehicle)
|
||||||
|
deleted = deleted + 1
|
||||||
|
Debug("Deleted duplicate vehicle with plate: " .. plate)
|
||||||
|
else
|
||||||
|
plates[plate] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Debug("Deleted " .. deleted .. " duplicate vehicles")
|
||||||
|
end, false)
|
||||||
|
|
|
@ -77,6 +77,22 @@ CreateThread(function()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Check if a vehicle exists in the database
|
||||||
|
RegisterNetEvent('antidespawn:server:checkVehicleExists', function(plate)
|
||||||
|
local src = source
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
TriggerClientEvent('antidespawn:client:vehicleExistsResult', src, false, plate)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
||||||
|
local exists = result and #result > 0
|
||||||
|
TriggerClientEvent('antidespawn:client:vehicleExistsResult', src, exists, plate)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
-- Check if a player owns a vehicle
|
-- Check if a player owns a vehicle
|
||||||
RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate)
|
RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate)
|
||||||
local src = source
|
local src = source
|
||||||
|
@ -87,6 +103,12 @@ RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, false, plate)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?', {plate, Player.PlayerData.citizenid}, function(result)
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?', {plate, Player.PlayerData.citizenid}, function(result)
|
||||||
local isOwned = result and #result > 0
|
local isOwned = result and #result > 0
|
||||||
TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, isOwned, plate)
|
TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, isOwned, plate)
|
||||||
|
@ -100,6 +122,12 @@ RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, co
|
||||||
|
|
||||||
if not Player then return end
|
if not Player then return end
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Skipping vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Check if vehicle exists in player_vehicles (any player)
|
-- Check if vehicle exists in player_vehicles (any player)
|
||||||
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
||||||
if not result or #result == 0 then
|
if not result or #result == 0 then
|
||||||
|
@ -163,10 +191,19 @@ RegisterNetEvent('antidespawn:server:updateVehicle', function(plate, coords, hea
|
||||||
if not Player then return end
|
if not Player then return end
|
||||||
if not vehicles[plate] then return end
|
if not vehicles[plate] then return end
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Skipping update for vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Check if vehicle exists in player_vehicles (any player)
|
-- Check if vehicle exists in player_vehicles (any player)
|
||||||
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
||||||
if not result or #result == 0 then
|
if not result or #result == 0 then
|
||||||
Debug("Vehicle not found in database: " .. plate)
|
Debug("Vehicle not found in database: " .. plate)
|
||||||
|
-- Remove from tracking as it no longer exists in the database
|
||||||
|
vehicles[plate] = nil
|
||||||
|
MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -210,6 +247,12 @@ RegisterNetEvent('antidespawn:server:removeVehicle', function(plate)
|
||||||
local src = source
|
local src = source
|
||||||
if not vehicles[plate] then return end
|
if not vehicles[plate] then return end
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Skipping removal for vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
vehicles[plate] = nil
|
vehicles[plate] = nil
|
||||||
|
|
||||||
MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {
|
MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {
|
||||||
|
@ -226,6 +269,12 @@ RegisterNetEvent('antidespawn:server:respawnVehicle', function(plate)
|
||||||
|
|
||||||
if not Player then return end
|
if not Player then return end
|
||||||
|
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Skipping respawn for vehicle with invalid plate")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Anti-Duplication: Check if there's already an active spawn request for this plate
|
-- Anti-Duplication: Check if there's already an active spawn request for this plate
|
||||||
if activeSpawns[plate] then
|
if activeSpawns[plate] then
|
||||||
Debug("Anti-Dupe: Already processing spawn request for: " .. plate)
|
Debug("Anti-Dupe: Already processing spawn request for: " .. plate)
|
||||||
|
@ -305,6 +354,14 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function()
|
||||||
|
|
||||||
-- Load all vehicles in the database, not just owned ones
|
-- Load all vehicles in the database, not just owned ones
|
||||||
for plate, vehicle in pairs(vehicles) do
|
for plate, vehicle in pairs(vehicles) do
|
||||||
|
-- Skip vehicles with empty or invalid plates
|
||||||
|
if not plate or plate == "" or string.len(plate) < 2 then
|
||||||
|
Debug("Skipping load for vehicle with invalid plate")
|
||||||
|
vehicles[plate] = nil
|
||||||
|
MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate})
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
-- Check if vehicle is in garage by querying the database
|
-- Check if vehicle is in garage by querying the database
|
||||||
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
||||||
if not result or #result == 0 then
|
if not result or #result == 0 then
|
||||||
|
@ -354,6 +411,7 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function()
|
||||||
loadedCount = loadedCount + 1
|
loadedCount = loadedCount + 1
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Warte kurz und lade dann die Fahrzeuge
|
-- Warte kurz und lade dann die Fahrzeuge
|
||||||
|
@ -379,6 +437,7 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
-- Cleanup alte Einträge (älter als 24 Stunden)
|
-- Cleanup alte Einträge (älter als 24 Stunden)
|
||||||
CreateThread(function()
|
CreateThread(function()
|
||||||
while true do
|
while true do
|
||||||
|
@ -511,6 +570,24 @@ RegisterCommand('activespawns', function(source, args, rawCommand)
|
||||||
end
|
end
|
||||||
end, true)
|
end, true)
|
||||||
|
|
||||||
|
-- Check if a vehicle exists in the database
|
||||||
|
RegisterNetEvent('antidespawn:server:checkVehicleExists', function(plate, callback)
|
||||||
|
local src = source
|
||||||
|
|
||||||
|
MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result)
|
||||||
|
local exists = result and #result > 0
|
||||||
|
TriggerClientEvent('antidespawn:client:vehicleExistsResult', src, exists, plate)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Client callback for vehicle existence check
|
||||||
|
RegisterNetEvent('antidespawn:client:vehicleExistsResult', function(exists, plate)
|
||||||
|
-- This event will be handled by the callback system
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Clean up when resource stops
|
-- Clean up when resource stops
|
||||||
AddEventHandler('onResourceStop', function(resourceName)
|
AddEventHandler('onResourceStop', function(resourceName)
|
||||||
if resourceName == GetCurrentResourceName() then
|
if resourceName == GetCurrentResourceName() then
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue