FiveM State Bags: Entity(entity).state, GlobalState und Handler

Wie FiveM State Bags funktionieren: Entity(entity).state, Player(source).state, LocalPlayer.state, GlobalState, :set, Change-Handler und wann du sie Events vorziehst

Du möchtest ein kleines Datenstück zwischen dem Server und jedem Client teilen, z.B. dass ein Fahrzeug verriegelt ist, dass ein Spieler in Handschellen liegt oder das aktuelle Wetter, und schreibst ständig Events, die bei jeder Änderung auslösen und für später ankommende Spieler aus der Sync geraten. State Bags sind die eingebaute Antwort.

Dieser Artikel behandelt die State-Bag-Typen, wie man sie schreibt und liest, wie man auf Änderungen reagiert und wann ein Event immer noch die bessere Wahl ist.

Was ein State Bag ist

Ein State Bag ist ein tabellenähnlicher Speicher für Schlüssel und Werte, der an etwas gebunden ist. Die Runtime synchronisiert ihn für dich, auch für Spieler, die sich verbinden, nachdem der Wert gesetzt wurde. FiveM bietet dir drei Arten:

Bag Lesen und Schreiben mit Lebt auf
Eine Entität Entity(entity).state Die Entität (NPC, Fahrzeug, Objekt)
Ein Spieler Player(source).state auf dem Server, LocalPlayer.state auf dem Client Der Spieler
Der Server GlobalState Der ganze Server

In allen kannst du einen Wert wie ein normales Feld lesen:

lua
local locked = Entity(vehicle).state.locked

Schreiben vom Server

Auf dem Server wird das Setzen eines Wertes zu den Clients repliziert, die diesen Bag sehen können:

lua
-- server
local veh = CreateVehicle(`adder`, 215.0, -810.0, 30.7, 90.0, true, true)
Entity(veh).state.locked = true

Player(source).state.cuffed = true

GlobalState.weather = 'RAIN'

Du kannst entweder den Feldstil oder den expliziten Aufruf verwenden, mit dem du auch wählen kannst, ob der Wert repliziert wird:

lua
Entity(veh).state:set('locked', true, true)

:set(key, value, replicated) nimmt den Schlüssel, den Wert und einen Boolean. Mit true wird der Wert zur anderen Seite gesendet, mit false bleibt er auf der Seite, die ihn schrieb.

Tipp: Werte können Zahlen, Strings, Booleans und Tabellen sein. Eine Tabelle wird kopiert, wenn du sie setzt, also ändert eine Änderung eines Feldes in der Tabelle, die du zurückbekommst, nichts. Setze die ganze Tabelle erneut, um sie zu aktualisieren.

Schreiben vom Client

Ein Client kann auf seinen eigenen Spieler und auf Entitäten, die er kontrolliert, schreiben, aber eine einfache Zuweisung bleibt lokal:

lua
-- client
LocalPlayer.state:set('inService', true, true)  -- replicated to the server
LocalPlayer.state.hasMask = true                -- local only

Der Server kann Player(source).state.inService danach lesen. Behandle es als unvertraut: Ein modifizierter Client kann jeden Wert schreiben, den er will. Nutze von Clients geschriebene State für Komfort, wie UI-Flaggen, und halte alles mit einem Vorteil (Geld, Job, Berechtigungen) auf dem Server.

GlobalState ist das Gegenteil: Der Server schreibt es, jeder Client liest es, und Clients können es nicht für andere ändern.

lua
-- client
local weather = GlobalState.weather

Auf Änderungen reagieren

Anstatt einen Wert in einer Schleife abzufragen, registriere einen Handler, der läuft, wenn sich ein Schlüssel ändert. Das ist der Hauptgrund, State Bags auf dem Client zu verwenden:

lua
-- AddStateBagChangeHandler(keyFilter, bagFilter, handler)
AddStateBagChangeHandler('locked', nil, function(bagName, key, value, reserved, replicated)
    local entity = GetEntityFromStateBagName(bagName)
    if entity == 0 then return end

    SetVehicleDoorsLocked(entity, value and 2 or 1)
end)
  • keyFilter ist der Schlüssel, der dich interessiert, oder nil für jeden Schlüssel.
  • bagFilter begrenzt den Bag, z.B. einen bestimmten Spieler-Bag oder nil für alle.
  • bagName sieht aus wie entity:1234, player:5 oder global. GetEntityFromStateBagName verwandelt einen Entity-Bag in ein Handle, und GetPlayerFromStateBagName macht das gleiche für einen Spieler-Bag.

Auf dem Client existiert die Entität möglicherweise noch nicht, wenn der Handler auslöst, z.B. für ein Fahrzeug, das noch Streaming ist. GetEntityFromStateBagName kann in diesem Fall 0 zurückgeben, überprüfe es also. Das State erneut zu lesen, wenn die Entität Streaming ist, ist die sichere Gewohnheit.

Die gleiche Funktion existiert auf dem Server, wo sie praktisch ist, um auf einen Client zu reagieren, der einen replizierten Wert schreibt.

State Bags oder Events

Verwende einen State Bag, wenn Verwende ein Event, wenn
Der Wert den aktuellen Zustand von etwas beschreibt (verriegelt, gefesselt, im Dienst) Etwas ist einmal passiert (ein Kauf, ein Treffer, ein Tastendruck)
Spieler, die später beitreten, den Wert sehen müssen Nur Spieler, die gerade jetzt da sind, müssen es wissen
Viele Spieler müssen es jederzeit lesen Ein Spieler muss von etwas erfahren
Du würdest sonst in einer Schleife abfragen Du musst ein Ergebnis oder eine einmalige Payload übergeben

Eine gute Regel: Events sind für Aktionen, State Bags sind für Zustand. Wenn ein Spieler, der in der Mitte beitritt, dieselbe Sache erneut mitgeteilt werden müsste, ist es Zustand. Siehe Client- und Server-Events für die andere Seite.

Häufige Fehler

  • Es für große oder sich schnell ändernde Daten verwenden. Jede Änderung wird über das Netzwerk gesendet. Schreibe eine Position nicht jeden Frame in einen State Bag.
  • Client-Schreibvorgänge vertrauen. Validiere alles, das ein Client auf dem Server gesetzt hat, bevor du darauf reagierst.
  • Erwarten, dass der Handler läuft, bevor die Entität existiert. Überprüfe das Handle und lese den State erneut, wenn die Entität erscheint.
  • Eine Tabelle vor Ort ändern. Das Lesen von state.items, das Hinzufügen und das Nicht-Setzen ändert nichts.
  • Zurücksetzen vergessen. State auf einer Entität geht mit der Entität weg, aber State auf einem Spieler oder GlobalState bleibt, bis du ihn leerst, also setze ihn auf nil, wenn du fertig bist.
lua
Player(source).state.cuffed = nil

Checkliste

Symptom Behebung
Client setzt einen Wert, aber der Server sieht ihn nie Verwende :set(key, value, true), damit er repliziert wird
Handler läuft, aber das Entity-Handle ist 0 Die Entität ist noch nicht Streaming: Überprüfe und lese den State später erneut
Späte Beiträge verpassen den Wert Verwende einen State Bag anstelle eines Events
Tabellenänderung synchronisiert sich nicht Setze die ganze Tabelle erneut mit :set
Kannst GlobalState nicht vom Client aus ändern Nur der Server schreibt es: Sende ein Event und lass den Server es setzen
Alter Wert bleibt nach dem Job Setze den Schlüssel auf nil

Kurze Antworten

Was ist ein State Bag in FiveM?

Ein Schlüssel- und Wertspeicher, der an eine Entität, einen Spieler oder den ganzen Server gebunden ist. Werte, die du setzt, werden vom Spiel automatisch zur anderen Seite synchronisiert, sodass du keine Events für jede Änderung auslösen musst.

Kann ein Client einen State Bag ändern und der Server sieht es?

Nur, wenn der Wert mit Replikation gesetzt wird, z.B. LocalPlayer.state:set('key', value, true). Eine einfache Zuweisung auf dem Client bleibt lokal, und der Server sollte niemals darauf vertrauen, wenn es wichtig ist.

Benötigen State Bags OneSync?

Entity State Bags sind von OneSync abhängig, das aktuelle Server standardmäßig verwenden. Player State und GlobalState sind leichter zu starten.

Scripts ohne dieses Problem

Parrots as PetsVierzehn Vögel, die auf deiner Schulter sitzen, mit dir fliegen und auf Zuruf zurückkommen.Script ansehen →Advanced BoostingFahrzeug-Boosting per Tablet: Aufträge von Klasse D bis S+, Crews und eine Live-Warteschlange.Script ansehen →Hookah SystemPlatzierbare Shishas und Lounge-Möbel mit über 50 Aromen und Effekten.Script ansehen →

Weiterlesen