Causas del Evento

Los eventos son geniales para asociar una lógica adicional a las acciones del juego, pero ellos tienen el inconveniente de proveer al lado de ningún contexto en cuanto a lo que ha causado que ocurra ese evento. El objeto :javadoc:`Cause`permite proporcionar y recibir información contextual adicional sobre el evento. Esta información contextual, luego, puede usarse para modificar el comportamiento de su oyente de eventos.

Por ejemplo, un complemento de protección de mundo necesita información sobre que jugador ha causado un ChangeBlockEvent para que ocurra antes de que puedan decidir si el evento debe ser cancelado o no. En lugar de ir con la ruta tradicional para crear una multitud de subeventos para las diferentes condiciones de fuente esta información en su lugar lo proporciona en la Causa del evento.

Cada evento proporciona un objeto de Causa que puede ser interrogado para obtener la información referente a porqué el evento fue activado. El objeto de Causa puede ser recuperado de un evento simplemente llamando Event#getCause().

Recuperación de objetos de una Causa

Estructuralmente, un objeto Cause contiene una lista secuencial de objetos. Existen varios métodos para recuperar información desde un objeto Cause los cuales discutiremos nosotros aquí. Para obtener una lista más completa, consulte el enlace javadocs.

Nota

Lo objetos dentro de una causa se ordenan de tal forma que el primer objeto será la causa más inmediata del evento y los siguientes objetos son de importancia decreciente y/o pueden solo proporcionar información contextual.

Cause#root() devuelve el primer objeto dentro de la causa. Este objeto es la causa más inmediata o directa del evento. Ya que una Causa no puede estar vacía, está garantizado tener una raíz.

Cause#first(Class) devuelve el primer objeto en la cadena de causa cuyo tipo es también el mismo o es un subtipo de la clase dada. Por ejemplo, dada una causa que contiene un jugador seguido por una entidad [Player, Entity, ...]

@Listener
public void onEvent(ExampleCauseEvent event) {
    Cause cause = event.getCause(); // [Player, Entity]
    Optional<Player> firstPlayer = cause.first(Player.class); // 1
    Optional<Entity> firstEntity = cause.first(Entity.class); // 2
}

Ambas opciones contendrían el objeto del jugador ya que es la solicitud de tipo directamente emparejada para un tipo de Jugador y que coincide con el requerimiento para un tipo de Entidad ya que el Jugador es un subtipo de Entidad.

Cause#last(Class) es similar a Cause#first(Class) excepto que devuelve el último valor en la cadena de causa que coincide con el tipo.

Continuando el ejemplo anterior, si en su lugar de cambiamos para llamar Cause#last(Class) la primera opción contendría todavía el objeto de jugador, pero la segundo opción contendría ahora la entidad que pasamos en la segunda posición de la causa.

Cause#containsType(Class) devuelve un valor boolean y puede ser utilizado para verificar si una cadena de causa contiene algún objeto que coincida con el tipo proporcionado.

Cause#all() simplemente devuelve todos los objetos dentro de la causa permitiendo un manejo más avanzado.

Causas Nombradas

Algunas veces el ordenamiento de objetos dentro de la causa no es suficiente para obtener la idea apropiada de lo que un objeto representa en relación con el evento. Esto es donde la :javadoc:`NamedCause`entra. Las causas con nombre proporcionan un método para etiquetar objetos dentro de una causa con un nombre **único** que les permite entonces ser identificados y solicitados fácilmente . Algunos ejemplos del uso de casos de causas nombradas es la `Notificación` de un ChangeBlockEvent.Grow o la Fuente de un DamageEntityEvent.

Recuperar una entrada con nombre de una causa

@Listener
public void onGrow(ChangeBlockEvent.Grow event) {
    Optional<Player> notifier = event.getCause().get(NamedCause.NOTIFIER, Player.class);
}

Este ejemplo hace uso de Cause#get(String, Class<T>) que puede ser utilizado para recuperar el objeto esperado asociado con un nombre si está presente dentro de la cadena de causa. Adicionalmente Cause#getNamedCauses() proporciona un Map<String, Object> que puede usarse para encontrar todos los nombres actuales y los objetos asociados.

Nota

Algunos nombres comunes de identificación para NamedCauses están presentes como campos estáticos en la clase NamedCause. Los identificadores que son especificados para ciertos eventos pueden encontrarse a menudo como campos estáticos en la clase de evento, por ejemplo DamageEntityEvent#SOURCE.

Creación de Causas personalizadas

La creación de una causa para utilizar cuando se dispara un evento es extremadamente fácil. La parte complicada es decidir que información incluir en la causa. Si se dispara un evento de su complemento que es usualmente desencadenado mediante otros medios tal vez quiera incluir su contenedor de plugin para que otros complementos sepan que el evento comenzó desde su complemento. O si se dispara el evento en nombre de un jugador debido a algunas acciones es usualmente una buena idea incluir a ese jugador en la causa.

Nota

Los objetos de causa son inmutables por lo tanto no pueden ser modificados una vez creados.

Utilizando Cause#of(NamedCause), puede compilar una causa desde una serie de objetos. Los objetos será agregados a la cadena de causa en el orden que se pasan al método, por lo que el primer parámetro de objeto se convertirá en la causa raíz. Recuerde que una Causa puede no estar vacía, así que al menos un parámetro no nulo es siempre requerido.

Si ya tiene un objeto de causa y quiere anexar algún objeto más a la cadena puede utilizar Cause#with(NamedCause, NamedCause…). Esto compila un nuevo objeto de Causa que contiene primero los objetos ya presentes en la causa original, seguido de los objetos adicionales que usted proporcionó.

Finalmente, si desea agregar un objeto a una causa con un nombre definido primero llame a NamedCause#of(String, Object) y entonces pase la instancia NamedCause para la cadena de causa como lo haría con un objeto normal.