El servidor y el tickrate
Un servidor se encarga de simular un entorno virtual tomando snapshots (pequeñas muestras de información) cada cierto tiempo y así poder registrar con precisión lo que sucede en la partida a cada instante. Decimos que un servidor es tickrate 100 cuando toma 100 muestras cada segundo (1 muestra cada 10 ms). Cuanto mayor sea el tickrate de un servidor mayor será la precisión en la simulación de la partida, acosta de consumir mayor ancho de banda y capacidad de proceso (CPU) en la máquina que hostea el servidor.
Tickrate 64 = 1 tick cada 15.62 ms
Tickrate 100 = 1 tick cada 10 ms
Tickrate 128 = 1 tick cada 7.8 ms
Tickrate 150 = 1 tick cada 6.7 ms
El cliente y el rate
Hasta ahora solo hemos hablado del servidor. Veamos que tienen que tener en cuenta los clientes que se conectan al mismo en función del tickrate al que se sirve la partida.
Supongamos que un cliente con un framerate estable de 100 fotogramas por segundo conecta a un servidor tickrate 100. Esto quiere decir que su máquina es capaz de producir 100 snapshots cada segundo. Para poder enviarle esa cantidad de información al servidor se requiere de un ancho de banda el cual determinaremos con el cvar rate que mide los bytes por segundo que queremos reservarle al juego a la hora de transmitir paquetes. Es importante aclarar que esta variable tan solo atañe al cliente, aunque el servidor pueda forzar el rate del cliente (sv_maxrate/sv_minrate).
Además del rate, el cliente puede definir dos parámetros más:
cl_cmdrate: cantidad de user commands (instrucciones de teclado y ratón) que el cliente sube al servidor por segundo.
cl_updaterate: cantidad de updates que el cliente demanda del servidor por segundo.
Lo más apropiado es que si el servidor es tickrate 100 y nuestra máquina es capaz de generar 100 fps, ambos cvars estén a 100. Si por el contrario nuestra máquina no fuera capaz de sustentar ese framerate lo más propio sería limitarlo en la media y ajustar tanto el cmdrate como el updaterate a esa media. Tampoco tiene ningún beneficio el subir o demandar más updates de los que el servidor puede ofrecer, así que jugar con cmdrate y updaterate superiores al tickrate del servidor es totalmente innecesario. Existe una tendencia bastante habitual a la hora de configurar el cl_cmdrate que consiste en incrementarlo una o varias unidades por encima del tickrate del servidor para corregir la posible pérdida de paquetes desde el cliente. Yo sinceramente no puedo afirmar que eso funcione porque en la documentación oficial de Valve no menciona nada al respecto. Daño no hace seguro así que si os inspira más confianza subirlo un par de unidades no os cortéis. En cuanto al cl_updaterate, como viene limitado por el tickrate del servidor, aumentarlo no tendría ningún efecto.
Es importante tener en cuenta que ambos parámetros dependen directamente del rate que tengamos definido. Tanto es así que si el rate es excesivamente bajo sufriremos de choke por no poder subir suficientes user commands al servidor o descargar el 100% de los updates que nos ofrece el servidor. Pero hablaré más sobre este tema en el siguiente apartado.
Nota: el cl_cmdrate puede también limitarse por el servidor (sv_maxcmdrate). El cl_updaterate no pero tiene su lógica
¿para qué iba a limitar un servidor la cantidad de updates que recibe el cliente más allá del tickrate preestablecido? Precisamente cuando creamos un servidor tickrate 64, 100 o 128 estamos limitando la cantidad de updates para cada cliente.
Servidor y cliente trabajando en conjunto
Probablemente ahora os estaréis preguntando qué rate es el ideal para poder jugar en buenas condiciones. Este apartado es fundamental e involucra tanto al servidor como al cliente. Para poder explicarlo primero hay que tirar de un poco de teoría.
Counter Strike: Global Offensive tiene un parámetro definido por el servidor (net_maxroutable) que determina cual es el tamaño máximo en bytes de cada paquete de información que se envía y se recibe en las comunicaciones cliente-servidor. El estándar está definido en 1200 bytes por paquete (en el source son 1260). ¿Qué quiere decir esto? Pues que dependiendo de nuestro cmdrate/updaterate necesitaremos enviar y recibir más o menos bytes por segundo:
- En un servidor tickrate 64 necesitaríamos 1200 * 64 = 76800 bytes. De ahí que los servidores de Valve tengan un rate por defecto de 80.000 bytes
- En un servidor tickrate 100, 1200*100 = 120000 bytes de rate.
- En un servidor tickrate 128*1200 = 153600 bytes de rate.
Esto es lo que dice la teoría. En la práctica el ancho de banda se optimiza muchísimo gracias a lo que se conoce como delta compression, la cual consiste en lo siguiente: el servidor no envía un snapshot completo por cada tick sino que tan solo envía los cambios que se han producido desde el último full-snapshot que se envió a cada cliente. Normalmente los full-snapshots se envían solo al inicio de cada ronda o cuando algún cliente sufre de packet loss intenso. Seguro que más de uno por aquí recordará los típicos subidones de choke que pegaban algunos servers públicos al iniciar las rondas; eso sucedía precisamente porque en ese instante el servidor trata de enviar full snapshots a todos los clientes y por algún motivo el ancho de banda es insuficiente, ya sea porque el hosting tiene una restricción de upload baja para la cantidad de clientes que tiene que soportar o porque los clientes tienen sus rates mal configurados y no perciben toda la información que el servidor necesita mandarles.
En definitva: el rate recomendado por Valve siguiendo la teoría expuesta anteriormente está muy por encima del consumo real medio que se hace gracias a la compresión delta, por lo que generalmente podríamos jugar con un rate inferior al sugerido. Ahora, yo recomiendo que todo el mundo empiece a alejarse ya de rates por debajo de los 80000 bytes en servidores tickrate 100 o 128. Y espero que esta información le llegue a unos cuantos server admins porque es bastante triste ver servidores limitados a un sv_maxrate de 30000 bytes o incluso menos.
Interpolación: cl_interp, cl_interp_ratio y lerp
La interpolación es un tema que a muchos nos trae de cabeza pero lo cierto es que es mucho más sencillo de lo que puede parecer.
La interpolación, definida de manera sencilla, consiste en generar uno o varios frames falsos a partir de uno anterior y otro posterior, de forma que conseguimos una animación fluída aunque no sea 100% representativa de la realidad. En un entorno virtual que funcionase casi en tiempo real (como una red LAN) la interpolación no es realmente necesaria ya que la probabilidad de que un cliente pierda algún paquete es ínfima. En cambio en entornos WAN (internet) la pérdida de paquetes se produce con relativa facilidad, especialmente en aquellas personas que juegan con wifi o con PCs que no pueden lidiar con el framerate requerido por el servidor, ya sea por insuficiencia de hardware o de ancho de banda. En esos casos la interpolación es un buen aliado.
El lerp, valor que podemos mostrar haciendo uso del net_graph 1, nos indica nuestra latencia de interpolación en milisegundos. En otras palabras: si tenemos un lerp de 10 ms en un servidor tickrate 100 significa que tenemos 1 frame extra para poder interpolar en caso de que haya pérdida de paquetes. Si tuviéramos 20 ms tendríamos 2 frames.
En cuanto a cómo configurar la interpolación, tan solo tenemos que tener en cuenta lo siguiente: el cl_interp lo dejamos a 0 y este se regulará en función del cl_interp_ratio y nuestro cl_updaterate, haciendo una división del primero entre el segundo; me explicaré con varios ejemplos:
- Situación A: server tickrate 100 con cl_interp_ratio 1 y cl_updaterate 100. El lerp lo calcularíamos de la siguiente forma -> 1/100 = 0.01 segundos = 10 ms = 1 frame adicional para interpolar. Es, si no me equivoco, la interpolación más baja que podemos configurar. Esta configuración es la recomendada cuando nuestra conexión es buena y el servidor funciona correctamente.
- Situación B: server tickrate 100 con cl_interp_ratio 2 y cl_updaterate 100. El lerp sería -> 2/100 = 0.02 segundos = 20 ms = 2 frames adicionales para interpolar.
Cuando el lerp está de color anaranjado significa que, en caso de pérdida de paquetes de algún cliente corremos el riesgo de perder frames y ver a la gente a saltos.
En resumen:
- cl_interp 0 // cl_interp_ratio 1: para conexiones/servidores decentes.
- cl_interp 0 // cl_interp_ratio 2: para conexiones/servidores poco eficientes.
El Netgraph
Es curioso que aunque somos muchos los que usamos el net_graph 1 a diario, pocos saben interpretar los distintos valores que se muestran en el mismo. Con la siguiente explicación voy a tratar de aparcar todas las dudas que podáis tener.
La captura que adjunto a continuación se ha realizado desde un cliente conectado a un servidor dedicado tickrate 128 con la siguiente configuración:
- fps_max 61
- cl_cmdrate 128
- cl_updaterate 128
- rate 80000
Después de todo lo que habéis leído hasta ahora pensaréis que es absurdo forzar el cliente a 61 fps si es capaz de lidiar un framerate superior. Lo hago simplemente en beneficio del ejemplo que explico a continuación.
A) FPS: indica la cantidad de fotogramas por segundo que se están renderizando en el cliente.
B) PING: tiempo en milisegundos que tarda un paquete enviado desde el cliente al servidor en volver de nuevo al cliente (round trip time, RTT).
C) IN: todo lo que se encuentra en esta fila, a excepción del lerp, hace referencia a la información que entra (IN) en el cliente; en otras palabras, lo que el cliente recibe del servidor.
D) OUT: todo lo que se encuentra en esta fila hace referencia a la información que sale (OUT) del cliente; en otras palabras, lo que cliente envía al servidor.
E) Tamaño en bytes de cada paquete que se recibe del servidor. Recordemos que el parámetro net_maxroutable definía que como máximo los paquetes podían ser de 1200 bytes. Aquí podemos comprobar que, gracias a la compresión delta, el tamaño de cada paquete es muy inferior a 1200 bytes.
F) Tamaño en bytes de cada paquete que el cliente envía al servidor.
G) Consumo medio de ancho de banda de descarga en kilobytes/s.
H) Consumo medio de ancho de banda de subida en kilobytes/s.
I) cl_updaterate del cliente.
J) cl_cmdrate del cliente.
K) Media de updates que se reciben del servidor por segundo.
L) Media de client command updates que el cliente envía al servidor por segundo. Como veréis, a pesar de tener el cl_cmdrate a 128 en la configuración de nuestro cliente, tan solo se están enviando 60. La razón es bien sencilla: el cliente tan solo está renderizando 60 frames por segundo (fps_max 61) y por lo tanto no puede subir más información que la que su máquina renderiza.
M) Lerp: latencia de interpolación del cliente en milisegundos.
Como ya expliqué en el apartado Servidor y cliente trabajando en conjunto, cada update que enviamos y recibimos del servidor consume una cantidad determinada de bytes. Si nos fijamos en los valores de la captura del netgraph anterior veremos que en el instante que se tomó la captura, el tamaño de los paquetes que estábamos enviando al servidor (F) era de 78 bytes. Si multiplicamos 78 por L deberíamos obtener una cifra muy aproximada a H. Hagamos la comprobación:
78 bytes * 60 = 4680 bytes; 4680 bytes / 1024 = 4,57 Kilobytes
Como veréis en el netgraph nos marca 4,59 Kilobytes. Ese desajuste de 2 centésimas es por estar tratando con medias y redondeos.
Por último destacar también que podemos deducir el tickrate del servidor a partir de los valores máximos de I y J permitidos por el servidor. En cualquier caso, si tenéis dudas podéis poner el net_graph 4 y comprobar el tick directamente.
Conclusión
Quizá la principal razón por la que en muchas ocasiones las balas no registran correctamente es por problemas de configuración tanto en cliente como en servidor. En un servidor con tickrate 100, un cliente que tan solo sube 30 command updates por segundo (cl_cmdrate 30) dificultará el registro de hits ya que el 70% de los frames serán interpolaciones, lo cual reduce la precisión notablemente. Para evitar este tipo de irregularidades y conseguir que el servidor sea equitativo con todos los clientes quizá lo más recomendable sea forzar desde el servidor tanto el rate como el cmdrate de todos los clientes a una cifra común. El rate deberá ser lo suficientemente elevado para satisfacer la demanda del tickrate del servidor.
RPV
Sabe dios que muchos no leeréis todo lo expuesto anteriormente así que aquí simplemente daré las recomendaciones pertinentes para configurar clientes y servidores de 10 slots, aunque yo os recomiendo toda la lectura para que entendáis lo que estáis poniendo. Los valores expuestos a continuación serán solo válidos en condiciones óptimas tanto de servidor como de los clientes conectados al mismo (latencias, fps, capacidad de proceso del servidor y anchos de banda). El server admin y el cliente deberán de configurar lo que se ajuste a sus necesidades, haciendo uso del netgraph como herramienta de benchmarking.
CVARS
Servidor tickrate 64
servidor:
- sv_maxrate 80000
- sv_minrate 80000
- sv_maxcmdrate 64
- sv_mincmdrate 64
cliente:
- rate 80000
- cl_cmdrate 64
- cl_updaterate 64
Servidor tickrate 100
servidor:
- sv_maxrate 120000
- sv_minrate 120000
- sv_maxcmdrate 100
- sv_mincmdrate 100
cliente:
- rate 120000
- cl_cmdrate 100
- cl_updaterate 100
Servidor tickrate 128
servidor:
- sv_maxrate 153600
- sv_minrate 153600
- sv_maxcmdrate 128
- sv_mincmdrate 128
cliente:
- rate 153600
- cl_cmdrate 128
- cl_updaterate 128
Interpolación:
- cl_inter 0 // cl_interp_ratio 1: para conexiones/servidores decentes.
- cl_interp 0 // cl_interp_ratio 2: para conexiones/servidores poco eficientes.
Nota: Cuando se fuerzan los valores rate y cmdrate desde el servidor, el cliente solo tiene control sobre el updaterate.
Fuente: mediavida