Bolsas de estado de FiveM: Entity(entity).state, GlobalState y manejadores

Cómo funcionan las bolsas de estado de FiveM: Entity(entity).state, Player(source).state, LocalPlayer.state, GlobalState, :set, manejadores de cambios, y cuándo preferirlas a los eventos

Quieres compartir un pequeño dato entre el servidor y cada cliente, por ejemplo que un vehículo está bloqueado, que un jugador está esposado, o el clima actual, y sigues escribiendo eventos que se disparan en cada cambio y se dessincronizan para los jugadores que se unen después. Las bolsas de estado son la respuesta integrada.

Este artículo cubre los tipos de bolsas de estado, cómo escribir y leer, cómo reaccionar a cambios, y cuándo un evento sigue siendo la mejor opción.

¿Qué es una bolsa de estado?

Una bolsa de estado es un almacén tipo tabla de claves y valores adjunto a algo. El tiempo de ejecución lo sincroniza por ti, incluso para los jugadores que se conectan después de que se estableció el valor. FiveM te da tres tipos:

Bolsa Lee y escribe con Vive en
Una entidad Entity(entity).state La entidad (ped, vehículo, objeto)
Un jugador Player(source).state en el servidor, LocalPlayer.state en el cliente El jugador
El servidor GlobalState Todo el servidor

En todos ellos lees un valor como un campo normal:

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

Escribiendo desde el servidor

En el servidor, establecer un valor lo replica a los clientes que pueden ver esa bolsa:

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'

Puedes usar el estilo de campo o la llamada explícita, que también te permite elegir si el valor se replica:

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

:set(key, value, replicated) toma la clave, el valor y un booleano. Con true el valor se envía al otro lado, con false se queda en el lado que lo escribió.

Consejo: los valores pueden ser números, cadenas, booleanos y tablas. Una tabla se copia cuando la estableces, por lo que cambiar un campo en la tabla que lees no hace nada. Establece la tabla completa nuevamente para actualizarla.

Escribiendo desde el cliente

Un cliente puede escribir en su propio jugador y en entidades que controla, pero una asignación simple permanece local:

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

El servidor puede leer Player(source).state.inService después de eso. Trátalo como no confiable: un cliente modificado puede escribir cualquier valor que quiera. Usa estado escrito por cliente por conveniencia, como indicadores de interfaz de usuario, y mantén cualquier cosa con una ventaja adjunta (dinero, trabajo, permisos) en el servidor.

GlobalState es lo opuesto: el servidor lo escribe, cada cliente lo lee, y los clientes no pueden cambiarlo para otros.

lua
-- client
local weather = GlobalState.weather

Reaccionando a cambios

En lugar de sondear un valor en un bucle, registra un manejador que se ejecute cuando cambie una clave. Esta es la razón principal para usar bolsas de estado en el 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 es la clave que te importa, o nil para cada clave.
  • bagFilter limita la bolsa, por ejemplo una bolsa de jugador específica, o nil para todas.
  • bagName se parece a entity:1234, player:5 o global. GetEntityFromStateBagName convierte una bolsa de entidad en un identificador, y GetPlayerFromStateBagName hace lo mismo para una bolsa de jugador.

En el cliente, la entidad puede no existir aún cuando se dispara el manejador, por ejemplo para un vehículo que aún se está transmitiendo. GetEntityFromStateBagName puede devolver 0 en ese caso, así que verifica si lo hace. Leer el estado nuevamente cuando la entidad se transmite es el hábito seguro.

La misma función existe en el servidor, donde es útil para reaccionar a un cliente que escribe un valor replicado.

Bolsas de estado o eventos

Usa una bolsa de estado cuando Usa un evento cuando
El valor describe el estado actual de algo (bloqueado, esposado, de servicio) Algo sucedió una vez (una compra, un golpe, una pulsación de botón)
Los jugadores que se unen después deben ver el valor Solo los jugadores presentes ahora necesitan saber
Muchos jugadores necesitan leerlo en cualquier momento Un jugador necesita que se le diga algo
De lo contrario, sondarías en un bucle Necesitas pasar un resultado o una carga útil única

Una buena regla: los eventos son para acciones, las bolsas de estado son para estado. Si un jugador que se une a mitad de camino necesitaría que se le dijera lo mismo nuevamente, es estado. Ver eventos del cliente y el servidor para el otro lado.

Errores comunes

  • Usarlo para datos grandes o que cambian rápidamente. Cada cambio se envía a través de la red. No escribas una posición en una bolsa de estado cada fotograma.
  • Confiar en las escrituras del cliente. Valida cualquier cosa que un cliente establezca antes de actuar en ella en el servidor.
  • Esperar que el manejador se ejecute antes de que exista la entidad. Verifica el identificador y lee el estado nuevamente cuando aparezca la entidad.
  • Mutar una tabla en su lugar. Leer state.items, agregarle y no establecerlo nuevamente no cambia nada.
  • Olvidar el reinicio. El estado en una entidad desaparece con la entidad, pero el estado en un jugador o GlobalState se queda hasta que lo limpies, así que establécelo en nil cuando hayas terminado.
lua
Player(source).state.cuffed = nil

Lista de verificación

Síntoma Solución
El cliente establece un valor pero el servidor nunca lo ve Usa :set(key, value, true) para que se replique
El manejador se ejecuta pero el identificador de la entidad es 0 La entidad aún no se ha transmitido: verifica y lee el estado nuevamente más tarde
Los recién llegados se pierden el valor Usa una bolsa de estado en lugar de un evento
El cambio de tabla no se sincroniza Establece la tabla completa nuevamente con :set
No se puede cambiar GlobalState desde el cliente Solo el servidor la escribe: envía un evento y deja que el servidor la establezca
El valor antiguo permanece después de que el trabajo esté terminado Establece la clave en nil

Respuestas rápidas

¿Qué es una bolsa de estado en FiveM?

Un almacén de clave y valor adjunto a una entidad, un jugador o todo el servidor. Los valores que estableces se sincronizan al otro lado por el juego, por lo que no necesitas disparar un evento para cada cambio.

¿Puede un cliente cambiar una bolsa de estado y que el servidor la vea?

Solo si el valor se establece con replicación activada, por ejemplo LocalPlayer.state:set('key', value, true). Una asignación simple en el cliente permanece local, y el servidor nunca debería confiar en ella para nada que importe.

¿Las bolsas de estado necesitan OneSync?

Las bolsas de estado de entidad dependen de OneSync, que los servidores actuales utilizan por defecto. El estado del jugador y GlobalState son los casos más fáciles para comenzar.

Scripts que evitan este problema

Parrots as PetsCatorce pájaros que van en tu hombro, vuelan contigo y vuelven cuando los llamas.Ver script →Advanced BoostingBoosting de vehículos desde una tablet: contratos de clase D a S+, crews y cola en vivo.Ver script →Hookah SystemCachimbas y muebles de lounge colocables, con más de 50 sabores y efectos.Ver script →

Sigue leyendo