local QBCore = exports['qb-core']:GetCoreObject() -- Interne Konfiguration für das Fahrzeugadmin-System local AdminConfig = { -- Erlaubte Jobs für das Vehicle Admin System AllowedJobs = { ['police'] = true, ['admin'] = true, ['mechanic'] = true, ['ambulance'] = true, ['cardealer'] = true, }, -- Debug-Modus Debug = false, -- Log-Einstellungen Log = { Enabled = true, Webhook = "https://discord.com/api/webhooks/1366812966049288192/9ZjJC9_gLX6Fk-acf0YSW_haGWpCqG9zRGWaj0wCKLZefp8FX-GwNZBP77H6K93KfIw3", -- Verwende den gleichen Webhook wie im Garagensystem Colors = { green = 56108, grey = 8421504, red = 16711680, orange = 16744192, blue = 2061822, purple = 11750815, }, SystemName = "Evolution_State_life Log [Fahrzeugadmin]", }, -- Standard-Garagen falls keine in QBCore definiert sind DefaultGarages = { ['legion'] = { label = 'Legion Square Garage' }, ['pillboxgarage'] = { label = 'Pillbox Garage' }, ['spanishave'] = { label = 'Spanish Avenue Garage' }, ['caears24'] = { label = 'Caears 24 Garage' }, ['littleseoul'] = { label = 'Little Seoul Garage' }, ['rockfordgarage'] = { label = 'Rockford Garage' }, ['lamesamotel'] = { label = 'Lamesa Motel Garage' }, ['airportp'] = { label = 'Airport Parking' }, ['depot'] = { label = 'Depot' }, ['impound'] = { label = 'Impound Lot' }, ['pdgarage'] = { label = 'Police Garage' }, ['emsgarage'] = { label = 'EMS Garage' }, ['mechgarage'] = { label = 'Mechanic Garage' } } } -- Versuche, die Garagen aus dem externen Config zu laden local ExternalGarages = {} -- Job Permission Check local function HasPermission(source) local Player = QBCore.Functions.GetPlayer(source) if not Player then return false end -- Check if player has admin permission if QBCore.Functions.HasPermission(source, 'admin') then return true end -- Check if player has allowed job local playerJob = Player.PlayerData.job.name return AdminConfig.AllowedJobs[playerJob] == true end -- Get all players from database QBCore.Functions.CreateCallback('vehicleadmin:getPlayers', function(source, cb) if not HasPermission(source) then cb(false) return end MySQL.Async.fetchAll('SELECT citizenid, charinfo FROM players ORDER BY charinfo', {}, function(result) if not result then cb({}) return end local players = {} for i = 1, #result do local charinfo = json.decode(result[i].charinfo) if charinfo and charinfo.firstname and charinfo.lastname then table.insert(players, { citizenid = result[i].citizenid, name = charinfo.firstname .. ' ' .. charinfo.lastname }) end end cb(players) end) end) -- Funktion zum Abrufen des Fahrzeugnamens local function GetVehicleDisplayName(model) -- Versuche zuerst, den Namen aus QBCore zu bekommen local vehicleData = QBCore.Shared.Vehicles[model] if vehicleData and vehicleData.name then return vehicleData.name end -- Fallback: Versuche, den Namen aus der Fahrzeugklasse zu bekommen local vehicleClass = GetVehicleClassFromName(model) if vehicleClass then local classes = { [0] = "Kompakt", [1] = "Limousine", [2] = "SUV", [3] = "Coupé", [4] = "Muscle", [5] = "Sport Classic", [6] = "Sport", [7] = "Super", [8] = "Motorrad", [9] = "Geländewagen", [10] = "Industrie", [11] = "Nutzfahrzeug", [12] = "Van", [13] = "Fahrrad", [14] = "Boot", [15] = "Hubschrauber", [16] = "Flugzeug", [17] = "Service", [18] = "Notdienst", [19] = "Militär", [20] = "Kommerziell", [21] = "Zug", [22] = "Öffentlich" } return model .. " (" .. (classes[vehicleClass] or "Unbekannt") .. ")" end -- Wenn alles fehlschlägt, gib einfach den Modellnamen zurück return model end -- Get vehicles for specific player QBCore.Functions.CreateCallback('vehicleadmin:getPlayerVehicles', function(source, cb, citizenid) if not HasPermission(source) then cb(false) return end MySQL.Async.fetchAll('SELECT * FROM player_vehicles WHERE citizenid = ?', {citizenid}, function(result) if not result then cb({}) return end local vehicles = {} for i = 1, #result do local vehicle = result[i] local displayName = vehicle.name -- Wenn kein Name gesetzt ist, versuche den Namen aus dem Modell zu bekommen if not displayName or displayName == "" then displayName = GetVehicleDisplayName(vehicle.vehicle) end table.insert(vehicles, { plate = vehicle.plate or 'UNKNOWN', vehicle = vehicle.vehicle or 'unknown', garage = vehicle.garage or 'none', state = vehicle.garage == "OUT" and 0 or 1, -- Anpassung an euer Garagensystem fuel = vehicle.fuel or 100, engine = vehicle.engine or 1000, body = vehicle.body or 1000, citizenid = vehicle.citizenid, name = displayName, mods = vehicle.mods or "{}" }) end cb(vehicles) end) end) -- Get all garages from your config QBCore.Functions.CreateCallback('vehicleadmin:getGarages', function(source, cb) if not HasPermission(source) then cb(false) return end local garages = {} -- Verwende die externen Garagen aus dem Garagensystem if next(ExternalGarages) ~= nil then for k, v in pairs(ExternalGarages) do table.insert(garages, { name = v.name, label = v.name -- Ihr könnt hier auch eine Label-Property hinzufügen }) end else -- Fallback auf Standard-Garagen for garageName, garageData in pairs(AdminConfig.DefaultGarages) do table.insert(garages, { name = garageName, label = garageData.label or garageName }) end end -- Sortiere alphabetisch table.sort(garages, function(a, b) return a.name < b.name end) cb(garages) end) -- Check player's job and return permissions QBCore.Functions.CreateCallback('vehicleadmin:getPlayerJob', function(source, cb) local Player = QBCore.Functions.GetPlayer(source) if not Player then cb(false) return end local hasPermission = HasPermission(source) local jobName = Player.PlayerData.job.name local jobLabel = Player.PlayerData.job.label cb({ hasPermission = hasPermission, jobName = jobName, jobLabel = jobLabel }) end) -- Move vehicle to garage RegisterNetEvent('vehicleadmin:moveToGarage', function(plate, garage) local src = source if not HasPermission(src) then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Du hast keine Berechtigung für diese Aktion', type = 'error' }) return end -- Delete vehicle from world if it exists local vehicles = GetAllVehicles() for i = 1, #vehicles do local veh = vehicles[i] if DoesEntityExist(veh) then local vehPlate = GetVehicleNumberPlateText(veh):gsub("%s+", "") if vehPlate == plate:gsub("%s+", "") then DeleteEntity(veh) break end end end -- Update database - Anpassung an euer Garagensystem MySQL.Async.execute('UPDATE player_vehicles SET garage = ? WHERE plate = ?', {garage, plate}, function(affectedRows) if affectedRows > 0 then -- Entferne das Fahrzeug aus dem Parking-System, falls vorhanden MySQL.Async.execute('DELETE FROM vehicle_parking WHERE plate = ?', {plate}) -- Log the action local Player = QBCore.Functions.GetPlayer(src) if Player then print(string.format('[VEHICLE ADMIN] %s (%s) moved vehicle %s to garage %s', Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname, Player.PlayerData.job.label, plate, garage )) -- Log für Discord if AdminConfig.Log and AdminConfig.Log.Enabled then sendToDiscord("Fahrzeugadmin", Player.PlayerData.charinfo.firstname .. " " .. Player.PlayerData.charinfo.lastname .. " (" .. Player.PlayerData.job.label .. ") hat Fahrzeug " .. plate .. " in Garage " .. garage .. " gestellt.", "blue") end end TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fahrzeug wurde in Garage ' .. garage .. ' gestellt', type = 'success' }) else TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fehler beim Verschieben des Fahrzeugs', type = 'error' }) end end) end) -- Delete vehicle from map RegisterNetEvent('vehicleadmin:deleteFromMap', function(plate) local src = source if not HasPermission(src) then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Du hast keine Berechtigung für diese Aktion', type = 'error' }) return end local vehicles = GetAllVehicles() local deleted = false for i = 1, #vehicles do local veh = vehicles[i] if DoesEntityExist(veh) then local vehPlate = GetVehicleNumberPlateText(veh):gsub("%s+", "") if vehPlate == plate:gsub("%s+", "") then DeleteEntity(veh) deleted = true break end end end -- Log the action local Player = QBCore.Functions.GetPlayer(src) if Player then print(string.format('[VEHICLE ADMIN] %s (%s) deleted vehicle %s from map', Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname, Player.PlayerData.job.label, plate )) -- Log für Discord if AdminConfig.Log and AdminConfig.Log.Enabled then sendToDiscord("Fahrzeugadmin", Player.PlayerData.charinfo.firstname .. " " .. Player.PlayerData.charinfo.lastname .. " (" .. Player.PlayerData.job.label .. ") hat Fahrzeug " .. plate .. " von der Map gelöscht.", "orange") end end if deleted then TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fahrzeug wurde von der Map gelöscht', type = 'success' }) else TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fahrzeug nicht auf der Map gefunden', type = 'info' }) end end) -- Repair vehicle RegisterNetEvent('vehicleadmin:repairVehicle', function(plate) local src = source if not HasPermission(src) then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Du hast keine Berechtigung für diese Aktion', type = 'error' }) return end -- Get vehicle mods first MySQL.Async.fetchAll('SELECT mods FROM player_vehicles WHERE plate = ?', {plate}, function(result) if result and result[1] and result[1].mods then local mods = json.decode(result[1].mods) -- Update mods with repaired values mods.engineHealth = 1000 mods.bodyHealth = 1000 mods.fuelLevel = 100 -- Reset door and window status if they exist if mods.doorStatus then mods.doorStatus = {} end if mods.windowStatus then mods.windowStatus = {} for i = 0, 7 do mods.windowStatus[tostring(i)] = true end end -- Update database with repaired mods MySQL.Async.execute('UPDATE player_vehicles SET mods = ? WHERE plate = ?', {json.encode(mods), plate}, function(affectedRows) -- Also repair if vehicle is on map local vehicles = GetAllVehicles() for i = 1, #vehicles do local veh = vehicles[i] if DoesEntityExist(veh) then local vehPlate = GetVehicleNumberPlateText(veh):gsub("%s+", "") if vehPlate == plate:gsub("%s+", "") then SetVehicleFixed(veh) SetVehicleDeformationFixed(veh) SetVehicleUndriveable(veh, false) SetVehicleEngineOn(veh, true, true) SetVehicleFuelLevel(veh, 100.0) -- Versuche, den Kraftstoff über das lc_fuel-Export zu setzen, falls verfügbar pcall(function() exports["lc_fuel"]:SetFuel(veh, 100) end) break end end end -- Log the action local Player = QBCore.Functions.GetPlayer(src) if Player then print(string.format('[VEHICLE ADMIN] %s (%s) repaired vehicle %s', Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname, Player.PlayerData.job.label, plate )) -- Log für Discord if AdminConfig.Log and AdminConfig.Log.Enabled then sendToDiscord("Fahrzeugadmin", Player.PlayerData.charinfo.firstname .. " " .. Player.PlayerData.charinfo.lastname .. " (" .. Player.PlayerData.job.label .. ") hat Fahrzeug " .. plate .. " repariert.", "green") end end if affectedRows > 0 then TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fahrzeug wurde repariert', type = 'success' }) else TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fehler beim Reparieren des Fahrzeugs', type = 'error' }) end end) else TriggerClientEvent('ox_lib:notify', src, { title = 'Fahrzeugverwaltung', description = 'Fahrzeug nicht gefunden', type = 'error' }) end end) end) -- Discord Log Funktion function sendToDiscord(title, message, color) if not AdminConfig.Log or not AdminConfig.Log.Enabled or not AdminConfig.Log.Webhook then return end local embed = { { ["title"] = message, ["type"] = "rich", ["color"] = AdminConfig.Log.Colors[color] or AdminConfig.Log.Colors.blue, ["footer"] = { ["text"] = AdminConfig.Log.SystemName or "Fahrzeugadmin", }, } } PerformHttpRequest(AdminConfig.Log.Webhook, function(err, text, headers) if err and err ~= 204 and err ~= 200 then print("Fehler beim Discord Webhook [" .. tostring(err) .. "]: " .. tostring(text)) end end, 'POST', json.encode({ username = title .. " - System", embeds = embed }), { ['Content-Type'] = 'application/json' }) end -- Command to open admin menu QBCore.Commands.Add('vehicleadmin', 'Öffne Fahrzeug Admin Menu', {}, false, function(source, args) local src = source if not HasPermission(src) then local Player = QBCore.Functions.GetPlayer(src) local jobName = Player and Player.PlayerData.job.name or 'Unbekannt' TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Dein Job (' .. jobName .. ') hat keine Berechtigung für dieses System', type = 'error' }) return end TriggerClientEvent('vehicleadmin:openMenu', src) end) -- Alternative command for police QBCore.Commands.Add('policegarage', 'Öffne Polizei Fahrzeug Menu', {}, false, function(source, args) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player or Player.PlayerData.job.name ~= 'police' then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Nur Polizisten können diesen Befehl verwenden', type = 'error' }) return end TriggerClientEvent('vehicleadmin:openMenu', src) end) -- Alternative command for mechanics QBCore.Commands.Add('mechanicadmin', 'Öffne Mechaniker Fahrzeug Menu', {}, false, function(source, args) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player or Player.PlayerData.job.name ~= 'mechanic' then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Nur Mechaniker können diesen Befehl verwenden', type = 'error' }) return end TriggerClientEvent('vehicleadmin:openMenu', src) end) -- Alternative command for ambulance QBCore.Commands.Add('emsadmin', 'Öffne EMS Fahrzeug Menu', {}, false, function(source, args) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player or Player.PlayerData.job.name ~= 'ambulance' then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Nur EMS können diesen Befehl verwenden', type = 'error' }) return end TriggerClientEvent('vehicleadmin:openMenu', src) end) -- Alternative command for cardealer QBCore.Commands.Add('dealeradmin', 'Öffne Autohändler Fahrzeug Menu', {}, false, function(source, args) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player or Player.PlayerData.job.name ~= 'cardealer' then TriggerClientEvent('ox_lib:notify', src, { title = 'Keine Berechtigung', description = 'Nur Autohändler können diesen Befehl verwenden', type = 'error' }) return end TriggerClientEvent('vehicleadmin:openMenu', src) end) -- Lade die Garagen aus dem Garagensystem Citizen.CreateThread(function() Wait(1000) -- Warte kurz, damit das Hauptsystem geladen ist -- Versuche, die Garagen aus dem Hauptsystem zu laden if _G.Config and _G.Config.Zonen then for k, v in pairs(_G.Config.Zonen) do table.insert(ExternalGarages, v) end print("[Fahrzeugadmin] Garagen aus dem Hauptsystem geladen: " .. #ExternalGarages .. " Garagen gefunden.") else print("[Fahrzeugadmin] Konnte keine Garagen aus dem Hauptsystem laden, versuche es später erneut.") end end) -- Versuche erneut, die Garagen zu laden, falls sie beim ersten Mal nicht verfügbar waren Citizen.CreateThread(function() Wait(5000) -- Warte länger, damit das Hauptsystem sicher geladen ist if #ExternalGarages == 0 and _G.Config and _G.Config.Zonen then for k, v in pairs(_G.Config.Zonen) do table.insert(ExternalGarages, v) end print("[Fahrzeugadmin] Garagen aus dem Hauptsystem nachgeladen: " .. #ExternalGarages .. " Garagen gefunden.") end end)