2025-08-06 10:11:58 +02:00
local QBCore = exports [ ' qb-core ' ] : GetCoreObject ( )
2025-08-06 12:37:47 +02:00
-- Lade die Garagen aus dem Hauptsystem
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
Config.Zonen = _G.Config . Zonen
print ( " [Fahrzeugadmin] Garagen aus dem Hauptsystem geladen: " .. # Config.Zonen .. " Garagen gefunden. " )
else
print ( " [Fahrzeugadmin] Konnte keine Garagen aus dem Hauptsystem laden, verwende Standard-Garagen. " )
end
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:37:47 +02:00
return Config.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:37:47 +02:00
-- Verwende die externen Garagen aus dem Garagensystem
if Config.Zonen then
for k , v in pairs ( Config.Zonen ) 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 ( Config.DefaultGarages ) do
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:37:47 +02:00
if Config.Log and Config.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
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:37:47 +02:00
if Config.Log and Config.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
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 )
exports [ " lc_fuel " ] : SetFuel ( veh , 100 )
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:37:47 +02:00
if Config.Log and Config.Log . Enabled then
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 )
if not Config.Log or not Config.Log . Enabled or not Config.Log . Webhook then return end
local embed = {
{
[ " title " ] = message ,
[ " type " ] = " rich " ,
[ " color " ] = Config.Log . Colors [ color ] or Config.Log . Colors.blue ,
[ " footer " ] = {
[ " text " ] = Config.Log . SystemName or " Fahrzeugadmin " ,
} ,
}
}
PerformHttpRequest ( Config.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 " ,
avatar_url = Config.Log . SystemAvatar ,
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 )