diff --git a/resources/[carscripts]/nordi_antidespawn/client/main.lua b/resources/[carscripts]/nordi_antidespawn/client/main.lua new file mode 100644 index 000000000..4e9f1cc51 --- /dev/null +++ b/resources/[carscripts]/nordi_antidespawn/client/main.lua @@ -0,0 +1,260 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local trackedVehicles = {} +local playerVehicles = {} + +-- 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 + +-- Prüfe ob Fahrzeug einem Spieler gehört +local function DoesVehicleBelongToPlayer(plate) + -- Verwende jg-advanced-garage Export + local vehicleData = exports['jg-advancedgarages']:GetVehicleByPlate(plate) + return vehicleData ~= nil +end + +-- Hauptloop für Fahrzeugtracking +CreateThread(function() + while true do + Wait(Config.SaveInterval) + + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + + -- Finde alle Fahrzeuge in der Nähe + 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) + local distance = #(playerCoords - vehicleCoords) + + -- Prüfe ob Fahrzeug einem Spieler gehört + if DoesVehicleBelongToPlayer(plate) then + -- Prüfe ob Fahrzeug nicht zu nah an einer Garage ist + local nearGarage = exports['jg-advancedgarages']:IsNearGarage(vehicleCoords, Config.MinGarageDistance) + + if not nearGarage then + -- Speichere Fahrzeugdaten + local vehicleData = { + plate = plate, + model = GetDisplayNameFromVehicleModel(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 = exports['LegacyFuel']:GetFuel(vehicle) or 100, -- Anpassen je nach Fuel System + mods = GetVehicleMods(vehicle) + } + + TriggerServerEvent('vehicle-persistence:server:saveVehiclePosition', vehicleData) + trackedVehicles[plate] = vehicle + + -- Verhindere Despawn + SetEntityAsMissionEntity(vehicle, true, true) + SetVehicleHasBeenOwnedByPlayer(vehicle, true) + + if Config.Debug then + print(string.format("Tracking vehicle: %s at distance: %.2f", plate, distance)) + end + end + end + end + end + end +end) + +-- Spawne gespeicherte Fahrzeuge +RegisterNetEvent('vehicle-persistence:client:spawnSavedVehicles', function(vehicles) + 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 + -- Prüfe ob Position nicht in einer Garage ist + local nearGarage = exports['jg-advancedgarages']:IsNearGarage(vector3(position.x, position.y, position.z), Config.MinGarageDistance) + + if not nearGarage then + -- Spawne Fahrzeug + local modelHash = GetHashKey(vehicleData.model) + + RequestModel(modelHash) + while not HasModelLoaded(modelHash) do + Wait(100) + end + + local vehicle = CreateVehicle(modelHash, position.x, position.y, position.z, rotation.z, true, false) + + if DoesEntityExist(vehicle) then + -- Setze Fahrzeugdaten + SetVehicleNumberPlateText(vehicle, vehicleData.plate) + SetVehicleEngineHealth(vehicle, vehicleData.engine_health) + SetVehicleBodyHealth(vehicle, vehicleData.body_health) + + -- Setze Fuel (anpassen je nach System) + if exports['LegacyFuel'] then + exports['LegacyFuel']:SetFuel(vehicle, vehicleData.fuel) + end + + -- Setze Mods + if vehicleData.mods then + local mods = json.decode(vehicleData.mods) + SetVehicleMods(vehicle, mods) + end + + -- Verhindere Despawn + SetEntityAsMissionEntity(vehicle, true, true) + SetVehicleHasBeenOwnedByPlayer(vehicle, true) + + trackedVehicles[vehicleData.plate] = vehicle + + if Config.Debug then + print(string.format("Spawned saved vehicle: %s", vehicleData.plate)) + end + end + + SetModelAsNoLongerNeeded(modelHash) + else + -- Entferne aus Datenbank da es zu nah an einer Garage ist + TriggerServerEvent('vehicle-persistence:server:removeVehicle', 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(5000) -- Warte bis alles geladen ist + TriggerServerEvent('vehicle-persistence:server:loadVehicles') +end) + +-- jg-advanced-garage Events +RegisterNetEvent('jg-advancedgarages:client:vehicle-stored', function(data) + -- Entferne aus Tracking wenn Fahrzeug gespeichert wird + if data and data.plate and trackedVehicles[data.plate] then + trackedVehicles[data.plate] = nil + if Config.Debug then + print(string.format("Vehicle stored, removed from tracking: %s", data.plate)) + end + end +end) + +RegisterNetEvent('jg-advancedgarages:client:vehicle-spawned', function(data) + -- Entferne aus Tracking da Fahrzeug jetzt über Garage gespawnt wurde + if data and data.plate and trackedVehicles[data.plate] then + trackedVehicles[data.plate] = nil + if Config.Debug then + print(string.format("Vehicle spawned from garage, removed from tracking: %s", data.plate)) + end + end +end) + +-- Cleanup beim Disconnect +AddEventHandler('onResourceStop', function(resourceName) + if resourceName == GetCurrentResourceName() then + -- Cleanup Code hier falls nötig + trackedVehicles = {} + end +end) diff --git a/resources/[carscripts]/nordi_antidespawn/config.lua b/resources/[carscripts]/nordi_antidespawn/config.lua new file mode 100644 index 000000000..bf217220d --- /dev/null +++ b/resources/[carscripts]/nordi_antidespawn/config.lua @@ -0,0 +1,40 @@ +Config = {} + +-- Speicherintervall in Millisekunden (5000 = 5 Sekunden) +Config.SaveInterval = 5000 + +-- Maximale Distanz zum Fahrzeug bevor es als "verlassen" gilt +Config.MaxDistance = 100.0 + +-- Debug Modus +Config.Debug = false + +-- Fahrzeugklassen die gespeichert werden sollen +Config.AllowedVehicleClasses = { + 0, -- Compacts + 1, -- Sedans + 2, -- SUVs + 3, -- Coupes + 4, -- Muscle + 5, -- Sports Classics + 6, -- Sports + 7, -- Super + 8, -- Motorcycles + 9, -- Off-road + 10, -- Industrial + 11, -- Utility + 12, -- Vans + 13, -- Cycles + 14, -- Boats + 15, -- Helicopters + 16, -- Planes + 17, -- Service + 18, -- Emergency + 19, -- Military + 20, -- Commercial + 21, -- Trains + 22, -- Open Wheel +} + +-- Mindestdistanz zu Garagen um Fahrzeuge zu tracken +Config.MinGarageDistance = 50.0 diff --git a/resources/[carscripts]/nordi_antidespawn/fxmanifest.lua b/resources/[carscripts]/nordi_antidespawn/fxmanifest.lua new file mode 100644 index 000000000..a1d3a13e6 --- /dev/null +++ b/resources/[carscripts]/nordi_antidespawn/fxmanifest.lua @@ -0,0 +1,25 @@ +fx_version 'cerulean' +game 'gta5' + +author 'YourName' +description 'Vehicle Persistence System for jg-advanced-garage' +version '1.0.0' + +shared_scripts { + 'config.lua' +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'server/main.lua' +} + +client_scripts { + 'client/main.lua' +} + +dependencies { + 'qb-core', + 'jg-advancedgarages', + 'oxmysql' +} diff --git a/resources/[carscripts]/nordi_antidespawn/server/main.lua b/resources/[carscripts]/nordi_antidespawn/server/main.lua new file mode 100644 index 000000000..c8a484946 --- /dev/null +++ b/resources/[carscripts]/nordi_antidespawn/server/main.lua @@ -0,0 +1,116 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +-- Erstelle Tabelle bei Serverstart +CreateThread(function() + MySQL.query([[ + CREATE TABLE IF NOT EXISTS `vehicle_positions` ( + `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, + `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) + + if not Player then return end + + 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)) + 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}) + + if Config.Debug then + print(string.format("Removed vehicle from persistence: %s", plate)) + end +end) + +-- Cleanup alte Einträge (älter als 24 Stunden) +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 + end +end) diff --git a/resources/[inventory]/tgiann-inventory/configs/configMaxStack.lua b/resources/[inventory]/tgiann-inventory/configs/configMaxStack.lua index 64d7086c3..926c5af15 100644 --- a/resources/[inventory]/tgiann-inventory/configs/configMaxStack.lua +++ b/resources/[inventory]/tgiann-inventory/configs/configMaxStack.lua @@ -19,6 +19,8 @@ config.maxStacks = { weapon_petrolcan = 1, printerdocument = 1, plastic_box = 1, + vehiclekeys = 1, + keyring = 1, c_necklace = 1, c_bproof = 1,