Cacharreando Jobs


Este asunto de los Jobs requería un poco de estudio, así que acudí a San Google para orientarme al respecto y me bajé un tutorial de Youtube. Resulta que estaba dando palos de ciego, como suele suceder cuando uno se mete en cosas sin estudiar de antemano todos los elementos implicados.
Comienzo con respuesta a mi duda: los Jobs no son hilos. En realidad, son operaciones (o kernels) que se ejecutan en hilos de trabajo. Aparentemente, no son una solución mágica para todo, su verdadero valor se revela cuando necesitas descargar operaciones pesadas del hilo principal, para que éste haga otras cosas. Es recomendable realizar pruebas de rendimiento para ver si en verdad, convertir algo en Job es más rentable que hacerlo en tu Update(), a la manera tradicional.
Existen un montón de tipos diferentes de Jobs. Para mí ahora solo son importantes dos: el normal y el paralelo (IJob/IJobParallelFor). El primero ejecuta una operación, el segundo, trabaja sobre un arreglo, ejecutando una operación en paralelo sobre cada elemento del mismo. O sea, podemos crear un IJobParallelFor que tome un arreglo de conexiones de clientes y envíe o lea datos de cada una de ellas, en paralelo, o hasta donde los permitan los  worker threads de Unity, que supongo dependan de los núcleos disponibles en el CPU.
De los componentes del famoso Data Oriented Technology Stack, quizás los Jobs sean los más fáciles de comprender, aunque no carecen de detalles conflictivos. Estamos hablando de código que se ejecuta concurrentemente, con posibilidades de causar todo tipo de desastres si escribimos en un mismo lugar desde dos operaciones diferentes. Hay margen de sobra para meter la pata, causar race conditions y jodernos la vida con facilidad. Veamos un ejemplo, a modo de mini tutorial:

struct Prueba: IJob
{
  public int ttt;
 
  public void Execute()
  {
     /*  Hacer algo muy complicado con ttt */
  }
}

public class LoQueSea: MonoBehaviour
{
  private JobHandle handle;

  void Update()
  {
    int t;
    var job = new Prueba() {
      ttt = t
    }
    //programar su ejecucion
    handle= job.Schedule(handle);
    /* Hacer otras cosas */
    /* Importante!! Aqui no podemos modificar las variables que el job esta usando */
    handle.Complete(); //completamos el Job
   
  }
}

Sin embargo, si creen que usar Jobs aumenta el rendimiento, esperen a combinarlos con el Burst Compiler. El resultado me hubiera hecho caerme de culo de no haber estado sentado. Basta con agregar el atributo [BurstCompile]:

[BurstCompile]
struct Prueba: IJob


Como ven, nada que un programador no pueda entender con un tutorial básico y una hora de estudio. Usarlo adecuadamente ya es otra cosa.
Para concluir, les recuerdo que pueden comprar la novela en Amazon.  Arriba, que no he logrado una venta este mes y así no podré comprarme el yate.

Cacharreando Transport 2

Ante todo, les recuerdo que mi primera novela está disponible en Amazon (desde hace años, y también la segunda), en digital y físico, incluyendo Kindle Unlimited. Los ingresos serán utilizados para financiar el desarrollo de un RPG, del cual he hablado muchísimo durante los últimos años. Considerada una de las diez mejores novelas cubanas de fantasía, me han dicho que no está tan mala. No dejen de comprarlo, o sugerir a sus amigos lectores que lo hagan. Pueden tomarlo como una especie de campaña de crowdfunding.
Entrando en el tema de hoy, al fin he conseguido un progreso apreciable en mis pruebas de multijugador. Ayer, luego de lidiar durante unos días con errores derivados de los Jobs y cosas así, logré corregir el último problema y enviar un paquete complejo con las coordenadas de un click al servidor. Aún me falta por validar si los valores interpretados en el servidor son correctos, pero no me alcanzó el tiempo para eso, pues también tenía que escribir. Supongo que algunos dirán que el avance no es tan significativo, pero si con el país paralizado, nuestro gobierno dice que creceremos, no veo por qué yo no puedo considerar esto como un gran salto para la humanidad gamer.
Queda por delante reorganziar el servidor para lidiar con múltiples clientes, beneficiándose al mismo tiempo del sistema de Jobs de Unity. Y ya que mencionamos el tema, resulta que todos estos días lo he estado considerando como un sistema de programación multihilos, pero ahora mismo no me queda muy claro. El caso es que los Jobs de Unity se inician y se concluyen con Schedule y Complete. Necesitas hacer un Complete para detenerlos y poder asignarle nuevos valores a sus variables, luego de lo cual puedes volver a echarlos a andar. Si alguien me aclara algo en este asunto le estaría agradecido. La etapa siguiente sería pasar a Netcode, que es el API de alto nvel que saldrá en algún momento de este año.
Y como tema bonus de hoy, fuera de programa, les hablaré de otro problema que me estuvo atormentando durante días. Ni en el foro oficial, ni en reddit logré encontrar la solución, que vino a mí el sábado mientras le mostraba el proyecto al resto del equipo. El lío en cuestión era que los árboles solo se veían correctamente en el centro y borde inferior de la pantalla, el resto de los árboles en el área visible se veía borroso y estático. Suponía que algún parámetro de calidad era el culpable, esto, pero no lo encontraba ni en la cámara, ni en la definición del árbol, ni en las opciones del terreno. Hasta el sábado. El responsable sí estaba en las opciones del terreno, y se trataba de la distancia a la cual los árboles son sustituidos por billboards, los cuales no se animan y se ven horribles. Incrementar el valor resolvió el asunto, y ahora todos los árboles visibles se muestran correctamente y se animan.

Cacharreando Transport

Luego de varios días de estudio y pruebas con Unity Transport, puedo decir que estoy pasando de la fase "No sé nada", a "Ahora sé mucho menos". A eso, en programación, se le llama progreso.
Como había mencionado anteriormente, Unity Transport es una API de redes de muy bajo nivel. Mis experiencias con juegos multijugador son casi nulas, así que no puedo hablar acerca de las diferencias entre una API de bajo nivel y una de alto nivel. De tanto leer por ahí, creo que una de alto nivel debería ofrecer cosas como compresión y predicción, entre otras. Y volviendo a lo mencionado anteriormente, esta nueva API de alto nivel se llama Netcode, y está al caer, pero podemos llevarnos una idea de cómo será si miramos dentro del FPS Sample. 
En conclusión, ¿qué he logrado hacer? Pues bastante poco: conectar el cliente al servidor y enviar números enteros en paquetes separados. El próximo paso es enviar paquetes de datos más complejos, compuestos por diferentes valores, como tres floats (un vector), cadenas, etc.
Técnicamente, Unity Transport no es tan complejo de usar, debido principalmente a que es muy simple. Una vez que logras rastrear los principios básicos dentro de los ejemplos, puedes implementar el envío de paquetes. Lo complicado es armar todo un protocolo a partir de ahí. Ya que hablo de ejemplos, olviden por completo los que están a la vista. Los que de verdad ayudan son los que vienen incluidos en el repo, junto con el código del paquete.

La Guardia de Mundodisco llegará a la TV

Traída por la BBC y Narrativia, esta serie estará basada en los libros de la Guardia de la Ciudad de Ankh-Morpork. El cast también trae sorpresas muy buenas, como Richard Dormer (lo recordarán de Game of Thrones) en el papel de Sam Vimes.


Una elección que me parece excelente. Sin embargo, Lara Rossi no me da la Lady Sibyll de los libros: una solterona grande y gorda.

Juegos conectados con Unity: explicando la situación actual

Hace unos días un amigo me hizo una propuesta de trabajar en un juego multijugador. Yo mismo había estado dándole vueltas a la idea de echarle un vistazo a este asunto, o sea, una masturbación mental en toda regla, y con las dos manos. La propuesta acabó por decidirme a estudiar el tema en serio.
¿Qué podía salir mal? Unity es un motor maduro, con soporte de red desde hace tiempo, con todo lo que debe llevar y esas cosas. Para mi decepción, en este momento solo hay una palabra para definir el estado de la API de conectividad en Unity: cagazón. O mejor dicho, dos palabras: gran cagazón. Vayamos por partes y empecemos con un poco de historia.
En un principio fue Unet. Y vieron los usuarios que Unet era una cagazón que no sería para nada, así que se inventaron Mirror, Photon y otras muchas soluciones que solucionaban, y de paso, le permitían a los desarrolladores alimentar a su familia (y por familia me refiero a cualquier combinacion posible de personas de ambos sexos, animales incluidos, para que no se me ofenda ningún susceptible). Y como ya esto daba un poquito de vergüenza, en Unity decidieron ponerse las pilas y darle la patada a Unet, reemplazándola con una API más joven, más bonita y más potente.
Hasta ahí y en papeles, todo bien. Pero el caso es que la patada a Unet fue demasiado rápida, la declararon obsoleta en el 2018.x, dejando el 2019.x con... nada. En el 2019 solo nos queda Photon Bolt, sin soporte para LAN (hay que pasar por caja y pagar su servicio en la nube), Forge (lo mismo), o fajarnos con Unity Transport Package, que es experimental y de muy bajo nivel. Para el tercer trimestre saldrá la famosa API más bonita y potente, llamada Netcode, también experimental.
Déjenme que les cuente algo sobre las funciones "experimentales" en Unity. Es como un ciego tirándole piedras a un gorrión. Las cosas pueden funcionar o no, o simplemente cambiar de un día para otro. Por algo son experimentales, ¿no? Y ahora les diré algo sobre los trimestres de Unity: son como los plazos que da ETECSA para cumplir sus planes. O sea, que el tercer trimestre es muy largo y Netcode podría presentarse en sociedad a finales de septiembre. O a principios de octubre. O algo así. La respuesta de Unity es que vayan resolviendo con UTP o Photon Bolt.  
Yo, por suerte, no tengo apuro. Voy a sentarme a esperar a Netcode.