1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-08-06 15:36:50 +02:00
parent 6d22d5f77c
commit 63fbc60a00
86 changed files with 8352 additions and 3428 deletions

View file

@ -0,0 +1,5 @@
function Debug(text)
if Config.Debug then
print(text)
end
end

View file

@ -0,0 +1,180 @@
QBCore = exports['qb-core']:GetCoreObject()
Player = nil
npcHandle = nil
isNPCSpawned = false
CurrentZone = nil
CurrentActionData = {}
hasAlreadyEnteredMarker = false
Citizen.CreateThread(function()
while Player == nil do
Player = exports['qb-core']:GetPlayerData()
Wait(0)
end
end)
Citizen.CreateThread(function()
while true do
Wait(15000)
local ped = PlayerPedId()
if IsPedInAnyVehicle(ped, false) then
local veh = GetVehiclePedIsIn(ped, false)
local mods = QBCore.Functions.GetVehicleProperties(veh)
print("Triggert setMods: "..json.encode(mods))
TriggerServerEvent('mh_garage:setMods', mods)
end
end
end)
-- Funktion zum Spawnen des NPCs
function SpawnGuardNPC(npc)
-- Ped Model laden
RequestModel(npc.model)
local timeout = 0
while not HasModelLoaded(npc.model) and timeout < 100 do
timeout = timeout + 1
Wait(100)
end
if not HasModelLoaded(npc.model) then
return
end
-- NPC erstellen
npcHandle = CreatePed(4, npc.model, npc.spawn.x, npc.spawn.y, npc.spawn.z, npc.spawn.w, false, true)
if not DoesEntityExist(npcHandle) then
return
end
-- NPC Eigenschaften setzen
SetEntityAsMissionEntity(npcHandle, true, true)
SetBlockingOfNonTemporaryEvents(npcHandle, true)
SetPedDiesWhenInjured(npcHandle, false)
SetPedCanPlayAmbientAnims(npcHandle, true)
SetPedCanRagdollFromPlayerImpact(npcHandle, false)
SetEntityInvincible(npcHandle, true)
FreezeEntityPosition(npcHandle, true)
-- Optional: Animation für den NPC
TaskStartScenarioInPlace(npcHandle, "WORLD_HUMAN_GUARD_STAND", 0, true)
isNPCSpawned = true
end
-- Funktion zum Entfernen des NPCs
function RemoveGuardNPC()
if DoesEntityExist(npcHandle) then
DeleteEntity(npcHandle)
isNPCSpawned = false
end
end
-- Hauptthread zum Überprüfen der Spieler-Position
CreateThread(function()
while true do
Wait(0)
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local isInMarker = false
for k, v in pairs(Config.Zonen) do
local dist = #(coords - vector3(v.NPC.spawn.x, v.NPC.spawn.y, v.NPC.spawn.z))
local spawnDistance = v.NPC.distance
if dist <= spawnDistance then
isInMarker = true
CurrentZone = v
end
end
if isInMarker and not hasAlreadyEnteredMarker then
hasAlreadyEnteredMarker = true
SpawnGuardNPC(CurrentZone.NPC)
AddTargetOptions()
end
if not isInMarker and hasAlreadyEnteredMarker then
hasAlreadyEnteredMarker = false
CurrentZone = nil
exports['qb-target']:RemoveTargetEntity(npcHandle)
RemoveGuardNPC()
end
end
end)
function AddTargetOptions()
local opt = {
{
type = "client",
event = "mh_garage:storeVehicle",
icon = "fas fa-parking",
label = "Fahrzeug einparken",
},
{
type = "client",
event = "mh_garage:retrieveOwnerVehicle",
icon = "fas fa-car",
label = "Eigene Fahrzeug ausparken",
},
{
type = "client",
event = "mh_garage:retrieveVehicle",
icon = "key",
label = "Schlüssel Fahrzeug ausparken",
}
}
if Config.Verwaltung.garage then
table.insert(opt, {
type = "client",
event = "mh_garage:verwaltungVeh",
icon = "hand",
label = "Fahrzeuge Verwalten",
})
end
exports['qb-target']:AddTargetEntity(npcHandle, {
options = opt,
distance = 2.5
})
end
function Notification(text, type)
lib.notify({
title = "Garage - "..CurrentZone.name,
description = text,
type = type,
position = 'top',
})
end
---------------------------- NetEvents
RegisterNetEvent('mh_jobgarage:notify')
AddEventHandler('mh_jobgarage:notify', function(title, text, type)
Notification(text, type)
end)
function GetVehicleDamagePercentage(vehicle)
if not vehicle then return 0 end
-- Hole die verschiedenen Gesundheitswerte
local engineHealth = GetVehicleEngineHealth(vehicle)
local bodyHealth = GetVehicleBodyHealth(vehicle)
local tankHealth = GetVehiclePetrolTankHealth(vehicle)
-- Normalisiere die Werte (Standard-Maximalwerte: 1000.0)
local enginePercent = (engineHealth / 1000.0) * 100
local bodyPercent = (bodyHealth / 1000.0) * 100
local tankPercent = (tankHealth / 1000.0) * 100
-- Berechne Durchschnitt als Gesamtzustand
local totalHealth = (enginePercent + bodyPercent + tankPercent) / 3
-- Runde auf ganze Zahlen
return math.floor(totalHealth)
end

View file

@ -0,0 +1,152 @@
RegisterNetEvent('mh_garage:retrieveOwnerVehicle')
AddEventHandler('mh_garage:retrieveOwnerVehicle', function()
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local random = SelectName()
local opt = {}
QBCore.Functions.TriggerCallback('mh_garage:retrieveOwnerVehicle', function(cb)
if cb == false then
Notification("Es ist kein Fahrzeug hier!", "inform")
return
end
for i = 1, #cb, 1 do
local mods = json.decode(cb[i].mods)
table.insert(opt, {
title = cb[i].name,
description = "Kennzeichen: "..cb[i].plate, --[[ \nTankinhalt: "..math.round(mods.fuelLevel, 2).."%" ]]
icon = "car",
onSelect = function()
cb[i].mods = mods
SpawnThisVehicle(cb[i])
end
})
end
lib.registerContext({
id = "retrieveVehicle",
title = random.name,
options = opt
})
lib.showContext("retrieveVehicle")
end, CurrentZone.name)
end)
RegisterNetEvent('mh_garage:retrieveVehicle')
AddEventHandler('mh_garage:retrieveVehicle', function()
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local random = SelectName()
local opt = {}
QBCore.Functions.TriggerCallback('mh_garage:retrieveKeyVehicle', function(cb)
if cb == false then
Notification("Es ist kein Fahrzeug hier!", "inform")
return
end
for i = 1, #cb, 1 do
if cb[i].garage ~= "OUT" then
local mods = json.decode(cb[i].mods)
table.insert(opt, {
title = cb[i].name,
description = "Kennzeichen: "..cb[i].plate, --[[ \nTankinhalt: "..math.round(mods.fuelLevel, 2).."%" ]]
icon = "car",
onSelect = function()
cb[i].mods = mods
SpawnThisVehicle(cb[i])
end
})
end
end
lib.registerContext({
id = "retrieveVehicle",
title = random.name,
options = opt
})
lib.showContext("retrieveVehicle")
end, CurrentZone.name)
end)
function SpawnThisVehicle(vehicle)
local spawnPoint = nil
-- Freien Spawnpunkt suchen
for _, spot in pairs(CurrentZone.vehicle_spawn) do
if not IsAnyVehicleNearPoint(spot.x, spot.y, spot.z, 3.0) then
spawnPoint = spot
break
end
end
if spawnPoint then
QBCore.Functions.SpawnVehicle(vehicle.vehicle, function(veh)
-- Fahrzeug ID für Server
local netId = NetworkGetNetworkIdFromEntity(veh)
-- Grundeinstellungen
SetVehicleNumberPlateText(veh, vehicle.plate)
SetVehicleDoorsLocked(veh, 0)
SetEntityHeading(veh, spawnPoint.w)
-- Motor aus
SetVehicleEngineOn(veh, false, true, true)
-- Fahrzeug Eigenschaften
local mods = type(vehicle.mods) == 'string' and json.decode(vehicle.mods) or vehicle.mods
-- Grundwerte setzen
SetVehicleFuelLevel(veh, mods.fuelLevel)
exports["lc_fuel"]:SetFuel(veh, mods.fuelLevel)
SetVehicleEngineHealth(veh, mods.engineHealth)
SetVehicleBodyHealth(veh, mods.bodyHealth)
SetVehicleDirtLevel(veh, mods.dirtLevel)
-- Türen Status
if mods.doorStatus then
for doorIndex = 0, 5 do
if mods.doorStatus[tostring(doorIndex)] then
SetVehicleDoorBroken(veh, doorIndex, true)
end
end
end
-- Fenster Status
if mods.windowStatus then
for windowIndex = 0, 7 do
if not mods.windowStatus[tostring(windowIndex)] then
SmashVehicleWindow(veh, windowIndex)
end
end
end
-- Alle Mods anwenden
QBCore.Functions.SetVehicleProperties(veh, mods)
-- Fahrzeug auf den Boden setzen
SetVehicleOnGroundProperly(veh)
-- Server über gespawntes Fahrzeug informieren
TriggerServerEvent('mh_garage:spawnedVehicle', netId, vehicle.plate)
-- Optional: Erfolgsmeldung
lib.notify({
title = "Fahrzeug geparkt...",
description = "Dein Fahrzeug steht auf Parkplatz "..math.random(1, 15),
type = "success"
})
end, vector3(spawnPoint.x, spawnPoint.y, spawnPoint.z), true)
else
QBCore.Functions.Notify('Alle Parkplätze sind belegt!', 'error')
lib.notify({
title = "Fahrzeug nicht gefunden",
description = "Alle Parkplätze sind belegt!",
type = "success"
})
end
end

View file

@ -0,0 +1,131 @@
RegisterNetEvent('mh_garage:storeVehicle')
AddEventHandler('mh_garage:storeVehicle', function()
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local vehicles = GetGamePool('CVehicle')
local random = SelectName()
local opt = {}
for i = 1, #vehicles, 1 do
local veh_coords = GetEntityCoords(vehicles[i])
local distance = #(veh_coords - coords)
if distance < 15.0 then
local mods = QBCore.Functions.GetVehicleProperties(vehicles[i])
local lc_fuelLevel = exports["lc_fuel"]:GetFuel(vehicles[i]) -- Get the fuel level
mods.fuelLevel = lc_fuelLevel
table.insert(opt, {
title = "Kennzeichen: "..mods.plate,
description = GetRandomCarDescription(),
icon = "car",
onSelect = function()
print(CurrentZone.price)
if CurrentZone.price ~= nil then
lib.hideContext("StoredVehicles")
lib.registerContext({
id = "thisVehicle",
title = random.name,
options = {
{title = "Kosten: "..CurrentZone.price.."$"},
{title = "", disabled = true},
{
title = "Akzeptieren",
description = "Geld wird vom Bankkonto abgebucht!",
icon = "check",
onSelect = function()
lib.hideContext("thisVehicle")
QBCore.Functions.TriggerCallback('mh_garage:storedVehicle', function(cb)
if cb.status then
TriggerServerEvent('mh_Parking:deleteVehicle', mods.plate, NetworkGetNetworkIdFromEntity(vehicles[i]))
--DeleteVehicle(vehicles[i])
Notification(cb.text, cb.type, CurrentZone.name)
else
if cb.police and Config.EnabledPolice then
exports["roadphone"]:sendDispatch("Hier hat grade jemand versucht, ein Fahrzeug einzuparken.\nDas Zündschloss sah Beschädigt aus.\nKennzeichen: "..veh.plate, 'police', nil)
end
Notification(cb.text, cb.type)
end
end, mods, CurrentZone)
end
},
{
title = "Abbrechen",
description = "Das ist sehr Schade,",
icon = "close",
onSelect = function()
lib.hideContext("thisVehicle")
end
}
}
})
lib.showContext("thisVehicle")
else
QBCore.Functions.TriggerCallback('mh_garage:storedVehicle', function(cb)
if cb.status then
TriggerServerEvent('mh_Parking:deleteVehicle', mods.plate, NetworkGetNetworkIdFromEntity(vehicles[i]))
--DeleteVehicle(vehicles[i])
Notification(cb.text, cb.type, CurrentZone.name)
else
if cb.police and Config.EnabledPolice then
exports["roadphone"]:sendDispatch("Hier hat grade jemand versucht, ein Fahrzeug einzuparken.\nDas Zündschloss sah Beschädigt aus.\nKennzeichen: "..veh.plate, 'police', nil)
end
Notification(cb.text, cb.type)
end
end, mods, CurrentZone)
end
end
})
lib.registerContext({
id = "StoredVehicles",
title = random.name.."\n\n"..random.description,
options = opt
})
lib.showContext("StoredVehicles")
end
end
end)
function SelectName()
local names = {
{name = "Garagen-Guru",
description = "passt auf, dass keiner falsch parkt, Schranken nicht durchdrehen und Autos nicht fliegen!"},
{name = "Torflüsterer",
description = "Redet Schranken gut zu wenn diese wieder nicht funktionieren."},
{name = "Parkplatz-Papst",
description = "segnet jedes Auto, das diese heilige Halle betritt. Kein Ölverlust ohne dein Amen!"},
{name = "Schranken-Schamane",
description = "Elektronik und Technik? Kein Problem! Ich kontrolliere den Strom der Schranken mit reiner Willenskraft und Kabelbinder!"},
{name = "Chef vom Schuppen",
description = "Wer falsch parkt, kriegt nicht den Abschleppdienst, sondern eine Ansprache. Kurz. Hart. Legendär!"}
}
return names[math.random(1, #names)]
end
function GetRandomCarDescription()
local descriptions = {
"Das Auto für alle, die beim Beschleunigen mehr Spaß haben als beim Ankommen.",
"Wenn du ein Auto suchst, das schneller fährt als dein WiFi, bist du hier richtig.",
"Nicht das schnellste Auto, aber hey, es hat vier Räder und eine Hupe!",
"Das einzig wahre Fahren keine GPS-Fehler, nur pure Straßenmagie.",
"Mit diesem Auto wirst du die Straße genauso lieben wie das Benzin in deinem Tank.",
"Fahr einfach, und schau, wie viele Leute sich fragen, ob du gerade von der Rennstrecke kommst.",
"Dieses Auto bringt mehr Nervenkitzel als ein Achterbahn-Abenteuer!",
"Dieses Fahrzeug hat mehr Charakter als deine letzte Beziehung.",
"Es ist nicht das teuerste Auto, aber es fährt immer noch besser als deine Laune nach dem Montagmorgen!",
"Mit diesem Wagen wirst du zur Legende oder zumindest zum König des Parkhauses.",
"Schneller als dein Chefs Auto, langsamer als dein Instagram-Feed.",
"Wenn der Sound des Motors dich mehr motiviert als dein Wecker am Morgen!",
"Sicheres Fahren ist wichtig. Aber Spaß haben das ist die wahre Kunst!",
"Nicht der neueste Sportwagen, aber dafür ein echter Klassiker auf der Straße.",
"Weniger PS als dein Laptop, aber hey, er fährt!"
}
-- Zufällige Beschreibung auswählen
local randomIndex = math.random(1, #descriptions)
-- Beschreibung zurückgeben
return descriptions[randomIndex]
end

View file

@ -0,0 +1,44 @@
-- vehicleadmin.lua - Füge diese Datei in deinen client-Ordner ein
-- Füge einen Menüpunkt für das Fahrzeugadmin-System zum NPC-Menü hinzu
-- Diese Funktion wird aufgerufen, wenn der NPC-Target erstellt wird
local function AddVehicleAdminOption()
-- Prüfe, ob der Spieler die Berechtigung hat
QBCore.Functions.TriggerCallback('vehicleadmin:getPlayerJob', function(jobData)
if jobData and jobData.hasPermission then
-- Füge den Menüpunkt zum NPC hinzu, wenn der Spieler berechtigt ist
exports['qb-target']:AddTargetEntity(npcHandle, {
options = {
{
type = "client",
event = "vehicleadmin:openMenu",
icon = "fas fa-car-mechanic",
label = "Fahrzeugverwaltung",
}
},
distance = 2.5
})
end
end)
end
-- Registriere einen Event-Handler, der nach dem Hinzufügen der Standard-Target-Optionen ausgeführt wird
RegisterNetEvent('mh_garage:targetOptionsAdded')
AddEventHandler('mh_garage:targetOptionsAdded', function()
AddVehicleAdminOption()
end)
-- Füge einen Hook in die bestehende AddTargetOptions-Funktion ein
local originalAddTargetOptions = AddTargetOptions
AddTargetOptions = function()
originalAddTargetOptions()
TriggerEvent('mh_garage:targetOptionsAdded')
end
-- Registriere den Befehl für das Fahrzeugadmin-System
RegisterCommand('vehicleadmin', function()
TriggerEvent('vehicleadmin:openMenu')
end, false)
-- Registriere die Tastenbelegung (optional)
RegisterKeyMapping('vehicleadmin', 'Öffne Fahrzeug Admin Menu', 'keyboard', '')

View file

@ -0,0 +1,56 @@
-- vehicleadmin_integration.lua
-- Diese Datei integriert das Fahrzeugadmin-System mit dem Garagensystem
-- Füge einen Menüpunkt für das Fahrzeugadmin-System zum NPC-Menü hinzu
local function AddVehicleAdminOption()
-- Prüfe, ob der Spieler die Berechtigung hat
QBCore.Functions.TriggerCallback('vehicleadmin:getPlayerJob', function(jobData)
if jobData and jobData.hasPermission then
-- Füge den Menüpunkt zum NPC hinzu, wenn der Spieler berechtigt ist
if npcHandle and DoesEntityExist(npcHandle) then
exports['qb-target']:AddTargetEntity(npcHandle, {
options = {
{
type = "client",
event = "vehicleadmin:openMenu",
icon = "fas fa-car-mechanic",
label = "Fahrzeugverwaltung",
}
},
distance = 2.5
})
end
end
end)
end
-- Überschreibe die AddTargetOptions-Funktion, um unsere Option hinzuzufügen
local originalAddTargetOptions = AddTargetOptions
if originalAddTargetOptions then
AddTargetOptions = function()
originalAddTargetOptions()
AddVehicleAdminOption()
end
end
-- Registriere einen Event-Handler für das Hinzufügen der Target-Optionen
RegisterNetEvent('mh_garage:targetOptionsAdded')
AddEventHandler('mh_garage:targetOptionsAdded', function()
AddVehicleAdminOption()
end)
-- Füge einen Event-Handler hinzu, der nach dem Spawnen des NPCs ausgeführt wird
RegisterNetEvent('mh_garage:npcSpawned')
AddEventHandler('mh_garage:npcSpawned', function()
Wait(500) -- Warte kurz, damit der NPC vollständig gespawnt ist
AddVehicleAdminOption()
end)
-- Füge einen Hook in die SpawnGuardNPC-Funktion ein, um unseren Event auszulösen
local originalSpawnGuardNPC = SpawnGuardNPC
if originalSpawnGuardNPC then
SpawnGuardNPC = function(npc)
originalSpawnGuardNPC(npc)
TriggerEvent('mh_garage:npcSpawned')
end
end

View file

@ -0,0 +1,76 @@
RegisterNetEvent('mh_garage:verwaltungVeh')
AddEventHandler('mh_garage:verwaltungVeh', function()
QBCore.TriggerCallback('mh_garage:verwaltung', function(cb)
Debug("Verwaltung CB: "..json.encode(cb))
if cb[1] ~= nil then
local opt = {}
for i = 1, #cb, 1 do
local isingarage = cb[i].current_in_garage
local des = ""
if isingarage then
des = "Bearbeite das Fahrzeug\nKennzeichen: "..cb[i].current_plate.."\nGarage: "..cb[i].current_garage
else
des = "Bearbeite das Fahrzeug\nKennzeichen: "..cb[i].current_plate.."\nLetzte bekannte Garage: "..cb[i].current_garage
end
table.insert(opt, {
title = cb[i].current_name,
description = des,
icon = "car",
onSelect = function()
OpenVerwaltung(cb[i])
end
})
end
else
lib.notify({
title = "Fahrzeug Verwaltung",
description = "Du bist nicht im Besitz eines Fahrzeuges!",
type = "inform"
})
end
end)
end)
function OpenVerwaltung(vehicleInfos)
Debug("OpenVerwaltung: "..json.encode(vehicleInfos))
local garages = {}
for k, v in pairs(Config.Zonen) do
table.insert(garages, v.name)
end
lib.registerMenu({
id = 'some_menu_id',
title = 'Menu title',
position = 'top-right',
onSideScroll = function(selected, scrollIndex, args)
print("Scroll: ", selected, scrollIndex, args)
end,
onSelected = function(selected, secondary, args)
if not secondary then
print("Normal button")
else
if args.isCheck then
print("Check button")
end
if args.isScroll then
print("Scroll button")
end
end
print(selected, secondary, json.encode(args, {indent=true}))
end,
options = {
{label = "Name ändern", icon = "paper"},
{label = 'Transport to:', icon = 'arrows-up-down-left-right', values=garages},
}
}, function(selected, scrollIndex, args)
print(selected, scrollIndex, args)
end)
RegisterCommand('testmenu', function()
lib.showMenu('some_menu_id')
end)
end

View file

@ -0,0 +1,163 @@
Config = {}
Config.Debug = true
Config.PriceModel = false
Config.CallKeyVehicles = true
Config.Verwaltung = {
garage = false,
garage_change = 1000, -- Kosten um das Fahrzeug in einer anderen Garage zu versetzen.
garage_time = 10, -- Zeit in Minuten bis das Fahrzeug in der neuen Garage ist!
repair = false,
repair_car = 600, -- Kosten wenn das Fahrzeug Repariert werden soll
repair_time = 10, --Zeit in Minuten bis das Fahrzeug Repariert ist!
tank = false,
tank_car = 300, -- Kosten wenn das Fahrzeug getankt werden soll
tank_time = 3, -- Zeit in Minuten bis das Fahrzeug voll getankt ist
}
Config.Zonen = {
{
name = "pillboxgarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(213.9830, -808.7876, 30.0149, 166.4462),
model = "s_m_m_security_01",
distance = 30.0
},
vehicle_spawn = {
vector4(216.0978, -804.5941, 29.7967, 61.7316),
vector4(216.4074, -801.9208, 29.7928, 63.4452),
vector4(217.3208, -799.2861, 29.7802, 67.0612),
vector4(218.2428, -796.9962, 29.7684, 86.0924)
}
},
{
name = "grovegarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(-74.8718, -1824.8325, 25.9420, 249.5276),
model = "G_F_Y_Families_01",
distance = 30.0
},
vehicle_spawn = {
vector4(-62.5727, -1840.5316, 25.6792, 321.5169),
vector4(-60.1089, -1842.8113, 25.5816, 323.8478),
vector4(-60.1089, -1842.8113, 25.5816, 323.8478),
vector4(-54.8264, -1847.2078, 25.3799, 317.6915)
}
},
{
name = "vespuccigarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(-1184.6665, -1509.8247, 3.6493, 312.6639),
model = "s_m_m_security_01",
distance = 30.0
},
vehicle_spawn = {
vector4(-1191.6841, -1504.4095, 3.3688, 303.5921),
vector4(-1194.9706, -1500.1947, 3.3634, 310.3644),
vector4(-1196.7946, -1496.9948, 3.3652, 303.5580),
vector4(-1198.0444, -1493.9160, 3.3705, 311.4306)
}
},
{
name = "vinewoodgarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(-340.6176, 266.3422, 84.6795, 22.1944),
model = "s_m_m_security_01",
distance = 30.0
},
vehicle_spawn = {
vector4(-349.4257, 272.3725, 83.1077, 277.4619),
vector4(-349.8885, 276.0246, 83.9945, 276.0025),
vector4(-349.4035, 279.3595, 83.9495, 275.8749),
vector4(-349.3278, 282.7364, 83.9431, 278.1651)
}
},
{
name = "sandygarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(1637.97, 3796.94, 34.21, 189.13),
model = "s_m_m_security_01",
distance = 30.0
},
vehicle_spawn = {
vector4(1648.57, 3804.84, 33.81, 210.66),
vector4(1651.82, 3806.69, 33.82, 209.34),
vector4(1655.3, 3808.84, 33.83, 217.08),
vector4(1659.01, 3810.84, 33.84, 216.15)
}
},
{
name = "paletogarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(67.5230, 6412.9517, 30.4838, 230.1375),
model = "s_m_m_security_01",
distance = 30.0
},
vehicle_spawn = {
vector4(64.5739, 6406.8584, 30.2258, 208.3274),
vector4(61.9570, 6404.0493, 30.2258, 202.9158),
vector4(59.0419, 6401.0122, 30.2258, 211.3612),
vector4(73.0162, 6404.4741, 30.2258, 131.4993)
}
},
{
name = "eastsidegarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(1010.1598, -2289.5979, 29.5095, 186.2906),
model = "s_m_m_security_01",
distance = 30.0
},
vehicle_spawn = {
vector4(1003.6630, -2299.5208, 29.5095, 266.1712),
vector4(1005.3187, -2304.5198, 29.5095, 261.7787),
vector4(1005.2725, -2308.4385, 29.5095, 277.7379),
vector4(1004.2752, -2313.1870, 29.5095, 268.2005)
}
},
{
name = "cayogarage",
price = nil, --pro FZ
NPC = {
spawn = vector4(4505.5659, -4549.3335, 3.0960, 69.6222),
model = "IG_JuanStrickler",
distance = 30.0
},
vehicle_spawn = {
vector4(4501.0264, -4546.2852, 3.0278, 24.5729),
vector4(4497.0498, -4536.6616, 3.1636, 276.0185),
}
},
}
Config.Log = {
Webhook = "https://discord.com/api/webhooks/1366812966049288192/9ZjJC9_gLX6Fk-acf0YSW_haGWpCqG9zRGWaj0wCKLZefp8FX-GwNZBP77H6K93KfIw3",
Color = {
green = 56108,
grey = 8421504,
red = 16711680,
orange = 16744192,
blue = 2061822,
purple = 11750815,
},
SystemName = "Evolution_State_life Log [Garage]",
UserAvatar = '',
SystemAvatar = '',
}

View file

@ -0,0 +1,3 @@
cprice = {
["asea"] = 3,
}

View file

@ -0,0 +1,19 @@
author 'Mîhó'
fx_version 'adamant'
game 'gta5'
lua54 'yes'
client_scripts {
'@ox_lib/init.lua',
'config/*.lua',
'client/*.lua',
'client/vehicleadmin.lua'
}
server_scripts {
'@oxmysql/lib/MySQL.lua',
'config/*.lua',
'server/*.lua',
'server/vehicleadmin.lua'
}

View file

@ -0,0 +1,59 @@
function sendToDiscord(Titel, Text, Color) ------ Sende Nachricht an Channel: Join/Left
local embeds = {
{
["title"]=Text,
["type"]="rich",
["color"] =Config.Log.Color[Color],
["footer"]= {
["text"]= Config.Log.SystemName,
},
}
}
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 = Titel.." - Mîhó",avatar_url = Config.SystemAvatar, embeds = embeds, tts = TTS}), { ['Content-Type'] = 'application/json' })
end
AddEventHandler('mh_garage:log')
RegisterServerEvent('mh_garage:log', function(type)
local Player = QBCore.Functions.GetPlayer(source)
local PlyData = Player.PlayerData
local Color = "purple"
Playerinfo = {
name = PlyData.charinfo.firstname .. " ".. PlyData.charinfo.lastname,
citizenid = PlyData.citizenid,
}
local user = Playerinfo.name.."[".. Playerinfo.citizenid .."]"
if type == "call" then
Text = "Dr. Teddy wurde von " .. user .." gerufen."
Color = "grey"
elseif type == "cash" then
Text = user.." hat Bar Bezahlt."
Color = "green"
elseif type == "bank" then
Text = user .. "hat via Überweisung Bezahlt."
Color = "green"
elseif type == "noMoney" then
Text = user .." Hatte nicht genug Geld."
Color = "orange"
elseif type == "noPlayer" then
Text = user .. " Wurde nicht gefunden und abgebrochen!"
Color = "red"
elseif type == "storno" then
Text = user .. " Hat die Behandlung doch Abgelehnt."
Color = "red"
elseif type == "heal" then
Text = user.. " Wurde Geheilt."
Color = "green"
elseif type == "end" then
Text = "NPC wurde wieder Entfernt..."
Color = "blue"
end
sendToDiscord("Garage", Text, Color)
end)

View file

@ -0,0 +1,159 @@
QBCore = exports['qb-core']:GetCoreObject()
local test_vari = {}
RegisterServerEvent('mh_garage:setMods')
AddEventHandler('mh_garage:setMods', function(mods)
if test_vari[mods.plate] == true then
return
else
MySQL.query("SELECT mods FROM player_vehicles WHERE plate = ?", {mods.plate}, function(rs)
-- Prüfen ob rs überhaupt Daten enthält
if rs and rs[1] then
-- Wenn mods ein String ist, konvertieren wir es zu einem Table
local modsData = type(rs[1].mods) == "string" and json.decode(rs[1].mods) or rs[1].mods
if not modsData or next(modsData) == nil then
-- Hier sollten Sie wahrscheinlich auch die mods-Daten übergeben, nicht nur plate
MySQL.query("UPDATE player_vehicles SET mods = ? WHERE plate = ?", {json.encode(mods), mods.plate})
test_vari[mods.plate] = true
else
test_vari[mods.plate] = true
end
end
end)
end
end)
QBCore.Functions.CreateCallback('mh_garage:storedVehicle', function(source, cb, veh, zone)
local Player = QBCore.Functions.GetPlayer(source)
if Player ~= nil then
if Player.Functions.GetMoney('bank', zone.price) then
MySQL.query("SELECT * FROM player_vehicles WHERE citizenid = ? AND plate = ?", {Player.PlayerData.citizenid, veh.plate}, function(rs)
if rs[1] ~= nil then
MySQL.query("UPDATE player_vehicles SET garage = ?, mods = ? WHERE plate = ?", {zone.name, json.encode(veh), veh.plate})
DelVehParking(veh.plate)
cb({
status = true,
text = "Fahrzeug erfolgreich eingeparkt!",
type = "success",
other = false,
police = false
})
else
MySQL.query("SELECT * FROM vehicle_keys WHERE owner = ? AND plate = ?", {Player.PlayerData.citizenid, veh.plate}, function(rs)
if rs[1] ~= nil then
MySQL.query("UPDATE player_vehicles SET garage = ?, mods = ? WHERE plate = ?", {zone.name, json.encode(veh), veh.plate})
--TriggerEvent('mh_Parking:removeVehicle', source, veh.plate)
--DelVehParking(veh.plate)
cb({
status = true,
text = "Fahrzeug erfolgreich eingeparkt!",
type = "success",
other = true,
police = false
})
else
cb({
status = false,
text = "Du besitzt kein Schlüssel für dieses Fahrzeug.",
type = "warning",
other = false,
police = true
})
end
end)
end
end)
end
end
end)
function DelVehParking(plate)
MySQL.query("SELECT * FROM vehicle_parking WHERE plate = ?", {plate}, function(rs)
if rs[1] ~= nil then
MySQL.query("DELETE FROM vehicle_parking WHERE plate = ?", {plate})
end
end)
end
QBCore.Functions.CreateCallback('mh_garage:retrieveOwnerVehicle', function(source, cb, zone)
local _source = source
local Player = QBCore.Functions.GetPlayer(_source)
local pedid = Player.PlayerData.citizenid
local veh = {}
MySQL.query("SELECT * FROM player_vehicles WHERE citizenid = ? and garage = ?", {pedid, zone}, function(rs)
if rs ~= nil and rs[1] ~= nil then
for k, v in pairs (rs) do
table.insert(veh, {
vehicle = v.vehicle,
mods = v.mods,
plate = v.plate,
name = v.name
})
end
Wait(100)
cb(veh)
else
cb(false)
end
end)
end)
QBCore.Functions.CreateCallback('mh_garage:retrieveKeyVehicle', function(source, cb, zone)
local _source = source
local Player = QBCore.Functions.GetPlayer(_source)
local pedid = Player.PlayerData.citizenid
local veh = {}
MySQL.query("SELECT pv.* FROM player_vehicles pv JOIN vehicle_keys vk ON pv.plate = vk.plate WHERE vk.owner = ? AND vk.count > 0 AND pv.garage = ?", {pedid, zone}, function(vehicles)
if vehicles and #vehicles > 0 then
for _, vehicle in pairs(vehicles) do
table.insert(veh, {
vehicle = vehicle.vehicle,
mods = vehicle.mods,
plate = vehicle.plate,
name = vehicle.name
})
end
Wait(100)
cb(veh)
else
cb(false)
end
end)
end)
QBCore.Functions.CreateCallback('mh_garage:verwaltung', function(source, cb)
local Player = QBCore.Functions.GetPlayer(source)
local vehicles = {}
MySQL.query("SELECT * FROM player_vehicles WHERE citizenid = ?", {Player.PlayerData.citizenid}, function(rs)
if rs and rs[1] then
for k, v in pairs(rs) do
table.insert(vehicles, {
current_garage = v.garage,
current_in_garage = v.parking,
current_name = v.name,
current_plate = v.plate,
})
end
end
end)
return vehicles
end)
RegisterServerEvent('mh_garage:spawnedVehicle')
AddEventHandler('mh_garage:spawnedVehicle', function(netID, plate)
MySQL.query("UPDATE player_vehicles SET garage = ? WHERE plate = ?", {"OUT", plate})
end)
QBCore.Functions.CreateCallback('mh_garage:CheckownerVehicles', function(source, cb, plate)
MySQL.query("SELECT * FROM player_vehicles WHERE plate = ?", {plate}, function(rs)
if rs ~= nil and rs[1] ~= nil then
cb(true)
else
cb(false)
end
end)
end)

View file

@ -0,0 +1,181 @@
-- vehicleadmin.lua - Füge diese Datei in deinen server-Ordner ein
-- Erweitere die Log-Funktion für das Fahrzeugadmin-System
RegisterServerEvent('vehicleadmin:log')
AddEventHandler('vehicleadmin:log', function(action, plate, garage)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local playerName = Player.PlayerData.charinfo.firstname .. " " .. Player.PlayerData.charinfo.lastname
local citizenid = Player.PlayerData.citizenid
local jobName = Player.PlayerData.job.name
local jobLabel = Player.PlayerData.job.label
local logText = ""
local logColor = "blue"
if action == "move" then
logText = playerName .. " (" .. jobLabel .. ") hat Fahrzeug " .. plate .. " in Garage " .. garage .. " gestellt."
elseif action == "delete" then
logText = playerName .. " (" .. jobLabel .. ") hat Fahrzeug " .. plate .. " von der Map gelöscht."
logColor = "orange"
elseif action == "repair" then
logText = playerName .. " (" .. jobLabel .. ") hat Fahrzeug " .. plate .. " repariert."
logColor = "green"
end
-- Verwende die bestehende Log-Funktion
sendToDiscord("Fahrzeugadmin", logText, logColor)
-- Speichere den Log in der Datenbank (optional)
MySQL.Async.execute('INSERT INTO admin_logs (action, player_name, citizenid, job, target_plate, target_garage, timestamp) VALUES (?, ?, ?, ?, ?, ?, NOW())',
{action, playerName, citizenid, jobName, plate, garage or "none"})
end)
-- Füge zusätzliche Callback-Funktionen für erweiterte Features hinzu
QBCore.Functions.CreateCallback('vehicleadmin:getVehicleHistory', function(source, cb, plate)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then
cb(false)
return
end
-- Prüfe, ob der Spieler die Berechtigung hat
local hasPermission = false
local playerJob = Player.PlayerData.job.name
if QBCore.Functions.HasPermission(src, 'admin') then
hasPermission = true
elseif playerJob == 'police' or playerJob == 'mechanic' then
hasPermission = true
end
if not hasPermission then
cb(false)
return
end
-- Hole den Fahrzeugverlauf aus der Datenbank
MySQL.Async.fetchAll('SELECT * FROM admin_logs WHERE target_plate = ? ORDER BY timestamp DESC LIMIT 20', {plate}, function(results)
if results and #results > 0 then
cb(results)
else
cb({})
end
end)
end)
-- Füge einen Event-Handler für das Löschen von Fahrzeugen hinzu
RegisterServerEvent('vehicleadmin:deleteVehicle')
AddEventHandler('vehicleadmin:deleteVehicle', function(plate)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
-- Prüfe, ob der Spieler die Berechtigung hat
local hasPermission = false
local playerJob = Player.PlayerData.job.name
if QBCore.Functions.HasPermission(src, 'admin') then
hasPermission = true
elseif playerJob == 'police' or playerJob == 'mechanic' then
hasPermission = true
end
if not hasPermission then
TriggerClientEvent('ox_lib:notify', src, {
title = 'Keine Berechtigung',
description = 'Du hast keine Berechtigung für diese Aktion',
type = 'error'
})
return
end
-- Lösche das Fahrzeug aus der Datenbank
MySQL.Async.execute('DELETE FROM player_vehicles WHERE plate = ?', {plate}, function(rowsChanged)
if rowsChanged > 0 then
-- Lösche auch alle zugehörigen Schlüssel
MySQL.Async.execute('DELETE FROM vehicle_keys WHERE plate = ?', {plate})
-- Lösche das Fahrzeug aus dem Parking-System
MySQL.Async.execute('DELETE FROM vehicle_parking WHERE plate = ?', {plate})
-- Log die Aktion
TriggerEvent('vehicleadmin:log', "delete_permanent", plate, nil)
TriggerClientEvent('ox_lib:notify', src, {
title = 'Fahrzeugverwaltung',
description = 'Fahrzeug wurde permanent gelöscht',
type = 'success'
})
else
TriggerClientEvent('ox_lib:notify', src, {
title = 'Fahrzeugverwaltung',
description = 'Fahrzeug nicht gefunden',
type = 'error'
})
end
end)
end)
-- Füge einen Event-Handler für das Ändern des Fahrzeugbesitzers hinzu
RegisterServerEvent('vehicleadmin:changeOwner')
AddEventHandler('vehicleadmin:changeOwner', function(plate, newOwnerCID)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
-- Prüfe, ob der Spieler die Berechtigung hat
if not QBCore.Functions.HasPermission(src, 'admin') then
TriggerClientEvent('ox_lib:notify', src, {
title = 'Keine Berechtigung',
description = 'Nur Admins können den Besitzer ändern',
type = 'error'
})
return
end
-- Prüfe, ob der neue Besitzer existiert
MySQL.Async.fetchAll('SELECT * FROM players WHERE citizenid = ?', {newOwnerCID}, function(players)
if not players or #players == 0 then
TriggerClientEvent('ox_lib:notify', src, {
title = 'Fehler',
description = 'Spieler mit dieser Citizen ID nicht gefunden',
type = 'error'
})
return
end
-- Ändere den Besitzer des Fahrzeugs
MySQL.Async.execute('UPDATE player_vehicles SET citizenid = ? WHERE plate = ?', {newOwnerCID, plate}, function(rowsChanged)
if rowsChanged > 0 then
-- Erstelle einen neuen Schlüssel für den neuen Besitzer
MySQL.Async.execute('INSERT INTO vehicle_keys (plate, owner, count) VALUES (?, ?, 1) ON DUPLICATE KEY UPDATE count = 1', {plate, newOwnerCID})
-- Log die Aktion
local newOwnerInfo = json.decode(players[1].charinfo)
local newOwnerName = newOwnerInfo.firstname .. " " .. newOwnerInfo.lastname
TriggerEvent('vehicleadmin:log', "change_owner", plate, newOwnerName)
TriggerClientEvent('ox_lib:notify', src, {
title = 'Fahrzeugverwaltung',
description = 'Fahrzeugbesitzer wurde geändert',
type = 'success'
})
else
TriggerClientEvent('ox_lib:notify', src, {
title = 'Fahrzeugverwaltung',
description = 'Fahrzeug nicht gefunden',
type = 'error'
})
end
end)
end)
end)