Como os comunicáis con servidor sockets correctamente ?

mTr

Hola querido foro, abro este post para preguntar a los usuarios de esta maravillosa comunidad, por sus técnicas y truquillos a la hora de trabajar con servidores de sockets, basados en protocolos de bytes.

Lo primero es disculparme con vosotros, por que quizás mi terminología no sea la correcta. He aprendido a programar por mi mismo, y no me ha enseñado nadie, con lo cual algunos términos puede que sean erróneos, pero intentare esforzarme en ello y ademas intentare explicarlo de otra forma mas sencilla para que nos entendamos.

Este servidor trabaja de tal forma:

-Servidor abre un puerto al que se conectan los clientes, y comienza a escuchar.
-Cuando el cliente se conecta, manda un mensaje al servidor con el protocolo Conectado y el servidor crea un nuevo proceso para el y le asigna un puerto único. Ademas, los otros clientes lo añaden a su lista de jugadores.
-Servidor crea un mensaje en el que el primer byte, señala el tipo de protocolo (en este caso, RecibirId), y tras ello añade la ID.
-Cliente recibe el mensaje, lee el primer byte y actúa según ello, en este caso, modifica su parámetro ID y enviando otro mensaje con su posición y rotación.

Esto mismo se utiliza mas tarde, por ejemplo para moverse, o para añadir nuevos jugadores conectados.

En mi caso, yo estoy trasteando con un servidor que encontré siguiendo un tutorial muy sencillo, para XNA (Si, ya se que lo han matado :qq: pero me encanta C#), quizás sirva para otros lenguajes, pero no estoy seguro xD. Os dejo el enlace al svn por si tenéis curiosidad:
https://phstudios.svn.beanstalkapp.com/samples/trunk/RelayServer/

Es bastante básico, la verdad, pero para hacer mis experimentos, me sobra! Ya que de hecho, es la primera vez que trabajo con sockets. Yo lo he estado modificando un poco a mi gusto, sobretodo para que me mostrara mas información en la consola, o para que mostrase los paquetes que envía... Pero ningún cambio importante.

Al principio todo iba bastante bien, los clientes se conectaban, se veían uno a otro, e incluso desaparecían cuando se desconectaban. Entonces me prepare para comunicar el movimiento... Y aquí llegaron los problemas. Uno de los principales problemas, creo, viene de mi sistema de movimiento. Intentare resumirlo:
El personaje se mueve con el ratón, haces click en un tile, el cliente calcula la posición y añade los waypoints o nodos conseguidos mediante A*Star, después el objeto Player se va moviendo por los waypoints hasta llegar a su destino.

En principio no hay ningún problema con el sistema de movimiento. Si, realmente el código en si es rudimentario, pero funciona. El problema viene cuando se intenta comunicar esto al servidor, y de ahí al resto de jugadores. Lo primero que intente fue lo que decía el tutorial de este servidor, crear un protocolo nuevo para cuando se moviese el jugador, enviar su posición actual. Pero esto daba resultados un poco inesperados, los jugadores dejaban de moverse antes de llegar al waypoint y cosas así, las animaciones no ocurrían o incluso saturaban el servidor por que se enviaba 100(fps) veces por segundo.

Después pensé que debía de adaptarlo para mi juego, y que lo que debía de mandar era el waypoint, y no la posición, pero por mucho que lo intentaba fallaba, con resultados como que desaparecían los jugadores, que no se calculaba bien la ruta y devolvía posiciones infinitas, o que crasheaba el cliente, así que desistí.
Mas tarde encontré lo que creía ser una solución en un proyecto que encontré por code.google, una solución bastante simple, tan simple como un timer para enviar tu posición. De hecho cuando la encontré, pensé... Por que no habré caído?, así es como funciona! Así que me dispuse a encontrar el equilibrio perfecto para que se actualizase la posición... Y como os esperáis, sin mucho éxito.

Cuando era poco tiempo(100 - 500ms), y se conectaban mas de 2 jugadores, el servidor se saturaba y crasheaba. Cuando era mucho tiempo(1s / 2s), el servidor aguantaba pero los jugadores se veían pegando saltos. El termino medio, era una mezcla de ambas, aunque me fije que a 750ms no daba tantos problemas como en los extremos. Para colmo, al usar este método, los otros jugadores conectados no podían ser animados, ya que como dije, el movimiento se basa en waypoints, y el jugador hace la animación de andar al seguir la ruta de los waypoints y mientras su velocidad sea mayor de 0.

A partir de ahí, he ido probando de muchas formas mas, pero sin buenos resultados. Como pasar la posición delta (posición - antiguaPosición), añadir un nuevo protocolo para la validación de la posición, intentar predecir el movimiento, o pasar la posición mediante las ID de los tiles en vez de coordenadas...

Así que tras un par de semanas buscando y probando formas de solucionar el problema, me decidí a escribir este post para preguntaros por las formas, métodos o truquillos que vosotros utilizáis para estos casos. No pido que me solucionéis el problema, mas bien lo que pido son consejos y otras formas con las que podría probar para solucionarlo. Quizás me he dejado algo por el camino, no lo se.

Si he de pegar algo de código, lo haré, aunque soy un poco reacio a ello ya que lo tengo hecho un desastre con tanto cambio! xD

Gracias por adelantado. Y perdonad por el tocho!

elkaoD

¿Todo esto ocurre en tiempo real o por turnos? Supongo que RT pero porsiaca.

La solución correcta es mandar el waypoint. Supongo que lo desechaste porque no lo conseguiste, pero en realidad es la forma adecuada.

Ten en cuenta que mandando el waypoint, si tu juego es RT, tienes que mandar el tiempo de inicio del movimiento junto con el waypoint para casar tiempos en el servidor. Si no haces esto vas a tener estados diferentes entre todos los clientes+server. Por ejemplo: si yo recibo 200ms después que te estás moviendo, llegarás a tu destino 200ms después de la realidad en mi PC). Si es por turnos o no afecta esa descoordinación da un poco igual.

El método actual (timers) también lo puedes usar pero es overkill. Es el método que se usa en juegos sin waypoints (p.ej. Counter Strike), pero en este juego... ¿para qué? Mucho trabajo para nada.

Ten en cuenta que tienes que hacer lo de casar tiempos como con waypoint (ver anteriores párrafos).

Además mientras tanto debes interpolar el camino para que no se vean los saltos que comentas... lo cual es un coñazo considerable, fuente de errores, cuesta más de cuadrar gamestates entre todos los PCs y más cuando te la suda en realidad donde está el muñecajo porque con el waypoint sobra.

1
mTr

Gracias, me has aclarado muchas cosas, voy a darle duro!

Edit: Se me olvido. Si, es todo en tiempo real.

r2d2rigo

Vengo y pongo unos TL;DRs a tope y me voy:

http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/
https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization
http://www.gabrielgambetta.com/?p=22

1 1 respuesta
B

Es enfocado a node pero te valdrá la teoría, http://onedayitwillmake.com/blog/2011/08/creating-realtime-multiplayer-games-using-node-js/

2
mTr

Gracias a los 2! Me espera una buena noche trasteando y empollando :D

elkaoD

#4 el de Gaffer siempre me ha parecido de lo mejor. Tiene también por ahí otros tutes, como el de timesteps, que son la bomba.

Para el que no se los haya leído, 200% recomendado.

mTr

Justo estoy ahora con ese, y es una pasada... hay un enlace sobre como lo hicieron para los AOE que esta muy interesante también. La verdad que me estoy enterando de muchas cosas. Gracias de nuevo a todos.

Usuarios habituales