ed
This commit is contained in:
		
							parent
							
								
									b1ab09bb49
								
							
						
					
					
						commit
						950ae04a0f
					
				
					 2 changed files with 469 additions and 264 deletions
				
			
		|  | @ -2,6 +2,8 @@ local QBCore = exports['qb-core']:GetCoreObject() | |||
| local trackedVehicles = {} | ||||
| local lastKnownCoords = {} | ||||
| local garagePending = {} -- Fahrzeuge, die gerade in die Garage gestellt werden | ||||
| local spawnedVehicles = {} -- Track recently spawned vehicles to prevent duplication | ||||
| local vehicleOwnership = {} -- Cache vehicle ownership status | ||||
|  | ||||
| -- Helper function to count table entries | ||||
| function tableLength(T) | ||||
|  | @ -17,40 +19,67 @@ local function Debug(msg) | |||
|     end | ||||
| end | ||||
|  | ||||
| -- Extrem starke Anti-Despawn Funktion | ||||
| -- IMPORTANT: Move this function definition to the top, before it's called | ||||
| local function PreventDespawn(vehicle) | ||||
|     if not DoesEntityExist(vehicle) then return false end | ||||
| -- Anti-Duplication: Check if a vehicle with this plate already exists in the world | ||||
| local function DoesVehicleExistInWorld(plate) | ||||
|     local vehicles = GetGamePool('CVehicle') | ||||
|     local count = 0 | ||||
|      | ||||
|     -- Grundlegende Persistenz | ||||
|     SetEntityAsMissionEntity(vehicle, true, true) | ||||
|     SetVehicleHasBeenOwnedByPlayer(vehicle, true) | ||||
|     SetVehicleNeedsToBeHotwired(vehicle, false) | ||||
|      | ||||
|     -- Zusätzliche Flags | ||||
|     SetEntityLoadCollisionFlag(vehicle, true) | ||||
|     SetVehicleIsStolen(vehicle, false) | ||||
|     SetVehicleIsWanted(vehicle, false) | ||||
|      | ||||
|     -- Verhindere dass das Fahrzeug als "abandoned" markiert wird | ||||
|     if DecorIsRegisteredAsType("IgnoredByQuickSave", 2) then | ||||
|         DecorSetBool(vehicle, "IgnoredByQuickSave", false) | ||||
|     for _, vehicle in pairs(vehicles) do | ||||
|         local vehPlate = QBCore.Functions.GetPlate(vehicle) | ||||
|         if vehPlate == plate then | ||||
|             count = count + 1 | ||||
|             if count > 1 then | ||||
|                 -- More than one vehicle with this plate exists! | ||||
|                 Debug("DUPLICATION DETECTED: Multiple vehicles with plate " .. plate .. " exist!") | ||||
|                 return true | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|      | ||||
|     -- Setze Fahrzeug auf Boden | ||||
|     SetVehicleOnGroundProperly(vehicle) | ||||
|      | ||||
|     -- Verhindere dass das Fahrzeug gelöscht wird | ||||
|     NetworkRegisterEntityAsNetworked(vehicle) | ||||
|     local netID = NetworkGetNetworkIdFromEntity(vehicle) | ||||
|     SetNetworkIdExistsOnAllMachines(netID, true) | ||||
|     SetNetworkIdCanMigrate(netID, true) | ||||
|      | ||||
|     return true | ||||
|     return false | ||||
| end | ||||
|  | ||||
| -- Function to check if player owns the vehicle | ||||
| -- Anti-Duplication: Check if vehicle was recently spawned | ||||
| local function WasVehicleRecentlySpawned(plate) | ||||
|     if spawnedVehicles[plate] then | ||||
|         local timeSinceSpawn = GetGameTimer() - spawnedVehicles[plate] | ||||
|         if timeSinceSpawn < 60000 then -- 60 seconds cooldown | ||||
|             Debug("Anti-Dupe: Vehicle " .. plate .. " was recently spawned (" .. math.floor(timeSinceSpawn/1000) .. " seconds ago)") | ||||
|             return true | ||||
|         else | ||||
|             -- Reset the timer if it's been more than 60 seconds | ||||
|             spawnedVehicles[plate] = nil | ||||
|         end | ||||
|     end | ||||
|     return false | ||||
| end | ||||
|  | ||||
| -- Anti-Duplication: Mark vehicle as recently spawned | ||||
| local function MarkVehicleAsSpawned(plate) | ||||
|     spawnedVehicles[plate] = GetGameTimer() | ||||
|     Debug("Anti-Dupe: Marked vehicle " .. plate .. " as recently spawned") | ||||
|      | ||||
|     -- Clean up old entries every 5 minutes | ||||
|     SetTimeout(300000, function() | ||||
|         for p, time in pairs(spawnedVehicles) do | ||||
|             if GetGameTimer() - time > 300000 then -- 5 minutes | ||||
|                 spawnedVehicles[p] = nil | ||||
|             end | ||||
|         end | ||||
|     end) | ||||
| end | ||||
|  | ||||
| -- Function to check if player owns the vehicle with caching | ||||
| local function DoesPlayerOwnVehicle(plate) | ||||
|     -- Check cache first | ||||
|     if vehicleOwnership[plate] ~= nil then | ||||
|         -- Cache expires after 5 minutes | ||||
|         local timeSinceCheck = GetGameTimer() - vehicleOwnership[plate].timestamp | ||||
|         if timeSinceCheck < 300000 then -- 5 minutes | ||||
|             return vehicleOwnership[plate].owned | ||||
|         end | ||||
|     end | ||||
|      | ||||
|     local playerData = QBCore.Functions.GetPlayerData() | ||||
|     if not playerData then return false end | ||||
|      | ||||
|  | @ -61,10 +90,14 @@ local function DoesPlayerOwnVehicle(plate) | |||
|     TriggerServerEvent('antidespawn:server:checkVehicleOwnership', plate) | ||||
|      | ||||
|     -- Register one-time event handler for the response | ||||
|     RegisterNetEvent('antidespawn:client:vehicleOwnershipResult') | ||||
|     local eventHandler = AddEventHandler('antidespawn:client:vehicleOwnershipResult', function(result, checkPlate) | ||||
|         if plate == checkPlate then | ||||
|             isOwned = result | ||||
|             -- Cache the result | ||||
|             vehicleOwnership[plate] = { | ||||
|                 owned = result, | ||||
|                 timestamp = GetGameTimer() | ||||
|             } | ||||
|         end | ||||
|     end) | ||||
|      | ||||
|  | @ -102,6 +135,37 @@ local function IsVehicleClassAllowed(vehicle) | |||
|     return false | ||||
| end | ||||
|  | ||||
| -- Extrem starke Anti-Despawn Funktion | ||||
| local function PreventDespawn(vehicle) | ||||
|     if not DoesEntityExist(vehicle) then return false end | ||||
|      | ||||
|     -- Grundlegende Persistenz | ||||
|     SetEntityAsMissionEntity(vehicle, true, true) | ||||
|     SetVehicleHasBeenOwnedByPlayer(vehicle, true) | ||||
|     SetVehicleNeedsToBeHotwired(vehicle, false) | ||||
|      | ||||
|     -- Zusätzliche Flags | ||||
|     SetEntityLoadCollisionFlag(vehicle, true) | ||||
|     SetVehicleIsStolen(vehicle, false) | ||||
|     SetVehicleIsWanted(vehicle, false) | ||||
|      | ||||
|     -- Verhindere dass das Fahrzeug als "abandoned" markiert wird | ||||
|     if DecorIsRegisteredAsType("IgnoredByQuickSave", 2) then | ||||
|         DecorSetBool(vehicle, "IgnoredByQuickSave", false) | ||||
|     end | ||||
|      | ||||
|     -- Setze Fahrzeug auf Boden | ||||
|     SetVehicleOnGroundProperly(vehicle) | ||||
|      | ||||
|     -- Verhindere dass das Fahrzeug gelöscht wird | ||||
|     NetworkRegisterEntityAsNetworked(vehicle) | ||||
|     local netID = NetworkGetNetworkIdFromEntity(vehicle) | ||||
|     SetNetworkIdExistsOnAllMachines(netID, true) | ||||
|     SetNetworkIdCanMigrate(netID, true) | ||||
|      | ||||
|     return true | ||||
| end | ||||
|  | ||||
| -- Funktion um Fahrzeugmods zu erhalten | ||||
| local function GetVehicleMods(vehicle) | ||||
|     local mods = {} | ||||
|  | @ -301,8 +365,6 @@ function GetVehicleByPlate(plate) | |||
|     return nil | ||||
| end | ||||
|  | ||||
| -- AFTER ALL FUNCTIONS ARE DEFINED, THEN ADD EVENT HANDLERS AND THREADS | ||||
|  | ||||
| -- Event Handler für Fahrzeug betreten (nur Fahrersitz) | ||||
| CreateThread(function() | ||||
|     while true do | ||||
|  | @ -320,6 +382,14 @@ CreateThread(function() | |||
|             if driver == playerPed and IsVehicleClassAllowed(currentVehicle) then | ||||
|                 local plate = QBCore.Functions.GetPlate(currentVehicle) | ||||
|                  | ||||
|                 -- Anti-Duplication: Check if this plate already exists multiple times | ||||
|                 if DoesVehicleExistInWorld(plate) then | ||||
|                     Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not tracking") | ||||
|                     -- Optionally, you could delete the duplicate here | ||||
|                     -- DeleteEntity(currentVehicle) | ||||
|                     goto continue | ||||
|                 end | ||||
|                  | ||||
|                 -- Check if this vehicle is already being tracked | ||||
|                 if not trackedVehicles[plate] and not garagePending[plate] then | ||||
|                     -- Check if player owns this vehicle | ||||
|  | @ -328,7 +398,6 @@ CreateThread(function() | |||
|                         local maxTrackedVehicles = 100 -- Adjust as needed | ||||
|                         if tableLength(trackedVehicles) >= maxTrackedVehicles then | ||||
|                             Debug("Maximum number of tracked vehicles reached") | ||||
|                             -- You could implement logic to remove the oldest vehicle here | ||||
|                         else | ||||
|                             trackedVehicles[plate] = currentVehicle | ||||
|                              | ||||
|  | @ -356,12 +425,10 @@ CreateThread(function() | |||
|                 end | ||||
|             end | ||||
|         end | ||||
|         ::continue:: | ||||
|     end | ||||
| end) | ||||
|  | ||||
| -- Rest of your code (threads, event handlers, etc.) | ||||
|  | ||||
|  | ||||
| -- Kontinuierliche Despawn-Verhinderung für alle getrackten Fahrzeuge | ||||
| CreateThread(function() | ||||
|     while true do | ||||
|  | @ -371,6 +438,15 @@ CreateThread(function() | |||
|         local playerPos = GetEntityCoords(playerPed) | ||||
|          | ||||
|         for plate, vehicle in pairs(trackedVehicles) do | ||||
|             -- Anti-Duplication: Check if multiple vehicles with this plate exist | ||||
|             if DoesVehicleExistInWorld(plate) then | ||||
|                 Debug("Anti-Dupe: Detected duplicate during tracking for plate " .. plate .. ", removing from tracking") | ||||
|                 trackedVehicles[plate] = nil | ||||
|                 lastKnownCoords[plate] = nil | ||||
|                 TriggerServerEvent('antidespawn:server:removeVehicle', plate) | ||||
|                 goto continue | ||||
|             end | ||||
|              | ||||
|             -- Prüfe ob Fahrzeug gerade in die Garage gestellt wird | ||||
|             if garagePending[plate] then | ||||
|                 Debug("Fahrzeug wird gerade in Garage gestellt, entferne aus Tracking: " .. plate) | ||||
|  | @ -406,6 +482,14 @@ CreateThread(function() | |||
|             else | ||||
|                 Debug("Fahrzeug existiert nicht mehr: " .. plate) | ||||
|                  | ||||
|                 -- Anti-Duplication: Check if vehicle was recently spawned before respawning | ||||
|                 if WasVehicleRecentlySpawned(plate) then | ||||
|                     Debug("Anti-Dupe: Not respawning recently spawned vehicle: " .. plate) | ||||
|                     trackedVehicles[plate] = nil | ||||
|                     lastKnownCoords[plate] = nil | ||||
|                     goto continue | ||||
|                 end | ||||
|                  | ||||
|                 -- Versuche Fahrzeug wiederherzustellen, aber nur wenn es nicht in die Garage gestellt wird | ||||
|                 if lastKnownCoords[plate] and not garagePending[plate] then | ||||
|                     Debug("Versuche Fahrzeug wiederherzustellen: " .. plate) | ||||
|  | @ -420,6 +504,7 @@ CreateThread(function() | |||
|                     lastKnownCoords[plate] = nil | ||||
|                 end | ||||
|             end | ||||
|             ::continue:: | ||||
|         end | ||||
|     end | ||||
| end) | ||||
|  | @ -461,6 +546,12 @@ end) | |||
| RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) | ||||
|     Debug("Spawne Fahrzeug: " .. data.plate) | ||||
|      | ||||
|     -- Anti-Duplication: Check if vehicle was recently spawned | ||||
|     if WasVehicleRecentlySpawned(data.plate) then | ||||
|         Debug("Anti-Dupe: Blocking respawn of recently spawned vehicle: " .. data.plate) | ||||
|         return | ||||
|     end | ||||
|      | ||||
|     -- Prüfe ob Fahrzeug bereits existiert | ||||
|     local existingVehicle = GetVehicleByPlate(data.plate) | ||||
|     if existingVehicle then | ||||
|  | @ -477,6 +568,12 @@ RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) | |||
|         return | ||||
|     end | ||||
|      | ||||
|     -- Anti-Duplication: Check if player owns this vehicle | ||||
|     if not DoesPlayerOwnVehicle(data.plate) then | ||||
|         Debug("Anti-Dupe: Player does not own vehicle, not spawning: " .. data.plate) | ||||
|         return | ||||
|     end | ||||
|      | ||||
|     -- Konvertiere Modell zu Hash wenn nötig | ||||
|     local modelHash = data.model | ||||
|     if type(modelHash) == "string" then | ||||
|  | @ -508,6 +605,13 @@ RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) | |||
|     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 | ||||
|          | ||||
|  | @ -522,6 +626,9 @@ RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) | |||
|         end | ||||
|          | ||||
|         if DoesEntityExist(vehicle) then | ||||
|             -- Anti-Duplication: Mark as recently spawned | ||||
|             MarkVehicleAsSpawned(data.plate) | ||||
|              | ||||
|             -- Warte bis Fahrzeug vollständig geladen ist | ||||
|             Wait(500) | ||||
|              | ||||
|  | @ -560,17 +667,6 @@ RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) | |||
|     end | ||||
| end) | ||||
|  | ||||
| -- Hilfsfunktion um Fahrzeug anhand Kennzeichen zu finden | ||||
| function GetVehicleByPlate(plate) | ||||
|     local vehicles = GetGamePool('CVehicle') | ||||
|     for _, vehicle in pairs(vehicles) do | ||||
|         if QBCore.Functions.GetPlate(vehicle) == plate then | ||||
|             return vehicle | ||||
|         end | ||||
|     end | ||||
|     return nil | ||||
| end | ||||
|  | ||||
| -- Event für Garage Store (wird ausgelöst, wenn der Spieler ein Fahrzeug in die Garage stellen will) | ||||
| RegisterNetEvent('jg-advancedgarages:client:store-vehicle', function(garageId, garageVehicleType) | ||||
|     local playerPed = PlayerPedId() | ||||
|  | @ -663,21 +759,32 @@ RegisterCommand('fixvehicle', function() | |||
|     if vehicle ~= 0 then | ||||
|         local plate = QBCore.Functions.GetPlate(vehicle) | ||||
|          | ||||
|         -- Anti-Duplication: Check if this plate already exists multiple times | ||||
|         if DoesVehicleExistInWorld(plate) then | ||||
|             Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not fixing") | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Prüfe ob Fahrzeug gerade in die Garage gestellt wird | ||||
|         if not garagePending[plate] then | ||||
|             PreventDespawn(vehicle) | ||||
|             trackedVehicles[plate] = vehicle | ||||
|             lastKnownCoords[plate] = GetEntityCoords(vehicle) | ||||
|              | ||||
|             -- Registriere Fahrzeug beim Server | ||||
|             local vehicleCoords = GetEntityCoords(vehicle) | ||||
|             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) | ||||
|             -- Check if player owns this vehicle | ||||
|             if DoesPlayerOwnVehicle(plate) then | ||||
|                 PreventDespawn(vehicle) | ||||
|                 trackedVehicles[plate] = vehicle | ||||
|                 lastKnownCoords[plate] = GetEntityCoords(vehicle) | ||||
|                  | ||||
|                 -- Registriere Fahrzeug beim Server | ||||
|                 local vehicleCoords = GetEntityCoords(vehicle) | ||||
|                 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) | ||||
|             else | ||||
|                 Debug("Fahrzeug gehört nicht dem Spieler, kann nicht fixiert werden: " .. plate) | ||||
|             end | ||||
|         else | ||||
|             Debug("Fahrzeug wird gerade in Garage gestellt, kann nicht fixiert werden: " .. plate) | ||||
|         end | ||||
|  | @ -686,11 +793,66 @@ RegisterCommand('fixvehicle', function() | |||
|     end | ||||
| end, false) | ||||
|  | ||||
| -- Server-side event handler for ownership verification | ||||
| RegisterNetEvent('antidespawn:client:vehicleOwnershipResult', function(result, plate) | ||||
|     -- This event is handled by the DoesPlayerOwnVehicle function | ||||
| end) | ||||
|  | ||||
| -- Clean up resources when script stops | ||||
| AddEventHandler('onResourceStop', function(resourceName) | ||||
|     if resourceName == GetCurrentResourceName() then | ||||
|         Debug("Resource stopping, clearing all data") | ||||
|         trackedVehicles = {} | ||||
|         lastKnownCoords = {} | ||||
|         garagePending = {} | ||||
|         spawnedVehicles = {} | ||||
|         vehicleOwnership = {} | ||||
|     end | ||||
| end) | ||||
|  | ||||
| -- Debug command to check vehicle duplication | ||||
| RegisterCommand('checkdupes', function() | ||||
|     local vehicles = GetGamePool('CVehicle') | ||||
|     local plates = {} | ||||
|     local dupes = {} | ||||
|      | ||||
|     for _, vehicle in pairs(vehicles) do | ||||
|         local plate = QBCore.Functions.GetPlate(vehicle) | ||||
|         if plates[plate] then | ||||
|             if not dupes[plate] then | ||||
|                 dupes[plate] = 2 | ||||
|             else | ||||
|                 dupes[plate] = dupes[plate] + 1 | ||||
|             end | ||||
|         else | ||||
|             plates[plate] = true | ||||
|         end | ||||
|     end | ||||
|      | ||||
|     local dupeCount = 0 | ||||
|     for plate, count in pairs(dupes) do | ||||
|         Debug("Duplicate found: " .. plate .. " (Count: " .. count .. ")") | ||||
|         dupeCount = dupeCount + 1 | ||||
|     end | ||||
|      | ||||
|     if dupeCount == 0 then | ||||
|         Debug("No duplicate vehicles found") | ||||
|     else | ||||
|         Debug("Found " .. dupeCount .. " duplicate vehicles") | ||||
|     end | ||||
| end, false) | ||||
|  | ||||
| -- Debug command to clear recently spawned vehicles list | ||||
| RegisterCommand('clearspawned', function() | ||||
|     spawnedVehicles = {} | ||||
|     Debug("Cleared recently spawned vehicles list") | ||||
| end, false) | ||||
|  | ||||
| -- Debug command to clear ownership cache | ||||
| RegisterCommand('clearownership', function() | ||||
|     vehicleOwnership = {} | ||||
|     Debug("Cleared vehicle ownership cache") | ||||
| end, false) | ||||
|  | ||||
|  | ||||
|  | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| local QBCore = exports['qb-core']:GetCoreObject() | ||||
| local vehicles = {} | ||||
| local activeSpawns = {} -- Track active spawn requests to prevent duplicates | ||||
|  | ||||
| -- Debug Funktion | ||||
| local function Debug(msg) | ||||
|  | @ -65,26 +66,63 @@ CreateThread(function() | |||
|     end) | ||||
| end) | ||||
|  | ||||
| -- Registriere ein Fahrzeug | ||||
| -- Check if a player owns a vehicle | ||||
| RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not Player 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) | ||||
|         local isOwned = result and #result > 0 | ||||
|         TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, isOwned, plate) | ||||
|     end) | ||||
| end) | ||||
|  | ||||
| -- Enhanced anti-duplication for vehicle registration | ||||
| RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, coords, heading, mods) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not plate or not model or not coords then | ||||
|         Debug("Ungültige Daten beim Registrieren eines Fahrzeugs") | ||||
|         return | ||||
|     end | ||||
|     if not Player then return end | ||||
|      | ||||
|     -- Stelle sicher, dass das Modell als Zahl gespeichert wird | ||||
|     if type(model) == "string" then | ||||
|         model = tonumber(model) or model | ||||
|     end | ||||
|      | ||||
|     -- Prüfe ob Fahrzeug in der Garage ist | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND state = ?', {plate, 1}, function(result) | ||||
|         if result and #result > 0 then | ||||
|     -- Verify ownership before registering | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) | ||||
|         if not result or #result == 0 then | ||||
|             Debug("Vehicle not found in database: " .. plate) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Check if player owns the vehicle | ||||
|         local isOwner = false | ||||
|         for _, veh in ipairs(result) do | ||||
|             if veh.citizenid == Player.PlayerData.citizenid then | ||||
|                 isOwner = true | ||||
|                 break | ||||
|             end | ||||
|         end | ||||
|          | ||||
|         if not isOwner then | ||||
|             Debug("Player does not own vehicle: " .. plate) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Check if vehicle is in garage | ||||
|         local inGarage = false | ||||
|         for _, veh in ipairs(result) do | ||||
|             if veh.state == 1 then | ||||
|                 inGarage = true | ||||
|                 break | ||||
|             end | ||||
|         end | ||||
|          | ||||
|         if inGarage then | ||||
|             Debug("Fahrzeug ist in der Garage, nicht registrieren: " .. plate) | ||||
|              | ||||
|             -- Entferne aus Anti-Despawn Datenbank falls vorhanden | ||||
|             -- Remove from Anti-Despawn database if present | ||||
|             if vehicles[plate] then | ||||
|                 vehicles[plate] = nil | ||||
|                 MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|  | @ -93,6 +131,7 @@ RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, co | |||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Continue with registration as before | ||||
|         vehicles[plate] = { | ||||
|             model = model, | ||||
|             coords = coords, | ||||
|  | @ -101,9 +140,10 @@ RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, co | |||
|             mods = mods, | ||||
|             last_updated = os.time() | ||||
|         } | ||||
|          | ||||
|         MySQL.query("INSERT INTO vehicle_antidespawn (plate, model, coords, heading, fuel, mods) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE coords = VALUES(coords), heading = VALUES(heading), mods = VALUES(mods), last_updated = CURRENT_TIMESTAMP", { | ||||
|             plate, | ||||
|             tostring(model), -- Speichere als String in der Datenbank | ||||
|             tostring(model), | ||||
|             json.encode(coords), | ||||
|             heading, | ||||
|             100, | ||||
|  | @ -116,11 +156,43 @@ end) | |||
|  | ||||
| -- Aktualisiere ein Fahrzeug | ||||
| RegisterNetEvent('antidespawn:server:updateVehicle', function(plate, coords, heading, mods) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not Player then return end | ||||
|     if not vehicles[plate] then return end | ||||
|      | ||||
|     -- Prüfe ob Fahrzeug in der Garage ist | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND state = ?', {plate, 1}, function(result) | ||||
|         if result and #result > 0 then | ||||
|     -- Verify ownership before updating | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) | ||||
|         if not result or #result == 0 then | ||||
|             Debug("Vehicle not found in database: " .. plate) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Check if player owns the vehicle | ||||
|         local isOwner = false | ||||
|         for _, veh in ipairs(result) do | ||||
|             if veh.citizenid == Player.PlayerData.citizenid then | ||||
|                 isOwner = true | ||||
|                 break | ||||
|             end | ||||
|         end | ||||
|          | ||||
|         if not isOwner then | ||||
|             Debug("Player does not own vehicle: " .. plate) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Check if vehicle is in garage | ||||
|         local inGarage = false | ||||
|         for _, veh in ipairs(result) do | ||||
|             if veh.state == 1 then | ||||
|                 inGarage = true | ||||
|                 break | ||||
|             end | ||||
|         end | ||||
|          | ||||
|         if inGarage then | ||||
|             Debug("Fahrzeug ist in der Garage, entferne aus Tracking: " .. plate) | ||||
|             vehicles[plate] = nil | ||||
|              | ||||
|  | @ -148,6 +220,7 @@ end) | |||
|  | ||||
| -- Entferne ein Fahrzeug | ||||
| RegisterNetEvent('antidespawn:server:removeVehicle', function(plate) | ||||
|     local src = source | ||||
|     if not vehicles[plate] then return end | ||||
|      | ||||
|     vehicles[plate] = nil | ||||
|  | @ -159,30 +232,76 @@ RegisterNetEvent('antidespawn:server:removeVehicle', function(plate) | |||
|     Debug("Fahrzeug entfernt: " .. plate) | ||||
| end) | ||||
|  | ||||
| -- Respawn ein Fahrzeug | ||||
| -- Enhanced anti-duplication for vehicle respawning | ||||
| RegisterNetEvent('antidespawn:server:respawnVehicle', function(plate) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not vehicles[plate] then  | ||||
|         Debug("Fahrzeug nicht in Datenbank: " .. plate) | ||||
|         return  | ||||
|     if not Player then return end | ||||
|      | ||||
|     -- Anti-Duplication: Check if there's already an active spawn request for this plate | ||||
|     if activeSpawns[plate] then | ||||
|         Debug("Anti-Dupe: Already processing spawn request for: " .. plate) | ||||
|         return | ||||
|     end | ||||
|      | ||||
|     -- Prüfe ob Fahrzeug in der Garage ist | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND state = ?', {plate, 1}, function(result) | ||||
|         if result and #result > 0 then | ||||
|             Debug("Fahrzeug ist in der Garage, nicht respawnen: " .. plate) | ||||
|              | ||||
|             -- Entferne aus Anti-Despawn Datenbank | ||||
|             vehicles[plate] = nil | ||||
|              | ||||
|             MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", { | ||||
|                 plate | ||||
|             }) | ||||
|     -- Mark as active spawn | ||||
|     activeSpawns[plate] = true | ||||
|      | ||||
|     -- Set a timeout to clear the active spawn status | ||||
|     SetTimeout(10000, function() | ||||
|         activeSpawns[plate] = nil | ||||
|     end) | ||||
|      | ||||
|     -- Verify ownership before respawning | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) | ||||
|         if not result or #result == 0 then | ||||
|             Debug("Vehicle not found in database: " .. plate) | ||||
|             activeSpawns[plate] = nil | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Sende Spawn-Event zurück an den Client | ||||
|         -- Check if player owns the vehicle | ||||
|         local isOwner = false | ||||
|         for _, veh in ipairs(result) do | ||||
|             if veh.citizenid == Player.PlayerData.citizenid then | ||||
|                 isOwner = true | ||||
|                 break | ||||
|             end | ||||
|         end | ||||
|          | ||||
|         if not isOwner then | ||||
|             Debug("Player does not own vehicle: " .. plate) | ||||
|             activeSpawns[plate] = nil | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         if not vehicles[plate] then  | ||||
|             Debug("Fahrzeug nicht in Datenbank: " .. plate) | ||||
|             activeSpawns[plate] = nil | ||||
|             return  | ||||
|         end | ||||
|          | ||||
|         -- Check if vehicle is in garage | ||||
|         local inGarage = false | ||||
|         for _, veh in ipairs(result) do | ||||
|             if veh.state == 1 then | ||||
|                 inGarage = true | ||||
|                 break | ||||
|             end | ||||
|         end | ||||
|          | ||||
|         if inGarage then | ||||
|             Debug("Fahrzeug ist in der Garage, nicht respawnen: " .. plate) | ||||
|              | ||||
|             -- Remove from Anti-Despawn database | ||||
|             vehicles[plate] = nil | ||||
|             MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|             activeSpawns[plate] = nil | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Send spawn event back to client | ||||
|         TriggerClientEvent('antidespawn:client:spawnVehicle', src, { | ||||
|             plate = plate, | ||||
|             model = vehicles[plate].model, | ||||
|  | @ -212,68 +331,83 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function() | |||
|     local loadedCount = 0 | ||||
|     local vehiclesToLoad = {} | ||||
|      | ||||
|     -- Sammle alle Fahrzeuge, die geladen werden sollen | ||||
|     for plate, vehicle in pairs(vehicles) do | ||||
|         -- Prüfe ob das Fahrzeug in der Garage ist | ||||
|         MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) | ||||
|             -- Prüfe ob das Fahrzeug überhaupt existiert | ||||
|             if not result or #result == 0 then | ||||
|                 Debug("Fahrzeug existiert nicht in player_vehicles: " .. plate) | ||||
|                 -- Entferne aus Anti-Despawn Datenbank | ||||
|                 vehicles[plate] = nil | ||||
|                 MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|                 return | ||||
|             end | ||||
|              | ||||
|             -- Prüfe ob das Fahrzeug in der Garage ist (state = 1) | ||||
|             local inGarage = false | ||||
|             for _, veh in ipairs(result) do | ||||
|                 if veh.state == 1 then | ||||
|                     inGarage = true | ||||
|                     break | ||||
|                 end | ||||
|             end | ||||
|              | ||||
|             if inGarage then | ||||
|                 Debug("Fahrzeug ist in der Garage, nicht laden: " .. plate) | ||||
|                 -- Entferne aus Anti-Despawn Datenbank | ||||
|                 vehicles[plate] = nil | ||||
|                 MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|                 return | ||||
|             end | ||||
|              | ||||
|             -- Lade nur Fahrzeuge in der Nähe des Spielers | ||||
|             local distance = #(playerCoords - vector3(vehicle.coords.x, vehicle.coords.y, vehicle.coords.z)) | ||||
|              | ||||
|             if distance < 100.0 then | ||||
|                 -- Stelle sicher, dass das Modell als Zahl gespeichert ist | ||||
|                 local model = vehicle.model | ||||
|                 if type(model) == "string" then | ||||
|                     model = tonumber(model) or model | ||||
|                 end | ||||
|                  | ||||
|                 table.insert(vehiclesToLoad, { | ||||
|                     plate = plate, | ||||
|                     model = model, | ||||
|                     coords = vehicle.coords, | ||||
|                     heading = vehicle.heading, | ||||
|                     fuel = vehicle.fuel, | ||||
|                     mods = vehicle.mods | ||||
|                 }) | ||||
|                  | ||||
|                 loadedCount = loadedCount + 1 | ||||
|             end | ||||
|         end) | ||||
|     end | ||||
|      | ||||
|     -- Warte kurz und lade dann die Fahrzeuge | ||||
|     SetTimeout(3000, function() | ||||
|         for _, vehicleData in ipairs(vehiclesToLoad) do | ||||
|             TriggerClientEvent('antidespawn:client:spawnVehicle', src, vehicleData) | ||||
|             Debug("Fahrzeug für Spieler geladen: " .. vehicleData.plate) | ||||
|     -- Get all vehicles owned by this player | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE citizenid = ?', {Player.PlayerData.citizenid}, function(ownedVehicles) | ||||
|         if not ownedVehicles or #ownedVehicles == 0 then | ||||
|             Debug("Spieler besitzt keine Fahrzeuge") | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         Debug("Fahrzeugladung abgeschlossen. " .. loadedCount .. " Fahrzeuge geladen.") | ||||
|         -- Create a lookup table for owned vehicles | ||||
|         local ownedPlates = {} | ||||
|         for _, veh in ipairs(ownedVehicles) do | ||||
|             ownedPlates[veh.plate] = veh.state | ||||
|         end | ||||
|          | ||||
|         -- Sammle alle Fahrzeuge, die geladen werden sollen | ||||
|         for plate, vehicle in pairs(vehicles) do | ||||
|             -- Check if player owns this vehicle | ||||
|             if ownedPlates[plate] then | ||||
|                 -- Skip if vehicle is in garage (state = 1) | ||||
|                 if ownedPlates[plate] == 1 then | ||||
|                     Debug("Fahrzeug ist in der Garage, nicht laden: " .. plate) | ||||
|                     -- Remove from Anti-Despawn database | ||||
|                     vehicles[plate] = nil | ||||
|                     MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|                     goto continue | ||||
|                 end | ||||
|                  | ||||
|                 -- Lade nur Fahrzeuge in der Nähe des Spielers | ||||
|                 local distance = #(playerCoords - vector3(vehicle.coords.x, vehicle.coords.y, vehicle.coords.z)) | ||||
|                  | ||||
|                 if distance < 100.0 then | ||||
|                     -- Stelle sicher, dass das Modell als Zahl gespeichert ist | ||||
|                     local model = vehicle.model | ||||
|                     if type(model) == "string" then | ||||
|                         model = tonumber(model) or model | ||||
|                     end | ||||
|                      | ||||
|                     table.insert(vehiclesToLoad, { | ||||
|                         plate = plate, | ||||
|                         model = model, | ||||
|                         coords = vehicle.coords, | ||||
|                         heading = vehicle.heading, | ||||
|                         fuel = vehicle.fuel, | ||||
|                         mods = vehicle.mods | ||||
|                     }) | ||||
|                      | ||||
|                     loadedCount = loadedCount + 1 | ||||
|                 end | ||||
|             else | ||||
|                 -- Vehicle not owned by this player, remove from tracking | ||||
|                 Debug("Fahrzeug gehört nicht dem Spieler, entferne aus Tracking: " .. plate) | ||||
|                 vehicles[plate] = nil | ||||
|                 MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|             end | ||||
|             ::continue:: | ||||
|         end | ||||
|          | ||||
|         -- Warte kurz und lade dann die Fahrzeuge | ||||
|         SetTimeout(3000, function() | ||||
|             for _, vehicleData in ipairs(vehiclesToLoad) do | ||||
|                 -- Anti-Duplication: Check if there's already an active spawn request for this plate | ||||
|                 if not activeSpawns[vehicleData.plate] then | ||||
|                     activeSpawns[vehicleData.plate] = true | ||||
|                      | ||||
|                     -- Set a timeout to clear the active spawn status | ||||
|                     SetTimeout(10000, function() | ||||
|                         activeSpawns[vehicleData.plate] = nil | ||||
|                     end) | ||||
|                      | ||||
|                     TriggerClientEvent('antidespawn:client:spawnVehicle', src, vehicleData) | ||||
|                     Debug("Fahrzeug für Spieler geladen: " .. vehicleData.plate) | ||||
|                 else | ||||
|                     Debug("Anti-Dupe: Already processing spawn request for: " .. vehicleData.plate) | ||||
|                 end | ||||
|             end | ||||
|              | ||||
|             Debug("Fahrzeugladung abgeschlossen. " .. loadedCount .. " Fahrzeuge geladen.") | ||||
|         end) | ||||
|     end) | ||||
| end) | ||||
|  | ||||
|  | @ -387,116 +521,6 @@ RegisterCommand('clearvehicles', function(source, args, rawCommand) | |||
|     end | ||||
| end, true) | ||||
|  | ||||
|  | ||||
| -- Check if a player owns a vehicle | ||||
| RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not Player then return end | ||||
|      | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?', {plate, Player.PlayerData.citizenid}, function(result) | ||||
|         local isOwned = result and #result > 0 | ||||
|         TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, isOwned, plate) | ||||
|     end) | ||||
| end) | ||||
|  | ||||
| -- Modified registerVehicle function to verify ownership | ||||
| RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, coords, heading, mods) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not Player then return end | ||||
|      | ||||
|     -- Verify ownership before registering | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?', {plate, Player.PlayerData.citizenid}, function(result) | ||||
|         if not result or #result == 0 then | ||||
|             Debug("Player does not own vehicle: " .. plate) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Check if vehicle is in garage | ||||
|         if result[1].state == 1 then | ||||
|             Debug("Fahrzeug ist in der Garage, nicht registrieren: " .. plate) | ||||
|              | ||||
|             -- Remove from Anti-Despawn database if present | ||||
|             if vehicles[plate] then | ||||
|                 vehicles[plate] = nil | ||||
|                 MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|                 Debug("Fahrzeug aus Anti-Despawn entfernt: " .. plate) | ||||
|             end | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Continue with registration as before | ||||
|         vehicles[plate] = { | ||||
|             model = model, | ||||
|             coords = coords, | ||||
|             heading = heading, | ||||
|             fuel = 100, | ||||
|             mods = mods, | ||||
|             last_updated = os.time() | ||||
|         } | ||||
|          | ||||
|         MySQL.query("INSERT INTO vehicle_antidespawn (plate, model, coords, heading, fuel, mods) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE coords = VALUES(coords), heading = VALUES(heading), mods = VALUES(mods), last_updated = CURRENT_TIMESTAMP", { | ||||
|             plate, | ||||
|             tostring(model), | ||||
|             json.encode(coords), | ||||
|             heading, | ||||
|             100, | ||||
|             json.encode(mods) | ||||
|         }) | ||||
|          | ||||
|         Debug("Fahrzeug registriert: " .. plate .. " (Modell: " .. tostring(model) .. ")") | ||||
|     end) | ||||
| end) | ||||
|  | ||||
| -- Also modify respawnVehicle to verify ownership | ||||
| RegisterNetEvent('antidespawn:server:respawnVehicle', function(plate) | ||||
|     local src = source | ||||
|     local Player = QBCore.Functions.GetPlayer(src) | ||||
|      | ||||
|     if not Player then return end | ||||
|      | ||||
|     -- Verify ownership before respawning | ||||
|     MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?', {plate, Player.PlayerData.citizenid}, function(result) | ||||
|         if not result or #result == 0 then | ||||
|             Debug("Player does not own vehicle: " .. plate) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         if not vehicles[plate] then  | ||||
|             Debug("Fahrzeug nicht in Datenbank: " .. plate) | ||||
|             return  | ||||
|         end | ||||
|          | ||||
|         -- Check if vehicle is in garage | ||||
|         if result[1].state == 1 then | ||||
|             Debug("Fahrzeug ist in der Garage, nicht respawnen: " .. plate) | ||||
|              | ||||
|             -- Remove from Anti-Despawn database | ||||
|             vehicles[plate] = nil | ||||
|             MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) | ||||
|             return | ||||
|         end | ||||
|          | ||||
|         -- Send spawn event back to client | ||||
|         TriggerClientEvent('antidespawn:client:spawnVehicle', src, { | ||||
|             plate = plate, | ||||
|             model = vehicles[plate].model, | ||||
|             coords = vehicles[plate].coords, | ||||
|             heading = vehicles[plate].heading, | ||||
|             fuel = vehicles[plate].fuel, | ||||
|             mods = vehicles[plate].mods | ||||
|         }) | ||||
|          | ||||
|         Debug("Fahrzeug Respawn angefordert: " .. plate) | ||||
|     end) | ||||
| end) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| -- Befehl zum Leeren der Datenbank | ||||
| RegisterCommand('clearalldespawn', function(source, args, rawCommand) | ||||
|     if source == 0 then -- Nur über Konsole ausführbar | ||||
|  | @ -505,5 +529,24 @@ RegisterCommand('clearalldespawn', function(source, args, rawCommand) | |||
|         Debug("Alle Fahrzeuge aus der Datenbank entfernt.") | ||||
|     end | ||||
| end, true) | ||||
|          | ||||
|  | ||||
| -- Debug command to check active spawns | ||||
| RegisterCommand('activespawns', function(source, args, rawCommand) | ||||
|     if source == 0 then -- Nur über Konsole ausführbar | ||||
|         local count = 0 | ||||
|         for plate, _ in pairs(activeSpawns) do | ||||
|             Debug("Active spawn: " .. plate) | ||||
|             count = count + 1 | ||||
|         end | ||||
|         Debug("Total active spawns: " .. count) | ||||
|     end | ||||
| end, true) | ||||
|  | ||||
| -- Clean up when resource stops | ||||
| AddEventHandler('onResourceStop', function(resourceName) | ||||
|     if resourceName == GetCurrentResourceName() then | ||||
|         Debug("Resource stopping, clearing all data") | ||||
|         vehicles = {} | ||||
|         activeSpawns = {} | ||||
|     end | ||||
| end) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Nordi98
						Nordi98