Framework hub
Move into the QBCore landing page to compare verified scripts, framework fit, and install-ready products built for modern FiveM servers.
Open QBCore hubSobald die Richtung klar ist, kommst du über diese Angebotsseiten direkt zu verifizierten Scripts, kuratierten Bundles und framework-spezifischen Kaufpfaden.
Framework 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 shopLaunch faster
Bundles shorten the path from planning to launch by grouping the highest-leverage scripts into a cleaner commercial starting point.
View bundlesWirtschaftsskripte 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.
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.
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.
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.

Housing-Skripte gehören zu den komplexesten Ressourcen auf einem FiveM-Server. Sie verwalten Shell-Instanzen, Möbelplatzierung, Türschlösser, Schlüsselverwaltung, Garagenintegration und Immobilientransaktionen — alles gleichzeitig, alles an einen einzigen Datenbankeintrag gebunden. Wenn Housing kaputtgeht, kommen ganze RP-Communities zum Stillstand. Zivilisten können ihre Häuser nicht betreten, über Wochen aufgebaute Möbelarrangements verschwinden und der Immobilienmarkt — oft ein zentraler Treiber der Serverwirtschaft — kommt zum Erliegen.
Das Kernproblem ist, dass Housing-Skripte an der Schnittstelle von mindestens fünf getrennten Systemen sitzen: der Datenbankschicht, dem Streaming-System für MLO-Interieurs, dem Inventar-Framework für Stashes, der Türschloss-Ressource und der Identifikator-Verwaltung des Frameworks. Jede dieser Abhängigkeiten führt einen potenziellen Fehlerpunkt ein. Eine einzige Datenbankmigration, die ändert, wie Spieler-Identifikatoren gespeichert werden, kann jede Immobilie auf dem Server unzugänglich machen. Eine Shell-Ressource, die nicht in der richtigen Reihenfolge gestartet wurde, teleportiert Spieler ins Leere. Ein Möbel-Save-Event, das feuert, aber in die falsche Datenbankspalte schreibt, verwirft stillschweigend jede Dekoration, die ein Spieler platziert.
Diese Komplexität wird durch die fragmentierte Natur der FiveM-Housing-Implementierungen noch verstärkt. ESX-Server betreiben typischerweise esx_property oder benutzerdefinierte Forks, QBCore-Server verwenden qb-houses mit qb-apartments und qb-garages als Begleitressourcen, und QBox-Server tendieren zu ox_housing-Mustern, die nativ mit ox_inventory und ox_doorlock integrieren. Jedes Framework strukturiert Immobiliendaten anders, speichert Möbel in seinem eigenen Format und handhabt die Schlüsselzuweisung über seinen eigenen Mechanismus. Ein Fix, der auf einem Framework funktioniert, wird auf einem anderen nichts tun — oder aktiv Dinge kaputtmachen.
Dieser Leitfaden identifiziert die zwölf Housing-Fehler, die wir in Support-Tickets, Server-Logs und Community-Foren sehen. Jedes untenstehende Problem wurde auf einem Live-Server reproduziert und gegen den zugrundeliegenden Datenbankzustand verifiziert. Du lernst, wie du die Ursache mit SQL-Abfragen und server-seitigen Prints diagnostizierst, wie du den Fix so anwendest, dass er Neustarts überlebt, und welche Integrations-Sonderfälle selbst erfahrene Admins auf dem falschen Fuß erwischen.
Bevor du mit der Fehlersuche beginnst, öffne deine Server-Konsole und deinen Datenbank-Client nebeneinander. Fast jedes Housing-Problem hinterlässt Spuren an einem dieser beiden Orte. Der Rest besteht darin, zu wissen, wo man suchen muss.

Bevor du in die einzelnen Probleme eintauchst, ordne das beobachtete Symptom der wahrscheinlichsten Ursache zu.
| Symptom | Wahrscheinlichste Ursache | Erster Prüfschritt |
|---|---|---|
| Kann Haus nicht betreten | Interaktionszone falsch konfiguriert oder Shell nicht geladen | Spielerposition an der Tür mit Config-Koordinaten vergleichen |
| Möbel werden nicht gespeichert | Save-Event feuert nicht oder Datenformat-Inkonsistenz | Server-Print im Save-Handler hinzufügen, housing_furniture-Tabelle inspizieren |
| Schlüssel gewähren keinen Zugriff | Identifikator-Format hat sich seit Immobilienerstellung geändert | SELECT owner FROM housing_properties vs aktuelle Framework-ID |
| Stash öffnet sich nicht | Inventarsystem findet Stash-Identifikator nicht | Stash-ID-Format und ob Stash beim Serverstart registriert wurde |
| Haus-Blip wird nicht angezeigt | Besitzabfrage gab leeres Ergebnis oder Blip-Code lief vor Datenladung | Besitzprüfungsergebnis, Timing der Blip-Erstellung |
| Dekorationsmodus stürzt ab | Ungültige Furniture-Model-Hashes oder zu viele Props gespawnt | Hashes gegen GTA V-Prop-Liste validieren, maximale platzierbare Items reduzieren |
| Shell-Interior wird nicht gerendert | Shell-Ressource startete nach Housing-Ressource | Server.cfg-Ressourcenreihenfolge, Shell-Stream-Ordner-Inhalt |
| Kauftransaktion schlägt fehl | Preis auf null gesetzt, falsches Konto anvisiert oder Schlüssel nie zugewiesen | Jeden Schritt des Kauf-Handlers loggen |
| Mitbewohner kann nicht eintreten | Entry-Handler prüft nur owner-Feld, nicht access-Tabelle | Entry-Event verfolgen, um zu bestätigen, dass beide Abfragen existieren |
| Garage funktioniert nicht | Garagenkoordinaten fehlen oder Handler in Config deaktiviert | Housing-Config auf garage_enabled-Flag und Koordinatengültigkeit prüfen |
| Türschloss-Konflikte | Zwei Ressourcen steuern dieselbe Tür-Entität | Housing-Tür-Einträge aus Doorlock-Ressourcen-Config entfernen |
| Grundsteuer wird nicht eingezogen | Server-seitiger Timer läuft nicht oder Berechnung ergab null | Konsolenfehler beim Startup, Steuer-Log-Ausgabe |
Wenn ein Housing-Skript kaputtgeht, ist der Instinkt, die Ressource neuzustarten und zu hoffen. Das maskiert das Problem bestenfalls für ein paar Stunden. Arbeite stattdessen diese Diagnosekette systematisch durch. Jeder Schritt eliminiert eine Fehlerkategorie, bevor du Zeit für tieferes Debugging aufwendest.
Der gesamte Housing-Zustand lebt in der Datenbank. Beginne mit einer einfachen Besitzabfrage für den Spieler, der das Problem meldet:
SELECT * FROM housing_properties WHERE owner = 'citizenid:ABC12345';
Wenn dies leer zurückgibt, hat sich der Identifikator des Spielers möglicherweise geändert — eine häufige Folge des Wechsels von Steam- zu Lizenz-basierter Identifikation, der Migration von ESX zu QBCore oder der Aktualisierung deines Frameworks. Vergleiche den gespeicherten owner-Wert mit dem, was die GetPlayerIdentifier-Funktion deines Frameworks aktuell für diesen Spieler zurückgibt. Wenn sie sich unterscheiden, brauchst du ein Identifikator-Migrationsskript, keinen Housing-Fix.
Prüfe auch die Zeilenanzahl der Tabellen. Wenn housing_furniture 0 Zeilen hat, aber housing_properties befüllt ist, scheitert dein Möbel-Save stillschweigend. Wenn housing_properties Zeilen hat, aber housing_keys leer ist, wurde das Schlüsselsystem nie angeschlossen.
MLO-Interieurs und Shells werden von separaten Ressourcen geladen, nicht vom Housing-Skript selbst. Führe in deiner Server-Konsole status aus und bestätige, dass alle Shell-Ressourcen grün anzeigen. Wenn eine Shell-Ressource nicht gestartet ist, versucht das Housing-Skript, einen Spieler in ein Interior zu teleportieren, das nicht existiert — der Spieler landet im Leeren, fällt durch die Map oder bleibt im Ladebildschirm hängen.
Die Ressourcen-Startreihenfolge ist hier entscheidend. Shell-Ressourcen müssen vor der Housing-Ressource gestartet werden. Wenn Housing zuerst startet und eine leere Shell-Liste bei der Initialisierung cached, entdeckt es später hinzugefügte Shells nicht ohne Neustart.
# server.cfg — korrekte Reihenfolge
ensure [shells] # alle MLO/Shell-Ressourcen
ensure [fivemx-housing] # Housing-Ressourcen nach Shells
Die Möbel-Persistenz bricht auf zwei Arten: Das Save-Event feuert nie, oder es feuert, schreibt aber Daten, die das Spiel nicht zurückparsen kann. Füge einen server-seitigen Print in deinem Möbel-Save-Handler hinzu:
-- Server-seitiger Save-Handler
RegisterNetEvent('housing:saveFurniture', function(propertyId, furniture)
print(string.format('[HOUSING-DEBUG] Save furniture for property %s: %d items', propertyId, #furniture))
-- Bestehende Save-Logik
end)
Wenn der Print nie erscheint, erreicht dein client-seitiger Save-Trigger den Server nicht. Wenn er erscheint, aber Items immer noch nicht bestehen bleiben, inspiziere, was tatsächlich in der Datenbank gelandet ist:
SELECT property_id, LEFT(furniture_data, 200) FROM housing_furniture WHERE property_id = 'some-uuid';
Achte auf die JSON-Struktur. Einige Skripte speichern die Position als Array [x, y, z], andere als Objekt {x: 0, y: 1, z: 2}, und manche verwenden einzelne Spalten. Eine Inkonsistenz zwischen dem, was der Client sendet, und dem, was die Datenbankabfrage erwartet, ist der mit Abstand häufigste Möbel-Bug.
Der Türschloss-Zustand sollte Neustarts überleben. Wenn Türen nach jedem Server-Neustart entriegelt werden, wird der Schloss-Zustand in eine In-Memory-Tabelle oder eine ressourcen-lokale Variable geschrieben statt in die Datenbank. Prüfe, ob deine Housing-Ressource einen Türschloss-Migrations- oder Initialisierungsschritt hat:
-- Prüfen, ob Türzustand in DB persistiert wird
MySQL.query('SELECT * FROM housing_doors WHERE property_id = ?', {propertyId}, function(result)
if result[1] then
print('[HOUSING-DEBUG] Door state loaded from DB: locked=' .. tostring(result[1].locked))
else
print('[HOUSING-DEBUG] No door state in DB — state is memory-only')
end
end)
Wenn es überhaupt keine housing_doors-Tabelle gibt, speichert dein Housing-Skript den Türzustand ausschließlich in der Datenbank der Türschloss-Ressource. Das ist in Ordnung, solange die Türschloss-Ressource ebenfalls in die Datenbank persistiert, aber es schafft eine versteckte Abhängigkeit.
Schlüssel sind typischerweise eine Join-Tabelle zwischen Spieler-Identifikatoren und Immobilien-IDs. Führe eine Diagnoseabfrage aus:
SELECT hp.id, hp.owner, hk.identifier, hk.access_level
FROM housing_properties hp
LEFT JOIN housing_keys hk ON hp.id = hk.property_id
WHERE hp.owner = 'citizenid:ABC12345';
Eine fehlende Zeile in housing_keys bedeutet, dass der Schlüssel nie ausgestellt wurde. Eine Identifikator-Inkonsistenz bedeutet, dass der Schlüssel existiert, aber nicht mit der aktuellen ID des Spielers übereinstimmt. Ein NULL-Access-Level wird normalerweise als owner interpretiert, aber einige Systeme erfordern einen expliziten String wie 'owner' oder 'roommate'.
Jedes FiveM-Framework implementiert Housing anders. Das Verständnis des Ansatzes deines Frameworks ist essenziell, bevor du Code anfasst.
esx_property und esx_garageESXs offizielle Housing-Suite besteht aus esx_property für die Interior-Verwaltung, esx_garage für verknüpfte Garagenfunktionalität und esx_doorlock für die Zugriffskontrolle. Immobilien werden in einer server-seitigen Lua-Tabelle definiert — normalerweise Config.Properties in esx_property/config.lua — wobei jeder Eintrag Interior-Koordinaten, eine MLO/Shell-Referenz, einen Preis und eine Blip-Konfiguration angibt.
In ESX Housing werden Möbel von einer separaten Ressource namens furni oder einem benutzerdefinierten Fork gehandhabt. Die Möbeldaten werden als JSON-String in einer furniture-Spalte innerhalb der Properties-Tabelle oder einer dedizierten user_furniture-Tabelle gespeichert. Das Identifikator-Format verwendet ESXs xPlayer.identifier, was typischerweise die Steam-Hex-ID ist.
ESXs Schlüsselsystem speichert Schlüssel in owned_properties, wobei das owner-Feld auf den Identifikator des Spielers gesetzt ist. Mitbewohner und Schlüsselfreigabe verwenden esx_property:addAccess / esx_property:removeAccess-Events, die an eine shared_access-Tabelle anhängen.
Der häufigste ESX-Housing-Fehler ist die Interior-Koordinaten-Inkonsistenz: Entwickler kopieren oft Property-Einträge und vergessen, Interior-Offsets zu aktualisieren, wodurch zwei Immobilien dasselbe Shell-Interior laden. Ein weiteres häufiges Problem ist die Garagen-Abschleppgebühren-Integration — esx_garage zieht für die Fahrzeugabholung von der Bank ab, aber wenn das Bankkonto des Spielers ein anderes Identifikator-Schema als der Immobilienbesitzer verwendet, schlägt die Abbuchung stillschweigend fehl und das Fahrzeug bleibt beschlagnahmt.
qb-houses, qb-apartments, qb-garagesQBCore implementiert Housing als drei kooperierende Ressourcen. qb-houses verwaltet kaufbare Einzelimmobilien mit konfigurierbaren Shells und Preisstufen. qb-apartments handhabt das Apartmentgebäude-System mit Lobby-Shells, Aufzug-Teleports und festen Wohneinheits-Interieurs. qb-garages stellt die Garagenverbindung bereit — jedes Haus oder Apartment kann einen verknüpften Garageneintrag haben, der Fahrzeuge bei Bedarf spawnt.
In QBCore werden Möbel von qb-interior gehandhabt, das ein Target-basiertes Platzierungssystem verwendet. Möbelpositionen werden als JSON-Arrays in einer furniture-Spalte innerhalb der player_houses-Tabelle oder einer dedizierten house_furniture-Tabelle gespeichert. Die citizenid (Bürger-Identifikationsnummer) ist durchgängig der Primärschlüssel, was einfacher ist als Steam-Hex-IDs, aber bedeutet, dass du konsistent sein musst — das Mischen von license:-Präfix-Identifikatoren mit citizen-IDs zerstört jede Abfrage.
QBCores Schlüsselsystem läuft über qb-keys oder qb-doorlock, wobei jede Tür eine doorId hat, die auf einen eindeutigen Hash einer Immobilie zurückverweist. Schlüssel werden als Array von citizen-IDs im Tür-Datensatz gespeichert. Das häufige Fehlermuster ist die Tür-Hash-Kollision: Wenn zwei Immobilien dieselben Türkoordinaten teilen (häufig in Apartmentgebäuden), kann qb-doorlock sie nicht unterscheiden und alle Mieter teilen sich am Ende den Zugriff.
QBCore-Apartment-Shells verwenden IPL-Loading über qb-interiors shells.lua. Jeder Apartmenttyp referenziert ein natives GTA V-IPL. Wenn das IPL nicht geladen ist, bevor der Spieler teleportiert wird, landet der Spieler in einer leeren Welt. Der Fix ist, RequestIpl explizit in qb-apartments vor dem Teleport-Trigger aufzurufen oder sicherzustellen, dass die IPL-Ressource vor Apartments in server.cfg startet.
ox_housing-MusterQBox-Server verwenden typischerweise ox_housing, wenn verfügbar, oder eine eng integrierte Kombination aus ox_inventory, ox_doorlock und einem benutzerdefinierten Housing-Skript. Der ox_housing-Ansatz speichert Immobilien im ox-Datenbankschema mit standardisierter Spaltenbenennung: owner (charid), shell, price, furniture (JSONB) und metadata (JSONB für erweiterbare Daten wie Garagenkoordinaten, Steuersätze und Schlüsselinhaber-Arrays).
Die Möbel-Persistenz in QBox wird über das Item-System von ox_inventory gehandhabt — platzierte Möbel-Items werden als Inventar-Items mit Positions-Metadaten behandelt. Das bedeutet, dass Möbelabfragen inventartabellenübergreifend sind:
SELECT * FROM ox_inventory WHERE name LIKE 'furniture_%' AND metadata->>'propertyId' = 'some-property-id';
Die ox_doorlock-Integration speichert Türkonfigurationen in einer JSON-Datei (doors.lua), nicht in der Datenbank. Wenn dein Housing-Skript Türen dynamisch erstellt (z. B. beim Immobilienkauf), musst du ox_doorlock:editDoorLock und ox_doorlock:addKeyholder server-seitig auslösen. Der häufige QBox-Fallstrick ist das Erstellen von Türen im Housing-Skript, ohne sie bei ox_doorlock zu registrieren, was zu Türen führt, die in der Housing-Datenbank existieren, aber keinen entsprechenden Türschloss-Eintrag haben.
Die Identifikator-Verwaltung in QBox verwendet Charakter-IDs (charid), die inhärent an einen einzelnen Charakter-Slot gebunden sind. Wenn ein Spieler seinen Charakter löscht und neu erstellt, geht der gesamte Immobilienbesitz verloren — die alte charid ist keinem aktiven Charakter mehr zugeordnet. QBox-Server, die langfristiges Wirtschafts-RP betreiben, sollten in Betracht ziehen, Steam-Hex- oder Lizenz-Identifikatoren als owner-Feld zu verwenden.
Über die zwölf FAQ-Einträge oben hinaus treten diese systemischen Probleme in allen Frameworks wiederholt auf und verdienen besondere Aufmerksamkeit.
Wenn ein Spieler eine Immobilie kauft und sie nach einem Neustart wieder auf unbesessen zurückfällt, schließt der Kauf-Handler die Transaktion ab (Geld abgezogen, Bestätigungsnachricht angezeigt), committet aber nie in die Datenbank. Verfolge das Kauf-Event vom client-seitigen Trigger durch jeden Callback:
-- Server-seitiger Kauf-Handler: häufig fehlender Schritt
RegisterNetEvent('housing:buyProperty', function(propertyId)
local xPlayer = ESX.GetPlayerFromId(source)
local property = Config.Properties[propertyId]
-- Geldabzug — das funktioniert normalerweise
xPlayer.removeAccountMoney('bank', property.price)
-- Datenbank-Insert — DAS fehlt in kaputten Skripten
MySQL.insert('INSERT INTO owned_properties (owner, property_id, purchased_date) VALUES (?, ?, NOW())', {
xPlayer.identifier, propertyId
})
-- Schlüsselzuweisung — ebenfalls häufig fehlend
MySQL.insert('INSERT INTO housing_keys (property_id, identifier, access_level) VALUES (?, ?, ?)', {
propertyId, xPlayer.identifier, 'owner'
})
end)
Wenn dein Housing-Skript nur eine In-Memory-Variable setzt oder eine client-seitige Benachrichtigung ohne den SQL-Insert auslöst, geht der Kauf beim Neustart verloren.
Möbel-Reset bedeutet, dass das Speichern funktioniert, aber das Laden nicht, oder beides funktioniert nicht. Füge einen server-seitigen Check beim Spieler-Spawn hinzu:
AddEventHandler('playerSpawned', function()
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
MySQL.query('SELECT furniture_data FROM housing_furniture WHERE owner = ?', {xPlayer.identifier}, function(result)
if result[0] then
print(string.format('[HOUSING-LOAD] Found %d bytes of furniture data for %s', #result[0].furniture_data, xPlayer.identifier))
TriggerClientEvent('housing:loadFurniture', src, json.decode(result[0].furniture_data))
else
print('[HOUSING-LOAD] No furniture data found for ' .. xPlayer.identifier)
end
end)
end)
Wenn das Load-Event feuert, aber Möbel nicht erscheinen, scheitert der client-seitige Handler möglicherweise stillschweigend an fehlerhaften Daten. Umschließe deinen client-seitigen Load-Handler mit pcall und logge alle Fehler.
Die Garagenverknüpfung erfordert drei Dinge: eine Garagenkoordinate in der Immobilien-Config, einen für den Spieler sichtbaren Garagenmarker oder -zone und eine Fahrzeuglisten-Abfrage, die auf den Identifikator der Garage beschränkt ist. Wenn Fahrzeuge nicht erscheinen:
-- Garagen-zu-Immobilien-Verknüpfung verifizieren
SELECT hp.id AS property_id, hg.garage_id, hg.vehicle_list
FROM housing_properties hp
LEFT JOIN housing_garages hg ON hp.garage_id = hg.id
WHERE hp.owner = 'citizenid:ABC12345';
Ein NULL in garage_id oder vehicle_list bedeutet, dass die Garage nie konfiguriert wurde oder die Verknüpfungsspalte falsch benannt ist. QBCore verwendet oft garage (Singular), während die Abfrage garage_id erwartet — prüfe dein Schema auf den exakten Spaltennamen.
Wenn einige Immobilien ihr Interior laden und andere nicht, liegt das Problem fast immer in der Immobilien-Konfiguration, nicht in der MLO-Ressource. Jeder Immobilieneintrag in Config.Properties spezifiziert einen Interior-Typ oder ein Shell-Modell. Wenn die Config auf eine Shell verweist, die in deinem installierten Shell-Pack nicht existiert, gelingt der Teleport, aber es wird kein Interior gerendert:
-- Shell-Verfügbarkeit prüfen
local shell = GetHashKey(property.shell) -- z. B. 'shell_v16low'
RequestModel(shell)
local timeout = 0
while not HasModelLoaded(shell) and timeout < 5000 do
timeout = timeout + 100
Wait(100)
end
if not HasModelLoaded(shell) then
print('[HOUSING-ERROR] Shell model ' .. property.shell .. ' failed to load — check if shell resource is installed and started')
else
print('[HOUSING-OK] Shell model ' .. property.shell .. ' loaded in ' .. timeout .. 'ms')
end
Wenn der Türschloss-Zustand nach Server-Neustart zurückgesetzt wird, werden die Schlossdaten im Speicher gespeichert. Der Fix erfordert das Persistieren des Schloss-Zustands in der Datenbanktabelle der Türschloss-Ressource:
-- QBCore / qb-doorlock
UPDATE qbdoorlock_keys SET citizenid = 'ABC12345' WHERE doorhash = 'hash_of_house_door';
-- ESX / esx_doorlock
UPDATE owned_doors SET locked = 1 WHERE property_id = 'some-uuid';
Konsultiere die Dokumentation deiner Türschloss-Ressource für das exakte Schema. Das Housing-Skript muss die Setter-Funktion der Türschloss-Ressource aufrufen — nicht eine Lua-Variable setzen — wenn ein Spieler eine Tür ver- oder entriegelt.
Der Housing-Zustand repräsentiert dutzende Stunden Spieler-Investition. Eine beschädigte Möbel-Tabelle oder ein kaputtes Schlüsselsystem kann Spieler dauerhaft vom Server vertreiben. Diese präventiven Maßnahmen kosten Minuten in der Implementierung und sparen Wochen an Support-Tickets.
Housing-Tabellen verdienen ihren eigenen Backup-Zeitplan, unabhängig von deinem allgemeinen Datenbank-Backup. Ein vollständiges Server-Backup alle 24 Stunden ist für Code-Änderungen in Ordnung, aber Housing-Möbel ändern sich ständig — ein Spieler, der drei Stunden dekoriert und es durch ein 23 Stunden altes Backup verliert, wird „wir haben Backups" nicht als Antwort akzeptieren.
Plane separate, hochfrequente Backups für diese Tabellen:
# Cron-Job — alle 2 Stunden
0 */2 * * * mysqldump -u root mydb housing_properties housing_furniture housing_keys housing_garages > /backups/housing_$(date +\%Y\%m\%d_\%H).sql
Exportiere vor jeder Datenbankmigration oder Schemaänderung explizit die Housing-Tabellen. Migrationen, die Identifikator-Spalten oder das Möbel-Schema berühren, sind die gefährlichste Operation für die Housing-Integrität.
Biete Spielern eine Möglichkeit, ihre Möbel-Layouts zu exportieren. Dies dient als Self-Service-Wiederherstellungsmechanismus und schafft Vertrauen:
RegisterCommand('exportfurniture', function(source, args)
local xPlayer = ESX.GetPlayerFromId(source)
MySQL.query('SELECT furniture_data FROM housing_furniture WHERE owner = ?', {xPlayer.identifier}, function(result)
if result[1] then
local export = json.encode(result[1].furniture_data)
-- Auf Server im exports-Ordner speichern
SaveResourceFile(GetCurrentResourceName(), ('exports/%s_furniture.json'):format(xPlayer.identifier), export, -1)
TriggerClientEvent('chat:addMessage', source, {args = {'System', 'Furniture exported to server.'}})
end
end)
end)
Führe diese Abfrage monatlich aus, um Identifikator-Drift zu erkennen:
SELECT hp.id, hp.owner, COUNT(hk.id) as key_count
FROM housing_properties hp
LEFT JOIN housing_keys hk ON hp.id = hk.property_id
WHERE hp.owner IS NOT NULL AND hp.owner != ''
GROUP BY hp.id, hp.owner
HAVING COUNT(hk.id) = 0;
Dies findet jede Immobilie, bei der der Besitzer keinen Schlüsseleintrag hat — was bedeutet, dass sie nicht eintreten können. Eine geplante Abfrage wie diese fängt die stillen Fehler, bevor Spieler sie melden.
Das Vorladen von Shells eliminiert die Ladeverzögerung, die Spieler durch die Welt fallen lässt. Lade beim Ressourcenstart alle Shell-Modelle in den Speicher:
Citizen.CreateThread(function()
for _, shell in pairs(Config.Shells) do
local model = GetHashKey(shell)
RequestModel(model)
while not HasModelLoaded(model) do
Wait(0)
end
print('[HOUSING] Preloaded shell: ' .. shell)
end
end)
Sei selektiv — lade nur Shells vor, die du tatsächlich verwendest. Das Laden aller Shell-Modelle aus einem 50-MLO-Pack verbraucht erheblichen Speicher. Ordne in server.cfg deine Ressourcen so, dass Shell-Packs zuerst starten, dann jede Ressource, die davon abhängt, und Housing zuletzt.
Die zuverlässigste Prävention ist eine dokumentierte, durchgesetzte Ressourcen-Startreihenfolge:
# server.cfg — Housing-Abhängigkeitsreihenfolge
ensure mapmanager
ensure spawnmanager
ensure sessionmanager
ensure [gameplay] # grundlegende Gameplay-Ressourcen
ensure [shells] # ALLE MLO- und Shell-Interieurs
ensure [inventory] # ox_inventory oder qb-inventory
ensure [doorlocks] # ox_doorlock oder qb-doorlock
ensure [housing] # Housing-Skript — NACH allen Abhängigkeiten
ensure [garages] # Garagensystem — NACH Housing
Wenn eine Abhängigkeit nicht startet, initialisiert sich die Housing-Ressource nicht ordnungsgemäß und du siehst klare Fehler in der Konsole. Wenn Abhängigkeiten in falscher Reihenfolge starten, sind die Fehler still — die Ressource initialisiert sich mit veralteten Daten und scheitert später, zur Laufzeit, wenn ein Spieler versucht, sein Haus zu betreten.
Führe diesen Check nach jedem Server-Neustart aus:
housing_properties ab — zähle Zeilen, verifiziere, dass das letzte Kaufdatum aktuell isthousing_furniture ab — verifiziere, dass die Zeilenanzahl nicht null ist, wenn Spieler dekoriert habenFünf Minuten Validierung fangen 90 % der Housing-Fehler ab, bevor ein Spieler ihnen begegnet. Füge dies zu deiner Server-Neustart-Checkliste hinzu und du wirst nie wieder ein „mein Haus ist kaputt"-Ticket bearbeiten müssen, das hätte verhindert werden können.
Betretungsfehler haben drei häufige Ursachen: Die Interaktionszone ist falsch konfiguriert (Koordinaten stimmen nicht mit der Tür überein), das Shell-Interior wurde noch nicht gestreamt, oder der Spieler wird nicht als Besitzer erkannt. Gib die Position des Spielers aus, wenn er vor der Tür steht, und vergleiche sie mit der Config. Wenn die Koordinaten übereinstimmen, aber der Teleport fehlschlägt, sind die Interior-Koordinaten falsch – verwende die dokumentierten Koordinaten der Shell-Ressource, schätze nicht.
Die Möbel-Persistenz schlägt fehl, wenn das Speicherevent nicht ausgelöst wird oder das Datenformat nicht zum Datenbankschema passt. Füge im Save-Handler serverseitig einen print-Befehl hinzu, um zu bestätigen, dass er feuert, und überprüfe dann die Tabelle housing_furniture. Wenn das Event feuert, aber nichts geschrieben wird, liegt es meist an der falschen Speicherung der Position – prüfe, ob dein Skript einzelne float-Spalten (x, y, z) oder einen JSON-Blob erwartet.
Hausschlüssel bilden eine Spieler-ID auf eine Immobilien-ID ab. Wenn Schlüssel keinen Zugriff gewähren, stimmt das Format der ID nicht. Am häufigsten wechselte der Server irgendwann von Steam-Hex zu license-IDs oder citizen-IDs, und die vorhandenen Immobilieneinträge wurden nie migriert. Führe SELECT owner FROM housing_properties aus und vergleiche das mit dem, was dein Framework jetzt zurückgibt.
Stash-Fehler treten auf, wenn das Inventarsystem die Stash-ID nicht finden kann. Jedes Haus benötigt eine eindeutige Stash-ID (üblich: 'house_<propertyId>'), die bei deiner Inventar-Ressource registriert ist. ox_inventory erfordert die Registrierung über exports.ox_inventory:RegisterStash beim Serverstart, nicht on demand. Überprüfe, ob das Format der Stash-ID mit dem übereinstimmt, was das Housing-Skript generiert.
Blips für eigene Immobilien werden clientseitig erstellt, nachdem die Immobilien-Daten des Spielers geladen wurden. Wenn der Blip nicht erscheint, war entweder der Besitz-Check leer oder der Blip-Code wurde ausgeführt, bevor die Daten ankamen. Füge eine kleine Wartezeit ein oder verwende einen callback-basierten Ansatz, damit die Blip-Erstellung erst nach vollständigem Laden der Liste der eigenen Immobilien feuert.
Abstürze beim Dekorieren haben drei Ursachen: ungültige Furniture-Model-Hashes (das Modell existiert nicht in GTA V), zu viele gleichzeitig gespawnte Props während des Platzierens, oder Speicherüberlauf durch hochpolygone Modelle. Reduziere die maximale Anzahl platzierbarer Objekte pro Immobilie, validiere alle Furniture-Hashes gegen die GTA V-Prop-Liste und leere den Asset-Cache zwischen Abstürzen.
Shell-Interiors sind separate Streaming-Ressourcen. Wenn die Shell nicht gerendert wird, starte die Shell-Ressource *vor* der Housing-Ressource in der server.cfg, überprüfe, ob die Modelldateien der Shell im stream/-Ordner existieren, und bestätige, dass die Interior-Koordinaten mit der tatsächlichen Position der Shell übereinstimmen. Manche Shells erfordern IPL-Entfernung (RemoveIpl), wenn sie denselben Raum wie ein standardmäßiges GTA-Interior belegen.
Kaufvorgänge haben mehrere Fehlerquellen: nicht ausreichendes Guthaben, bereits besessene Immobilie, Preis aufgrund eines Rechenfehlers auf 0 gesetzt, oder die Geldabhebung zielt auf das falsche Konto (Bargeld vs. Bank). Logge jeden Schritt des Kauf-Handlers serverseitig. Der häufigste stille Fehler ist, dass die Immobilie in der DB als verkauft markiert, aber der Schlüssel nie zugewiesen wird.
Mitbewohner werden als zusätzliche Einträge in einer Tabelle housing_access gespeichert, getrennt vom owner-Feld in housing_properties. Wenn ein Mitbewohner nicht eintreten kann, prüft der Entry-Handler vermutlich nur den Besitzer, nicht die Zugriffstabelle. Verfolge das Entry-Event und bestätige, dass es beide Quellen abfragt, bevor der Zugriff verweigert wird.
Hausgaragen sind ein sekundäres Feature, das explizite Garagenkoordinaten in der Immobilien-Config erfordert. Viele Housing-Skripte liefern den Garage-Event-Handler standardmäßig deaktiviert aus. Überprüfe die Housing-Config auf ein garage_enabled-Flag pro Immobilie und bestätige, dass die Garagenkoordinaten in einem befahrbaren Bereich liegen (nicht innerhalb einer Wand).
Türkonflikte treten auf, wenn sowohl eine Türschloss-Ressource (z. B. qb-doorlock) als auch das Housing-Skript versuchen, dieselbe Tür-Entität zu steuern. Die Lösung ist einfach: Entferne die Tür-Einträge aus der Config von qb-doorlock für alle Türen, die vom Housing verwaltet werden. Lass das Housing-Skript seine eigenen Türzustände verwalten – du kannst nicht zwei Ressourcen haben, die eine Tür besitzen.
Grundsteuer läuft über einen serverseitigen Timer (meist stündlich). Wenn die Steuer nicht eingezogen wird, läuft der Timer nicht (prüfe auf serverseitige Fehler beim Start), die Bankabbuchung zielt auf den falschen Kontotyp, oder die Steuerberechnung ergab Null. Logge jeden Steuereinzugsversuch mit Betrag und Zielkonto.