API
Leer los eventos configurados y los que están corriendo, arrancar y parar uno, y leer las estadísticas de jugadores y clanes.
CaptureService es por donde otro plugin lee y maneja ExyliaCapture: los eventos que configuró un
administrador, los que están corriendo ahora mismo, arrancarlos y pararlos, y las estadísticas que
dejan atrás.
ExyliaAPI.get(CaptureService.class).ifPresent(capture ->
capture.activeEvents().forEach(event ->
getLogger().info(event.displayName() + " has " + event.participants() + " players")));El artefacto, el repositorio y la línea del plugin.yml son los mismos para todos los plugins de
Exylia y están en la página de la API pública.
En este plugin un "evento" es un modo de juego que se está jugando — un KOTH, una conquista, un
payload —, no algo para lo que registres un listener. CaptureEvent es un record común que describe
una partida de uno de esos modos. Los tres eventos de Bukkit que el plugin sí publica están en
Eventos del ciclo de vida, y llevan una instantánea CaptureEvent.
Una config es un evento que montó un administrador; una partida es una ocurrencia suya. Existe
como mucho una partida de cada config a la vez, y la partida lleva el id de su config: por eso
start(String), stop(String) y event(String) toman la misma cadena, y una config se puede volver
a arrancar en cuanto su partida terminó.
Eventos configurados
| Método | Qué hace |
|---|---|
config(String configId) | Una config como Optional<CaptureConfig>. Vacío cuando ninguna config tiene ese id. |
configs() | Todas las configs de evento, habilitadas o no. |
startableConfigs() | Las configs que se podrían arrancar ahora mismo: habilitadas, completas y sin partida en curso. |
eventTypes() | Todos los tipos de evento que el plugin sabe correr, como Set<String> de ids de tipo. |
Una config a la que le falta su zona queda fuera de startableConfigs() pero sigue apareciendo en
configs(), para que un menú de administración pueda mostrarla como incompleta en vez de esconderla.
CaptureConfig.type() es un String porque los tipos son un registro con el que se puede extender el
plugin: KOTH, conquista, payload y el resto son lo que viene de fábrica, no lo que es posible, y un
modo registrado por otro plugin también aparece ahí. Compara un tipo contra eventTypes() y no contra
una constante tuya.
Eventos en curso
| Método | Qué hace |
|---|---|
event(String eventId) | Un evento en curso como Optional<CaptureEvent>. Vacío cuando no hay nada corriendo con ese id. |
activeEvents() | Todos los eventos que están corriendo ahora mismo. Vacío cuando no hay ninguno. |
isRunning(String configId) | Si esa config tiene una partida en curso. |
eventOf(UUID player) | El evento en el que participa un jugador, como Optional<CaptureEvent>. Vacío cuando no participa en ninguno. |
participants(String eventId) | Todos los que participan, como List<UUID>. Vacío cuando no hay nada corriendo con ese id. |
points(String eventId, UUID player) | Lo que lleva puntuado un jugador. 0 cuando el evento no está corriendo o no puntúa por puntos. |
scores(String eventId) | La puntuación de todos, como Map<UUID, Integer>. Vacío en un modo que no puntúa por puntos. |
Un jugador cuenta como participante desde el primer momento en que pisa una zona, y sigue contando
hasta que el evento termina: por eso eventOf responde también por alguien que ya se fue caminando,
que es lo que necesita una recompensa o un scoreboard. scores es una foto de los marcadores, así que
se puede ordenar y dibujar sin que el siguiente tick la cambie por debajo.
Acciones
| Método | Qué hace |
|---|---|
start(String configId) | Arranca una partida de una config. Devuelve el id de la partida nueva, o vacío cuando no pudo arrancar. |
stop(String eventId) | Termina una partida antes de tiempo. true cuando había algo corriendo con ese id. |
start se niega cuando la config está deshabilitada, incompleta o ya corriendo, y lo dice en el log
del plugin en vez de lanzar: una automatización que arranca eventos por horario no tendría que atrapar
nada.
stop termina la partida con el motivo STOPPED y sin pasar ganador. Lo que pasa después es cosa
del modo, igual que cuando se le acaba el reloj: KOTH Points, KOTH Capture Points, Destroy The Core y
Conquest se resuelven con las puntuaciones que haya, anuncian el podio y pagan a los tres primeros;
KOTH y Payload terminan sin ganador; un Bounty acredita y paga a su objetivo como
superviviente.
Menús
| Método | Qué hace |
|---|---|
void openMenu(Player) | Abre a un jugador el menú de capturas, el mismo que abre /capture. |
La pantalla que quiere un NPC de lobby o un ítem de la hotbar: lo que está en vivo, lo que está programado y cuándo, dibujado con los propios archivos de menú del servidor. Llámalo desde el hilo dueño del jugador, como ya lo es un handler de interacción.
Eventos del ciclo de vida
Tres eventos de Bukkit en net.exylia.lib.api.capture.event siguen una partida. Cada uno lleva una
instantánea CaptureEvent o CaptureConfig, nunca el juego vivo. Ellos, y openMenu, necesitan
exylia-api v1.133.0 o posterior.
| Evento | Cuándo | Cancelable |
|---|---|---|
CaptureStartEvent | Una partida de una config está a punto de arrancar. getConfig(). | Sí |
ZoneCaptureEvent | Alguien tomó una zona. getEvent(), getZone(), getPlayer(), getClan(). | No |
CaptureEndEvent | La partida terminó. getEvent(), getWinner(), getReason(). | No |
@EventHandler
public void onEnd(CaptureEndEvent event) {
if (event.getReason() == CaptureEndReason.FINISHED) {
event.getWinner().ifPresent(uuid -> announce(event.getEvent().displayName(), uuid));
}
}CaptureStartEvent se lanza cuando la config existe, está habilitada, completa, no está ya
corriendo y es de un tipo conocido — y antes de que la partida registre una zona, muestre nada o
ejecute un comando de inicio. Todo arranque pasa por aquí: un comando, el horario, el menú de
administración y start(String) por igual. Un arranque cancelado se rechaza como cualquier otro:
start devuelve vacío, el rechazo queda en el log, y al admin que lo arrancó por comando se le dice
que falló sin motivo, así que un handler que cancela debería explicar el porqué él mismo.
ZoneCaptureEvent se lanza cada vez que se toma una zona: la colina en un KOTH (una vez por
captura cuando sigue corriendo), cada punto en KOTH Capture Points, una zona de Conquest que cae ante
un clan, y el objetivo de un Bounty al morir a manos de alguien. Llega después de que la captura
esté en las estadísticas y antes de que el modo decida si ganó, así que una captura ganadora va
seguida de CaptureEndEvent. getZone(), getPlayer() y getClan() son todos Optional: la zona
solo tiene nombre en Conquest, y el clan solo cuando la partida puntúa por clan. KOTH Points, Payload y
Destroy The Core no tienen un momento de tomar una zona y nunca lo lanzan.
CaptureEndEvent se lanza una vez por partida, después de que el modo la resuelva — el resultado
anunciado, los comandos de fin ejecutados y las recompensas del ganador entregadas — y antes de que la
partida deje de listarse, así que scores(String) todavía responde por ella. getWinner() es el
único jugador a cuyo favor terminó; está vacío cuando nadie ganó, y también cuando el resultado es
compartido, se saca de las puntuaciones o el objetivo de un Bounty sobrevivió a la caza.
getReason() es un CaptureEndReason:
| Constante | Significado |
|---|---|
FINISHED | Alguien llegó a lo que el modo persigue: aguantó la colina, alcanzó el objetivo, llevó el carro a destino, mató al objetivo. |
TIME_UP | Se acabó el reloj antes. |
STOPPED | Parada antes de tiempo: por un admin, stop(String), el apagado del plugin, o un Bounty sin nadie a quien cazar. |
Cada evento se lanza en el hilo que lo provocó — el del propio emisor para un comando, el hilo global para el horario y para una partida terminada por sus zonas o su reloj — y es asíncrono cuando ese no es el hilo principal. En Folia ninguno de ellos es un único hilo principal, así que programa todo lo que toque el resto del mundo.
Estadísticas
| Método | Qué hace |
|---|---|
stats(UUID player) | Los totales de un jugador en todos los eventos. |
stats(UUID player, String configId) | Los totales de un jugador en un evento. |
clanStats(String clanId) | Los totales de un clan en todos los eventos. |
topPlayers(int limit) | Los mejores jugadores en general, como CompletableFuture<List<CaptureStats>>, el mejor primero. |
topPlayers(String configId, int limit) | Lo mismo para un evento. |
topClans(int limit) | Los mejores clanes en general, como CompletableFuture<List<CaptureClanStats>>, el mejor primero. |
cachedTopPlayers() | El podio que el plugin mantiene caliente para sus propios placeholders, el mejor primero. |
cachedTopClans() | Lo mismo para clanes. |
stats lee la caché y nunca falla: un jugador sin fila recibe una con todos los contadores a cero, y
la fila real se busca en segundo plano para la llamada siguiente.
topPlayers y topClans van a la base de datos y completan en un hilo de base de datos. Para un
placeholder o un redibujado de menú usa mejor cachedTopPlayers() y cachedTopClans(): diez filas
refrescadas por temporizador, y vacías hasta que corre el primer refresco, que es justo la distinción
que necesita un placeholder — puede imprimir un valor de reserva en vez de bloquear un tick con una
consulta.
Tipos
CaptureConfig — id (que además es con lo que se arranca el evento), displayName, type (del
registro), enabled, iconMaterial y maxDurationMillis, que vale 0 cuando el evento corre hasta
que alguien gane. La zona, las tablas de recompensas y los ajustes propios del modo quedan fuera: son
la geometría y los tipos de recompensa del propio plugin, y no hay nada ahí sobre lo que un tercero
pueda actuar sin ser también dueño del modo.
CaptureEvent — una foto de una partida: id (el id de su config), displayName, type,
state, elapsedMillis, remainingMillis, infiniteDuration y participants, la cantidad de
jugadores que estuvieron dentro de una zona al menos una vez. El plugin tickea una partida varias veces
por segundo, así que los tiempos de aquí son los que había en el momento de la consulta: vuelve a
preguntar en vez de guardarte una entre ticks.
CaptureStats — player, eventConfigId, wins, captures, timeCapturedSeconds, points y
leaderboardPoints. Una sola forma cubre los dos alcances: eventConfigId va vacío para los totales
de todos los eventos y nombra la config en la fila de un evento. Un jugador que nunca participó igual
tiene uno de estos con todos los contadores a cero, así que un menú o un placeholder nunca tiene que
manejar una fila ausente.
CaptureClanStats — clanId, wins, captures, points, leaderboardPoints. Solo se escribe
cuando un evento corre en modo clan, que necesita un plugin de clanes instalado: sin él cada evento
puntúa de forma individual y estos se quedan a cero.
CaptureState — en qué punto de su vida está una partida: IDLE (construida y sin arrancar, o ya
terminada y a punto de olvidarse), RUNNING (el reloj corre y las zonas están vivas) o ENDING (hay
ganador y se están repartiendo las recompensas).
Lo que no expone
La geometría de las zonas, las tablas de recompensas, las escrituras del programador de horarios, los menús de administración y las filas crudas de configuración quedan fuera a propósito: un contrato público no se puede romper después, así que lleva lo que una integración necesita y nada que solo tuviera sentido dentro de una versión.
Si de verdad te falta algo, pídelo en Discord.
¿Falta algo en esta página? Dínoslo en Discord