1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-08-07 14:00:58 +02:00
parent 187f3ee8ff
commit 07aee0f73e
2 changed files with 377 additions and 120 deletions

View file

@ -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)

View file

@ -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