Main/resources/[carscripts]/nordi_antidespawn/client/main.lua
2025-08-06 17:49:33 +02:00

347 lines
13 KiB
Lua

local QBCore = exports['qb-core']:GetCoreObject()
local trackedVehicles = {}
local spawnedVehicles = {}
-- Funktion um zu prüfen ob Fahrzeugklasse erlaubt ist
local function IsVehicleClassAllowed(vehicle)
local vehicleClass = GetVehicleClass(vehicle)
for _, allowedClass in pairs(Config.AllowedVehicleClasses) do
if vehicleClass == allowedClass then
return true
end
end
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
}
-- 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}
return mods
end
-- Funktion um Fahrzeugmods zu setzen
local function SetVehicleMods(vehicle, mods)
if not mods then return end
-- Basis Mods
for i = 0, 49 do
if mods[tostring(i)] 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
-- 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
end
-- Verhindere Despawn für alle getrackten Fahrzeuge
local function PreventVehicleDespawn(vehicle)
if DoesEntityExist(vehicle) then
SetEntityAsMissionEntity(vehicle, true, true)
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
SetVehicleNeedsToBeHotwired(vehicle, false)
SetVehicleOnGroundProperly(vehicle)
FreezeEntityPosition(vehicle, false)
-- Verhindere dass das Fahrzeug als "abandoned" markiert wird
DecorSetBool(vehicle, "IgnoredByQuickSave", false)
-- Setze Vehicle als persistent
SetEntityLoadCollisionFlag(vehicle, true)
end
end
-- Hauptloop für Fahrzeugtracking
CreateThread(function()
while true do
Wait(Config.SaveInterval)
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
-- Finde alle Fahrzeuge
local vehicles = GetGamePool('CVehicle')
for _, vehicle in pairs(vehicles) do
if DoesEntityExist(vehicle) and IsVehicleClassAllowed(vehicle) then
local plate = QBCore.Functions.GetPlate(vehicle)
local vehicleCoords = GetEntityCoords(vehicle)
-- Prüfe ob es ein Spielerfahrzeug ist (nicht NPC)
local isPlayerVehicle = false
local driver = GetPedInVehicleSeat(vehicle, -1)
if driver == 0 or IsPedAPlayer(driver) then
isPlayerVehicle = true
elseif trackedVehicles[plate] or spawnedVehicles[plate] then
-- Bereits getrackt = Spielerfahrzeug
isPlayerVehicle = true
end
if isPlayerVehicle then
-- Verhindere Despawn
PreventVehicleDespawn(vehicle)
-- Speichere Fahrzeugdaten
local vehicleData = {
plate = plate,
model = GetEntityModel(vehicle),
position = {x = vehicleCoords.x, y = vehicleCoords.y, z = vehicleCoords.z},
rotation = {x = 0.0, y = 0.0, z = GetEntityHeading(vehicle)},
engineHealth = GetVehicleEngineHealth(vehicle),
bodyHealth = GetVehicleBodyHealth(vehicle),
fuel = 100, -- Standardwert, anpassen je nach Fuel System
mods = GetVehicleMods(vehicle)
}
-- Versuche Fuel zu bekommen
if GetResourceState('LegacyFuel') == 'started' then
vehicleData.fuel = exports['LegacyFuel']:GetFuel(vehicle) or 100
elseif GetResourceState('ps-fuel') == 'started' then
vehicleData.fuel = exports['ps-fuel']:GetFuel(vehicle) or 100
end
TriggerServerEvent('vehicle-persistence:server:saveVehiclePosition', vehicleData)
trackedVehicles[plate] = vehicle
if Config.Debug then
local distance = #(playerCoords - vehicleCoords)
print(string.format("Tracking vehicle: %s (Model: %s) at distance: %.2f", plate, GetDisplayNameFromVehicleModel(GetEntityModel(vehicle)), distance))
end
end
end
end
-- Prüfe ob getrackte Fahrzeuge noch existieren
for plate, vehicle in pairs(trackedVehicles) do
if not DoesEntityExist(vehicle) then
trackedVehicles[plate] = nil
if Config.Debug then
print(string.format("Vehicle no longer exists, removed from tracking: %s", plate))
end
end
end
end
end)
-- Spawne gespeicherte Fahrzeuge
RegisterNetEvent('vehicle-persistence:client:spawnSavedVehicles', function(vehicles)
if Config.Debug then
print(string.format("Attempting to spawn %d saved vehicles", #vehicles))
end
for _, vehicleData in pairs(vehicles) do
local position = json.decode(vehicleData.position)
local rotation = json.decode(vehicleData.rotation)
-- Prüfe ob Fahrzeug bereits existiert
local existingVehicle = GetVehicleByPlate(vehicleData.plate)
if not existingVehicle then
CreateThread(function()
local modelHash = vehicleData.model
if type(modelHash) == "string" then
modelHash = GetHashKey(modelHash)
end
RequestModel(modelHash)
local timeout = 0
while not HasModelLoaded(modelHash) and timeout < 50 do
Wait(100)
timeout = timeout + 1
end
if HasModelLoaded(modelHash) then
local vehicle = CreateVehicle(modelHash, position.x, position.y, position.z, rotation.z, true, false)
if DoesEntityExist(vehicle) then
-- Warte bis Fahrzeug vollständig geladen ist
Wait(500)
-- Setze Fahrzeugdaten
SetVehicleNumberPlateText(vehicle, vehicleData.plate)
SetVehicleEngineHealth(vehicle, vehicleData.engine_health or 1000.0)
SetVehicleBodyHealth(vehicle, vehicleData.body_health or 1000.0)
-- Setze Fuel
if GetResourceState('LegacyFuel') == 'started' then
exports['LegacyFuel']:SetFuel(vehicle, vehicleData.fuel or 100)
elseif GetResourceState('ps-fuel') == 'started' then
exports['ps-fuel']:SetFuel(vehicle, vehicleData.fuel or 100)
end
-- Setze Mods
if vehicleData.mods then
local mods = json.decode(vehicleData.mods)
SetVehicleMods(vehicle, mods)
end
-- Verhindere Despawn
PreventVehicleDespawn(vehicle)
spawnedVehicles[vehicleData.plate] = vehicle
trackedVehicles[vehicleData.plate] = vehicle
if Config.Debug then
print(string.format("Successfully spawned saved vehicle: %s", vehicleData.plate))
end
else
if Config.Debug then
print(string.format("Failed to create vehicle: %s", vehicleData.plate))
end
end
SetModelAsNoLongerNeeded(modelHash)
else
if Config.Debug then
print(string.format("Failed to load model for vehicle: %s", vehicleData.plate))
end
end
end)
else
-- Fahrzeug existiert bereits, füge zu Tracking hinzu
trackedVehicles[vehicleData.plate] = existingVehicle
PreventVehicleDespawn(existingVehicle)
if Config.Debug then
print(string.format("Vehicle already exists, added to tracking: %s", vehicleData.plate))
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
-- Lade Fahrzeuge beim Spawn
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
Wait(10000) -- Längere Wartezeit bis alles geladen ist
TriggerServerEvent('vehicle-persistence:server:loadVehicles')
end)
-- Lade Fahrzeuge auch beim Resource Start
CreateThread(function()
Wait(15000) -- Warte bis Server vollständig geladen ist
if QBCore.Functions.GetPlayerData().citizenid then
TriggerServerEvent('vehicle-persistence:server:loadVehicles')
end
end)
-- jg-advanced-garage Events
RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data)
if data and data.plate then
if trackedVehicles[data.plate] then
trackedVehicles[data.plate] = nil
end
if spawnedVehicles[data.plate] then
spawnedVehicles[data.plate] = nil
end
if Config.Debug then
print(string.format("Vehicle stored in garage, removed from tracking: %s", data.plate))
end
end
end)
RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data)
if data and data.plate then
if trackedVehicles[data.plate] then
trackedVehicles[data.plate] = nil
end
if spawnedVehicles[data.plate] then
spawnedVehicles[data.plate] = nil
end
if Config.Debug then
print(string.format("Vehicle spawned from garage, removed from tracking: %s", data.plate))
end
end
end)
-- Kontinuierliche Despawn-Verhinderung
CreateThread(function()
while true do
Wait(30000) -- Alle 30 Sekunden
for plate, vehicle in pairs(trackedVehicles) do
if DoesEntityExist(vehicle) then
PreventVehicleDespawn(vehicle)
else
trackedVehicles[plate] = nil
spawnedVehicles[plate] = nil
end
end
end
end)
-- Cleanup beim Disconnect
AddEventHandler('onResourceStop', function(resourceName)
if resourceName == GetCurrentResourceName() then
trackedVehicles = {}
spawnedVehicles = {}
end
end)