1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-08-06 18:18:04 +02:00
parent d2b98317d3
commit b2c41ba5eb
4 changed files with 214 additions and 380 deletions

View file

@ -1,26 +1,44 @@
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
local function IsVehicleClassAllowed(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
if vehicleClass == allowedClass then
return true
end
end
return false
end
-- Stärkere Despawn-Verhinderung
-- Starke Anti-Despawn Funktion
local function PreventDespawn(vehicle)
if DoesEntityExist(vehicle) then
-- Grundlegende Persistenz
SetEntityAsMissionEntity(vehicle, true, true)
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
SetVehicleNeedsToBeHotwired(vehicle, false)
SetEntityLoadCollisionFlag(vehicle, true)
-- Zusätzliche Flags
SetEntityLoadCollisionFlag(vehicle, true)
SetVehicleIsStolen(vehicle, false)
SetVehicleIsWanted(vehicle, false)
@ -29,95 +47,11 @@ local function PreventDespawn(vehicle)
DecorSetBool(vehicle, "IgnoredByQuickSave", false)
end
-- Setze Fahrzeug auf Boden
SetVehicleOnGroundProperly(vehicle)
return true
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
-- Event Handler für Fahrzeug betreten (nur Fahrersitz)
CreateThread(function()
local lastVehicle = 0
@ -136,14 +70,19 @@ CreateThread(function()
-- Nur wenn Spieler der Fahrer ist (Seat -1)
if driver == playerPed and IsVehicleClassAllowed(currentVehicle) then
local plate = QBCore.Functions.GetPlate(currentVehicle)
playerDrivenVehicles[plate] = currentVehicle
trackedVehicles[plate] = currentVehicle
-- Sofort starke Despawn-Verhinderung
PreventDespawn(currentVehicle)
if Config.Debug then
print(string.format("Player started driving vehicle: %s", plate))
end
Debug("Fahrzeug wird nun getrackt: " .. plate)
-- 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
@ -156,96 +95,47 @@ CreateThread(function()
while true do
Wait(10000) -- Alle 10 Sekunden
for plate, vehicle in pairs(playerDrivenVehicles) do
for plate, vehicle in pairs(trackedVehicles) do
if DoesEntityExist(vehicle) then
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)
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
-- Aktualisiere Position
local vehicleCoords = GetEntityCoords(vehicle)
local vehicleHeading = GetEntityHeading(vehicle)
-- Verstärke Despawn-Schutz bei jedem Save
PreventDespawn(vehicle)
TriggerServerEvent('antidespawn:server:updateVehicle', plate, vehicleCoords, vehicleHeading)
-- 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,
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
Debug("Aktualisiere Fahrzeug: " .. plate)
else
-- Fahrzeug existiert nicht mehr, entferne aus Liste
playerDrivenVehicles[plate] = nil
if Config.Debug then
print(string.format("Player driven vehicle no longer exists: %s", plate))
end
trackedVehicles[plate] = nil
Debug("Fahrzeug existiert nicht mehr: " .. plate)
end
end
end
end)
-- Spawne gespeicherte Fahrzeuge
RegisterNetEvent('vehicle-persistence:client:spawnSavedVehicles', function(vehicles)
if Config.Debug then
print(string.format("Received %d vehicles to spawn", #vehicles))
end
-- Lade Fahrzeuge beim Spawn
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
Debug("Spieler geladen, lade Fahrzeuge...")
Wait(10000) -- Warte bis alles geladen ist
TriggerServerEvent('antidespawn:server:loadVehicles')
end)
for _, vehicleData in pairs(vehicles) do
if Config.Debug then
print(string.format("Processing vehicle: %s", vehicleData.plate))
end
local position = json.decode(vehicleData.position)
local rotation = json.decode(vehicleData.rotation)
-- Spawne ein Fahrzeug
RegisterNetEvent('antidespawn:client:spawnVehicle', function(data)
Debug("Spawne Fahrzeug: " .. data.plate)
-- 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)
local existingVehicle = GetVehicleByPlate(data.plate)
if existingVehicle then
Debug("Fahrzeug existiert bereits: " .. data.plate)
trackedVehicles[data.plate] = existingVehicle
PreventDespawn(existingVehicle)
return
end
if Config.Debug then
print(string.format("Requesting model: %s (Hash: %s)", vehicleData.model, modelHash))
end
-- Spawne Fahrzeug
local modelHash = data.model
RequestModel(modelHash)
local timeout = 0
@ -255,65 +145,31 @@ RegisterNetEvent('vehicle-persistence:client:spawnSavedVehicles', function(vehic
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)
local vehicle = CreateVehicle(modelHash, data.coords.x, data.coords.y, data.coords.z, data.heading, 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 Kennzeichen
SetVehicleNumberPlateText(vehicle, data.plate)
-- 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)
if GetResourceState(Config.FuelSystem) == 'started' then
exports[Config.FuelSystem]:SetFuel(vehicle, data.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
-- Verhindere Despawn
PreventDespawn(vehicle)
playerDrivenVehicles[vehicleData.plate] = vehicle
-- Füge zu getrackten Fahrzeugen hinzu
trackedVehicles[data.plate] = vehicle
if Config.Debug then
print(string.format("Successfully spawned saved vehicle: %s", vehicleData.plate))
end
Debug("Fahrzeug erfolgreich gespawnt: " .. data.plate)
else
if Config.Debug then
print(string.format("Failed to create vehicle: %s", vehicleData.plate))
end
Debug("Fehler beim Spawnen des Fahrzeugs: " .. data.plate)
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
Debug("Modell konnte nicht geladen werden: " .. data.plate)
end
end)
@ -328,65 +184,18 @@ function GetVehicleByPlate(plate)
return nil
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
RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data)
if data and data.plate and playerDrivenVehicles[data.plate] then
playerDrivenVehicles[data.plate] = nil
if Config.Debug then
print(string.format("Vehicle stored in garage, removed from tracking: %s", data.plate))
end
if data and data.plate and trackedVehicles[data.plate] then
trackedVehicles[data.plate] = nil
TriggerServerEvent('antidespawn:server:removeVehicle', data.plate)
Debug("Fahrzeug in Garage gespeichert, entferne aus Tracking: " .. data.plate)
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
AddEventHandler('onResourceStop', function(resourceName)
if resourceName == GetCurrentResourceName() then
playerDrivenVehicles = {}
trackedVehicles = {}
end
end)

View file

@ -1,13 +1,13 @@
Config = {}
-- Debug Modus
Config.Debug = true
-- Speicherintervall in Millisekunden (5000 = 5 Sekunden)
Config.SaveInterval = 5000
-- Maximale Distanz zum Fahrzeug bevor es als "verlassen" gilt
Config.MaxDistance = 1.0
-- Debug Modus
Config.Debug = true
-- Fuel System
Config.FuelSystem = "LegacyFuel" -- Anpassen an dein Fuel System
-- Fahrzeugklassen die gespeichert werden sollen
Config.AllowedVehicleClasses = {
@ -36,5 +36,7 @@ Config.AllowedVehicleClasses = {
22, -- Open Wheel
}
-- Mindestdistanz zu Garagen um Fahrzeuge zu tracken
Config.MinGarageDistance = 0.0
-- Blacklisted vehicle classes
Config.BlacklistedVehicleClasses = {
-- 21, -- Trains
}

View file

@ -2,7 +2,7 @@ fx_version 'cerulean'
game 'gta5'
author 'YourName'
description 'Vehicle Persistence System for jg-advanced-garage'
description 'Vehicle Anti-Despawn System for QB-Core'
version '1.0.0'
shared_scripts {
@ -15,11 +15,11 @@ server_scripts {
}
client_scripts {
'config.lua',
'client/main.lua'
}
dependencies {
'qb-core',
'jg-advancedgarages',
'oxmysql'
'jg-advancedgarages'
}

View file

@ -1,85 +1,131 @@
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
CreateThread(function()
MySQL.query([[
CREATE TABLE IF NOT EXISTS `vehicle_positions` (
CREATE TABLE IF NOT EXISTS `vehicle_antidespawn` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`plate` varchar(50) NOT NULL,
`citizenid` varchar(50) NOT NULL,
`model` varchar(50) NOT NULL,
`position` longtext NOT NULL,
`rotation` longtext NOT NULL,
`engine_health` float DEFAULT 1000.0,
`body_health` float DEFAULT 1000.0,
`coords` longtext NOT NULL,
`heading` float NOT NULL,
`fuel` int(11) DEFAULT 100,
`mods` longtext DEFAULT NULL,
`last_updated` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `plate` (`plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
]])
end)
-- Speichere Fahrzeugposition
RegisterNetEvent('vehicle-persistence:server:saveVehiclePosition', function(vehicleData)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
Debug("Datenbank initialisiert")
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 = [[
INSERT INTO vehicle_positions (plate, citizenid, model, position, rotation, engine_health, body_health, fuel, mods)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
position = VALUES(position),
rotation = VALUES(rotation),
engine_health = VALUES(engine_health),
body_health = VALUES(body_health),
fuel = VALUES(fuel),
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))
for _, vehicle in pairs(results) do
vehicles[vehicle.plate] = {
model = vehicle.model,
coords = json.decode(vehicle.coords),
heading = vehicle.heading,
fuel = vehicle.fuel,
last_updated = vehicle.last_updated
}
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)
-- Entferne Fahrzeug aus Datenbank
RegisterNetEvent('vehicle-persistence:server:removeVehicle', function(plate)
MySQL.execute('DELETE FROM vehicle_positions WHERE plate = ?', {plate})
-- Registriere ein Fahrzeug
RegisterNetEvent('antidespawn:server:registerVehicle', function(plate, model, coords, heading)
local src = source
if Config.Debug then
print(string.format("Removed vehicle from persistence: %s", plate))
if not plate or not model or not coords then
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)
@ -87,30 +133,7 @@ end)
CreateThread(function()
while true do
Wait(3600000) -- 1 Stunde
MySQL.execute('DELETE FROM vehicle_positions WHERE last_updated < DATE_SUB(NOW(), INTERVAL 24 HOUR)')
if Config.Debug then
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
MySQL.query("DELETE FROM vehicle_antidespawn WHERE last_updated < DATE_SUB(NOW(), INTERVAL 24 HOUR)")
Debug("Alte Fahrzeugeinträge bereinigt")
end
end)