2025-08-06 10:11:58 +02:00
local QBCore = exports [ ' qb-core ' ] : GetCoreObject ( )
2025-08-06 12:45:18 +02:00
-- 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 ,
} ,
2025-08-06 12:37:47 +02:00
2025-08-06 12:45:18 +02:00
-- 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 ' }
}
}
2025-08-06 12:37:47 +02:00
2025-08-06 12:45:18 +02:00
-- Versuche, die Garagen aus dem externen Config zu laden
local ExternalGarages = { }
if _G.Config and _G.Config . Zonen then
ExternalGarages = _G.Config . Zonen
print ( " [Fahrzeugadmin] Garagen aus dem Hauptsystem geladen: " .. # ExternalGarages .. " Garagen gefunden. " )
else
print ( " [Fahrzeugadmin] Konnte keine Garagen aus dem Hauptsystem laden, verwende Standard-Garagen. " )
end
2025-08-06 11:48:14 +02:00
-- Job Permission Check
local function HasPermission ( source )
2025-08-06 10:11:58 +02:00
local Player = QBCore.Functions . GetPlayer ( source )
if not Player then return false end
2025-08-06 11:48:14 +02:00
-- 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
2025-08-06 12:45:18 +02:00
return AdminConfig.AllowedJobs [ playerJob ] == true
2025-08-06 10:11:58 +02:00
end
-- Get all players from database
QBCore.Functions . CreateCallback ( ' vehicleadmin:getPlayers ' , function ( source , cb )
2025-08-06 11:48:14 +02:00
if not HasPermission ( source ) then
2025-08-06 10:11:58 +02:00
cb ( false )
return
end
MySQL.Async . fetchAll ( ' SELECT citizenid, charinfo FROM players ORDER BY charinfo ' , { } , function ( result )
2025-08-06 12:21:15 +02:00
if not result then
cb ( { } )
return
end
2025-08-06 10:11:58 +02:00
local players = { }
for i = 1 , # result do
local charinfo = json.decode ( result [ i ] . charinfo )
2025-08-06 12:21:15 +02:00
if charinfo and charinfo.firstname and charinfo.lastname then
table.insert ( players , {
citizenid = result [ i ] . citizenid ,
name = charinfo.firstname .. ' ' .. charinfo.lastname
} )
end
2025-08-06 10:11:58 +02:00
end
cb ( players )
end )
end )
-- Get vehicles for specific player
QBCore.Functions . CreateCallback ( ' vehicleadmin:getPlayerVehicles ' , function ( source , cb , citizenid )
2025-08-06 11:48:14 +02:00
if not HasPermission ( source ) then
2025-08-06 10:11:58 +02:00
cb ( false )
return
end
MySQL.Async . fetchAll ( ' SELECT * FROM player_vehicles WHERE citizenid = ? ' , { citizenid } , function ( result )
2025-08-06 12:21:15 +02:00
if not result then
cb ( { } )
return
end
2025-08-06 10:11:58 +02:00
local vehicles = { }
for i = 1 , # result do
local vehicle = result [ i ]
table.insert ( vehicles , {
2025-08-06 12:21:15 +02:00
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 ,
2025-08-06 10:11:58 +02:00
citizenid = vehicle.citizenid ,
2025-08-06 12:21:15 +02:00
name = vehicle.name or " Unbekanntes Fahrzeug " ,
mods = vehicle.mods or " {} "
2025-08-06 10:11:58 +02:00
} )
end
cb ( vehicles )
end )
end )
2025-08-06 12:21:15 +02:00
-- Get all garages from your config
2025-08-06 10:11:58 +02:00
QBCore.Functions . CreateCallback ( ' vehicleadmin:getGarages ' , function ( source , cb )
2025-08-06 11:48:14 +02:00
if not HasPermission ( source ) then
2025-08-06 10:11:58 +02:00
cb ( false )
return
end
local garages = { }
2025-08-06 12:21:15 +02:00
2025-08-06 12:45:18 +02:00
-- Verwende die externen Garagen, wenn verfügbar
if next ( ExternalGarages ) ~= nil then
for k , v in pairs ( ExternalGarages ) do
2025-08-06 12:37:47 +02:00
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
2025-08-06 12:45:18 +02:00
for garageName , garageData in pairs ( AdminConfig.DefaultGarages ) do
2025-08-06 12:37:47 +02:00
table.insert ( garages , {
name = garageName ,
label = garageData.label or garageName
} )
end
2025-08-06 10:11:58 +02:00
end
2025-08-06 12:21:15 +02:00
-- Sortiere alphabetisch
table.sort ( garages , function ( a , b )
return a.name < b.name
end )
2025-08-06 10:11:58 +02:00
cb ( garages )
end )
2025-08-06 11:48:14 +02:00
-- 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 )
2025-08-06 10:11:58 +02:00
-- Move vehicle to garage
RegisterNetEvent ( ' vehicleadmin:moveToGarage ' , function ( plate , garage )
local src = source
2025-08-06 11:48:14 +02:00
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
2025-08-06 10:11:58 +02:00
-- Delete vehicle from world if it exists
local vehicles = GetAllVehicles ( )
for i = 1 , # vehicles do
local veh = vehicles [ i ]
2025-08-06 12:21:15 +02:00
if DoesEntityExist ( veh ) then
local vehPlate = GetVehicleNumberPlateText ( veh ) : gsub ( " %s+ " , " " )
if vehPlate == plate : gsub ( " %s+ " , " " ) then
DeleteEntity ( veh )
break
end
2025-08-06 10:11:58 +02:00
end
end
2025-08-06 12:21:15 +02:00
-- Update database - Anpassung an euer Garagensystem
MySQL.Async . execute ( ' UPDATE player_vehicles SET garage = ? WHERE plate = ? ' , { garage , plate } , function ( affectedRows )
2025-08-06 10:11:58 +02:00
if affectedRows > 0 then
2025-08-06 12:21:15 +02:00
-- Entferne das Fahrzeug aus dem Parking-System, falls vorhanden
MySQL.Async . execute ( ' DELETE FROM vehicle_parking WHERE plate = ? ' , { plate } )
2025-08-06 11:48:14 +02:00
-- Log the action
local Player = QBCore.Functions . GetPlayer ( src )
2025-08-06 12:21:15 +02:00
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
2025-08-06 12:45:18 +02:00
if AdminConfig.Log and AdminConfig.Log . Enabled then
2025-08-06 12:37:47 +02:00
sendToDiscord ( " Fahrzeugadmin " , Player.PlayerData . charinfo.firstname .. " " .. Player.PlayerData . charinfo.lastname .. " ( " .. Player.PlayerData . job.label .. " ) hat Fahrzeug " .. plate .. " in Garage " .. garage .. " gestellt. " , " blue " )
end
2025-08-06 12:21:15 +02:00
end
2025-08-06 11:48:14 +02:00
2025-08-06 10:11:58 +02:00
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
2025-08-06 11:48:14 +02:00
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
2025-08-06 10:11:58 +02:00
local vehicles = GetAllVehicles ( )
local deleted = false
for i = 1 , # vehicles do
local veh = vehicles [ i ]
2025-08-06 12:21:15 +02:00
if DoesEntityExist ( veh ) then
local vehPlate = GetVehicleNumberPlateText ( veh ) : gsub ( " %s+ " , " " )
if vehPlate == plate : gsub ( " %s+ " , " " ) then
DeleteEntity ( veh )
deleted = true
break
end
2025-08-06 10:11:58 +02:00
end
end
2025-08-06 11:48:14 +02:00
-- Log the action
local Player = QBCore.Functions . GetPlayer ( src )
2025-08-06 12:21:15 +02:00
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
2025-08-06 12:45:18 +02:00
if AdminConfig.Log and AdminConfig.Log . Enabled then
2025-08-06 12:37:47 +02:00
sendToDiscord ( " Fahrzeugadmin " , Player.PlayerData . charinfo.firstname .. " " .. Player.PlayerData . charinfo.lastname .. " ( " .. Player.PlayerData . job.label .. " ) hat Fahrzeug " .. plate .. " von der Map gelöscht. " , " orange " )
end
2025-08-06 12:21:15 +02:00
end
2025-08-06 11:48:14 +02:00
2025-08-06 10:11:58 +02:00
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 ' ,
2025-08-06 11:48:14 +02:00
type = ' info '
2025-08-06 10:11:58 +02:00
} )
end
end )
-- Repair vehicle
RegisterNetEvent ( ' vehicleadmin:repairVehicle ' , function ( plate )
local src = source
2025-08-06 11:48:14 +02:00
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
2025-08-06 10:11:58 +02:00
2025-08-06 12:21:15 +02:00
-- 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 = { }
2025-08-06 10:11:58 +02:00
end
2025-08-06 11:48:14 +02:00
2025-08-06 12:21:15 +02:00
if mods.windowStatus then
mods.windowStatus = { }
for i = 0 , 7 do
mods.windowStatus [ tostring ( i ) ] = true
end
end
2025-08-06 11:48:14 +02:00
2025-08-06 12:21:15 +02:00
-- 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 )
2025-08-06 12:45:18 +02:00
-- Versuche, den Kraftstoff über das lc_fuel-Export zu setzen, falls verfügbar
pcall ( function ( )
exports [ " lc_fuel " ] : SetFuel ( veh , 100 )
end )
2025-08-06 12:21:15 +02:00
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
2025-08-06 12:45:18 +02:00
if AdminConfig.Log and AdminConfig.Log . Enabled then
2025-08-06 12:37:47 +02:00
sendToDiscord ( " Fahrzeugadmin " , Player.PlayerData . charinfo.firstname .. " " .. Player.PlayerData . charinfo.lastname .. " ( " .. Player.PlayerData . job.label .. " ) hat Fahrzeug " .. plate .. " repariert. " , " green " )
end
2025-08-06 12:21:15 +02:00
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 )
2025-08-06 11:48:14 +02:00
else
TriggerClientEvent ( ' ox_lib:notify ' , src , {
title = ' Fahrzeugverwaltung ' ,
2025-08-06 12:21:15 +02:00
description = ' Fahrzeug nicht gefunden ' ,
2025-08-06 11:48:14 +02:00
type = ' error '
} )
end
end )
end )
2025-08-06 12:37:47 +02:00
-- Discord Log Funktion
function sendToDiscord ( title , message , color )
2025-08-06 12:45:18 +02:00
if not AdminConfig.Log or not AdminConfig.Log . Enabled or not AdminConfig.Log . Webhook then return end
2025-08-06 12:37:47 +02:00
local embed = {
{
[ " title " ] = message ,
[ " type " ] = " rich " ,
2025-08-06 12:45:18 +02:00
[ " color " ] = AdminConfig.Log . Colors [ color ] or AdminConfig.Log . Colors.blue ,
2025-08-06 12:37:47 +02:00
[ " footer " ] = {
2025-08-06 12:45:18 +02:00
[ " text " ] = AdminConfig.Log . SystemName or " Fahrzeugadmin " ,
2025-08-06 12:37:47 +02:00
} ,
}
}
2025-08-06 12:45:18 +02:00
PerformHttpRequest ( AdminConfig.Log . Webhook , function ( err , text , headers )
2025-08-06 12:37:47 +02:00
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
2025-08-06 10:11:58 +02:00
-- Command to open admin menu
QBCore.Commands . Add ( ' vehicleadmin ' , ' Öffne Fahrzeug Admin Menu ' , { } , false , function ( source , args )
local src = source
2025-08-06 11:48:14 +02:00
if not HasPermission ( src ) then
local Player = QBCore.Functions . GetPlayer ( src )
local jobName = Player and Player.PlayerData . job.name or ' Unbekannt '
2025-08-06 10:11:58 +02:00
TriggerClientEvent ( ' ox_lib:notify ' , src , {
title = ' Keine Berechtigung ' ,
2025-08-06 11:48:14 +02:00
description = ' Dein Job ( ' .. jobName .. ' ) hat keine Berechtigung für dieses System ' ,
2025-08-06 10:11:58 +02:00
type = ' error '
} )
return
end
TriggerClientEvent ( ' vehicleadmin:openMenu ' , src )
2025-08-06 11:48:14 +02:00
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 )
2025-08-06 12:45:18 +02:00
-- Versuche, die Garagen aus dem externen Config zu laden (erneut)
Citizen.CreateThread ( function ( )
Wait ( 5000 ) -- Warte länger, damit das Hauptsystem sicher geladen ist
-- Versuche, die Garagen aus dem Hauptsystem zu laden
if _G.Config and _G.Config . Zonen then
ExternalGarages = _G.Config . Zonen
print ( " [Fahrzeugadmin] Garagen aus dem Hauptsystem nachgeladen: " .. # ExternalGarages .. " Garagen gefunden. " )
end
end )