¿Cómo puedo asignar ID de entidad de manera robusta en un juego de red?

17

Estoy trabajando en un sistema de entidad para un juego en red y estoy asignando a cada entidad una identificación de entero de 32 bits única que puedo usar para serializar referencias a entidades y las entidades mismas.

Actualmente solo estoy incrementando un contador cada vez que se crea una entidad. Supongo que los identificadores finalmente se agotarán, pero realmente no espero tener 4 mil millones de entidades. Además, esto evita el problema si la entidad # 5 se destruye y obtenemos una identificación de 5. ¿Está destinado a referirse al nuevo # 5 o al antiguo # 5 eliminado?

El problema es que no estoy seguro de cómo manejar / evitar colisiones. Actualmente, si un cliente recibe una actualización para una entidad con una identificación más alta que su "identificación libre" actual, simplemente supera su identificación gratuita más allá de eso. Pero eso no parece muy robusto.

Pensé en asignar rangos a cada cliente para que puedan asignar entidades sin conflictos (digamos que los n bits superiores son el número de jugador), pero me preocupa lo que sucede si los rangos comienzan a superponerse con el tiempo.

¿Hay una mejor manera de manejar esto? ¿Debería preocuparme si los identificadores se desbordan o superan el límite permitido? Podría agregar código para detectar estos casos, pero ¿qué haría si suceden además del bloqueo?

Otra opción es usar algo con una mayor probabilidad de ser único, como un GUID de 128 bits, pero eso parece realmente pesado para un juego que está tratando de minimizar el tráfico de red. Además, de manera realista, nunca necesitaría más entidades a la vez y luego encajaría en un entero de 32 bits o incluso 24 bits.

¡Gracias!

Lucas
fuente
1
¿Por qué no todos los clientes tienen las mismas entidades? ¿Los clientes no están sincronizados? ¿O es un gran mundo de algún tipo donde los clientes no todos ejecutan el mismo juego?
Philip
2
Mi arquitectura hasta ahora sigue un poco la UE3 (más información aquí ). Básicamente, los clientes solo conocen las entidades que están cerca de ellos en el mundo. Además, los clientes no se ejecutan en paso de bloqueo, pero el servidor controla la mayor parte de la lógica y puede sobrescribir los datos del cliente en cualquier momento. Supongo que ahora que lo pienso, solo puedo permitir que el servidor cree entidades y hacer que los clientes usen RPC para hacer esto. No estoy seguro del mejor enfoque. Soy programador de gráficos por día :)
Lucas
1
Creo que, como usted dice, solo debe ser manejado por el servidor si eso es factible dentro de su arquitectura dada. Luego, mantenga una pila de ID de entidad libre que exista separada de la lista / mapa de entidad, para que sepa qué ID están disponibles. Si falla un modelo de servidor autorizado, su enfoque a distancia debería funcionar bien, en términos de rangos. Cuatro mil millones es mucho, incluso para dividir entre 4000 jugadores en un MMO. Luego use el mismo enfoque para realizar un seguimiento de las ID disponibles que con una autenticación. servidor.
Ingeniero
@Lucas, su enlace dice "El servidor identifica el conjunto de actores" relevantes "para cada cliente". Esto implica que el servidor conoce todas las entidades y está en condiciones de enumerarlas.
Kylotan
1
Claro, pero qué pasa si un cliente crea una nueva entidad A pero antes de que pueda obtener el mensaje de creación, el servidor crea una nueva entidad B, a ambos se les asigna la misma identificación "libre".
Lucas

Respuestas:

13

Lo que he hecho es hacer que el servidor haga todo . El cliente (s) simplemente puede pedirle al servidor que haga algo, pero no puede hacer nada por sí mismo. En este caso, el servidor siempre será el que asigne los ID y el problema resuelto.

No he tratado con la predicción del lado del cliente mientras esperaba que el servidor aprobara acciones como: "Dispara un cohete" o "Haz una estación solar aquí". Estas acciones querrán crear entidades, y las entidades tienen ID. Hasta ahora, estoy sentado esperando a que llegue el servidor, pero creo que lo que hay que hacer es crear una entidad temporal mientras espera la aprobación del servidor. Cuando reciba la aprobación del servidor, el servidor asignará una ID y podrá actualizar o sobrescribir el objeto temporal.

Tampoco he tratado con un desbordamiento de ID, pero si el servidor tiene el control total y detecta un desbordamiento, podría hacer cualquier manejo que considere necesario (reiniciar en 0, elegir de una pila libre, bloquearse, etc.) y todo los clientes ni siquiera lo sabrán ni les importará. Los clientes solo aceptarán las ID entregadas por el servidor.

John McDonald
fuente
Gracias por toda la buena información chicos! Terminé yendo con el servidor crea el enfoque de todas las entidades, pero si encuentro que introduce demasiada latencia, intentaré el método de Trevor.
Lucas
Para identificadores específicos del cliente (necesarios para la predicción mientras espera el servidor), simplemente puede usar un prefijo en la identificación.
danijar
6

Cuando hice esto para un juego comercial multijugador, hice exactamente lo que propones: usar un entero GUID de 32 bits, donde los ocho bits superiores son el número de jugador, y los veinticuatro bits inferiores contienen un número localmente único.

Si / cuando el número local se desborda (en mi caso, casi nunca sucedería; bajo el uso normal, se necesitarían de cuatro a cinco días de tiempo de reproducción continua en una sola sesión de red para que ocurra), el propietario enviará un Mensaje "Restablecimiento de todos mis objetos" y renumerar todos los objetos aún existentes a partir de cero. El mensaje les dijo a todos los pares que descartaran los objetos que habían recibido y que los volvieran a consultar.

Un enfoque más sofisticado sería un mensaje "Objeto con GUID 'n' es ahora Objeto con GUID 'm'" para cada objeto existente. Pero en mi caso, era poco probable que ocurriera realmente, y no pensé que a la gente realmente le importaría que los objetos remotos desaparecieran del mundo durante medio segundo, después de cinco días sin parar en una sola sesión de red. ;)

Trevor Powell
fuente
Esa es una buena idea para manejar el desbordamiento. Simple, pero no lo pensé :). "Olvidar" todas sus entidades es bueno, ya que básicamente puede reutilizar la misma ruta de código que utiliza el cliente cuando se une al juego
Lucas
4

Si tus clientes pueden generar sus propias entidades, supongo que tienes un juego multijugador de igual a igual.

Si ese es el caso, probablemente no tenga demasiados clientes. Ciertamente, no más de 256. Y su identificación de entidad está garantizada para caber en 24 bits (¡16000000+ entidades son suficientes para todos!). Entonces, solo haga que el byte más alto de su identificación sea igual a la identificación del cliente:

entityId = clientId<<24 + (maxEntityIn++)

o algo.

Y si me equivoco y tiene un servidor autorizado, simplemente nunca cree nuevas entidades en los clientes.

No importa
fuente
1

Estoy usando el método 'más ingenuo' (solo incrementa un número entero para cada nueva ID) en mi juego persistente de varios jugadores y funciona bien porque no dejo que el cliente cree nuevas ID: s.

Si deja que el cliente decida (mediante el uso de una especie de técnica GUID explicada), el cliente también puede introducir varios errores al asignar una ID antigua a un nuevo elemento (eso es exactamente lo que pensé en la cabeza pensando como 5 segundos , puede haber muchas otras lagunas).

Como de costumbre, para evitar trampas , el servidor debe hacer TODA la creación y validación .

Valmond
fuente