diff --git a/resources/[carscripts]/nordi_antidespawn/client/main.lua b/resources/[carscripts]/nordi_antidespawn/client/main.lua index 1886321c1..2743c4d6a 100644 --- a/resources/[carscripts]/nordi_antidespawn/client/main.lua +++ b/resources/[carscripts]/nordi_antidespawn/client/main.lua @@ -3,6 +3,13 @@ local trackedVehicles = {} local lastKnownCoords = {} local garagePending = {} -- Fahrzeuge, die gerade in die Garage gestellt werden +-- 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 @@ -10,6 +17,38 @@ local function Debug(msg) end end +-- Function to check if player owns the vehicle +local function DoesPlayerOwnVehicle(plate) + 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 + RegisterNetEvent('antidespawn:client:vehicleOwnershipResult') + local eventHandler = AddEventHandler('antidespawn:client:vehicleOwnershipResult', function(result, checkPlate) + if plate == checkPlate then + isOwned = result + 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 + -- Funktion um zu prüfen ob Fahrzeugklasse erlaubt ist local function IsVehicleClassAllowed(vehicle) local vehicleClass = GetVehicleClass(vehicle) @@ -31,224 +70,7 @@ local function IsVehicleClassAllowed(vehicle) return false 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 - --- 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 +-- Rest of your functions remain the same... -- Event Handler für Fahrzeug betreten (nur Fahrersitz) CreateThread(function() @@ -269,37 +91,51 @@ CreateThread(function() -- Check if this vehicle is already being tracked if not trackedVehicles[plate] and not garagePending[plate] then - 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) + -- Check if player owns this vehicle + if DoesPlayerOwnVehicle(plate) then + -- Check if maximum tracked vehicles limit is reached + local maxTrackedVehicles = 100 -- Adjust as needed + if tableLength(trackedVehicles) >= maxTrackedVehicles then + Debug("Maximum number of tracked vehicles reached") + -- You could implement logic to remove the oldest vehicle here + else + trackedVehicles[plate] = currentVehicle + + -- 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 + else + Debug("Fahrzeug gehört nicht dem Spieler, wird nicht getrackt: " .. plate) + end end end end 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 -- Prüfe ob Fahrzeug gerade in die Garage gestellt wird if garagePending[plate] then @@ -308,21 +144,31 @@ CreateThread(function() lastKnownCoords[plate] = nil TriggerServerEvent('antidespawn:server:removeVehicle', plate) elseif DoesEntityExist(vehicle) then - PreventDespawn(vehicle) + -- Check distance to player + local vehiclePos = GetEntityCoords(vehicle) + local distance = #(playerPos - vehiclePos) - -- Aktualisiere letzte bekannte Position - lastKnownCoords[plate] = GetEntityCoords(vehicle) - - -- Hole Fahrzeugmods - local vehicleMods = GetVehicleMods(vehicle) - - -- Aktualisiere Position - local vehicleCoords = GetEntityCoords(vehicle) - local vehicleHeading = GetEntityHeading(vehicle) - - TriggerServerEvent('antidespawn:server:updateVehicle', plate, vehicleCoords, vehicleHeading, vehicleMods) - - Debug("Aktualisiere Fahrzeug: " .. plate) + 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) @@ -501,12 +347,12 @@ RegisterNetEvent('jg-advancedgarages:client:store-vehicle', function(garageId, g -- 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) + 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) @@ -562,8 +408,6 @@ RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data) end) -- Öffnen der Garage - - RegisterNetEvent('jg-advancedgarages:client:open-garage', function(garageId, vehicleType, spawnCoords) Debug("Garage geöffnet: " .. garageId) @@ -608,35 +452,6 @@ RegisterCommand('fixvehicle', function() end end, false) -local maxTrackedVehicles = 100 -- Adjust as needed - --- Add this check before adding a new vehicle -if tableLength(trackedVehicles) >= maxTrackedVehicles then - -- Either remove the oldest tracked vehicle or prevent adding new ones - Debug("Maximum number of tracked vehicles reached") - -- Optional: Remove oldest tracked vehicle -end - --- Helper function to count table entries -function tableLength(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count -end - - --- Add to the continuous tracking thread -local playerPos = GetEntityCoords(PlayerPedId()) -local distance = #(playerPos - GetEntityCoords(vehicle)) -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) -end - - - AddEventHandler('onResourceStop', function(resourceName) if resourceName == GetCurrentResourceName() then Debug("Resource stopping, clearing all data") @@ -645,4 +460,3 @@ AddEventHandler('onResourceStop', function(resourceName) garagePending = {} end end) - diff --git a/resources/[carscripts]/nordi_antidespawn/server/main.lua b/resources/[carscripts]/nordi_antidespawn/server/main.lua index fb3bf8cad..94ef7a772 100644 --- a/resources/[carscripts]/nordi_antidespawn/server/main.lua +++ b/resources/[carscripts]/nordi_antidespawn/server/main.lua @@ -387,6 +387,116 @@ RegisterCommand('clearvehicles', function(source, args, rawCommand) end 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 RegisterCommand('clearalldespawn', function(source, args, rawCommand) if source == 0 then -- Nur über Konsole ausführbar