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