Auswahl der richtigen Speicherstrategie
Die Persistenz der Spielerdaten ist einer der kritischsten Aspekte der FiveM-Serverentwicklung. Alle Informationen über einen Spieler, von seinem Geldguthaben und seiner Jobzuweisung bis hin zu seinem Charakterauftritt und seinem Fähigkeitsniveau, müssen Serverneustarts und Spielerunterbrechungen überstehen. FiveM bietet mehrere Speichermechanismen, die jeweils für unterschiedliche Anwendungsfälle geeignet sind. MySQL-Datenbanken bieten über Bibliotheken wie oxmysql relationalen Speicher für strukturierte Daten, die spielerübergreifend abgefragt werden müssen. Der Key-Value-Pair-Speicher (KVP) bietet eine schnelle lokale Persistenz für Einstellungen auf Serverebene. State Bags ermöglichen eine Echtzeit-Datensynchronisierung zwischen Server und Client ohne manuelle Ereignisbehandlung. Die besten Server kombinieren alle drei Ansätze und verwenden MySQL für permanente Aufzeichnungen, KVP für Konfigurations-Caching und State Bags für Live-Sitzungsdaten, die andere Spieler sehen müssen.
Datenbankschemadesign für Spielerdaten
Ein gut gestaltetes Datenbankschema trennt Anliegen in logische Tabellen, anstatt alles in einer einzigen JSON-Spalte abzulegen. Obwohl es verlockend ist, alle Spielerdaten als JSON-Blob zu speichern, erschwert dieser Ansatz das Abfragen, Indizieren und Debuggen erheblich. Verwende stattdessen dedizierte Tabellen für unterschiedliche Datendomänen. Die Hauptspielertabelle enthält Identitäts- und Authentifizierungsfelder, während zugehörige Tabellen Jobdaten, Bankkonten, Inventar und Charaktermetadaten enthalten. Hier ist ein normalisiertes Schema für Kernspielerdaten:
Die Fremdschlüsseleinschränkung ON DELETE CASCADE stellt sicher, dass beim Löschen eines Zeichens alle zugehörigen Datensätze in untergeordneten Tabellen automatisch bereinigt werden, wodurch verwaiste Daten verhindert werden. Der last_updated-Zeitstempel mit ON UPDATE CURRENT_TIMESTAMP bietet einen integrierten Prüfpfad, der zeigt, wann jeder Spielerdatensatz zuletzt geändert wurde, was für die Fehlerbehebung bei Datenverlustberichten von unschätzbarem Wert ist.
Effizientes Laden von Daten auf Player Connect
Wenn ein Player eine Verbindung zum Server herstellt, musst du alle seine Daten aus der Datenbank laden und das In-Memory-Player-Objekt füllen. Der Schlüssel liegt darin, Datenbankabfragen stapelweise durchzuführen, anstatt sie einzeln auszuführen. Ein Spieler, der eine Verbindung herstellt, benötigt möglicherweise Daten von fünf oder mehr Tischen, und das Durchführen von fünf aufeinanderfolgenden Abfragen führt zu erheblicher Latenz beim Ladebildschirm. Verwende eine einzelne Abfrage mit mehreren Anweisungen oder führest du Abfragen mithilfe von Versprechen parallel aus. Hier ist ein optimiertes Lademuster:
Durch das gleichzeitige Auslösen aller fünf Abfragen entspricht die Gesamtladezeit der Dauer der langsamsten einzelnen Abfrage und nicht der Summe aller fünf. Bei einer gut indizierten Datenbank wird dadurch die Ladezeit des Players normalerweise von mehreren hundert Millisekunden auf unter 100 ms verkürzt. Behandeln immer den Fall, dass der Spielerdatensatz nicht vorhanden ist, was bei der ersten Verbindung oder nach einer Charakterlöschung der Fall ist.
Speichere von Daten mit Batch-Schreibvorgängen
Das Speichern von Spielerdaten bei jeder Änderung ist verschwenderisch und verursacht unnötige Datenbanklast. Implementiere stattdessen ein Dirty-Flag-System, das markiert, welche Datendomänen sich geändert haben, und diese in regelmäßigen Abständen in die Datenbank schreibt. Dieser Batch-Ansatz reduziert die Anzahl der Schreibvorgänge erheblich und stellt gleichzeitig sicher, dass Daten häufig genug gespeichert werden, um Verluste bei Abstürzen zu minimieren. Hier ist ein praktischer Speichermanager:
Jede Domäne, wie Geld, Job oder Position, wird unabhängig gespeichert, sodass eine Änderung des Geldguthabens eines Spielers nicht dazu führt, dass seine gesamten Charakterdaten neu geschrieben werden. Dieses selektive Speichern verringert auch das Risiko von Race Conditions, bei denen zwei Scripts gleichzeitig verschiedene Teile des Player-Objekts ändern und eines die Änderungen des anderen überschreibt.
Verwenden von State Bags für die Echtzeitsynchronisierung
State Bags sind ein FiveM-nativer Mechanismus zum Synchronisieren von Daten zwischen Server und Client, ohne benutzerdefinierte Ereignisse zu schreiben. Du funktionieren wie reaktive Eigenschaften: Wenn der Server einen Status-Bag-Wert festlegt, erhalten alle abonnierten Clients automatisch das Update. Dadurch sind sie ideal für Daten, die andere Spieler in Echtzeit sehen müssen, wie zum Beispiel über Kopf angezeigte Berufsbezeichnungen, Dienststatus oder benutzerdefinierte Spielertitel. Zustandsbeutel können für Entitäten (Spieler, Fahrzeuge, Objekte) oder global festgelegt werden. So nutze Player-State-Bags effektiv:
Der zweite Parameter von state:set steuert die Replikation. Wenn du es auf true setzen, wird auf alle Clients repliziert, während false nur auf den besitzenden Client repliziert. Verwende false für sensible Daten wie Bankguthaben, die andere Spieler nicht sehen sollten. Statustaschen bleiben für die Dauer der Player-Sitzung bestehen, werden jedoch nicht in der Datenbank gespeichert, sodass sie den MySQL-Speicher ergänzen, anstatt ihn zu ersetzen.
KVP-Speicher für die Serverkonfiguration
Der Schlüssel-Wert-Paar-Speicher bietet einen schnellen, dateibasierten Persistenzmechanismus, der in FiveM integriert ist. Im Gegensatz zu MySQL sind KVP-Vorgänge synchron und erfordern keine Netzwerkaufrufe, wodurch sie beim Lesen und Schreiben kleiner Datenmengen extrem schnell sind. KVP wird pro Ressource gespeichert, was bedeutet, dass jede Ressource ihren eigenen isolierten Schlüssel-Namespace hat. Dies macht KVP ideal zum Speichern von Ressourcenkonfigurationen, zum Zwischenspeichern häufig aufgerufener Referenzdaten oder zum Beibehalten serverweiter Einstellungen, die nicht in eine relationale Datenbank gehören:
Die Caching-Schicht verhindert wiederholte Festplattenlesevorgänge für Werte, auf die häufig zugegriffen wird. KVP eignet sich nicht für große Datensätze oder spielerspezifische Daten, die abgefragt werden müssen, da keine Indizierungs- oder Suchfunktion vorhanden ist. Betrachte es als einen Konfigurationsspeicher und nicht als eine Datenbank. Ein gängiges Muster besteht darin, die Ergebnisse teurer Datenbankabfragen in KVP mit einer TTL zwischenzuspeichern und den Zeitstempel zu überprüfen, bevor der zwischengespeicherte Wert zurückgegeben wird.
Datenmigration und Schemaaktualisierungen
Wenn sich dein Server weiterentwickelt, musst du Datenbankschemata aktualisieren, ohne dass vorhandene Spielerdaten verloren gehen. Erstelle ein Migrationssystem, das nachverfolgt, welche Schemaänderungen angewendet wurden, und ausstehende Migrationen beim Serverstart ausführt. Speichere den Migrationsverlauf in einer speziellen Tabelle, damit du genau sehen können, welche Änderungen wann angewendet wurden. Jede Migration sollte idempotent sein, was bedeutet, dass sie mehrere Male sicher ausgeführt werden kann, ohne dass es zu Fehlern kommt:
Teste Migrationen immer an einer Entwicklungskopie deiner Datenbank, bevor du sie in der Produktion anwenden. Bei großen Tabellen mit Millionen von Zeilen können ALTER TABLE-Operationen die Tabelle für längere Zeiträume sperren. In diesen Fällen solltest du erwägen, eine neue Tabelle mit dem gewünschten Schema zu erstellen, Daten stapelweise zu kopieren und dann die Tabellennamen während eines Wartungsfensters auszutauschen.
Backup-Strategien und Datenwiederherstellung
Ohne einen robusten Backup-Plan ist keine Persistenzstrategie vollständig. Automatisierte MySQL-Backups sollten mindestens täglich ausgeführt werden, wobei die Backup-Dateien auf einem separaten Server oder Cloud-Speicherdienst gespeichert werden. Verwende mysqldump mit dem Flag --single-transaction für InnoDB-Tabellen, um konsistente Sicherungen zu erstellen, ohne die Datenbank zu sperren. Implementiere über vollständige Backups hinaus ein Transaktionsprotokoll, das jede wesentliche Datenänderung aufzeichnet, damit du den Status eines Spielers jederzeit rekonstruieren können. Dies ist von unschätzbarem Wert, wenn ein Spieler den Verlust von Gegenständen meldet oder wenn ein Exploit entdeckt wird und du betroffene Konten zurücksetzen müssen. Bewahre Backups mindestens 30 Tage lang mit einer Rotationsrichtlinie auf, die tägliche Backups für die aktuelle Woche, wöchentliche Backups für den aktuellen Monat und monatliche Backups darüber hinaus vorsieht. Teste dein Wiederherstellungsverfahren regelmäßig, indem du einst Testserver aus einem Backup hochfahren, um sicherzustellen, dass die Daten vollständig sind und der Server ordnungsgemäß startet, denn ein Backup, das du noch nie getestet haben, ist ein Backup, dem du nicht vertrauen können.

