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:
local locked = Entity(vehicle).state.lockedEscrevendo do servidor
No servidor, definir um valor o replica para os clientes que podem ver essa sacola:
-- 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:
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:
-- client
LocalPlayer.state:set('inService', true, true) -- replicated to the server
LocalPlayer.state.hasMask = true -- local onlyO 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.
-- client
local weather = GlobalState.weatherReagindo 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:
-- 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, ounilpara cada chave.bagFilterlimita a sacola, por exemplo uma sacola de jogador específica, ounilpara todas.bagNamepareceentity:1234,player:5ouglobal.GetEntityFromStateBagNametransforma uma sacola de entidade em um identificador, eGetPlayerFromStateBagNamefaz 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
GlobalStatepermanece até você limpá-lo, então defina-o paranilquando terminar.
Player(source).state.cuffed = nilChecklist
| 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 →