1
0
Fork 0
forked from Simnation/Main
Main/resources/[carscripts]/nordi_antidespawn/client/main.lua
2025-08-07 14:12:28 +02:00

1039 lines
37 KiB
Lua

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)