Sacolas de estado FiveM: Entity(entity).state, GlobalState e handlers

Como as sacolas de estado FiveM funcionam: Entity(entity).state, Player(source).state, LocalPlayer.state, GlobalState, :set, handlers de mudança, e quando preferir-las a eventos

Você quer compartilhar um pequeno pedaço de dados entre o servidor e cada cliente, por exemplo que um veículo está trancado, que um jogador está algemado, ou o clima atual, e você continua escrevendo eventos que disparam a cada mudança e saem de sincronização para jogadores que entram depois. Sacolas de estado são a resposta integrada.

Este artigo aborda os tipos de sacolas de estado, como escrevê-las e lê-las, como reagir a mudanças, e quando um evento ainda é a melhor escolha.

O que é uma sacola de estado

Uma sacola de estado é um armazenamento semelhante a uma tabela de chaves e valores anexado a algo. O tempo de execução a sincroniza para você, incluindo para jogadores que se conectam depois que o valor foi definido. FiveM oferece três tipos:

Sacola Ler e escrever com Reside em
Uma entidade Entity(entity).state A entidade (ped, veículo, objeto)
Um jogador Player(source).state no servidor, LocalPlayer.state no cliente O jogador
O servidor GlobalState O servidor inteiro

Em todos eles você lê um valor como um campo normal:

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

Escrevendo do servidor

No servidor, definir um valor o replica para os clientes que podem ver essa sacola:

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'

Você pode usar o estilo de campo ou a chamada explícita, que também permite escolher se o valor é replicado:

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

:set(key, value, replicated) leva a chave, o valor e um booleano. Com true o valor é enviado para o outro lado, com false ele permanece no lado que o escreveu.

Dica: Os valores podem ser números, cadeias de caracteres, booleanos e tabelas. Uma tabela é copiada quando você a define, portanto alterar um campo na tabela que você lê de volta não faz nada. Defina a tabela inteira novamente para atualizá-la.

Escrevendo do cliente

Um cliente pode escrever em seu próprio jogador e em entidades que controla, mas uma atribuição simples permanece local:

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

O servidor pode ler Player(source).state.inService depois disso. Trate-o como não confiável: um cliente modificado pode escrever qualquer valor que quiser. Use estado escrito pelo cliente para conveniência, como sinalizadores de UI, e mantenha qualquer coisa com uma vantagem anexada (dinheiro, trabalho, permissões) no servidor.

GlobalState é o oposto: o servidor escreve, cada cliente lê, e os clientes não podem alterá-lo para outros.

lua
-- client
local weather = GlobalState.weather

Reagindo a mudanças

Em vez de sondagem de um valor em um loop, registre um handler que execute quando uma chave mude. Esta é a razão principal para usar sacolas de estado no cliente:

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 é a chave que você se importa, ou nil para cada chave.
  • bagFilter limita a sacola, por exemplo uma sacola de jogador específica, ou nil para todas.
  • bagName parece entity:1234, player:5 ou global. GetEntityFromStateBagName transforma uma sacola de entidade em um identificador, e GetPlayerFromStateBagName faz o mesmo para uma sacola de jogador.

No cliente, a entidade pode não existir ainda quando o handler dispara, por exemplo para um veículo que ainda está sendo transmitido. GetEntityFromStateBagName pode retornar 0 nesse caso, então verifique. Ler o estado novamente quando a entidade for transmitida é o hábito seguro.

A mesma função existe no servidor, onde é prática para reagir a um cliente escrevendo um valor replicado.

Sacolas de estado ou eventos

Use uma sacola de estado quando Use um evento quando
O valor descreve o estado atual de algo (trancado, algemado, em serviço) Algo aconteceu uma vez (uma compra, um golpe, um pressionamento de botão)
Jogadores que entram depois devem ver o valor Apenas jogadores presentes agora precisam saber
Muitos jogadores precisam lê-lo a qualquer momento Um jogador precisa ser informado sobre algo
Caso contrário, você consultaria em um loop Você precisa passar um resultado ou um payload único

Uma boa regra: eventos são para ações, sacolas de estado são para estado. Se um jogador que entrasse no meio do caminho precisasse ser informado da mesma coisa novamente, é estado. Veja eventos de cliente e servidor para o outro lado.

Erros comuns

  • Usando para dados grandes ou que mudam rapidamente. Cada mudança é enviada pela rede. Não escreva uma posição em uma sacola de estado a cada quadro.
  • Confiando em escritas de cliente. Valide qualquer coisa que um cliente definiu antes de agir sobre ela no servidor.
  • Esperando que o handler execute antes de a entidade existir. Verifique o identificador e leia o estado novamente quando a entidade aparecer.
  • Mutando uma tabela no local. Ler state.items, adicionar a ela e não defini-la novamente não muda nada.
  • Esquecendo a redefinição. O estado em uma entidade desaparece com a entidade, mas o estado em um jogador ou GlobalState permanece até você limpá-lo, então defina-o para nil quando terminar.
lua
Player(source).state.cuffed = nil

Checklist

Sintoma Correção
Cliente define um valor mas o servidor nunca o vê Use :set(key, value, true) para que seja replicado
Handler executa mas o identificador de entidade é 0 A entidade ainda não foi transmitida: verifique e leia o estado novamente mais tarde
Aqueles que entram tarde perdem o valor Use uma sacola de estado em vez de um evento
Mudança de tabela não sincroniza Defina a tabela inteira novamente com :set
Não pode alterar GlobalState do cliente Apenas o servidor escreve: envie um evento e deixe o servidor defini-lo
O valor antigo permanece após o trabalho estar pronto Defina a chave para nil

Respostas rápidas

O que é uma sacola de estado no FiveM?

Um armazenamento de chave e valor anexado a uma entidade, um jogador ou o servidor inteiro. Os valores que você define são sincronizados para o outro lado pelo jogo, portanto você não precisa disparar um evento para cada mudança.

Um cliente pode alterar uma sacola de estado e fazer o servidor vê-la?

Apenas se o valor for definido com replicação ativa, por exemplo LocalPlayer.state:set('key', value, true). Uma atribuição simples no cliente permanece local, e o servidor nunca deve confiar nela para nada que importe.

As sacolas de estado precisam de OneSync?

As sacolas de estado de entidade dependem de OneSync, que os servidores atuais usam por padrão. O estado do jogador e GlobalState são os casos mais fáceis para começar.

Scripts sem esse problema

Parrots as PetsCatorze aves que andam no seu ombro, voam com você e voltam quando chamadas.Ver script →Advanced BoostingBoosting de veículos pelo tablet: contratos da classe D à S+, crews e fila ao vivo.Ver script →Hookah SystemNarguilés e móveis de lounge posicionáveis, com mais de 50 sabores e efeitos.Ver script →

Continue lendo