+0

Qué son los Runnables y cómo funciona el Bukkit Scheduler



Vamos a tocar un tema un poco más complejo. Aprenderemos que es el Bukkit Scheduler, y los Runnables.

Correr código de manera paralela

Hasta ahora nuestro código ha corrido en un único hilo. ¿Qué significa esto? Que si realizamos una acción de larga duración, como puede ser un contador, nuestro servidor se quedará colgado. Para ello, necesitamos correr código de forma paralela.

Runnable

Un Runnable es un objeto de Java que contiene un bloque de código que puede ser ejecutado en cualquier momento, ya sea desde el mismo hilo u otro thread. Nos ayudará a correr tareas de manera paralela.

Para crear un Runnable usaremos los paréntesis, seguido de una flecha, y luego el bloque de código.

Runnable runnable = () -> {  
    // Bloque de código  
};

Este fenómeno también es conocido como una función anónima, o una función lambda.

¡Ojo! Hemos de tener en cuenta que las variables pueden cambiar en un futuro, por lo tanto, las variables que usemos dentro del bloque de código sean finales, o no cambien una vez asignadas.

Bukkit Scheduler

El BukkitScheduler es una clase de ayuda que se encarga de ejecutar código paralelamente, para no bloquear el hilo principal. Este viene integrado dentro de Spigot, con lo cual es seguro de usar, y no bloqueará el servidor de Minecraft.

Podemos acceder al BukkitScheduler desde un método estático de la clase Bukkit llamado getScheduler (Bukkit.getScheduler()).

Para usarlo, hemos de crear lo que se denomina como "tarea bukkit" o BukkitTask. Hay dos tipos de tareas:

  • Síncronas: corren en el mismo hilo que el servidor de Minecraft. Sirven para poder interactuar con el juego, pero si realizamos una tarea larga bloqueará el servidor
  • Asíncronas: corren en un hilo diferente al del servidor de Minecraft. No se pueden usar para interactuar con cosas internas del servidor, pero son útiles para hacer tareas largas, como llamadas a bases de datos.

Hay tres tipos de operaciones en el Scheduler:

  • Correr una tarea al momento (runTask o runTaskAsynchronously)
  • Hacer que una tarea se ejecute más tarde (runTaskLater o runTaskLaterAsynchronously)
  • Hacer que sea una tarea que se repita cada cierto tiempo (runTaskTimer o runTaskTimerAsynchronously)

Para indicar tiempos sobre el retraso o la repetición, usaremos la medida de ticks, que básicamente son las veces que se actualiza el servidor cada segundo. Para que nos entendamos, 20 ticks equivalen a 1 segundo en la vida real.

La última cosa a tener en cuenta es que necesitaremos una instancia de nuestro plugin, en este caso la clase que extiende JavaPlugin. Para ello necesitaremos volver a nuestra clase principal y crear una variable que sea estática del tipo de nuestra clase principal, asignarla al iniciar el servidor (en el método onEnable) y luego un método que recupere esa variable estática.

Crear una cuenta atrás

De momento no he hecho más que pegar el rollazo, pero ahora vamos a verlo de manera práctica creando una cuenta atrás.

Para empezar, crearé un comando para realizar la cuenta atrás. Haremos una cuenta atrás que empiece de 5, baja a 4, 3, 2 hasta 1. Si nos ponemos a pensar cómo realizarlo, necesitaremos un bucle que empiece en 5 y termine en 1, y dentro de ese bucle llamar a nuestro scheduler para que corra una tarea más tarde que envíe un mensaje al chat a los jugadores sobre la cuenta atrás.

long ticksTotales = 5*20;  
  
for (int i = 5; i > 0; i--) {  
    // Necesario porque i cambiará cuando la tarea se ejecute en un futuro.  
    int numero = i;  
      
    Bukkit.getScheduler().runTaskLater(CursoSpigot.getInstance(), () -> {
	    Bukkit.broadcast(Component.text("Cuenta atrás: " + numero));  
    }, ticksTotales-(i*5L));  
}