Sé que mi configuración multijugador súper simple probablemente no sea una buena idea, pero ¿por qué?


11

Estoy haciendo un pequeño MOBA simple solo por diversión. Estaba haciendo todo para un solo jugador y luego me di cuenta "oh, mierda, probablemente debería agregar multijugador, ¿eh?"

Nunca he hecho nada con las redes antes, así que aprender a integrar Lidgren en mi juego fue divertido e increíble. La cuestión es que sé que la forma en que estoy haciendo las cosas es incorrecta, porque, por lo que sé, no es lo suficientemente robusta como para que la usen los juegos convencionales, pero ¿qué tiene de malo?

Lo que estoy haciendo es, básicamente, cada vez que un jugador realiza una acción, envía un mensaje al servidor diciendo "oye, acabo de hacer esto". El servidor y el cliente ejecutan la misma simulación. El servidor luego envía un mensaje a todos los demás clientes diciéndoles que ese tipo hizo eso.

En su mayor parte, excepto en algunos casos, cuando un jugador hace algo, el cliente asume que es genial y lo sigue por su cuenta. Entonces, cuando haces clic derecho en algún lugar para moverte allí, el cliente de ese jugador simplemente comienza a mover a su tipo allí, y luego envía un mensaje al servidor informándole al respecto.

Así que básicamente:

  • El jugador 1 lanza un hechizo para que se mueva 100% más rápido durante seis segundos
  • El cliente local del jugador 1 agrega ese beneficio a su objeto Unidad
  • El cliente del jugador 1 envía un mensaje al servidor diciendo "hey, acabo de lanzar este hechizo"
  • El servidor se asegura de que realmente tenía suficiente maná para lanzar ese hechizo, y si es así, agrega ese beneficio a la copia del servidor de ese objeto de Unidad
  • El servidor envía un mensaje a todos los demás clientes diciendo "oye, este tipo acaba de lanzar este hechizo"
  • Todos los demás clientes reciben el mensaje y dicen "ah, está bien", y agrega ese beneficio a su objeto de Unidad local para ese jugador

He estado hojeando cosas para ver cómo los grandes juegos hacen multijugador, y es un poco confuso para alguien que está comenzando a incursionar en estas cosas, pero parece que el motor de Source envía un paquete que contiene todos los cambios a todo en el mundo cada tic? Una vez más, totalmente nuevo en estas cosas, pero ¿puede realmente empujar esa cantidad de datos con tanta frecuencia?

Lo siento si esto es un poco divagante, pero básicamente, me preguntaba por qué mi sistema más simple no es el camino correcto, porque si lo fuera, otros juegos lo usarían, ¿verdad?


66
Un paso que falta es que el servidor también envía este mensaje al cliente original (no solo a todos los demás) para confirmar o negar el resultado de la simulación, el cliente de origen continúa o se adapta a la nueva realidad. Aparte de eso, este método está bien y las otras respuestas a continuación lo ayudarán a obtener una comprensión más profunda de otros aspectos.
Patrick Hughes

1
Lo sorprendente es que el resto de nosotros tenemos una esperanza razonable de que la red no sea tan difícil. Es factible
ashes999

Respuestas:


12

Además de la respuesta de Byte56, hay un par de cosas más a considerar:

¿Cómo vas a comunicarte entre los clientes sobre el movimiento de los jugadores? A diferencia de la mayoría de las acciones de otros jugadores, que tienden a ser eventos aislados y probablemente poco frecuentes, el movimiento es continuo. Existe un límite en la velocidad a la que puede (y quiere, para el caso) enviar y recibir actualizaciones. La predicción del lado del cliente que mencionó Byte56 generalmente implica actualizaciones periódicas sobre la posición y la velocidad del cliente. El cliente luego interpola localmente entre ellos, usando algo así como una Spline cúbica .

Un segundo problema, que se conecta con los anteriores, es que UDP no tiene entrega garantizada. No puede estar seguro de que cada mensaje que envía llega, o incluso llega en el orden correcto. Puede enviar paquetes 1, 2 y 3, y el servidor recibe 3, luego 1 y no 2. A menudo estarán en el orden correcto, y a menudo llegarán, pero no siempre. Por lo tanto, necesita un sistema que sea robusto para perder paquetes. Un simple sistema de confirmación es suficiente. Normalmente se usa un campo de bits que le dice al otro nodo si ha recibido los últimos 32 mensajes (para un int 32bit) y cuál fue el último mensaje recibido. De esta manera, puede etiquetar los mensajes como críticos o no, y reenviarlos si no reciben mensajes críticos. Hay una discusión bastante decente aquí .

También debe tener en cuenta, al hacer esto, que sus clientes no estarán sincronizados entre sí. Cada uno mostrará a los otros jugadores interpolando entre sus dos marcos de red anteriores mientras trabajas en el siguiente, en el mejor de los casos. Por lo tanto, necesita un sistema que tenga en cuenta (bastante) que lo que vio un jugador cuando realizó una acción no era el estado real del juego cuando realizó esa acción. Estaba reaccionando a un viejo estado de juego fuera de sincronización.

Finalmente, si este juego pretende ser competitivo, también debes preocuparte por hacer trampa. Por lo tanto, en la medida de lo posible (y razonable), debe desconfiar de los clientes y verificar que sus acciones fueron posibles. "No, no puedes atravesar esa pared. No, no puedes caminar más rápido que tu velocidad de carrera. No, no puedes decir que has alcanzado ese objetivo". etc.

Para más ideas, recomiendo navegar por los otros artículos en ese segundo enlace.

¡Buena suerte!


6

Lo que estás describiendo es esencialmente una predicción del lado del cliente , pero no dices qué sucede cuando el servidor y el cliente no están de acuerdo.

Evolucionó a partir de los días en que el cliente era solo una terminal tonta, enviando su entrada al servidor, y el servidor le dijo al cliente el resultado. Sin embargo, una vez que los juegos se movieron más allá de la LAN (y con frecuencia antes), la latencia fue notable en esta situación. Lo que estás describiendo, la predicción del lado del cliente se introdujo para solucionarlo. Ahora el cliente también simula el movimiento mientras espera que el servidor responda. Luego llegan a un acuerdo sobre el resultado. Con el servidor siendo la autoridad.

Los siguientes pasos son cómo responde a los desacuerdos. Si no tiene nada en su lugar para eso, obtendrá al cliente bandas de goma o teletransportación cuando el cliente y el servidor no estén de acuerdo.


5

Sincronización. Las otras respuestas no mencionan el momento de los eventos en el servidor y los diferentes clientes. Dependiendo del juego, esto podría ser algo a tener en cuenta. La latencia (también conocida como Lag) introduce un retraso variable entre cuando se envía un paquete y cuando se recibe. El tiempo puede ser complicado, pero intentaré explicar los posibles problemas lo mejor que pueda. Hay algunos juegos que pueden funcionar sin preocuparse por esto, pero aquí hay un ejemplo simple de dónde puede causar problemas.

Suponga que todos actúan en paquetes tan pronto como llegan.

@ Time 0 (wall time), Player 1 puts up a shield   (Message has been sent, but not received by anyone)
@ Time 1, Player 2 shoots player 1   (Message has been sent, but not received by anyone)

Suponga que el Tiempo 0 (T0) y T1 están muy juntos.

Lo que suceda a continuación depende de quién esté mirando esto y del orden en que los paquetes lleguen al servidor. El servidor siempre debe tener la última palabra. SI el servidor recibe los paquetes en el orden indicado anteriormente, entonces el servidor aplicará el escudo antes del disparo y el jugador 1 (P1) sobrevivirá. Desde la perspectiva de P1, habiendo colocado el escudo él mismo, verá el escudo antes del disparo y sobrevivirá. ¿Pero qué hay de P2? Verán el disparo de inmediato porque lo dispararon, pero ¿verán primero el escudo? Si (T0 + latency between P1 and the server + the latency between the server and P2) > T1, el escudo aparecerá después del disparo, y P2 pensará que su disparo ha matado a P1. El servidor tendrá que corregir esta situación de alguna manera.

Sin embargo, si el servidor recibe los paquetes en el orden inverso (lo cual es bastante posible, incluso si T0 <T1), entonces ocurre lo contrario. P1 está equivocado (y muerto), mientras que P2 es correcto (y victorioso).

Hay algunas maneras de lidiar con situaciones como esta, pero la más fácil es dejar que el servidor haga todo. Puede intentar simular esto en el cliente, pero no permita acciones permanentes, como la muerte. Los jugadores deberán esperar importantes confirmaciones de cambio de juego del servidor.

Enviar una marca de tiempo con acciones puede ser beneficioso. SI confía principalmente en los clientes, puede usar estas marcas de tiempo para determinar qué acción ocurrió primero, en lugar de seguir nuestra primera suposición. Esto puede ser complicado, porque recibir mensajes del pasado generalmente significa que debe poder revertir el tiempo.

El tiempo es divertido, ¿eh? No importa lo que termine haciendo, es útil estar al tanto de estos problemas de tiempo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.