I sacchetti di stato FiveM: Entity(entity).state, GlobalState e handler

Come funzionano i sacchetti di stato FiveM: Entity(entity).state, Player(source).state, LocalPlayer.state, GlobalState, :set, change handler, e quando preferirli agli eventi

Vuoi condividere un piccolo dato tra il server e ogni client, ad esempio che un veicolo è bloccato, che un giocatore è ammanettato, o il meteo attuale, e continui a scrivere eventi che si attivano ad ogni modifica e vanno fuori sincronia con i giocatori che si uniscono dopo. I sacchetti di stato sono la risposta integrata.

Questo articolo riguarda i tipi di state bag, come leggerli e scriverli, come reagire ai cambiamenti, e quando un evento è ancora la scelta migliore.

Che cos'è un state bag

Un state bag è un archivio simile a una tabella di chiavi e valori collegato a qualcosa. Il runtime lo sincronizza per te, incluso ai giocatori che si connettono dopo che il valore è stato impostato. FiveM ti dà tre tipi:

Bag Leggi e scrivi con Vive su
Un'entità Entity(entity).state L'entità (ped, veicolo, oggetto)
Un giocatore Player(source).state sul server, LocalPlayer.state sul client Il giocatore
Il server GlobalState L'intero server

In tutti loro leggi un valore come un campo normale:

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

Scrivere dal server

Sul server, impostare un valore lo replica ai client che possono vedere quel bag:

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'

Puoi usare lo stile di campo o la chiamata esplicita, che ti permette anche di scegliere se il valore è replicato:

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

:set(key, value, replicated) prende la chiave, il valore e un booleano. Con true il valore viene inviato all'altro lato, con false rimane dal lato che lo ha scritto.

Consiglio: i valori possono essere numeri, stringhe, booleani e tabelle. Una tabella viene copiata quando la imposti, quindi modificare un campo nella tabella che leggi di nuovo non fa nulla. Imposta di nuovo l'intera tabella per aggiornarla.

Scrivere dal client

Un client può scrivere nel suo proprio giocatore e nelle entità che controlla, ma un semplice assegnamento rimane locale:

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

Il server può leggere Player(source).state.inService dopo quello. Trattalo come inaffidabile: un client modificato può scrivere qualsiasi valore che vuole. Usa lo stato scritto dal client per convenienza, ad esempio flag UI, e tieni tutto ciò che ha un vantaggio allegato (denaro, lavoro, permessi) sul server.

GlobalState è il contrario: il server lo scrive, ogni client lo legge, e i client non possono cambiarlo per gli altri.

lua
-- client
local weather = GlobalState.weather

Reagire ai cambiamenti

Invece di sondare un valore in un loop, registra un handler che viene eseguito quando una chiave cambia. Questo è il motivo principale per usare i sacchetti di stato sul client:

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 è la chiave che ti interessa, o nil per ogni chiave.
  • bagFilter limita il bag, ad esempio un bag di giocatore specifico, o nil per tutti.
  • bagName sembra entity:1234, player:5 o global. GetEntityFromStateBagName trasforma un bag di entità in un handle, e GetPlayerFromStateBagName fa lo stesso per un bag di giocatore.

Sul client, l'entità potrebbe non esistere ancora quando l'handler si attiva, ad esempio per un veicolo che sta ancora caricandosi. GetEntityFromStateBagName può restituire 0 in quel caso, quindi controllalo. Riavviare lo stato quando l'entità si carica è l'abitudine sicura.

La stessa funzione esiste sul server, dove è pratica per reagire a un client che scrive un valore replicato.

State bag o eventi

Usa un state bag quando Usa un evento quando
Il valore descrive lo stato attuale di qualcosa (bloccato, ammanettato, in servizio) Qualcosa è accaduto una volta (un acquisto, un colpo, una pressione di pulsante)
I giocatori che si uniscono successivamente devono vedere il valore Solo i giocatori presenti al momento devono saperlo
Molti giocatori devono leggerlo in qualsiasi momento Un giocatore deve essere informato di qualcosa
Altrimenti dovresti sondare in un loop Devi passare un risultato o un payload una tantum

Una buona regola: gli eventi sono per le azioni, i sacchetti di stato sono per lo stato. Se un giocatore che si unisce a metà dovrebbe essere informato della stessa cosa di nuovo, è uno stato. Vedi client e server eventi per l'altro lato.

Errori comuni

  • Usarlo per dati grandi o che cambiano frequentemente. Ogni modifica viene inviata sulla rete. Non scrivere una posizione in un state bag ogni frame.
  • Fidarsi delle scritture del client. Convalida tutto ciò che un client ha impostato prima di agire su di esso sul server.
  • Aspettarsi che l'handler sia eseguito prima che l'entità esista. Controlla l'handle e riavvia lo stato quando l'entità appare.
  • Mutare una tabella sul posto. Leggere state.items, aggiungere ad esso e non impostarlo di nuovo non cambia nulla.
  • Dimenticare il ripristino. Lo stato su un'entità scompare con l'entità, ma lo stato su un giocatore o GlobalState rimane fino a quando non lo cancelli, quindi impostalo di nuovo su nil al termine.
lua
Player(source).state.cuffed = nil

Elenco di controllo

Sintomo Correzione
Il client imposta un valore ma il server non lo vede mai Usa :set(key, value, true) in modo che venga replicato
L'handler viene eseguito ma l'handle dell'entità è 0 L'entità non è ancora stata caricata: controlla e riavvia lo stato in seguito
I ritardatari mancano il valore Usa un state bag invece di un evento
La modifica della tabella non si sincronizza Imposta di nuovo l'intera tabella con :set
Non è possibile modificare GlobalState dal client Solo il server lo scrive: invia un evento e lascia che il server lo imposti
Il vecchio valore rimane dopo il completamento del lavoro Imposta la chiave su nil

Risposte rapide

Che cos'è un state bag in FiveM?

Un archivio chiave-valore collegato a un'entità, un giocatore o l'intero server. I valori che imposti vengono sincronizzati automaticamente dall'altro lato da parte del gioco, quindi non è necessario attivare un evento per ogni modifica.

Un client può modificare un state bag e farlo vedere al server?

Solo se il valore è impostato con replicazione attivata, ad esempio LocalPlayer.state:set('key', value, true). Un semplice assegnamento nel client rimane locale, e il server non dovrebbe mai fidarsi di esso per nulla che sia importante.

Gli state bag hanno bisogno di OneSync?

Gli state bag dell'entità dipendono da OneSync, che i server attuali utilizzano per impostazione predefinita. Lo stato del giocatore e GlobalState sono i casi più semplici per iniziare.

Script senza questo problema

Parrots as PetsQuattordici uccelli che stanno sulla tua spalla, volano con te e tornano quando li chiami.Vedi script →Advanced BoostingBoosting di veicoli dal tablet: contratti dalla classe D alla S+, crew e coda in tempo reale.Vedi script →Hookah SystemNarghilè e arredi lounge posizionabili, con oltre 50 gusti ed effetti.Vedi script →

Continua a leggere