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 local vehicleExistsCallbacks = {} -- Callbacks for vehicle existence checks -- Helper function to count table entries function tableLength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end -- Debug Funktion local function Debug(msg) if Config.Debug then print("[AntiDespawn] " .. msg) 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 local function DoesVehicleExistInWorld(plate) local vehicles = GetGamePool('CVehicle') local count = 0 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 return false end -- 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 -- Trigger server event to check ownership and wait for response local isOwned = nil -- Request ownership check from server TriggerServerEvent('antidespawn:server:checkVehicleOwnership', plate) -- Register one-time event handler for the response 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) -- Wait for response with timeout local timeout = 0 while isOwned == nil and timeout < 50 do Wait(10) timeout = timeout + 1 end -- Remove event handler RemoveEventHandler(eventHandler) return isOwned == true 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 local function IsVehicleClassAllowed(vehicle) local vehicleClass = GetVehicleClass(vehicle) -- Prüfe Blacklist for _, blacklistedClass in pairs(Config.BlacklistedVehicleClasses) do if vehicleClass == blacklistedClass then return false end end -- Prüfe Whitelist for _, allowedClass in pairs(Config.AllowedVehicleClasses) do if vehicleClass == allowedClass then return true end end 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 = {} -- Basis Mods for i = 0, 49 do mods[tostring(i)] = GetVehicleMod(vehicle, i) end -- Extras mods.extras = {} for i = 1, 12 do if DoesExtraExist(vehicle, i) then mods.extras[tostring(i)] = IsVehicleExtraTurnedOn(vehicle, i) end end -- Farben local primaryColor, secondaryColor = GetVehicleColours(vehicle) local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) mods.colors = { primary = primaryColor, secondary = secondaryColor, pearlescent = pearlescentColor, wheels = wheelColor } -- Custom Farben local hasCustomPrimaryColor = GetIsVehiclePrimaryColourCustom(vehicle) if hasCustomPrimaryColor then local r, g, b = GetVehicleCustomPrimaryColour(vehicle) mods.customPrimaryColor = {r = r, g = g, b = b} end local hasCustomSecondaryColor = GetIsVehicleSecondaryColourCustom(vehicle) if hasCustomSecondaryColor then local r, g, b = GetVehicleCustomSecondaryColour(vehicle) mods.customSecondaryColor = {r = r, g = g, b = b} end -- Neon mods.neon = { left = IsVehicleNeonLightEnabled(vehicle, 0), right = IsVehicleNeonLightEnabled(vehicle, 1), front = IsVehicleNeonLightEnabled(vehicle, 2), back = IsVehicleNeonLightEnabled(vehicle, 3) } local r, g, b = GetVehicleNeonLightsColour(vehicle) mods.neonColor = {r = r, g = g, b = b} -- Xenon mods.xenonColor = GetVehicleXenonLightsColour(vehicle) mods.xenonEnabled = IsToggleModOn(vehicle, 22) -- Livery mods.livery = GetVehicleLivery(vehicle) -- Fenster Tint mods.windowTint = GetVehicleWindowTint(vehicle) -- Rad Typ mods.wheelType = GetVehicleWheelType(vehicle) -- Rauch Farbe local r, g, b = GetVehicleTyreSmokeColor(vehicle) mods.tyreSmokeColor = {r = r, g = g, b = b} -- Dashboard & Interior Farbe mods.dashboardColor = GetVehicleDashboardColour(vehicle) mods.interiorColor = GetVehicleInteriorColour(vehicle) -- Toggles mods.bulletProofTires = not GetVehicleTyresCanBurst(vehicle) mods.turbo = IsToggleModOn(vehicle, 18) mods.xeonHeadlights = IsToggleModOn(vehicle, 22) return mods end -- Funktion um Fahrzeugmods zu setzen local function SetVehicleMods(vehicle, mods) if not mods then return end -- Setze Modkit SetVehicleModKit(vehicle, 0) -- Rad Typ zuerst setzen if mods.wheelType then SetVehicleWheelType(vehicle, mods.wheelType) end -- Basis Mods for i = 0, 49 do if mods[tostring(i)] ~= nil then SetVehicleMod(vehicle, i, mods[tostring(i)], false) end end -- Extras if mods.extras then for i = 1, 12 do if mods.extras[tostring(i)] ~= nil then SetVehicleExtra(vehicle, i, not mods.extras[tostring(i)]) end end end -- Farben if mods.colors then SetVehicleColours(vehicle, mods.colors.primary or 0, mods.colors.secondary or 0) SetVehicleExtraColours(vehicle, mods.colors.pearlescent or 0, mods.colors.wheels or 0) end -- Custom Farben if mods.customPrimaryColor then SetVehicleCustomPrimaryColour(vehicle, mods.customPrimaryColor.r, mods.customPrimaryColor.g, mods.customPrimaryColor.b) end if mods.customSecondaryColor then SetVehicleCustomSecondaryColour(vehicle, mods.customSecondaryColor.r, mods.customSecondaryColor.g, mods.customSecondaryColor.b) end -- Neon if mods.neon then SetVehicleNeonLightEnabled(vehicle, 0, mods.neon.left or false) SetVehicleNeonLightEnabled(vehicle, 1, mods.neon.right or false) SetVehicleNeonLightEnabled(vehicle, 2, mods.neon.front or false) SetVehicleNeonLightEnabled(vehicle, 3, mods.neon.back or false) end if mods.neonColor then SetVehicleNeonLightsColour(vehicle, mods.neonColor.r, mods.neonColor.g, mods.neonColor.b) end -- Xenon if mods.xenonEnabled then ToggleVehicleMod(vehicle, 22, true) if mods.xenonColor then SetVehicleXenonLightsColour(vehicle, mods.xenonColor) end end -- Livery if mods.livery then SetVehicleLivery(vehicle, mods.livery) end -- Fenster Tint if mods.windowTint then SetVehicleWindowTint(vehicle, mods.windowTint) end -- Rauch Farbe if mods.tyreSmokeColor then ToggleVehicleMod(vehicle, 20, true) -- Aktiviere Rauch SetVehicleTyreSmokeColor(vehicle, mods.tyreSmokeColor.r, mods.tyreSmokeColor.g, mods.tyreSmokeColor.b) end -- Dashboard & Interior Farbe if mods.dashboardColor then SetVehicleDashboardColour(vehicle, mods.dashboardColor) end if mods.interiorColor then SetVehicleInteriorColour(vehicle, mods.interiorColor) end -- Toggles if mods.bulletProofTires ~= nil then SetVehicleTyresCanBurst(vehicle, not mods.bulletProofTires) end if mods.turbo ~= nil then ToggleVehicleMod(vehicle, 18, mods.turbo) end -- Setze Felgen nochmal explizit if mods["23"] ~= nil then -- Vorderräder SetVehicleMod(vehicle, 23, mods["23"], false) end if mods["24"] ~= nil then -- Hinterräder SetVehicleMod(vehicle, 24, mods["24"], false) 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 Handler für Fahrzeug betreten (nur Fahrersitz) CreateThread(function() while true do Wait(1000) local playerPed = PlayerPedId() local currentVehicle = GetVehiclePedIsIn(playerPed, false) -- Spieler ist als Fahrer in ein Fahrzeug eingestiegen if currentVehicle ~= 0 then -- Prüfe ob Spieler auf Fahrersitz ist local driver = GetPedInVehicleSeat(currentVehicle, -1) -- Nur wenn Spieler der Fahrer ist (Seat -1) if driver == playerPed and IsVehicleClassAllowed(currentVehicle) then local plate = QBCore.Functions.GetPlate(currentVehicle) -- Skip vehicles with empty or invalid plates if not plate or plate == "" or string.len(plate) < 2 then Debug("Skipping vehicle with invalid plate") goto continue 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 if DoesVehicleExistInWorld(plate) then Debug("Anti-Dupe: Detected duplicate vehicle with plate " .. plate .. ", not tracking") goto continue end -- Check if this vehicle is already being tracked if not trackedVehicles[plate] and not garagePending[plate] then -- First verify this vehicle exists in the database CheckVehicleExists(plate, function(exists) if not exists then Debug("Vehicle not in database, not tracking: " .. plate) return end -- Track all vehicles that exist in the database trackedVehicles[plate] = currentVehicle -- Speichere letzte bekannte Position lastKnownCoords[plate] = GetEntityCoords(currentVehicle) -- Sofort starke Despawn-Verhinderung PreventDespawn(currentVehicle) Debug("Fahrzeug wird nun getrackt: " .. plate) -- Hole Fahrzeugmods local vehicleMods = GetVehicleMods(currentVehicle) -- Registriere Fahrzeug beim Server local vehicleCoords = GetEntityCoords(currentVehicle) local vehicleHeading = GetEntityHeading(currentVehicle) local vehicleModel = GetEntityModel(currentVehicle) TriggerServerEvent('antidespawn:server:registerVehicle', plate, vehicleModel, vehicleCoords, vehicleHeading, vehicleMods) end) end end end ::continue:: end end) -- Kontinuierliche Despawn-Verhinderung für alle getrackten Fahrzeuge CreateThread(function() while true do Wait(5000) -- Alle 5 Sekunden local playerPed = PlayerPedId() 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) trackedVehicles[plate] = nil lastKnownCoords[plate] = nil TriggerServerEvent('antidespawn:server:removeVehicle', plate) elseif DoesEntityExist(vehicle) then -- Check distance to player local vehiclePos = GetEntityCoords(vehicle) local distance = #(playerPos - vehiclePos) if distance > 500.0 then -- 500 units = about 500 meters Debug("Fahrzeug zu weit entfernt, entferne aus Tracking: " .. plate) trackedVehicles[plate] = nil lastKnownCoords[plate] = nil TriggerServerEvent('antidespawn:server:removeVehicle', plate) else PreventDespawn(vehicle) -- Aktualisiere letzte bekannte Position lastKnownCoords[plate] = vehiclePos -- Hole Fahrzeugmods local vehicleMods = GetVehicleMods(vehicle) -- Aktualisiere Position local vehicleHeading = GetEntityHeading(vehicle) TriggerServerEvent('antidespawn:server:updateVehicle', plate, vehiclePos, vehicleHeading, vehicleMods) Debug("Aktualisiere Fahrzeug: " .. plate) end 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 -- Store the plate and coords for use in the callback local currentPlate = plate local currentCoords = lastKnownCoords[plate] -- Verify this vehicle still exists in the database before respawning CheckVehicleExists(plate, function(exists) if not exists then Debug("Vehicle no longer in database, not respawning: " .. currentPlate) trackedVehicles[currentPlate] = nil lastKnownCoords[currentPlate] = nil return end -- Versuche Fahrzeug wiederherzustellen, aber nur wenn es nicht in die Garage gestellt wird if currentCoords and not garagePending[currentPlate] then Debug("Versuche Fahrzeug wiederherzustellen: " .. currentPlate) TriggerServerEvent('antidespawn:server:respawnVehicle', currentPlate) -- Entferne aus lokaler Tracking-Liste, wird nach Respawn wieder hinzugefügt trackedVehicles[currentPlate] = nil lastKnownCoords[currentPlate] = nil else -- Entferne aus Tracking trackedVehicles[currentPlate] = nil lastKnownCoords[currentPlate] = nil end end) -- Remove from tracking immediately to avoid processing it again while waiting for the callback trackedVehicles[plate] = nil lastKnownCoords[plate] = nil end ::continue:: end end end) -- Lade Fahrzeuge beim Spawn RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() Debug("Spieler geladen, warte vor dem Laden der Fahrzeuge...") -- Längere Wartezeit, um sicherzustellen, dass alles geladen ist Wait(15000) TriggerServerEvent('antidespawn:server:loadVehicles') end) -- Automatisches Laden beim Resource Start CreateThread(function() -- Längere Wartezeit beim Serverstart Wait(20000) -- Prüfe ob Spieler eingeloggt ist local playerData = QBCore.Functions.GetPlayerData() if playerData and playerData.citizenid then Debug("Resource gestartet, lade Fahrzeuge...") TriggerServerEvent('antidespawn:server:loadVehicles') else -- Warte auf Login, wenn Spieler noch nicht eingeloggt ist Debug("Warte auf Spieler-Login...") while true do Wait(5000) playerData = QBCore.Functions.GetPlayerData() if playerData and playerData.citizenid then Debug("Spieler jetzt eingeloggt, lade Fahrzeuge...") TriggerServerEvent('antidespawn:server:loadVehicles') break end end end end) -- Spawne ein Fahrzeug RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) 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 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 Debug("Fahrzeug existiert bereits: " .. data.plate) trackedVehicles[data.plate] = existingVehicle lastKnownCoords[data.plate] = GetEntityCoords(existingVehicle) PreventDespawn(existingVehicle) return end -- Prüfe ob Fahrzeug gerade in die Garage gestellt wird if garagePending[data.plate] then Debug("Fahrzeug wird gerade in Garage gestellt, nicht spawnen: " .. data.plate) return end -- Verify this vehicle exists in the database before spawning CheckVehicleExists(data.plate, function(exists) if not exists then Debug("Vehicle not in database, not spawning: " .. data.plate) return end -- Konvertiere Modell zu Hash wenn nötig 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 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: " .. data.plate .. " (Hash: " .. tostring(modelHash) .. ")") end end) 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() local vehicle = GetVehiclePedIsIn(playerPed, false) if vehicle ~= 0 then 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" garagePending[plate] = true SetTimeout(10000, function() if garagePending[plate] then Debug("Garage storage timeout for vehicle: " .. plate) garagePending[plate] = nil end end) -- Entferne aus Tracking if trackedVehicles[plate] then Debug("Fahrzeug wird in Garage gestellt, entferne aus Tracking: " .. plate) trackedVehicles[plate] = nil lastKnownCoords[plate] = nil TriggerServerEvent('antidespawn:server:removeVehicle', plate) end end end) -- jg-advanced-garage Events RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data) 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" garagePending[data.plate] = nil -- Entferne aus Tracking if trackedVehicles[data.plate] then trackedVehicles[data.plate] = nil lastKnownCoords[data.plate] = nil end -- Entferne aus Datenbank TriggerServerEvent('antidespawn:server:removeVehicle', data.plate) Debug("Fahrzeug in Garage gespeichert, aus DB entfernt: " .. data.plate) end end) RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data) 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" garagePending[data.plate] = nil Debug("Fahrzeug aus Garage gespawnt: " .. data.plate) -- Warte kurz bis das Fahrzeug vollständig gespawnt ist Wait(1000) -- Finde das Fahrzeug local vehicle = GetVehicleByPlate(data.plate) if vehicle then -- Füge zu getrackten Fahrzeugen hinzu trackedVehicles[data.plate] = vehicle lastKnownCoords[data.plate] = GetEntityCoords(vehicle) -- Verhindere Despawn PreventDespawn(vehicle) Debug("Fahrzeug aus Garage zum Tracking hinzugefügt: " .. data.plate) end end end) -- Öffnen der Garage RegisterNetEvent('jg-advancedgarages:client:open-garage', function(garageId, vehicleType, spawnCoords) Debug("Garage geöffnet: " .. garageId) -- No need to mark vehicles as potentially being stored here -- Let the actual store-vehicle event handle this end) -- Manuelle Lade-Funktion RegisterCommand('loadvehicles', function() Debug("Manuelles Laden der Fahrzeuge...") TriggerServerEvent('antidespawn:server:loadVehicles') end, false) -- Debug Command RegisterCommand('fixvehicle', function() local playerPed = PlayerPedId() local vehicle = GetVehiclePedIsIn(playerPed, false) if vehicle ~= 0 then 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 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 -- Verify this vehicle exists in the database CheckVehicleExists(plate, function(exists) if not exists then Debug("Vehicle not in database, cannot fix: " .. plate) return end 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) end) else Debug("Fahrzeug wird gerade in Garage gestellt, kann nicht fixiert werden: " .. plate) end else Debug("Du musst in einem Fahrzeug sitzen!") 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 = {} vehicleExistsCallbacks = {} 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 plate and plate ~= "" then 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 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) -- 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)