Category hub
Compare police, mechanic, drug, civilian, and economy systems in the main jobs hub before you commit to a single resource.
Open job scriptsStarke Job- und Roleplay-Setups hängen nie nur an einem Script. Über die folgenden Hubs vergleichst du installierbare Produkte, Bundles und den passenden Framework-Fit vor dem Kauf.
Category hub
Compare police, mechanic, drug, civilian, and economy systems in the main jobs hub before you commit to a single resource.
Open job scriptsFramework hub
Move into the QBCore landing page to compare verified scripts, framework fit, and install-ready products built for modern FiveM servers.
Open QBCore hubPremium catalog
Move from research into the main shop to compare real products, framework labels, screenshots, and production-ready quality signals.
Open premium shopWirtschaftsskripte sind das finanzielle Rückgrat jedes Rollenspiel-Servers. Wenn das Geld bricht, zahlen Jobs nicht mehr aus, Geschäfte verkaufen nichts mehr und Spieler verlieren innerhalb von Minuten das Vertrauen. Dieser Leitfaden behandelt die 12 kritischsten Wirtschaftsfehler auf ESX, QBCore und QBox – Duplikations-Exploits, Bankfehler, Ladenpreise und Inflationsmanagement – mit Diagnoseschritten und funktionierendem Code.
Wohnungsskripte gehören zu den komplexesten Ressourcen auf einem FiveM-Server – Innenräume, Möbel, Schlüssel, Lagerung, Mitbewohner und Immobilienwirtschaft in einem System. Dieser Leitfaden führt durch die 12 häufigsten Wohnungsfehler auf ESX, QBCore und QBox mit Diagnoseschritten und funktionierendem Code.
Drogen-Skripte kombinieren Inventarsysteme, Verarbeitungsschleifen, NPC-Interaktionen, Polizeialarm und Wirtschaftsintegration – mehr bewegliche Teile bedeuten mehr Fehlerquellen. Dieser Leitfaden behandelt die 12 häufigsten Fehler in ESX, QBCore und QBox mit Diagnoseschritten und funktionierendem Code.
Job-Skripte steuern alles von Polizeischichten bis zu Mechanikergehältern – wenn sie versagen, kommt die Wirtschaft deines Servers zum Stillstand. Dieser Leitfaden behandelt die 12 häufigsten Job-Skript-Fehler auf ESX, QBCore und QBox mit Schritt-für-Schritt-Diagnose und funktionierendem Code.

Job-Skripte betreiben alles — von Polizeistreifen über Taxi-Dispatch bis zu Mechanikergehältern — sie sind das Bindegewebe zwischen deinen Spielern und der Wirtschaft deines Servers. Ein ordnungsgemäß funktionierendes Jobsystem gibt jedem Spieler einen Zweck, einen Fortschrittspfad und einen Grund, sich wieder einzuloggen. Wenn Job-Skripte kaputtgehen, breitet sich der Schaden kaskadenartig aus: Spieler können kein Geld verdienen, Fraktionsleiter können ihre Kader nicht verwalten, illegale Wirtschaften stagnieren und die gesamte Roleplay-Schleife, die FiveM so fesselnd macht, kommt zum Stillstand.
Die Fehleroberfläche für Job-Skripte ist trügerisch breit. Ein einziger kaputter Job kann seine Ursache in einer von fünf Ebenen haben: dem Framework selbst (ESX, QBCore oder QBox), dem darunterliegenden Datenbankschema, der Abhängigkeitskette der Ressourcenstarts in deiner server.cfg, den über die Karte verstreuten Target- und Interaktionszonen oder den clientseitigen Event-Handlern, die bei Spielerinteraktion feuern. Framework-Versionsinkonsistenzen allein verursachen etwa ein Drittel aller Job-Skript-Fehler, die wir in Support-Tickets sehen — eine für ESX 1.2 gebaute Ressource scheitert stillschweigend auf ESX 1.10, weil sich Event-Payloads und Export-Signaturen geändert haben. Abhängigkeitsketten sind ebenso tückisch: Ein Polizei-Job, der von qb-target abhängt, das von qb-core abhängt, das von oxmysql abhängt — brich irgendein Glied dieser Kette und der gesamte Job geht dunkel, oft ohne klare Fehlermeldung.
Datenbankschema-Drift ist der stille Killer. Wenn du von einem Job-Skript zu einem anderen migrierst oder deine Framework-Version aktualisierst, können sich die Spaltennamen in deinen jobs- und job_grades-Tabellen unter deinen bestehenden Daten verschieben. Eine Spalte namens job_name in einem Schema wird zu name in einem anderen, und plötzlich wird jeder Spieler auf deinem Server als arbeitslos angezeigt. Event-Namenskollisionen verschlimmern das Problem: Zwei Ressourcen, die denselben Event-Handler registrieren (esx:setJob, QBCore:Server:SetJob), laufen gegeneinander, und der Verlierer lässt Spieler-Jobzuweisungen stillschweigend fallen, ohne eine Warnung zu loggen.
Der Einsatz ist höher, als die meisten Server-Betreiber realisieren. Daten zur Spielerbindung aus FiveM-Community-Umfragen zeigen durchgängig, dass „kein funktionierender Job finden" zu den Top-3-Gründen gehört, warum neue Spieler einen Server innerhalb der ersten 48 Stunden verlassen. Ein etablierter Spieler, der nach einem Ressourcen-Update den Zugriff auf seine Fraktion verliert, gibt dir in der Regel ein Support-Ticket, bevor er den Server wechselt. Dieser Leitfaden gibt dir das diagnostische Framework, um Job-Probleme zu beheben, bevor sie dich deine Spielerbasis kosten.
Dieser Leitfaden behandelt die 12 häufigsten Job-Skript-Fehler in ESX, QBCore und QBox, organisiert nach Diagnose-Ebene, sodass du jedes Symptom ohne Raten zu seiner Ursache zurückverfolgen kannst. Jeder Abschnitt enthält die exakten Symptome, die Schritt-für-Schritt-Diagnosen und funktionierenden Code, den du sofort einsetzen kannst.
Bevor du eine einzige Codezeile anfasst, brauchst du eine Diagnosemethodik. Zufälliges Neustarten von Ressourcen oder Copy-Pasten von Fixes aus Forenthreads, ohne zu verstehen, welche Ebene ausgefallen ist, macht aus einem 5-Minuten-Job-Fix einen 3-stündigen Serverausfall. Jeder Job-Skript-Fehler lebt in einer von vier Ebenen. Beginne bei Ebene 1 und arbeite dich nach unten — überspringe keine Ebenen, denn ein Problem auf Ebene 1 maskiert sich oft als Symptom auf Ebene 4.
Öffne deine F8-Konsole sofort, wenn eine Job-Aktion fehlschlägt — bevor du die Ressource neu lädst, bevor du den Server neustartest, bevor du irgendetwas anderes tust. Die Client-Konsole erfasst Lua-Laufzeitfehler, nil-Index-Versuche und fehlgeschlagene Event-Registrierungen, die beim Ressourcen-Neustart verschwinden. Suche speziell nach diesen Mustern:
attempt to index a nil value — Die Config-Tabelle oder Framework-Bridge des Skripts gab nil zurück. Bedeutet meist, dass die Ressource gestartet ist, bevor das Framework fertig geladen war. Prüfe deine server.cfg-Startreihenfolge: Dein Framework (es_extended oder qb-core) muss vor jeder Job-Ressource starten.SCRIPT ERROR: @qb-target/client.lua oder ähnlich — Eine Abhängigkeit konnte ihre Funktionen nicht exportieren. Verifiziere, dass die Abhängigkeitsressource sowohl gestartet ist als auch keine eigenen Startup-Fehler hat.^1[ERROR]^7 oder ^3[WARNING]^7 mit einem Ressourcennamen-Präfix — Viele Job-Skripte verwenden farbige Konsolen-Präfixe. Dies sind deine direktesten Hinweise.Verwende diesen Befehl in F8, um die aktuellen Job-Daten des Spielers live auszugeben — er funktioniert in allen drei Frameworks und sagt dir sofort, ob das Framework die Jobzuweisung sieht, die die Datenbank behauptet:
ESX:
-- In F8-Konsole ausführen
TriggerServerEvent('esx:getSharedObject', function(obj)
local xPlayer = obj.GetPlayerFromId(GetPlayerServerId(PlayerId()))
print(json.encode(xPlayer.job))
print(json.encode(xPlayer.job2)) -- ESX 1.10+ Multi-Job
end)
QBCore:
-- In F8-Konsole ausführen
local QBCore = exports['qb-core']:GetCoreObject()
local PlayerData = QBCore.Functions.GetPlayerData()
print(json.encode(PlayerData.job))
QBox (ox_core):
-- In F8-Konsole ausführen
TriggerServerEvent('ox:getPlayer', function(player)
print(json.encode(player.job))
end)
Wenn der ausgegebene Job-Name nil oder unemployed ist, aber deine Datenbank etwas anderes anzeigt, hat die Jobzuweisung den Client nie erreicht. Gehe zu Ebene 2.
Wechsle zu deiner Server-Konsole (txAdmin-Webpanel oder das Terminal, das FXServer.exe ausführt). Die Server-Konsole erfasst Datenbankabfragefehler, Event-Handler-Registrierungsfehler und Framework-Initialisierungsprobleme, die nie die F8-Konsole erreichen. Wichtige Suchbegriffe:
Unable to execute query — Die Ressource hat versucht, Job-Daten zu lesen oder zu schreiben, und die Datenbankabfrage ist fehlgeschlagen. Der Fehler enthält normalerweise das exakte SQL, das fehlgeschlagen ist, was dir sagt, welche Tabelle und Spalte nicht übereinstimmen.^1SCRIPT ERROR: citizen:/scripting/lua/scheduler.lua — Ein Lua-seitiger Fehler in einem Server-Skript, oft eine nil-Referenz in einer Job-Config oder einem Framework-Callback.Resource oxmysql has not been started (oder deine Datenbank-Ressource) — Der Datenbank-Connector läuft nicht, als die Job-Ressource versuchte, ihn abzufragen.Wenn die Server-Konsole sauber ist, aber der Client fehlschlägt, liegt das Problem in der clientseitigen Registrierung. Wenn die Server-Konsole Fehler zeigt, behebe diese zuerst — sie blockieren alles nachgelagerte.
Öffne deinen Datenbank-Client (HeidiSQL, DBeaver, phpMyAdmin) und führe gezielte Abfragen gegen die Tabellen aus, die dein Job-Skript verwendet. Nicht durchsuchen — mit Absicht abfragen:
-- ESX: Prüfen, ob der Job tatsächlich in der Job-Registrierung des Frameworks existiert
SELECT name, label FROM jobs WHERE name = 'police';
-- ESX: Grade und Gehälter für den Job prüfen
SELECT grade, name, label, salary FROM job_grades WHERE job_name = 'police' ORDER BY grade;
-- ESX: Prüfen, ob die Jobzuweisung eines bestimmten Spielers existiert
SELECT identifier, job, job_grade FROM users WHERE identifier LIKE '%steam:11000014%';
-- QBCore: Spieler-Metadaten prüfen (JSON-Spalte)
SELECT citizenid, JSON_EXTRACT(metadata, '$.job') AS job_data FROM players WHERE citizenid = 'ABC12345';
-- QBox: Spieler-Job prüfen (ox_core speichert Job in users-Tabelle)
SELECT username, job, job_grade FROM users WHERE username = 'char1:abc123';
Die häufigsten Fehler auf Datenbankebene:
jobs-Tabelle, aber nicht in job_grades — Spieler können zugewiesen werden, haben aber keinen Grad, also schlägt jede Berechtigungsprüfung fehl.jobs übereinstimmt — Meist übrig gebliebene Daten nach der Deinstallation einer Job-Ressource, ohne die Spielerzuweisungen zu bereinigen.0 oder NULL für den Grad des Spielers — Die Gehaltsschleife läuft, zahlt aber null.addon_account_data — Boss-Menü-Einzahlungen und -Abhebungen scheitern stillschweigend (nur ESX).Öffne die config.lua (oder shared/config.lua) der Job-Ressource und verfolge jeden Wert, der das fehlerhafte Feature steuert. Die häufigsten Fallstricke auf Config-Ebene:
Config.JobName = "Police" wird niemals mit einem Datenbankwert von "police" übereinstimmen. Lua-String-Vergleiche sind exakt. Wähle eine Groß-/Kleinschreibungs-Konvention und setze sie in deinen Datenbankwerten, Config-Dateien und Event-Handlern durch.vector3(450.0, -980.0, 30.0) könnte sich innerhalb einer Gebäudewand befinden, wenn die Karte aktualisiert wurde. Teleportiere zu jeder Zonenkoordinate in deiner Config mit /tp <x> <y> <z> und verifiziere, dass der Spieler nicht in eine Wand clippt.Config.BossMenuGrade = 4, aber dein Job nur die Grade 0-3 definiert, kann niemand jemals das Boss-Menü öffnen, weil Grad 4 nicht existiert. Der höchste existierende Grad ist Anzahl - 1, nicht Anzahl.Config.TargetSystem = 'ox_target' setzt, aber der Export exports['ox_target']:AddBoxZone() nil zurückgibt, weil ox_target nicht installiert ist, wird die Zone nie erstellt und das Skript macht ohne sie weiter.Sobald du alle vier Ebenen validiert und die fehlerhafte Ebene identifiziert hast, gehe zu den framework-spezifischen Abschnitten unten für den Fix.
Job-Skripte existieren nicht im Vakuum — sie docken an ein Framework an, das den zugrundeliegenden Spielerzustand, Datenbankoperationen und Event-Dispatch handhabt. Wenn du verstehst, wie jedes Framework Jobs modelliert, kannst du jeden Fehler zu seiner mechanischen Quelle zurückverfolgen, ohne eine einzige Zeile des Job-Skripts selbst zu lesen.
ESX modelliert Jobs als Zwei-Tabellen-Beziehung: jobs definiert den Job (Name, Label), und job_grades definiert die Ränge innerhalb dieses Jobs (Grad-Nummer, Grad-Name, Grad-Label, Gehalt). Spieler halten eine Referenz auf einen Job in der users-Tabelle über die job-Spalte (String, der mit jobs.name übereinstimmt) und job_grade (Integer, der mit job_grades.grade übereinstimmt). ESX 1.10+ führte eine job2-Spalte und job2_grade-Spalte für Dual-Job-Unterstützung ein — wenn deine Job-Ressource xPlayer.getJob() aufruft, aber der primäre Job des Spielers von einem Multi-Job-Addon überschrieben wurde, triffst du auf nil-Referenz-Fehler.
Das ESX-Job-Event-System läuft auf zwei gemeinsamen Events: esx:setJob (server-seitig, schreibt in die Datenbank und aktualisiert den Spielerzustand) und esx:playerLoaded (client-seitig, feuert nach der Charakterauswahl mit vollständigen Spielerdaten). Drittanbieter-Job-Ressourcen haken sich in esx:playerLoaded ein, um jobspezifische Kleidung anzuwenden, Blips zu spawnen und Target-Zonen zu registrieren. Wenn deine Job-Ressource startet, nachdem der Spieler bereits geladen wurde — häufig bei Verwendung von ensure statt Reihenfolge in server.cfg — ist das esx:playerLoaded-Event bereits gefeuert und die Job-Ressource initialisiert sich nie für diesen Client. Der Fix ist, die Initialisierungsfunktion der Ressource manuell aufzurufen oder einen RegisterNetEvent('esx:playerLoaded')-Listener hinzuzufügen, der das Setup erneut ausführt, wenn der Spieler seinen Charakter neu lädt.
ESXs Gesellschaftssystem (esx_society) fügt eine dritte Ebene hinzu: addon_account- und addon_account_data-Tabellen, die gemeinsame Job-Bankkonten halten. Jeder Job mit einem Gesellschaftsfonds benötigt eine Zeile in addon_account mit name = 'society_police' und eine entsprechende Zeile in addon_account_data mit dem Kontonamen. Wenn das Gesellschaftskonto fehlt, lädt das Boss-Menü, aber jede Einzahlung und Abhebung wirft einen stillen Fehler, der nur in der Server-Konsole als attempt to index nil value (local 'account') erscheint.
ESX-Gehaltsabrechnung Ausführungsreihenfolge:
es_extended/config.lua)es_extended/server/paycheck.lua iteriert alle verbundenen Spielerjob und job_grade aus xPlayer gelesenjob_grades nach dem passenden salary-Wert abxPlayer.addAccountMoney('bank', salary) aufWenn du eine print-Anweisung zwischen Schritt 3 und 4 hinzufügst, fängst du jeden Gehaltsabrechnungsfehler, bevor er live geht.
QBCore speichert Job-Daten in der metadata-JSON-Spalte des Spielers in der players-Tabelle — es gibt keine separate jobs-Tabelle im Standard-QBCore-Schema. Die Schlüsselstruktur ist metadata.job, die {name = "police", label = "LSPD", grade = {name = "officer", level = 2}, payment = 150, isboss = false, onduty = true} enthält. Dieser In-JSON-Ansatz bedeutet, dass Job-Daten bei der Charakterauswahl geladen und für die Dauer der Session im Server-Speicher gehalten werden — Datenbankschreibvorgänge finden nur bei expliziten SetJob- oder SetMetaData-Aufrufen statt.
Job-Definitionen in QBCore befinden sich in qb-core/shared/jobs.lua, einer gemeinsamen Lua-Datei, die sowohl Client als auch Server lesen können. Hier werden Grad-Namen, Zahlungsbeträge, Dienststatus-Standardwerte und Kleidungskomponenten-IDs definiert. Ein fehlender Eintrag in jobs.lua ist die mit Abstand häufigste Ursache für QBCore-Job-Fehler: Wenn der Server versucht, den Job eines Spielers auf 'mechanic' zu setzen, aber QBShared.Jobs['mechanic'] nicht existiert, schlägt der gesamte SetJob-Aufruf stillschweigend fehl und der Spieler bleibt arbeitslos.
QBCores Job-System ist auf drei externe Ressourcen für Kernfunktionalität angewiesen:
qb-management — Boss-Menü, Gesellschaftsfonds-Verwaltung, Mitarbeiterverwaltung. Hängt von qb-input und qb-menu ab.qb-bossmenu (Legacy, meist durch qb-management ersetzt) — Gleiche Funktionen, andere UI.qb-garages — Job-Fahrzeug-Spawn und -Speicherung, liest Config.JobVehiclePermissions, um den Zugriff zu steuern.Die QBCore-Job-Event-Kette:
qb-core:server:SetJob (server-seitig, schreibt Metadaten)
→ QBCore:Client:OnJobUpdate (client-seitig, an den betroffenen Spieler gefeuert)
→ Lokaler Spielerzustand aktualisiert
→ Kleidung erneut angewendet, wenn im Dienst
→ Blips erneut registriert, wenn die Job-Config Kartenmarker enthält
Wenn qb-management installiert ist, aber qb-input nicht, öffnet sich die Boss-Menü-UI, ist aber nicht interagierbar — kein Fehler, nur ein eingefrorenes NUI-Overlay. Prüfe immer Abhängigkeitsketten, wenn eine QBCore-Job-Ressource teilweise funktioniert.
QBox ist das moderne Rewrite von QBCore mit dem ox_lib- und oxmysql-Ökosystem. Das Job-System lebt in ox_core und unterscheidet sich erheblich von ESX und QBCore:
users-Tabelle zusammen mit allen anderen Spielerdaten gespeichert — keine JSON-Metadaten-Spalte, keine separate Jobs-Lookup-Tabelle. Die Spalte ist einfach job (varchar) und job_grade (integer).server.cfg oder dem Ressourcen-Manifest gesetzt werden. Beispiel: set ox:jobPoliceLabel "LSPD" konfiguriert das Polizei-Job-Label serverweit, ohne eine Lua-Config-Datei zu berühren.ox_core/data/jobs.lua als Lua-Tabelle definiert, indiziert nach Job-Namen, wobei jeder Grad label- und payment-Schlüssel enthält.ox_core integriert über den ox:manageSociety-Export — keine separate Ressource erforderlich. Gesellschaftsfonds befinden sich in der accounts-Tabelle mit type = 'society'.jobs-Spalte halten (ein JSON-Array), nicht einen einzelnen job + optionalen job2.QBoxs Event-System verwendet ox_lib-Callbacks anstelle von framework-spezifischen Events. Um den aktuellen Job des Spielers abzufragen:
lib.callback('ox:getPlayer', false, function(player)
print('Primary job:', player.job)
print('All jobs:', json.encode(player.jobs))
end)
Der häufigste QBox-Job-Fehler ist eine Convar-Fehlkonfiguration. Da Job-Labels und Gehaltswerte in server.cfg als Convars gesetzt werden, ist ein Tippfehler in einem Convar-Namen unsichtbar — es gibt keine Lua-Datei, die einen Fehler wirft, der Job zeigt einfach stillschweigend nil für sein Label und $0 für sein Gehalt an. Greppe immer deine server.cfg nach dem Job-Namen, um zu verifizieren, dass jede erforderliche Convar gesetzt ist.
Symptom: Der Spieler geht zu einem Job-NPC, interagiert per Target oder 3D-Text, aber nichts passiert — kein Menü, keine UI, kein Fehler. Oder das Menü öffnet sich, aber der „Beitreten"-Button tut nichts.
Ursachenkaskade, in der Reihenfolge der Wahrscheinlichkeit:
jobs-Tabelle. Auf QBCore gibt QBShared.Jobs['jobname'] nil zurück. Auf QBox ist der Job nicht in ox_core/data/jobs.lua definiert. Ohne registrierten Job hat der setJob-Aufruf kein Ziel und kehrt stillschweigend zurück.vector3(450.2, -985.7, 30.8) liegt, aber der NPC bei vector3(451.0, -984.0, 30.8) platziert wurde, kann der Spieler den NPC sehen, aber nicht interagieren — Zonen lösen nur innerhalb ihres konfigurierten Radius aus (typischerweise 1,5-2,0 Spiel-Einheiten).player.job.name, vergleicht gegen eine Whitelist oder Blacklist in der Skript-Config und der Vergleich schlägt fehl wegen einer Groß-/Kleinschreibungs-Inkonsistenz oder nil-Referenz.if player.job.name ~= 'unemployed' then return end am Anfang ihrer Beitrittsfunktion. Wenn der Spieler nie ordnungsgemäß von einem vorherigen (möglicherweise gelöschten) Job gefeuert wurde, steckt er fest.Einfaches Debug: Füge diese print-Anweisung am Anfang der Beitrittsfunktion hinzu:
print(string.format('[JOIN-DEBUG] Player: %s, CurrentJob: %s, TargetJob: %s, IsWhitelisted: %s',
GetPlayerName(source),
tostring(xPlayer.job.name),
tostring(Config.JobName),
tostring(DoesWhitelistPass(xPlayer))
))
Führe es aus, interagiere mit dem NPC und prüfe die Server-Konsole. Wenn die Zeile printed, funktioniert die Zone — das Problem liegt in der Logik danach. Wenn sie nicht printed, ist die Zone oder das Event falsch.
Symptom: Ein Admin oder Boss befördert einen Spieler, die Datenbank zeigt den neuen Grad, aber der Spieler sieht immer noch seinen alten Grad in der UI und kann nicht auf grad-gesperrte Features zugreifen.
Ursache: Die Beförderung schreibt in die Datenbank, aber das Framework benachrichtigt den Client nicht. Dies passiert, wenn das Beförderungstool (Admin-Menü, Boss-Menü) das SetJob-Event des Frameworks umgeht und direkt per SQL in die Datenbank schreibt.
Fix auf ESX: Statt UPDATE users SET job_grade = 3 WHERE identifier = '...' auszuführen, verwende das Framework-Event:
TriggerEvent('esx:setJob', targetPlayerSource, 'police', 3)
-- Dies feuert den internen Handler, der xPlayer.setJob() aufruft,
-- was in die DB schreibt UND den Client über das esx:setJob-Event aktualisiert.
Fix auf QBCore: Verwende Player.Functions.SetJob() — aktualisiere niemals Player.PlayerData.job.grade.level direkt und führe niemals rohes SQL aus:
local target = QBCore.Functions.GetPlayer(tonumber(targetSource))
target.Functions.SetJob('police', 3)
-- Dies triggert den OnJobUpdate-Callback, der den Client synchronisiert.
Wenn du bereits jemanden mit einer rohen SQL-Abfrage befördert hast und sie feststecken, lass sie F8 quit eingeben und neu verbinden. Das Framework lädt Spielerdaten beim Verbinden aus der Datenbank neu, sodass der neue Grad übernommen wird.
Symptom: Die Boss-NPC-Interaktion funktioniert, das NUI-Overlay erscheint, aber es zeigt keine Mitarbeiter, keinen Kontostand oder ist völlig leer/nicht anklickbar.
Auf ESX mit esx_society: Das Boss-Menü liest aus addon_account_data für den Gesellschaftskontostand und aus der users-Tabelle für Mitarbeiterlisten. Wenn der Kontostand $0 oder leer anzeigt, fehlt die addon_account_data-Zeile für diese Gesellschaft. Wenn keine Mitarbeiter erscheinen, hat die Abfrage mit WHERE job = 'police' keine Ergebnisse zurückgegeben — was bedeutet, dass keine Spieler tatsächlich den korrekten Job-Namen zugewiesen haben.
Auf QBCore mit qb-management: Ein leeres Boss-Menü bedeutet, dass der NUI-Callback zu qb-management:server:GetEmployees nil zurückgegeben hat. Der Callback hängt davon ab, dass QBCore.Functions.GetQBPlayers() eine gültige Tabelle zurückgibt — wenn qb-core läuft, aber GetQBPlayers() nil ist (beschädigter Core oder falsche Version), scheitert jede Management-Funktion. Prüfe deine qb-core-Version gegen die Versionsanforderung von qb-management in fxmanifest.lua.
Auf QBox: Das Boss-Menü ist der ox:manageSociety-Export. Wenn es sich überhaupt nicht öffnet, läuft ox_core nicht oder der Spieler hat nicht den erforderlichen Grad. Der Grad-Schwellenwert wird in ox_core/data/jobs.lua unter grades[maxGrade].isBoss = true gesetzt — wenn kein Grad isBoss gesetzt hat, gibt der Export nil zurück.
Symptom: Spieler sind im Dienst, das Gehaltsintervall vergeht (sichtbar im Job-UI-Timer), aber ihr Bankguthaben ändert sich nicht.
Der Gehaltsfehlerpfad ist der nuancierteste im FiveM-Job-Debugging, weil der Fehler standardmäßig still ist — die Gehaltsschleife läuft, stößt auf einen Fehler, fängt ihn ab und fährt mit dem nächsten Spieler fort, ohne zu loggen. Du musst die Schleife selbst instrumentieren:
-- Zu deiner Gehaltsschleife hinzufügen (server-seitig)
CreateThread(function()
while true do
Wait(Config.PaycheckInterval)
local players = GetPlayers() -- ESX- oder QBCore-Äquivalent
for _, playerId in ipairs(players) do
local xPlayer = ESX.GetPlayerFromId(playerId)
if not xPlayer then
print('[PAY-DEBUG] Player object nil for id:', playerId)
goto continue
end
if not xPlayer.job then
print('[PAY-DEBUG] Player ' .. xPlayer.name .. ' has no job table')
goto continue
end
if xPlayer.job.grade_name == 'unemployed' then
goto continue -- Erwartetes Überspringen, kein Debug nötig
end
local salary = xPlayer.job.grade_salary
if not salary or salary == 0 then
print('[PAY-DEBUG] Player ' .. xPlayer.name .. ' at grade ' .. xPlayer.job.grade .. ' has salary: ' .. tostring(salary))
goto continue
end
local result = xPlayer.addAccountMoney('bank', salary)
if not result then
print('[PAY-DEBUG] addAccountMoney failed for player ' .. xPlayer.name)
else
print('[PAY-DEBUG] Paid $' .. salary .. ' to ' .. xPlayer.name)
end
::continue::
end
end
end)
Die drei häufigsten Gehaltsfehler, die durch diese Instrumentierung aufgedeckt werden: Gehalt ist 0, weil die salary-Spalte des Job-Grads NULL oder 0 ist, addAccountMoney gibt nil zurück, weil das Bankkonto des Spielers nicht in user_accounts existiert, oder das Spieler-Objekt ist nil, weil der Spieler zwischen dem GetPlayers()-Aufruf und dem GetPlayerFromId()-Aufruf die Verbindung getrennt hat.
Jede Job-Ressource sollte ihre Framework-Versionsanforderung in fxmanifest.lua festpinnen. Ohne dies kann ein Framework-Auto-Update breaking changes einführen, die jeden Job auf deinem Server gleichzeitig deaktivieren:
-- In der fxmanifest.lua deiner Job-Ressource
dependencies {
'es_extended', -- Minimum: 1.10.0 für Multi-Job-Unterstützung
'oxmysql',
'esx_society',
'qb-target', -- Wenn qb-target statt ox_target verwendet wird
}
-- Setze auch eine Mindestversion in deiner Ressourcenbeschreibung oder README
Wenn du einen neuen Job hinzufügst, beginne mit einem validierten Template, anstatt die Config eines bestehenden Jobs zu kopieren und zu modifizieren. Ein Template fängt die Fehler, die du nicht sehen kannst — fehlende erforderliche Schlüssel, falsche Standardwerte, falsche Event-Registrierungsreihenfolge. Hier ist eine minimale Template-Struktur:
Config = {}
Config.JobName = 'CHANGE_ME' -- Muss exakt mit jobs-Tabelle / shared/jobs.lua übereinstimmen
Config.JobLabel = 'Change Me'
Config.EnableBlip = false
Config.BlipSprite = 1
Config.BlipColor = 3
Config.BlipCoords = vector3(0.0, 0.0, 0.0)
Config.BossMenuGrade = 4 -- Höchste Grad-Nummer + 1 (prüfe job_grades-Tabelle)
Config.EnableClothing = false
Config.ClothingGrades = {} -- {[0] = {male = {}, female = {}}}
Config.EnableVehicles = false
Config.Vehicles = {} -- {[grade] = {model = 'police', label = 'Cruiser'}}
Config.PaycheckInterval = 60000 -- in Millisekunden
Config.EnableBossMenu = false
Config.BossMenuCoords = vector3(0.0, 0.0, 0.0)
Bevor du eine neue Job-Ressource installierst, eine bestehende ersetzt oder deine Framework-Version aktualisierst, führe diese drei Befehle aus:
# 1. Sichere die jobs- und job_grades-Tabellen
mysqldump -u your_user -p your_database jobs job_grades > jobs_backup_$(date +%Y%m%d_%H%M%S).sql
# 2. Sichere Spieler-Jobzuweisungen
mysqldump -u your_user -p your_database users --where="job != 'unemployed'" > player_jobs_backup_$(date +%Y%m%d_%H%M%S).sql
# 3. Für ESX: Sichere Gesellschaftsfonds-Konten
mysqldump -u your_user -p your_database addon_account addon_account_data --where="name LIKE 'society_%'" > society_backup_$(date +%Y%m%d_%H%M%S).sql
Ein Rollback eines fehlerhaften Job-Updates ist ein einziger Befehl, wenn du den Dump hast — es sind Stunden manueller Datenreparatur, wenn nicht.
Wenn ein Job-Skript kaputtgeht, isoliere es. Erstelle einen lokalen Testserver nur mit dem Framework, dem Datenbank-Connector und der Job-Ressource (plus ihren direkten Abhängigkeiten). Starte den Server, trete als Test-Charakter bei und gehe jede Job-Funktion durch — beitreten, einstempeln, Boss-Menü aufrufen, Fahrzeug spawnen, Gehalt erhalten. Wenn alles isoliert funktioniert, ist das Problem ein Konflikt mit einer anderen Ressource auf deinem Produktionsserver. Wenn es isoliert fehlschlägt, liegt das Problem im Job-Skript selbst und du kannst ohne Produktionsdruck debuggen.
Die häufigsten konfliktverursachenden Ressourcen in der Produktion: Multi-Charakter-Skripte, die Spieler-Metadaten manipulieren, Wirtschafts-Skripte, die das Bank-/Geldsystem modifizieren, und Anti-Cheat-Ressourcen, die Event-Trigger blockieren, die sie nicht erkennen.
Fehler beim Einstempeln treten auf, wenn der zugewiesene Jobname des Spielers nicht exakt mit der Konfiguration übereinstimmt (Groß-/Kleinschreibung), die Koordinaten der Einstempelzone falsch sind oder das Skript vor dem Framework in der server.cfg startet. Gib den aktuellen Job des Spielers über das Framework aus, um zu prüfen, ob er übereinstimmt, teleportiere dich dann zu den Zonenkoordinaten, um deren Erreichbarkeit zu bestätigen. Überprüfe außerdem über F8 auf Zielzonenfehler – sowohl qb-target als auch ox_target protokollieren fehlgeschlagene Zonenregistrierungen.
Zahlungsausfälle treten irgendwo in der Kette auf: Die Gehaltsspalte in der Datenbank ist null, der Auszahlungsintervall-Timer feuert nie oder das Money-Add-Event gibt einen stillen Fehler aus. Frage deine job_grades-Tabelle ab, um sicherzustellen, dass die Gehaltswerte für die Grade deiner Spieler nicht null sind. Füge im serverseitigen Auszahlungs-Loop einen Debug-Print ein, um zu bestätigen, dass er tatsächlich läuft. Bei QBCore befindet sich das Gehalt in qb-core/shared/jobs.lua – ein fehlender Eintrag wird standardmäßig auf null gesetzt, ohne einen Fehler zu werfen.
Job-NPCs spawnen nicht, wenn der Ped-Modell-Hash ungültig ist, die Koordinaten innerhalb von Geometrie liegen oder der Spawn-Aufruf aufgrund eines Jobnamen-Konflikts nie ausgeführt wird. Teste mit einem bekanntermaßen funktionierenden Modell wie s_m_m_doctor_01 an denselben Koordinaten. Wenn der manuelle Spawn funktioniert, der des Skripts jedoch nicht, liegt der Spawn hinter einer fehlschlagenden Jobnamen-Prüfung. Gib den aktuellen Job des Spielers in der Spawn-Funktion aus, um dies zu überprüfen.
Launch faster
Bundles shorten the path from planning to launch by grouping the highest-leverage scripts into a cleaner commercial starting point.
Fehlende Blips werden durch ungültige Blip-Sprite-IDs, falsche Koordinaten oder Blip-Erstellungs-Code verursacht, der hinter einer fehlschlagenden Job-Prüfung steckt. Teste mit Sprite 1 an bekannten Koordinaten. Wenn der Test-Blips erscheint, wird der Blip-Code des Skripts nicht ausgeführt – meist, weil er innerhalb einer Job-Prüfung liegt, die nie bestanden wird. Überprüfe, ob die Blip-Erstellung beim Ressourcenstart oder nur dann ausgelöst wird, wenn der Job des Spielers validiert ist.
Der Dienststatus wird standardmäßig im Speicher gehalten und setzt sich bei Trennung zurück. Für Persistenz muss das Skript beim Umschalten des Dienstes in die Datenbank oder Framework-Metadaten schreiben. Bei QBCore verwende SetMetaData, um den Dienststatus zu schreiben. Bei ESX schreibe in eine Spalte der users-Tabelle. Wenn dein Skript keine Persistenz unterstützt, musst du das Datenbankschreiben selbst hinzufügen oder zu einem Skript wechseln, das dies handhabt.
Probleme mit Grad-Berechtigungen entstehen durch nicht übereinstimmende Grad-Nummern zwischen der Datenbank und der Skriptkonfiguration. Grade beginnen bei 0 (niedrigster). Frage deine job_grades-Tabelle ab und vergleiche die Grad-Nummern mit den Berechtigungsprüfungen in der Konfiguration. Ein Spieler mit Grad 2, der auf Inhalte von Grad 3 zugreifen können sollte, wurde entweder in der DB falsch befördert oder der Konfigurations-Schwellenwert ist auf 3 statt 2 gesetzt.
Der Fahrzeugzugang wird durch Jobname, Grad und in der Regel auch durch den Dienststatus gesteuert. Wenn die Garage einen berechtigten Spieler ablehnt, bestätige, dass sie Dienst haben (die meisten Fahrzeugzugriffe prüfen zuerst den Dienst), ihr Grad die in der Konfiguration festgelegte Mindestgrad-Anforderung erfüllt und der Fahrzeugspawnpunkt nicht physisch durch ein anderes Fahrzeug blockiert ist. Überprüfe auch, ob der Fahrzeugmodellname exakt dem Spawn-Namen entspricht – bei benutzerdefinierten Fahrzeugen wird die Groß-/Kleinschreibung beachtet.
Boss-Menüs erfordern den höchsten Grad (normalerweise Grad 4 oder höher) und eine korrekt positionierte Zielzone. Wenn das Menü nicht öffnet, gib den Grad des Spielers aus und bestätige, dass er den Schwellenwert von Config.BossMenuGrade erfüllt. Überprüfe auch, ob die Boss-Menü-Ressource (qb-management auf QBCore, esx_society auf ESX) läuft und sich deren Zielzone an den richtigen Koordinaten befindet – Zonenverschiebungen nach Kartenupdates sind eine häufige Ursache.
Fehler mit Gesellschaftsfonds treten auf, wenn das gemeinsame Bankkonto für einen Job nicht registriert ist. Bei ESX benötigt jeder Job mit einem Gesellschaftsfonds einen Eintrag in addon_account_data mit einem passenden Jobnamen. Wenn das Konto fehlt, füge es manuell per INSERT ein. Bei QBCore werden Gesellschaftsfonds von qb-management verwaltet – füge den Job zu dessen Konfiguration hinzu und starte die Ressource neu. Ändere niemals Gesellschaftsguthaben direkt in SQL, während der Server läuft.
Jobkonflikte entstehen, wenn zwei Skripte denselben Jobnamen in der Datenbank registrieren oder wenn ein Multi-Job-Addon mit der Single-Job-Logik des Frameworks interferiert. Frage deine jobs-Tabelle nach doppelten Namen ab. Wenn du ein Multi-Job-System betreibst, überprüfe, ob deine Framework-Version die gleichzeitige Jobzuweisung unterstützt – ältere ESX-Builds unterstützen nur einen aktiven Job, und das Multi-Job-Addon patcht dies auf Framework-Ebene.
Die Uniformanwendung hängt von deiner Kleidungsressource ab. Die Jobkonfiguration gibt GTA-Kleidungskomponenten-IDs für jeden Grad an. Wenn nichts angewendet wird, sind die Komponenten-IDs für die Ped-Anpassung deines Servers ungültig. Teste jeden Komponentenwert einzeln in deinem Kleidungsmenü, um herauszufinden, welche IDs gültig sind. Unterschiedliche Kleidungsressourcen (illenium-appearance, fivem-appearance, esx_skin) verwenden unterschiedliche Datenformate – stelle sicher, dass die Uniformkonfiguration dem erwarteten Format deines Kleidungssystems entspricht.
Die Whitelist-Überprüfung prüft den Job des Spielers in der Datenbank, bevor Interaktionen erlaubt werden. Wenn die Prüfung für einen Spieler fehlschlägt, der Zugriff haben sollte, frage direkt sein Job-Feld ab. Wenn das Feld korrekt ist, prüft das Skript möglicherweise ein anderes Identifikatorformat (citizenid vs. steam hex vs. license). Gib den Identifikator aus, den das Skript für die Whitelist-Prüfung verwendet, und vergleiche ihn mit dem Datenbankwert.