FiveM-Mechaniksystem: Tuning, Reparatur und Fahrzeugaufträge
Erstelle ein komplettes FiveM-Mechaniksystem mit Reparaturen, Tuning, Abschleppaufträgen, Werkstattoberflächen und Scripts für QBCore und ESX.
Agency Scripts
Gründer und leitender Entwickler bei Agency Scripts
Die Architektur eines Mechanikerjobs entwerfen
Ein Mechanikerjobsystem ist eine der beliebtesten und lohnendsten Funktionen, die du für einen FiveM-Rollenspielserver entwickeln kannst. Im Gegensatz zu einfachen Reparaturskripten, die lediglich SetVehicleFixed(), ein ordentliches Mechanikersystem bietet eine vollständige Jobökonomie mit spezialisierten Rollen, Teileinventaren und Interaktionen zwischen Spielern, die das Rollenspiel fördern. Die Architektur muss mehrere Mechanikerwerkstätten auf der Karte berücksichtigen, die jeweils unterschiedlichen Spielergruppen gehören können. Außerdem braucht sie eine Jobranghierarchie, die festlegt, wer welche Reparaturen durchführen darf. Als Grundlage benötigst du eine gemeinsame Konfiguration, in der Werkstattstandorte, verfügbare Dienstleistungen je Rang, Teilepreise und die erforderlichen Jobränge für fortgeschrittene Reparaturen wie Motorumbauten oder Turboladerinstallationen definiert sind. Das System sollte in das vorhandene Job-Framework deines Servers integriert werden, egal ob es QBCore, ESX oder eine eigene Lösung ist. So können Spieler dem Mechanikerjob mit korrekter Gehaltsabwicklung und Erfassung des Dienststatus beitreten und ihn wieder verlassen.
Jobränge und Berechtigungssystem
Ein abgestuftes Jobrangsystem verleiht deinem Mechanikerjob mehr Tiefe und motiviert Spieler, sich hochzuarbeiten. Lege zunächst klare Ränge mit bestimmten Berechtigungen fest: Ein Auszubildender kann vielleicht nur Fahrzeuge waschen und kleinere Karosserieschäden reparieren, ein regulärer Mechaniker kann Motorreparaturen und Reifenwechsel durchführen, ein leitender Mechaniker kann Leistungstuning und Lackierungen anbieten und der Werkstattbesitzer kann Mitarbeiter verwalten und Servicepreise festlegen. Speichere diese Rangdefinitionen in einer gemeinsamen Konfiguration, damit Client und Server einheitlich darauf zugreifen können. Hier ist eine Beispielkonfiguration, die Ränge den erlaubten Dienstleistungen zuordnet:
Config.MechanicGrades = {
[0] = {
label = 'Trainee',
services = {'wash', 'body_minor'},
payMultiplier = 0.7
},
[1] = {
label = 'Mechanic',
services = {'wash', 'body_minor', 'body_major', 'engine_repair', 'tire_replace', 'brake_repair'},
payMultiplier = 1.0
},
[2] = {
label = 'Senior Mechanic',
services = {'wash', 'body_minor', 'body_major', 'engine_repair', 'tire_replace',
'brake_repair', 'spray_paint', 'performance_tune', 'turbo_install'},
payMultiplier = 1.3
},
[3] = {
label = 'Shop Owner',
services = 'all',
payMultiplier = 1.5,
canManage = true
}
}
Config.ServicePrices = {
wash = 200,
body_minor = 800,
body_major = 2500,
engine_repair = 3500,
tire_replace = 1200,
brake_repair = 1500,
spray_paint = 5000,
performance_tune = 15000,
turbo_install = 25000
}
Validiere serverseitig immer den Rang des Spielers, bevor du eine Dienstleistung ausführst. Vertraue niemals darauf, dass der Client meldet, welche Dienstleistungen verfügbar sind, denn ein Cheater könnte die NUI so verändern, dass sie beliebige Dienstleistungsanfragen sendet. Der Server-Callback sollte den aktuellen Job des Spielers, seinen Rang und prüfen, ob die angeforderte Dienstleistung in der Liste für seinen Rang enthalten ist, bevor er mit der Reparatur fortfährt.
Fahrzeugreparaturen und Teilesystem
Realistische Reparaturmechaniken gehen über einen einzelnen Native-Aufruf hinaus. Anstatt ein Fahrzeug sofort zu reparieren, teile den Reparaturvorgang in Schritte auf, die Zeit in Anspruch nehmen und Teile aus dem Inventar des Mechanikers verbrauchen. Wenn ein Spieler sein Auto zur Motorreparatur bringt, muss der Mechaniker die richtigen Teile in seinem persönlichen Inventar oder im gemeinsamen Lager der Werkstatt haben. Verwende ein Fortschrittsbalkensystem, um die Dauer der Reparatur zu simulieren. So entstehen natürliche Rollenspielmomente, in denen der Kunde wartet und sich mit dem Mechaniker unterhält. Die Reparaturlogik sollte mithilfe von Native-Funktionen gezielt einzelne Fahrzeugkomponenten ansprechen. So kannst du den Motor reparieren, ohne Karosserieschäden zu beheben, oder Reifen wechseln, ohne den Motorzustand zu beeinflussen:
local RepairFunctions = {
engine_repair = function(vehicle)
local parts = {'engine_oil', 'spark_plugs', 'coolant'}
if not HasRequiredParts(parts) then
return false, 'Missing required parts'
end
RemovePartsFromInventory(parts)
-- Animate the repair
TaskTurnPedToFaceEntity(PlayerPedId(), vehicle, 1000)
Wait(1000)
if not StartProgressBar('Repairing engine...', 15000, 'mechanic_repair') then
return false, 'Repair cancelled'
end
SetVehicleEngineHealth(vehicle, 1000.0)
SetVehicleEngineOn(vehicle, true, true, false)
return true
end,
body_major = function(vehicle)
local parts = {'body_panel', 'filler_putty', 'paint_primer'}
if not HasRequiredParts(parts) then
return false, 'Missing required parts'
end
RemovePartsFromInventory(parts)
if not StartProgressBar('Repairing body damage...', 20000, 'mechanic_repair') then
return false, 'Repair cancelled'
end
SetVehicleBodyHealth(vehicle, 1000.0)
SetVehicleDeformationFixed(vehicle)
return true
end,
tire_replace = function(vehicle, tireIndex)
local parts = {'tire_set'}
if not HasRequiredParts(parts) then
return false, 'Missing required parts'
end
RemovePartsFromInventory(parts)
if not StartProgressBar('Replacing tire...', 8000, 'mechanic_repair') then
return false, 'Repair cancelled'
end
SetVehicleTyreFixed(vehicle, tireIndex)
return true
end
}
Das Teilesystem schafft eine zusätzliche Wirtschaftsebene auf deinem Server. Beschaffe Ersatzteile bei Großhändlern in Form von NPCs oder lass Spieler sie an Industriestandorten herstellen. Mechanikerwerkstätten können Teile zu Großhandelspreisen in größeren Mengen einkaufen und in einem gemeinsamen Werkstattinventar lagern. Dadurch muss der Werkstattbesitzer seine Lieferkette verwalten, damit der Betrieb reibungslos läuft. Diese Dynamik von Angebot und Nachfrage verleiht dem Rollenspielerlebnis enorme Tiefe.
Lackierungen und kosmetische Dienstleistungen
Lackierungen zählen zu den optisch ansprechendsten Dienstleistungen einer Mechanikerwerkstatt. Für eine gute Umsetzung musst du mit mehreren nativen Funktionen zur Fahrzeugfarbe arbeiten. FiveM bietet Natives für Primärfarbe, Sekundärfarbe, Perleffekt, Radfarbe und benutzerdefinierte RGB-Werte. Erstelle eine Farbauswahl, in der der Mechaniker Farben aus einer Vorgabe auswählen oder gegen einen Aufpreis benutzerdefinierte RGB-Werte eingeben kann. Die NUI sollte eine Echtzeitvorschau anzeigen, indem sie die Farbe vorübergehend auf das Fahrzeug anwendet, während der Mechaniker die Optionen durchgeht. So wendest du die Farbe serverseitig an, nachdem der Mechaniker die Lackierung bestätigt und der Kunde bezahlt hat:
RegisterNetEvent('mechanic:server:applyPaint', function(netId, paintData, customerId)
local src = source
local Mechanic = QBCore.Functions.GetPlayer(src)
local Customer = QBCore.Functions.GetPlayer(customerId)
if not Mechanic or not Customer then return end
if Mechanic.PlayerData.job.name ~= 'mechanic' then return end
local gradeServices = Config.MechanicGrades[Mechanic.PlayerData.job.grade.level].services
if gradeServices ~= 'all' and not TableContains(gradeServices, 'spray_paint') then
return TriggerClientEvent('QBCore:Notify', src, 'Not authorized', 'error')
end
local price = paintData.isCustomRGB and Config.ServicePrices.spray_paint * 1.5
or Config.ServicePrices.spray_paint
if Customer.Functions.RemoveMoney('cash', price, 'mechanic-paint') then
local shopCut = math.floor(price * 0.6)
local mechanicCut = price - shopCut
Mechanic.Functions.AddMoney('cash', mechanicCut, 'mechanic-paint-commission')
AddToShopFunds(Mechanic.PlayerData.job.grade.level >= 3 and src, shopCut)
TriggerClientEvent('mechanic:client:applyPaint', customerId, netId, paintData)
TriggerClientEvent('QBCore:Notify', src, 'Paint applied - earned $' .. mechanicCut, 'success')
TriggerClientEvent('QBCore:Notify', customerId, 'Vehicle painted for $' .. price, 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Customer cannot afford this', 'error')
end
end)
Zusätzlich zur Grundlackierung kannst du Folierungen, Neonbeleuchtung und Scheibentönung als separate kosmetische Dienstleistungen anbieten. Für jede Dienstleistung sollten eigene Ersatzteile und ein eigener Preis erforderlich sein. Für Neonbeleuchtung sind beispielsweise Neon-Kits aus dem Teileinventar nötig. Die visuellen Effekte werden mit den SetVehicleNeonLightEnabled und SetVehicleNeonLightsColour Natives angewendet. Für die Scheibentönung wird SetVehicleWindowTint mit verschiedenen Tönungsstufen, die durch lokale Servergesetze eingeschränkt sein können und der Polizei einen Grund geben, Spieler wegen illegaler Tönungen anzuhalten.
Leistungsupgrades und Tuning
Beim Leistungstuning können Mechaniker ihr Können richtig zeigen und auf dem Server gutes Geld verdienen. FiveM bietet umfangreiche Natives zur Fahrzeugmodifikation über die SetVehicleMod Funktion, die einen Mod-Typ und einen Mod-Index entgegennimmt. Die Mod-Typen umfassen Motor-Upgrades (Typ 11), Bremsen (Typ 12), Getriebe (Typ 13), Federung (Typ 15), Panzerung (Typ 16) und Turbo (Typ 18). Jeder Mod-Typ hat mehrere Stufen, die die Leistung des Fahrzeugs schrittweise verbessern. Erstelle eine Tuning-Oberfläche, die die verfügbaren Upgrades für das aktuelle Fahrzeug, die Kosten jeder Stufe und idealerweise einen Wertevergleich mit Vorher- und Nachher-Werten für Geschwindigkeit, Beschleunigung, Bremsen und Handling anzeigt:
function GetAvailableUpgrades(vehicle)
local upgrades = {}
local modTypes = {
{type = 11, label = 'Engine', icon = 'fa-engine'},
{type = 12, label = 'Brakes', icon = 'fa-brake'},
{type = 13, label = 'Transmission', icon = 'fa-gears'},
{type = 15, label = 'Suspension', icon = 'fa-car'},
{type = 16, label = 'Armor', icon = 'fa-shield'},
{type = 18, label = 'Turbo', icon = 'fa-bolt'}
}
SetVehicleModKit(vehicle, 0)
for _, mod in ipairs(modTypes) do
local currentLevel = GetVehicleMod(vehicle, mod.type)
local maxLevel = GetNumVehicleMods(vehicle, mod.type)
local isTurbo = mod.type == 18
table.insert(upgrades, {
type = mod.type,
label = mod.label,
icon = mod.icon,
currentLevel = currentLevel,
maxLevel = isTurbo and 1 or maxLevel,
installed = isTurbo and IsToggleModOn(vehicle, mod.type) or currentLevel >= 0,
price = CalculateUpgradePrice(mod.type, currentLevel + 1)
})
end
return upgrades
end
function ApplyPerformanceUpgrade(vehicle, modType, level)
SetVehicleModKit(vehicle, 0)
if modType == 18 then
ToggleVehicleMod(vehicle, 18, true)
else
SetVehicleMod(vehicle, modType, level, false)
end
end
Für Leistungsupgrades sollten hochwertige Teile wie Turbokits, Renngetriebe oder Sportbremsanlagen erforderlich sein. Diese Teile können von spezialisierten Lieferanten bezogen oder von Spielern mit den passenden Fähigkeiten hergestellt werden. So entstehen Abhängigkeiten zwischen verschiedenen Berufen, die die Serverwirtschaft bereichern. Überprüfe Upgrade-Anfragen immer serverseitig, damit Clients keine Modifikationen anwenden können, für die sie nicht bezahlt haben oder für die ihnen die benötigten Teile fehlen.
Abrechnungssystem und Umsatzaufteilung
Ein übersichtliches Abrechnungssystem verbindet das gesamte Mechanikererlebnis und verwaltet die finanziellen Transaktionen zwischen dem Mechaniker, dem Kunden und der Werkstatt. Wenn ein Mechaniker einen Auftrag abschließt, wird eine detaillierte Rechnung erstellt, auf der jede durchgeführte Dienstleistung und ihre Kosten aufgeführt sind. Zeige dem Kunden die Rechnung per Benachrichtigung oder NUI-Popup an, die er akzeptieren muss, bevor die Zahlung verarbeitet wird. Teile den Umsatz zwischen dem Mechaniker, der die Arbeit ausgeführt hat, und dem Geschäftskonto der Werkstatt auf. Das Aufteilungsverhältnis kann vom Werkstattbesitzer konfiguriert werden. Hier ist ein serverseitiges Abrechnungssystem zur Erstellung von Rechnungen und Verarbeitung von Zahlungen:
local activeInvoices = {}
RegisterNetEvent('mechanic:server:createInvoice', function(customerId, services)
local src = source
local Mechanic = QBCore.Functions.GetPlayer(src)
local Customer = QBCore.Functions.GetPlayer(customerId)
if not Mechanic or not Customer then return end
if Mechanic.PlayerData.job.name ~= 'mechanic' then return end
local totalPrice = 0
local lineItems = {}
for _, service in ipairs(services) do
local price = Config.ServicePrices[service.name]
if price then
totalPrice = totalPrice + price
table.insert(lineItems, {
name = service.label,
price = price
})
end
end
local invoiceId = 'INV-' .. os.time() .. '-' .. math.random(1000, 9999)
activeInvoices[invoiceId] = {
mechanic = src,
customer = customerId,
total = totalPrice,
items = lineItems,
shopId = Mechanic.PlayerData.metadata.currentShop,
timestamp = os.time()
}
TriggerClientEvent('mechanic:client:showInvoice', customerId, invoiceId, lineItems, totalPrice)
end)
RegisterNetEvent('mechanic:server:payInvoice', function(invoiceId)
local src = source
local invoice = activeInvoices[invoiceId]
if not invoice or invoice.customer ~= src then return end
local Customer = QBCore.Functions.GetPlayer(src)
local Mechanic = QBCore.Functions.GetPlayer(invoice.mechanic)
if Customer.Functions.RemoveMoney('cash', invoice.total, 'mechanic-invoice') then
local mechanicShare = math.floor(invoice.total * 0.4)
local shopShare = invoice.total - mechanicShare
if Mechanic then
Mechanic.Functions.AddMoney('cash', mechanicShare, 'mechanic-wage')
TriggerClientEvent('QBCore:Notify', invoice.mechanic,
'Received $' .. mechanicShare .. ' for services', 'success')
end
UpdateShopBalance(invoice.shopId, shopShare)
activeInvoices[invoiceId] = nil
TriggerClientEvent('QBCore:Notify', src, 'Paid $' .. invoice.total, 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Not enough cash', 'error')
end
end)
Unterstütze mehrere Zahlungsmethoden, darunter Bargeld, Banküberweisungen und sogar Kryptowährungen, falls dein Server über ein Kryptosystem verfügt. Protokolliere alle Transaktionen in einer Datenbank, damit Werkstattbesitzer ihre Umsätze überprüfen, ihre erfolgreichsten Mechaniker ermitteln und verdächtige Abrechnungsmuster erkennen können. Diese Finanzaufzeichnungen ermöglichen außerdem Steuersysteme und Roleplay-Interaktionen mit der Regierung, bei denen der Staat Werkstätten prüfen kann.
Lager und Shop-Inventar verwalten
Jede Werkstatt benötigt ein gemeinsames Lager, in dem Teile aufbewahrt werden und auf das alle Mitarbeiter im Dienst zugreifen können. Integriere dein Inventarsystem, egal ob ox_inventory, qb-inventory oder eine eigene Lösung, um ein werkstattspezifisches Lager einzurichten, auf das nur autorisierte Mechaniker zugreifen können. Der Werkstattbesitzer sollte Teile bei einem Großhändler-NPC bestellen können. Dabei wird Geld vom Geschäftskonto der Werkstatt abgezogen und die Teile werden nach einer konfigurierbaren Lieferzeit dem Lager hinzugefügt. Diese Verzögerung bildet reale Lieferketten nach und verhindert sofortige Nachbestellungen. Protokolliere den Zugriff auf das Lager, damit der Werkstattbesitzer sehen kann, welche Mechaniker welche Teile entnommen haben, und so internen Diebstahl verhindert. Clientseitig kannst du eine Zielinteraktion an einem bestimmten Objekt in der Werkstatt verwenden, etwa an einem Werkzeugschrank oder Teilelager, um das Lager zu öffnen. Kombiniere das Lager mit einem Crafting-System, in dem Mechaniker aus Rohmaterialien komplexe Teile herstellen können, etwa indem sie ein Turbogehäuse, ein Laufrad und ein Wastegate zu einem vollständigen Turbokit zusammenbauen. So kommt eine weitere kompetenzbasierte Ebene zum Beruf hinzu.
Abschleppwagen und Pannenhilfe
Wenn du den Mechanikerberuf um Abschlepp- und Pannenhilfsdienste erweiterst, steigert das die Aktivität und das Verdienstpotenzial des Berufs erheblich. Mechaniker sollten einen Abschleppwagen aus ihrer Werkstatt holen, zum Standort eines liegengebliebenen Spielers fahren, das defekte Fahrzeug mit der AttachEntityToEntity Native befestigen und zur Reparatur in die Werkstatt abschleppen können. Implementiere ein Dispositionssystem, über das Spieler per Telefon Pannenhilfe anfordern können. Dadurch wird ein Karten-Blip erstellt, der für alle Mechaniker im Dienst sichtbar ist. Der erste Mechaniker, der den Auftrag annimmt, erhält den Job, und es wird eine GPS-Route zum Standort des Kunden angezeigt. Berechne für das Befestigungssystem die passenden Versatzpositionen anhand des Abschleppwagenmodells, damit das abgeschleppte Fahrzeug korrekt auf der Ladefläche steht. Füge für den Abschleppdienst eine entfernungsabhängige Gebühr hinzu, sodass längere Abschleppfahrten den Kunden mehr kosten. Das gibt Mechanikern einen Anreiz, Aufträge in ihrer Umgebung anzunehmen, während lukrative Fernaufträge über die ganze Karte weiterhin möglich sind.