forked from Simnation/Main
ed
This commit is contained in:
parent
d2b98317d3
commit
b2c41ba5eb
4 changed files with 214 additions and 380 deletions
|
@ -1,26 +1,44 @@
|
||||||
local QBCore = exports['qb-core']:GetCoreObject()
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
local playerDrivenVehicles = {} -- Nur Fahrzeuge die der Spieler gefahren hat
|
local trackedVehicles = {}
|
||||||
|
|
||||||
|
-- Debug Funktion
|
||||||
|
local function Debug(msg)
|
||||||
|
if Config.Debug then
|
||||||
|
print("[AntiDespawn] " .. msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Funktion um zu prüfen ob Fahrzeugklasse erlaubt ist
|
-- Funktion um zu prüfen ob Fahrzeugklasse erlaubt ist
|
||||||
local function IsVehicleClassAllowed(vehicle)
|
local function IsVehicleClassAllowed(vehicle)
|
||||||
local vehicleClass = GetVehicleClass(vehicle)
|
local vehicleClass = GetVehicleClass(vehicle)
|
||||||
|
|
||||||
|
-- Prüfe Blacklist
|
||||||
|
for _, blacklistedClass in pairs(Config.BlacklistedVehicleClasses) do
|
||||||
|
if vehicleClass == blacklistedClass then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Prüfe Whitelist
|
||||||
for _, allowedClass in pairs(Config.AllowedVehicleClasses) do
|
for _, allowedClass in pairs(Config.AllowedVehicleClasses) do
|
||||||
if vehicleClass == allowedClass then
|
if vehicleClass == allowedClass then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Stärkere Despawn-Verhinderung
|
-- Starke Anti-Despawn Funktion
|
||||||
local function PreventDespawn(vehicle)
|
local function PreventDespawn(vehicle)
|
||||||
if DoesEntityExist(vehicle) then
|
if DoesEntityExist(vehicle) then
|
||||||
|
-- Grundlegende Persistenz
|
||||||
SetEntityAsMissionEntity(vehicle, true, true)
|
SetEntityAsMissionEntity(vehicle, true, true)
|
||||||
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
|
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
|
||||||
SetVehicleNeedsToBeHotwired(vehicle, false)
|
SetVehicleNeedsToBeHotwired(vehicle, false)
|
||||||
SetEntityLoadCollisionFlag(vehicle, true)
|
|
||||||
|
|
||||||
-- Zusätzliche Flags
|
-- Zusätzliche Flags
|
||||||
|
SetEntityLoadCollisionFlag(vehicle, true)
|
||||||
SetVehicleIsStolen(vehicle, false)
|
SetVehicleIsStolen(vehicle, false)
|
||||||
SetVehicleIsWanted(vehicle, false)
|
SetVehicleIsWanted(vehicle, false)
|
||||||
|
|
||||||
|
@ -29,95 +47,11 @@ local function PreventDespawn(vehicle)
|
||||||
DecorSetBool(vehicle, "IgnoredByQuickSave", false)
|
DecorSetBool(vehicle, "IgnoredByQuickSave", false)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Setze Fahrzeug auf Boden
|
|
||||||
SetVehicleOnGroundProperly(vehicle)
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
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
|
|
||||||
|
|
||||||
-- Event Handler für Fahrzeug betreten (nur Fahrersitz)
|
-- Event Handler für Fahrzeug betreten (nur Fahrersitz)
|
||||||
CreateThread(function()
|
CreateThread(function()
|
||||||
local lastVehicle = 0
|
local lastVehicle = 0
|
||||||
|
@ -136,14 +70,19 @@ CreateThread(function()
|
||||||
-- Nur wenn Spieler der Fahrer ist (Seat -1)
|
-- Nur wenn Spieler der Fahrer ist (Seat -1)
|
||||||
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)
|
||||||
playerDrivenVehicles[plate] = currentVehicle
|
trackedVehicles[plate] = currentVehicle
|
||||||
|
|
||||||
-- Sofort starke Despawn-Verhinderung
|
-- Sofort starke Despawn-Verhinderung
|
||||||
PreventDespawn(currentVehicle)
|
PreventDespawn(currentVehicle)
|
||||||
|
|
||||||
if Config.Debug then
|
Debug("Fahrzeug wird nun getrackt: " .. plate)
|
||||||
print(string.format("Player started driving vehicle: %s", plate))
|
|
||||||
end
|
-- Registriere Fahrzeug beim Server
|
||||||
|
local vehicleCoords = GetEntityCoords(currentVehicle)
|
||||||
|
local vehicleHeading = GetEntityHeading(currentVehicle)
|
||||||
|
local vehicleModel = GetEntityModel(currentVehicle)
|
||||||
|
|
||||||
|
TriggerServerEvent('antidespawn:server:registerVehicle', plate, vehicleModel, vehicleCoords, vehicleHeading)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,164 +95,81 @@ CreateThread(function()
|
||||||
while true do
|
while true do
|
||||||
Wait(10000) -- Alle 10 Sekunden
|
Wait(10000) -- Alle 10 Sekunden
|
||||||
|
|
||||||
for plate, vehicle in pairs(playerDrivenVehicles) do
|
for plate, vehicle in pairs(trackedVehicles) do
|
||||||
if DoesEntityExist(vehicle) then
|
if DoesEntityExist(vehicle) then
|
||||||
PreventDespawn(vehicle)
|
PreventDespawn(vehicle)
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Refreshing despawn protection for: %s", plate))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
playerDrivenVehicles[plate] = nil
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Player driven vehicle no longer exists: %s", plate))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Hauptloop für Fahrzeugtracking (nur für vom Spieler gefahrene Fahrzeuge)
|
-- Aktualisiere Position
|
||||||
CreateThread(function()
|
|
||||||
while true do
|
|
||||||
Wait(Config.SaveInterval)
|
|
||||||
|
|
||||||
-- Tracke nur Fahrzeuge die der Spieler gefahren hat
|
|
||||||
for plate, vehicle in pairs(playerDrivenVehicles) do
|
|
||||||
if DoesEntityExist(vehicle) then
|
|
||||||
local vehicleCoords = GetEntityCoords(vehicle)
|
local vehicleCoords = GetEntityCoords(vehicle)
|
||||||
|
local vehicleHeading = GetEntityHeading(vehicle)
|
||||||
|
|
||||||
-- Verstärke Despawn-Schutz bei jedem Save
|
TriggerServerEvent('antidespawn:server:updateVehicle', plate, vehicleCoords, vehicleHeading)
|
||||||
PreventDespawn(vehicle)
|
|
||||||
|
|
||||||
-- Speichere Fahrzeugdaten
|
Debug("Aktualisiere Fahrzeug: " .. plate)
|
||||||
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,
|
|
||||||
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)
|
|
||||||
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Saving player driven vehicle: %s", plate))
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
-- Fahrzeug existiert nicht mehr, entferne aus Liste
|
trackedVehicles[plate] = nil
|
||||||
playerDrivenVehicles[plate] = nil
|
Debug("Fahrzeug existiert nicht mehr: " .. plate)
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Player driven vehicle no longer exists: %s", plate))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Spawne gespeicherte Fahrzeuge
|
-- Lade Fahrzeuge beim Spawn
|
||||||
RegisterNetEvent('vehicle-persistence:client:spawnSavedVehicles', function(vehicles)
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
||||||
if Config.Debug then
|
Debug("Spieler geladen, lade Fahrzeuge...")
|
||||||
print(string.format("Received %d vehicles to spawn", #vehicles))
|
Wait(10000) -- Warte bis alles geladen ist
|
||||||
|
TriggerServerEvent('antidespawn:server:loadVehicles')
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Spawne ein Fahrzeug
|
||||||
|
RegisterNetEvent('antidespawn:client:spawnVehicle', function(data)
|
||||||
|
Debug("Spawne Fahrzeug: " .. data.plate)
|
||||||
|
|
||||||
|
-- Prüfe ob Fahrzeug bereits existiert
|
||||||
|
local existingVehicle = GetVehicleByPlate(data.plate)
|
||||||
|
if existingVehicle then
|
||||||
|
Debug("Fahrzeug existiert bereits: " .. data.plate)
|
||||||
|
trackedVehicles[data.plate] = existingVehicle
|
||||||
|
PreventDespawn(existingVehicle)
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, vehicleData in pairs(vehicles) do
|
-- Spawne Fahrzeug
|
||||||
if Config.Debug then
|
local modelHash = data.model
|
||||||
print(string.format("Processing vehicle: %s", vehicleData.plate))
|
|
||||||
end
|
|
||||||
|
|
||||||
local position = json.decode(vehicleData.position)
|
RequestModel(modelHash)
|
||||||
local rotation = json.decode(vehicleData.rotation)
|
local timeout = 0
|
||||||
|
while not HasModelLoaded(modelHash) and timeout < 100 do
|
||||||
|
Wait(100)
|
||||||
|
timeout = timeout + 1
|
||||||
|
end
|
||||||
|
|
||||||
-- Prüfe ob Fahrzeug bereits existiert
|
if HasModelLoaded(modelHash) then
|
||||||
local existingVehicle = GetVehicleByPlate(vehicleData.plate)
|
local vehicle = CreateVehicle(modelHash, data.coords.x, data.coords.y, data.coords.z, data.heading, true, false)
|
||||||
if not existingVehicle then
|
|
||||||
CreateThread(function()
|
|
||||||
local modelHash = vehicleData.model
|
|
||||||
if type(modelHash) == "string" then
|
|
||||||
modelHash = GetHashKey(modelHash)
|
|
||||||
end
|
|
||||||
|
|
||||||
if Config.Debug then
|
if DoesEntityExist(vehicle) then
|
||||||
print(string.format("Requesting model: %s (Hash: %s)", vehicleData.model, modelHash))
|
-- Setze Kennzeichen
|
||||||
end
|
SetVehicleNumberPlateText(vehicle, data.plate)
|
||||||
|
|
||||||
RequestModel(modelHash)
|
-- Setze Fuel
|
||||||
local timeout = 0
|
if GetResourceState(Config.FuelSystem) == 'started' then
|
||||||
while not HasModelLoaded(modelHash) and timeout < 100 do
|
exports[Config.FuelSystem]:SetFuel(vehicle, data.fuel or 100)
|
||||||
Wait(100)
|
|
||||||
timeout = timeout + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if HasModelLoaded(modelHash) then
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Model loaded, creating vehicle at: %.2f, %.2f, %.2f", position.x, position.y, position.z))
|
|
||||||
end
|
|
||||||
|
|
||||||
local vehicle = CreateVehicle(modelHash, position.x, position.y, position.z, rotation.z, true, false)
|
|
||||||
|
|
||||||
if DoesEntityExist(vehicle) then
|
|
||||||
Wait(1000) -- Warte bis Fahrzeug vollständig geladen
|
|
||||||
|
|
||||||
-- 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 success, mods = pcall(json.decode, vehicleData.mods)
|
|
||||||
if success then
|
|
||||||
SetVehicleMods(vehicle, mods)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Starke Despawn-Verhinderung
|
|
||||||
PreventDespawn(vehicle)
|
|
||||||
|
|
||||||
playerDrivenVehicles[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 Liste hinzu
|
|
||||||
playerDrivenVehicles[vehicleData.plate] = existingVehicle
|
|
||||||
PreventDespawn(existingVehicle)
|
|
||||||
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Vehicle already exists: %s", vehicleData.plate))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Verhindere Despawn
|
||||||
|
PreventDespawn(vehicle)
|
||||||
|
|
||||||
|
-- Füge zu getrackten Fahrzeugen hinzu
|
||||||
|
trackedVehicles[data.plate] = vehicle
|
||||||
|
|
||||||
|
Debug("Fahrzeug erfolgreich gespawnt: " .. data.plate)
|
||||||
|
else
|
||||||
|
Debug("Fehler beim Spawnen des Fahrzeugs: " .. data.plate)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
SetModelAsNoLongerNeeded(modelHash)
|
||||||
|
else
|
||||||
|
Debug("Modell konnte nicht geladen werden: " .. data.plate)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -328,65 +184,18 @@ function GetVehicleByPlate(plate)
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Lade Fahrzeuge beim Spawn
|
|
||||||
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
|
||||||
if Config.Debug then
|
|
||||||
print("Player loaded, waiting before loading vehicles...")
|
|
||||||
end
|
|
||||||
|
|
||||||
Wait(15000)
|
|
||||||
|
|
||||||
if Config.Debug then
|
|
||||||
print("Loading vehicles...")
|
|
||||||
end
|
|
||||||
|
|
||||||
TriggerServerEvent('vehicle-persistence:server:loadVehicles')
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Lade Fahrzeuge auch beim Resource Start
|
|
||||||
CreateThread(function()
|
|
||||||
Wait(20000)
|
|
||||||
|
|
||||||
local playerData = QBCore.Functions.GetPlayerData()
|
|
||||||
if playerData and playerData.citizenid then
|
|
||||||
if Config.Debug then
|
|
||||||
print("Resource started, loading vehicles for existing player...")
|
|
||||||
end
|
|
||||||
TriggerServerEvent('vehicle-persistence:server:loadVehicles')
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- jg-advanced-garage Events
|
-- jg-advanced-garage Events
|
||||||
RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data)
|
RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data)
|
||||||
if data and data.plate and playerDrivenVehicles[data.plate] then
|
if data and data.plate and trackedVehicles[data.plate] then
|
||||||
playerDrivenVehicles[data.plate] = nil
|
trackedVehicles[data.plate] = nil
|
||||||
if Config.Debug then
|
TriggerServerEvent('antidespawn:server:removeVehicle', data.plate)
|
||||||
print(string.format("Vehicle stored in garage, removed from tracking: %s", data.plate))
|
Debug("Fahrzeug in Garage gespeichert, entferne aus Tracking: " .. data.plate)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data)
|
|
||||||
if data and data.plate and playerDrivenVehicles[data.plate] then
|
|
||||||
playerDrivenVehicles[data.plate] = nil
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Vehicle spawned from garage, removed from tracking: %s", data.plate))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Debug Command
|
|
||||||
RegisterCommand('loadvehicles', function()
|
|
||||||
if Config.Debug then
|
|
||||||
print("Manual vehicle load triggered...")
|
|
||||||
TriggerServerEvent('vehicle-persistence:server:loadVehicles')
|
|
||||||
end
|
|
||||||
end, false)
|
|
||||||
|
|
||||||
-- Cleanup beim Disconnect
|
-- Cleanup beim Disconnect
|
||||||
AddEventHandler('onResourceStop', function(resourceName)
|
AddEventHandler('onResourceStop', function(resourceName)
|
||||||
if resourceName == GetCurrentResourceName() then
|
if resourceName == GetCurrentResourceName() then
|
||||||
playerDrivenVehicles = {}
|
trackedVehicles = {}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
Config = {}
|
Config = {}
|
||||||
|
|
||||||
|
-- Debug Modus
|
||||||
|
Config.Debug = true
|
||||||
|
|
||||||
-- Speicherintervall in Millisekunden (5000 = 5 Sekunden)
|
-- Speicherintervall in Millisekunden (5000 = 5 Sekunden)
|
||||||
Config.SaveInterval = 5000
|
Config.SaveInterval = 5000
|
||||||
|
|
||||||
-- Maximale Distanz zum Fahrzeug bevor es als "verlassen" gilt
|
-- Fuel System
|
||||||
Config.MaxDistance = 1.0
|
Config.FuelSystem = "LegacyFuel" -- Anpassen an dein Fuel System
|
||||||
|
|
||||||
-- Debug Modus
|
|
||||||
Config.Debug = true
|
|
||||||
|
|
||||||
-- Fahrzeugklassen die gespeichert werden sollen
|
-- Fahrzeugklassen die gespeichert werden sollen
|
||||||
Config.AllowedVehicleClasses = {
|
Config.AllowedVehicleClasses = {
|
||||||
|
@ -36,5 +36,7 @@ Config.AllowedVehicleClasses = {
|
||||||
22, -- Open Wheel
|
22, -- Open Wheel
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Mindestdistanz zu Garagen um Fahrzeuge zu tracken
|
-- Blacklisted vehicle classes
|
||||||
Config.MinGarageDistance = 0.0
|
Config.BlacklistedVehicleClasses = {
|
||||||
|
-- 21, -- Trains
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ fx_version 'cerulean'
|
||||||
game 'gta5'
|
game 'gta5'
|
||||||
|
|
||||||
author 'YourName'
|
author 'YourName'
|
||||||
description 'Vehicle Persistence System for jg-advanced-garage'
|
description 'Vehicle Anti-Despawn System for QB-Core'
|
||||||
version '1.0.0'
|
version '1.0.0'
|
||||||
|
|
||||||
shared_scripts {
|
shared_scripts {
|
||||||
|
@ -15,11 +15,11 @@ server_scripts {
|
||||||
}
|
}
|
||||||
|
|
||||||
client_scripts {
|
client_scripts {
|
||||||
|
'config.lua',
|
||||||
'client/main.lua'
|
'client/main.lua'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
'qb-core',
|
'qb-core',
|
||||||
'jg-advancedgarages',
|
'jg-advancedgarages'
|
||||||
'oxmysql'
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,85 +1,131 @@
|
||||||
local QBCore = exports['qb-core']:GetCoreObject()
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
local vehicles = {}
|
||||||
|
|
||||||
|
-- Debug Funktion
|
||||||
|
local function Debug(msg)
|
||||||
|
if Config.Debug then
|
||||||
|
print("[AntiDespawn] " .. msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Erstelle Tabelle bei Serverstart
|
-- Erstelle Tabelle bei Serverstart
|
||||||
CreateThread(function()
|
CreateThread(function()
|
||||||
MySQL.query([[
|
MySQL.query([[
|
||||||
CREATE TABLE IF NOT EXISTS `vehicle_positions` (
|
CREATE TABLE IF NOT EXISTS `vehicle_antidespawn` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`plate` varchar(50) NOT NULL,
|
`plate` varchar(50) NOT NULL,
|
||||||
`citizenid` varchar(50) NOT NULL,
|
|
||||||
`model` varchar(50) NOT NULL,
|
`model` varchar(50) NOT NULL,
|
||||||
`position` longtext NOT NULL,
|
`coords` longtext NOT NULL,
|
||||||
`rotation` longtext NOT NULL,
|
`heading` float NOT NULL,
|
||||||
`engine_health` float DEFAULT 1000.0,
|
|
||||||
`body_health` float DEFAULT 1000.0,
|
|
||||||
`fuel` int(11) DEFAULT 100,
|
`fuel` int(11) DEFAULT 100,
|
||||||
`mods` longtext DEFAULT NULL,
|
|
||||||
`last_updated` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`last_updated` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `plate` (`plate`)
|
UNIQUE KEY `plate` (`plate`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
]])
|
]])
|
||||||
end)
|
|
||||||
|
|
||||||
-- Speichere Fahrzeugposition
|
Debug("Datenbank initialisiert")
|
||||||
RegisterNetEvent('vehicle-persistence:server:saveVehiclePosition', function(vehicleData)
|
|
||||||
local src = source
|
|
||||||
local Player = QBCore.Functions.GetPlayer(src)
|
|
||||||
|
|
||||||
if not Player then return end
|
-- Lade alle Fahrzeuge aus der Datenbank
|
||||||
|
MySQL.query("SELECT * FROM vehicle_antidespawn", {}, function(results)
|
||||||
|
if results and #results > 0 then
|
||||||
|
Debug("Lade " .. #results .. " Fahrzeuge aus der Datenbank")
|
||||||
|
|
||||||
local query = [[
|
for _, vehicle in pairs(results) do
|
||||||
INSERT INTO vehicle_positions (plate, citizenid, model, position, rotation, engine_health, body_health, fuel, mods)
|
vehicles[vehicle.plate] = {
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
model = vehicle.model,
|
||||||
ON DUPLICATE KEY UPDATE
|
coords = json.decode(vehicle.coords),
|
||||||
position = VALUES(position),
|
heading = vehicle.heading,
|
||||||
rotation = VALUES(rotation),
|
fuel = vehicle.fuel,
|
||||||
engine_health = VALUES(engine_health),
|
last_updated = vehicle.last_updated
|
||||||
body_health = VALUES(body_health),
|
}
|
||||||
fuel = VALUES(fuel),
|
end
|
||||||
mods = VALUES(mods),
|
|
||||||
last_updated = CURRENT_TIMESTAMP
|
|
||||||
]]
|
|
||||||
|
|
||||||
MySQL.insert(query, {
|
|
||||||
vehicleData.plate,
|
|
||||||
Player.PlayerData.citizenid,
|
|
||||||
vehicleData.model,
|
|
||||||
json.encode(vehicleData.position),
|
|
||||||
json.encode(vehicleData.rotation),
|
|
||||||
vehicleData.engineHealth,
|
|
||||||
vehicleData.bodyHealth,
|
|
||||||
vehicleData.fuel,
|
|
||||||
json.encode(vehicleData.mods)
|
|
||||||
})
|
|
||||||
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Saved vehicle position for plate: %s", vehicleData.plate))
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Lade gespeicherte Fahrzeuge beim Serverstart
|
|
||||||
RegisterNetEvent('vehicle-persistence:server:loadVehicles', function()
|
|
||||||
local src = source
|
|
||||||
local Player = QBCore.Functions.GetPlayer(src)
|
|
||||||
|
|
||||||
if not Player then return end
|
|
||||||
|
|
||||||
MySQL.query('SELECT * FROM vehicle_positions WHERE citizenid = ?', {
|
|
||||||
Player.PlayerData.citizenid
|
|
||||||
}, function(result)
|
|
||||||
if result and #result > 0 then
|
|
||||||
TriggerClientEvent('vehicle-persistence:client:spawnSavedVehicles', src, result)
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Entferne Fahrzeug aus Datenbank
|
-- Registriere ein Fahrzeug
|
||||||
RegisterNetEvent('vehicle-persistence:server:removeVehicle', function(plate)
|
RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, coords, heading)
|
||||||
MySQL.execute('DELETE FROM vehicle_positions WHERE plate = ?', {plate})
|
local src = source
|
||||||
|
|
||||||
if Config.Debug then
|
if not plate or not model or not coords then
|
||||||
print(string.format("Removed vehicle from persistence: %s", plate))
|
Debug("Ungültige Daten beim Registrieren eines Fahrzeugs")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vehicles[plate] = {
|
||||||
|
model = model,
|
||||||
|
coords = coords,
|
||||||
|
heading = heading,
|
||||||
|
fuel = 100,
|
||||||
|
last_updated = os.time()
|
||||||
|
}
|
||||||
|
|
||||||
|
MySQL.query("INSERT INTO vehicle_antidespawn (plate, model, coords, heading, fuel) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE coords = VALUES(coords), heading = VALUES(heading), last_updated = CURRENT_TIMESTAMP", {
|
||||||
|
plate,
|
||||||
|
model,
|
||||||
|
json.encode(coords),
|
||||||
|
heading,
|
||||||
|
100
|
||||||
|
})
|
||||||
|
|
||||||
|
Debug("Fahrzeug registriert: " .. plate)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Aktualisiere ein Fahrzeug
|
||||||
|
RegisterNetEvent('antidespawn:server:updateVehicle', function(plate, coords, heading)
|
||||||
|
if not vehicles[plate] then return end
|
||||||
|
|
||||||
|
vehicles[plate].coords = coords
|
||||||
|
vehicles[plate].heading = heading
|
||||||
|
vehicles[plate].last_updated = os.time()
|
||||||
|
|
||||||
|
MySQL.query("UPDATE vehicle_antidespawn SET coords = ?, heading = ?, last_updated = CURRENT_TIMESTAMP WHERE plate = ?", {
|
||||||
|
json.encode(coords),
|
||||||
|
heading,
|
||||||
|
plate
|
||||||
|
})
|
||||||
|
|
||||||
|
Debug("Fahrzeug aktualisiert: " .. plate)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Entferne ein Fahrzeug
|
||||||
|
RegisterNetEvent('antidespawn:server:removeVehicle', function(plate)
|
||||||
|
if not vehicles[plate] then return end
|
||||||
|
|
||||||
|
vehicles[plate] = nil
|
||||||
|
|
||||||
|
MySQL.query("DELETE FROM vehicle_antidespawn WHERE plate = ?", {
|
||||||
|
plate
|
||||||
|
})
|
||||||
|
|
||||||
|
Debug("Fahrzeug entfernt: " .. plate)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Lade Fahrzeuge für einen Spieler
|
||||||
|
RegisterNetEvent('antidespawn:server:loadVehicles', function()
|
||||||
|
local src = source
|
||||||
|
local Player = QBCore.Functions.GetPlayer(src)
|
||||||
|
|
||||||
|
if not Player then return end
|
||||||
|
|
||||||
|
local playerCoords = GetEntityCoords(GetPlayerPed(src))
|
||||||
|
|
||||||
|
-- Lade nur Fahrzeuge in der Nähe des Spielers
|
||||||
|
for plate, vehicle in pairs(vehicles) do
|
||||||
|
local distance = #(playerCoords - vector3(vehicle.coords.x, vehicle.coords.y, vehicle.coords.z))
|
||||||
|
|
||||||
|
if distance < 100.0 then
|
||||||
|
TriggerClientEvent('antidespawn:client:spawnVehicle', src, {
|
||||||
|
plate = plate,
|
||||||
|
model = vehicle.model,
|
||||||
|
coords = vehicle.coords,
|
||||||
|
heading = vehicle.heading,
|
||||||
|
fuel = vehicle.fuel
|
||||||
|
})
|
||||||
|
|
||||||
|
Debug("Fahrzeug für Spieler geladen: " .. plate)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -87,30 +133,7 @@ end)
|
||||||
CreateThread(function()
|
CreateThread(function()
|
||||||
while true do
|
while true do
|
||||||
Wait(3600000) -- 1 Stunde
|
Wait(3600000) -- 1 Stunde
|
||||||
MySQL.execute('DELETE FROM vehicle_positions WHERE last_updated < DATE_SUB(NOW(), INTERVAL 24 HOUR)')
|
MySQL.query("DELETE FROM vehicle_antidespawn WHERE last_updated < DATE_SUB(NOW(), INTERVAL 24 HOUR)")
|
||||||
if Config.Debug then
|
Debug("Alte Fahrzeugeinträge bereinigt")
|
||||||
print("Cleaned up old vehicle positions")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- jg-advanced-garage Events
|
|
||||||
RegisterNetEvent('jg-advancedgarages:server:vehicle-stored', function(data)
|
|
||||||
-- Entferne Fahrzeug aus Persistence wenn es in Garage gespeichert wird
|
|
||||||
if data and data.plate then
|
|
||||||
TriggerEvent('vehicle-persistence:server:removeVehicle', data.plate)
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Vehicle stored in garage, removed from persistence: %s", data.plate))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
RegisterNetEvent('jg-advancedgarages:server:vehicle-spawned', function(data)
|
|
||||||
-- Entferne aus Persistence da Fahrzeug jetzt über Garage gespawnt wurde
|
|
||||||
if data and data.plate then
|
|
||||||
TriggerEvent('vehicle-persistence:server:removeVehicle', data.plate)
|
|
||||||
if Config.Debug then
|
|
||||||
print(string.format("Vehicle spawned from garage, removed from persistence: %s", data.plate))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue