Contenido generado con IA — puede contener errores.

Referenciadev

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")));
Agregarlo a tu proyecto

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.

CaptureEvent no es un evento de Bukkit

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étodoQué 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.

Los tipos de evento son un registro, no un enum

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étodoQué 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étodoQué 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étodoQué 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.

EventoCuándoCancelable
CaptureStartEventUna partida de una config está a punto de arrancar. getConfig().Sí
ZoneCaptureEventAlguien tomó una zona. getEvent(), getZone(), getPlayer(), getClan().No
CaptureEndEventLa 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:

ConstanteSignificado
FINISHEDAlguien llegó a lo que el modo persigue: aguantó la colina, alcanzó el objetivo, llevó el carro a destino, mató al objetivo.
TIME_UPSe acabó el reloj antes.
STOPPEDParada antes de tiempo: por un admin, stop(String), el apagado del plugin, o un Bounty sin nadie a quien cazar.
No siempre en el hilo principal

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étodoQué 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.

Los futures son lo único que consulta

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