diff --git a/resources/[carscripts]/nordi_antidespawn/client/main.lua b/resources/[carscripts]/nordi_antidespawn/client/main.lua index 2f76c757a..800a834a5 100644 --- a/resources/[carscripts]/nordi_antidespawn/client/main.lua +++ b/resources/[carscripts]/nordi_antidespawn/client/main.lua @@ -4,6 +4,7 @@ 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) @@ -19,6 +20,44 @@ local function Debug(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') @@ -114,6 +153,28 @@ local function DoesPlayerOwnVehicle(plate) 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) @@ -388,6 +449,24 @@ CreateThread(function() 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") @@ -397,7 +476,7 @@ CreateThread(function() -- 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 - TriggerServerEvent('antidespawn:server:checkVehicleExists', plate, function(exists) + CheckVehicleExists(plate, function(exists) if not exists then Debug("Vehicle not in database, not tracking: " .. plate) return @@ -492,19 +571,29 @@ CreateThread(function() 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) - TriggerServerEvent('antidespawn:server:respawnVehicle', 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: " .. plate) + trackedVehicles[plate] = nil + lastKnownCoords[plate] = nil + return + end - -- Entferne aus lokaler Tracking-Liste, wird nach Respawn wieder hinzugefügt - trackedVehicles[plate] = nil - lastKnownCoords[plate] = nil - else - -- Entferne aus Tracking - trackedVehicles[plate] = nil - lastKnownCoords[plate] = nil - 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) + TriggerServerEvent('antidespawn:server:respawnVehicle', plate) + + -- Entferne aus lokaler Tracking-Liste, wird nach Respawn wieder hinzugefügt + trackedVehicles[plate] = nil + lastKnownCoords[plate] = nil + else + -- Entferne aus Tracking + trackedVehicles[plate] = nil + lastKnownCoords[plate] = nil + end + end) end ::continue:: end @@ -548,6 +637,12 @@ end) 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) @@ -570,100 +665,107 @@ RegisterNetEvent('antidespawn:client:spawnVehicle', function(data) return end - -- Allow spawning of all vehicles, not just owned ones - -- No ownership check here - - -- 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) + -- 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 - -- 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) + -- 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 - 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) + 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 - SetModelAsNoLongerNeeded(modelHash) - else - Debug("Modell konnte nicht geladen werden: " .. data.plate .. " (Hash: " .. tostring(modelHash) .. ")") - 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: " .. + 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) @@ -674,6 +776,12 @@ RegisterNetEvent('jg-advancedgarages:client:store-vehicle', function(garageId, g 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() @@ -695,6 +803,12 @@ 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 @@ -713,6 +827,12 @@ 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 @@ -758,6 +878,24 @@ RegisterCommand('fixvehicle', function() 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") @@ -766,20 +904,27 @@ RegisterCommand('fixvehicle', function() -- Prüfe ob Fahrzeug gerade in die Garage gestellt wird if not garagePending[plate] then - -- Track all vehicles, regardless of ownership - 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) + -- 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 @@ -802,6 +947,7 @@ AddEventHandler('onResourceStop', function(resourceName) garagePending = {} spawnedVehicles = {} vehicleOwnership = {} + vehicleExistsCallbacks = {} end end) @@ -813,14 +959,16 @@ RegisterCommand('checkdupes', function() for _, vehicle in pairs(vehicles) do local plate = QBCore.Functions.GetPlate(vehicle) - if plates[plate] then - if not dupes[plate] then - dupes[plate] = 2 + 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 - dupes[plate] = dupes[plate] + 1 + plates[plate] = true end - else - plates[plate] = true end end @@ -849,3 +997,35 @@ RegisterCommand('clearownership', function() 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) diff --git a/resources/[carscripts]/nordi_antidespawn/server/main.lua b/resources/[carscripts]/nordi_antidespawn/server/main.lua index 5e94fd63f..a6116781f 100644 --- a/resources/[carscripts]/nordi_antidespawn/server/main.lua +++ b/resources/[carscripts]/nordi_antidespawn/server/main.lua @@ -77,6 +77,22 @@ CreateThread(function() end) end) +-- Check if a vehicle exists in the database +RegisterNetEvent('antidespawn:server:checkVehicleExists', function(plate) + local src = source + + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + TriggerClientEvent('antidespawn:client:vehicleExistsResult', src, false, plate) + return + end + + MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) + local exists = result and #result > 0 + TriggerClientEvent('antidespawn:client:vehicleExistsResult', src, exists, plate) + end) +end) + -- Check if a player owns a vehicle RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate) local src = source @@ -87,6 +103,12 @@ RegisterNetEvent('antidespawn:server:checkVehicleOwnership', function(plate) return end + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, false, plate) + return + end + MySQL.query('SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?', {plate, Player.PlayerData.citizenid}, function(result) local isOwned = result and #result > 0 TriggerClientEvent('antidespawn:client:vehicleOwnershipResult', src, isOwned, plate) @@ -100,6 +122,12 @@ RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, co if not Player then return end + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + Debug("Skipping vehicle with invalid plate") + return + end + -- Check if vehicle exists in player_vehicles (any player) MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) if not result or #result == 0 then @@ -163,10 +191,19 @@ RegisterNetEvent('antidespawn:server:updateVehicle', function(plate, coords, hea if not Player then return end if not vehicles[plate] then return end + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + Debug("Skipping update for vehicle with invalid plate") + return + end + -- Check if vehicle exists in player_vehicles (any player) 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) + -- Remove from tracking as it no longer exists in the database + vehicles[plate] = nil + MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) return end @@ -210,6 +247,12 @@ RegisterNetEvent('antidespawn:server:removeVehicle', function(plate) local src = source if not vehicles[plate] then return end + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + Debug("Skipping removal for vehicle with invalid plate") + return + end + vehicles[plate] = nil MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", { @@ -226,6 +269,12 @@ RegisterNetEvent('antidespawn:server:respawnVehicle', function(plate) if not Player then return end + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + Debug("Skipping respawn for vehicle with invalid plate") + return + end + -- Anti-Duplication: Check if there's already an active spawn request for this plate if activeSpawns[plate] then Debug("Anti-Dupe: Already processing spawn request for: " .. plate) @@ -305,6 +354,14 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function() -- Load all vehicles in the database, not just owned ones for plate, vehicle in pairs(vehicles) do + -- Skip vehicles with empty or invalid plates + if not plate or plate == "" or string.len(plate) < 2 then + Debug("Skipping load for vehicle with invalid plate") + vehicles[plate] = nil + MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {plate}) + goto continue + end + -- Check if vehicle is in garage by querying the database MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) if not result or #result == 0 then @@ -354,6 +411,7 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function() loadedCount = loadedCount + 1 end end) + ::continue:: end -- Warte kurz und lade dann die Fahrzeuge @@ -379,6 +437,7 @@ RegisterNetEvent('antidespawn:server:loadVehicles', function() end) end) + -- Cleanup alte Einträge (älter als 24 Stunden) CreateThread(function() while true do @@ -511,6 +570,24 @@ RegisterCommand('activespawns', function(source, args, rawCommand) end end, true) +-- Check if a vehicle exists in the database +RegisterNetEvent('antidespawn:server:checkVehicleExists', function(plate, callback) + local src = source + + MySQL.query('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) + local exists = result and #result > 0 + TriggerClientEvent('antidespawn:client:vehicleExistsResult', src, exists, plate) + end) +end) + +-- Client callback for vehicle existence check +RegisterNetEvent('antidespawn:client:vehicleExistsResult', function(exists, plate) + -- This event will be handled by the callback system +end) + + + + -- Clean up when resource stops AddEventHandler('onResourceStop', function(resourceName) if resourceName == GetCurrentResourceName() then