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)
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue