API
Qué puede hacer otro plugin con los efectos de muerte: el catálogo, lo que eligió un jugador, lo que lleva un arma, lanzar un efecto, los menús y entregar efectos y llaves.
KillEffectService lee el catálogo de ExyliaKillEffect, cambia lo que lleva un jugador, ata efectos a
las armas, lanza un efecto cuando se lo pides, abre las pantallas del propio plugin y entrega efectos y
llaves de caja. Con una sola búsqueda tienes toda la superficie.
ExyliaAPI.get(KillEffectService.class).ifPresent(effects ->
effects.chosenEffect(player.getUniqueId())
.ifPresent(effect -> player.sendMessage("Kill effect: " + effect.name())));Un resultado vacío en la búsqueda significa que los efectos de muerte no forman parte de este servidor, no que algo haya fallado.
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. Lanzar un efecto, los menús, los
desbloqueos, las llaves y KillEffectPlayEvent llegaron en exylia-api v1.133.0 y ExyliaKillEffect
1.4.0: compila contra esa etiqueta o una más nueva para usarlos.
Todo funciona con ids
Los efectos y las categorías se nombran por las claves que declara effects.yml. Los ids están
normalizados — minúsculas, letras, dígitos y guiones bajos — y se comparan sin importar mayúsculas, así
que el id que una tienda guardó el mes pasado sigue resolviendo después de que el dueño lo reescribiera
con otras mayúsculas.
Un plugin que llama esto ya decidió que el jugador puede tener el efecto: una caja abierta, un rango
comprado, una recompensa reclamada. Que lo anule un nodo que el comprador todavía no tiene no es lo que
pidió. mayUse está para quien sí quiera la comprobación, en sus propios términos.
El catálogo
| Método | Qué hace |
|---|---|
List<KillEffect> effects() | Todos los efectos declarados, en el orden del archivo. Es una foto: sirve para armar una página de tienda, sobra dentro de un bucle que podría pedir un id. |
Optional<KillEffect> effect(String effectId) | Un efecto por id. Vacío si el archivo no declara ninguno con ese id. |
boolean effectExists(String effectId) | Si el efecto existe. La forma barata de effect, para validar lo que escribió un jugador o lo que nombró una config. |
List<KillEffectCategory> categories() | Todas las categorías, en el orden en que se dibujan las pestañas. |
Optional<KillEffectCategory> category(String categoryId) | Una categoría por id. Vacío si el archivo no declara ninguna con ese id. |
List<KillEffect> effectsIn(String categoryId) | Los efectos de una categoría, en el orden en que se dibujan. Vacío si la categoría no existe. |
boolean mayUse(Player player, String effectId) | Si un jugador puede usar un efecto: su propio permiso, el de todos los efectos a la vez o el de su categoría entera. Un id desconocido nunca está permitido, así que un id viejo se lee como bloqueado y no como gratis. |
Lo que eligió un jugador
Todo lo que recibe un UUID lee lo que hay en memoria de un jugador conectado. Alguien cuya fila
todavía no llegó responde como si no hubiera elegido nada, en vez de dejar al que llama esperando a una
base de datos.
| Método | Qué hace |
|---|---|
Optional<KillEffect> chosenEffect(UUID player) | El efecto que eligió en el menú. Vacío si no eligió ninguno. |
boolean chooseEffect(Player player, String effectId) | Pone el efecto que reproducen sus muertes. false si ningún efecto lleva ese id, y entonces no se cambió nada. |
void clearEffect(Player player) | Lo deja sin efecto elegido. |
List<KillEffect> favourites(UUID player) | Los efectos que marcó, en el orden en que los marcó — el suyo, no el del catálogo. Vacío si no tiene ninguno o no está cargado. |
boolean isFavourite(UUID player, String effectId) | Si marcó un efecto. |
boolean toggleFavourite(Player player, String effectId) | Marca un efecto, o lo desmarca si ya estaba marcado. false si ningún efecto lleva ese id. |
void clearFavourites(Player player) | Vacía sus favoritos. |
Lo que lleva un arma
| Método | Qué hace |
|---|---|
boolean weaponBindingEnabled() | Si en este servidor se reproducen los efectos atados a las armas. Si no, atar uno escribe un valor que nunca va a sonar — así que pregunta antes de ofrecerlo. |
boolean playerChoiceEnabled() | Si en este servidor se reproduce el efecto que el jugador eligió en el menú. |
boolean fitsWeapon(String effectId, Material weapon) | Si el efecto acepta ese tipo de objeto. Un efecto que no declara armas encaja con todas. |
Optional<KillEffect> boundEffect(ItemStack weapon) | El efecto que lleva un arma. Vacío si no lleva ninguno. |
KillEffectBindResult bind(ItemStack weapon, String effectId) | Ata un efecto. El objeto se modifica en el sitio, y solo después de que pasen todas las comprobaciones. |
KillEffectBindResult unbind(ItemStack weapon) | Le quita el efecto sin devolver nada, para quien entrega la ficha por su cuenta. También en el sitio. |
Optional<ItemStack> token(String effectId, Player viewer) | El objeto que entrega una caja o una tienda: aplicarlo a un arma ata el efecto. Se dibuja para ese jugador, porque el nombre y el lore llevan placeholders. Vacío si ningún efecto lleva ese id. |
ItemStack remover(Player viewer) | El removedor. Aplicarlo a un arma le quita el efecto y devuelve la ficha. |
bind y unbind escriben sobre la copia del stack que les pasas. Pásales una copia y no un objeto que
siga dentro de una vista de inventario abierta: lo que ve el jugador se redibuja cuando devuelves el
stack a su sitio.
Lanzar un efecto
| Método | Qué hace |
|---|---|
boolean play(String effectId, Location where, Player killer, @Nullable LivingEntity victim) | Lanza un efecto en un lugar, como si allí hubiera ocurrido una baja. La bandera de región, KillEffectPlayEvent y la visibilidad de cada espectador siguen decidiendo; el arma, la elección del menú, la lista de mobs y el permiso se saltan, porque quien llama ya nombró el efecto. victim es el cuerpo que dibujan sus pasos, o null para ninguno. false si ningún efecto lleva ese id, no dibuja nada, la región lo silencia o un listener lo canceló. |
boolean playFor(Player killer, LivingEntity victim) | Lanza el efecto que gana una baja, decidiendo todo lo que decide una muerte real y en el mismo orden: si ese tipo de víctima lanza efectos, el efecto que llevaba el último golpe del asesino, y si no, su arma y su elección del menú según el modo del servidor. false si la baja no gana nada, o si play habría respondido false. |
boolean preview(Player viewer, String effectId) | Muestra el efecto en el escenario de previsualización del servidor, a solas, y devuelve al jugador — no hace falta tenerlo, así que sirve de "prueba antes de comprar" para una tienda. false si no hay escenario fijado, y se le avisa al jugador. |
play sirve para una cinemática, un jefe que muere fuera del sistema de daño o una victoria que debe
verse como una baja. playFor sirve para un plugin que detiene un golpe mortal antes de que el
servidor lo cuente como muerte — un tótem, un duelo que acaba en el último corazón. Una muerte que el
servidor sí reporta ya lanza su efecto, así que llamar a playFor también para ella lo lanza dos veces.
Llama a play en el hilo dueño de where y a playFor en el dueño de la víctima: el hilo principal
en Paper, el hilo de región en Folia. preview corresponde al hilo dueño del jugador.
Menús
| Método | Qué hace |
|---|---|
void openMenu(Player player) | Abre el menú de efectos igual que /killeffect, para un NPC, un objeto del hub o una tienda. Si la fila del jugador no está en memoria se lee antes, así que el menú puede aparecer un momento después de la llamada. En un servidor weapon se le avisa de que el menú está apagado. Seguro desde cualquier hilo. |
void openCrate(Player player) | Abre la caja igual que el comando y los bloques de caja: la pantalla que pregunta cuántas abrir y gasta las llaves. Con la caja apagada se le avisa. Seguro desde cualquier hilo. |
Tener efectos, y llaves de caja
| Método | Qué hace |
|---|---|
boolean unlock(Player player, String effectId) | Le da un efecto para siempre, igual que ganarlo en la caja — posesión sin nodo de permiso, que mayUse cuenta desde entonces. No elige nada ni entrega ningún objeto: sigue con chooseEffect o token para eso. false si ningún efecto lleva ese id, la caja ya se lo dio o su fila todavía no llegó; no se cambió nada. |
int keys(UUID player) | Cuántas llaves de caja tiene. 0 si no tiene ninguna o su fila todavía no llegó. |
void addKeys(Player player, int keys) | Da llaves, o las quita con un número negativo — así paga una tirada una tienda, un voto o una misión. La cuenta nunca baja de cero. Un jugador cuya fila todavía no llegó queda igual. |
KillEffectPlayEvent
net.exylia.lib.api.killeffect.event.KillEffectPlayEvent se lanza cuando todo lo demás ya aceptó que
un efecto debe sonar: existe, dibuja algo y la región permite efectos de muerte. Se lanza para las
bajas que reporta el servidor y para play y playFor por igual, y a propósito no se distinguen — una
arena que quiere los efectos callados los quiere callados en los dos casos.
@EventHandler
public void onKillEffect(KillEffectPlayEvent event) {
if (event.getLocation().getWorld().getName().equals("lobby")) event.setCancelled(true);
}| Método | Qué devuelve |
|---|---|
Player getPlayer() | El asesino: de quién es el efecto. |
@Nullable LivingEntity getVictim() | Sobre qué se lanza. null si un plugin lo lanzó en un lugar y no sobre un cuerpo. |
String getEffectId() | El efecto que va a sonar, normalizado. |
Location getLocation() | Dónde se lanza. Una copia: cambiarla no mueve nada. |
Cancelarlo no dibuja nada ni dice nada; la baja en sí queda intacta. El evento se llama en el hilo dueño del lugar, que en Folia es un hilo de región y no el principal.
KillEffectBindResult
Todas las comprobaciones corren antes de escribir nada, así que cualquier resultado que no sea BOUND
o UNBOUND significa que los dos objetos quedaron exactamente como estaban. isSuccess() es cierto
para esos dos y para nada más.
| Valor | Significado |
|---|---|
BOUND | El arma ahora lleva el efecto. |
UNBOUND | El arma ya no lleva ningún efecto. |
NOT_A_WEAPON | El objeto no es algo a lo que se pueda atar un efecto. |
WRONG_WEAPON | Es un arma, pero no una con la que este efecto declare encajar. |
UNKNOWN_EFFECT | Ningún efecto lleva ese id, que es también como se lee un id viejo. |
ALREADY_BOUND | El arma ya lleva un efecto; desátalo antes de atar otro. |
NO_EFFECT | El arma no lleva ningún efecto, así que no había nada que quitar. |
FAILED | Rechazado por un motivo que este contrato no nombra. |
Hoy nada produce FAILED. Está para que un motivo que se agregue más adelante dentro del plugin te
llegue como un valor que puedes manejar, y no como una excepción lanzada contra quien haya preguntado
— que en un servidor vivo es un plugin de terceros sin forma de recuperarse. Maneja los resultados que
te importan y deja que el resto caiga en una sola rama.
Los records
KillEffect lleva id(), categoryId(), name(), icon(), description(), priority() y
permission() — la descripción con las palabras del archivo, el icono tal como lo nombra el archivo, y
el permiso que concede ese efecto suelto, para que una tienda pueda venderlo sin saber cómo se arma el
nodo.
KillEffectCategory lleva id(), name(), icon(), priority() y permission(). Su permiso concede
todos los efectos de la categoría de una vez, que es lo que permite vender un rango como "todos los
efectos cósmicos" en vez de como una lista de ids que crece cada vez que el dueño agrega uno.
Los dos son fotos de lo que decía el archivo cuando preguntaste. Una recarga reemplaza el catálogo entero, así que un efecto guardado de una recarga a otra es la descripción vieja de un id que quizá ya no exista — vuelve a pedirlo en vez de guardarlo.
El plugin gemelo
HitEffectService es el mismo contrato para los efectos que se
reproducen al golpear. Los dos son idénticos en forma a propósito: mismos nombres de método, mismo
orden, mismos resultados. Una integración escrita contra uno se pasa al otro cambiando los tipos.
Lo que no expone
Lo que el efecto dibuja de verdad — los pasos que compila el motor de secuencias — no está aquí. Es la implementación de esa versión del efecto, cambia cada vez que el dueño edita una línea, y no significa nada fuera del plugin que lo reproduce. El editor in-game y las escrituras administrativas — revocar desbloqueos, atar bloques de caja — quedan afuera por lo mismo: un contrato público no se puede romper después, así que lleva lo que una integración realmente necesita y nada que solo tuviera sentido dentro de una versión.
Si te falta algo, pídelo en Discord.
¿Falta algo en esta página? Dínoslo en Discord