Causes des Events

Les événements sont utiles pour attacher une logique supplémentaire aux actions du jeu, mais ils ont l’inconvénient de ne fournir quasiment aucun contexte quant à ce qui a provoqué cet événement. L’objet Cause permet de fournir et de recevoir des informations contextuelles à propos de l’événement. Ces informations peuvent être utilisées pour modifier le comportement de votre event listener.

Par exemple, un plugin de protection de monde a besoin d’informations sur quel joueur a causé l’appel du ChangeBlockEvent avant de pouvoir décider si l’événement doit être annulé ou pas. Plutôt que de passer par la voie traditionnelle avec la création d’une multitude de sous-événements pour les différentes conditions de source, cette information est fournie dans la Cause de l’événement.

Chaque événement fournit un objet Cause qui peut être examiné pour obtenir des informations relatives à pourquoi l’événement a été déclenché. L’objet Cause peut être récupéré à partir d’un événement en appelant simplement Event#getCause().

Récupérer des objets à partir d’une cause

Structurellement, un objet Cause contient une liste séquentielle d’objets. Il y a de nombreuses méthodes de récupération des informations d’un objet Cause dont nous discuterons ici, pour obtenir une liste plus complète veuillez consulter les Javadocs.

Note

Les objets à l’intérieur d’une cause sont classés tels que le premier objet est la cause la plus immédiate de l’événement, et les objets suivants ont une importance décroissante et/ou peuvent seulement fournir des informations contextuelles.

Cause#root() retourne le premier objet à l’intérieur d’une cause. Cet objet est la cause la plus immédiate ou directe de l’événement. Puisqu’une Cause ne peut pas être vide, elle possède forcément une racine (root).

Cause#first(Class) retourne le premier objet dans la chaîne de cause dont le type est soit identitique soit un sous-type de la classe donnée. Par exemple, pour une cause qui contient un joueur suivi par une entité : [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
}

Les deux Optional contiendraient l’objet joueur puisque son type correspond directement à la demande pour un objet de type Player, et il correspond aussi à la demande pour un objet de type Entity puisque Player est un sous-type d’Entity.

Cause#last(Class) est semblable à Cause#first(Class), sauf qu’il retourne la dernière valeur dans la chaîne de cause correspondant au type.

Pour continuer dans l’exemple ci-dessus, si au lieu de ça nous l’avions changé pour appeler Cause#last(Class), le premier Optional contiendrait encore l’objet Player, mais le second Optional contiendrait désormais l’entité que nous avons passé en seconde position de la cause.

Cause#containsType(Class) retourne un booléen et peut être utilisé pour vérifier si une chaîne de cause contient un objet correspondant au type fournit.

Cause#all() retourne simplement tous les objets à l’intérieur de la cause pour permettre une gestion plus avancée.

Causes nommées

Parfois l’ordre des objets dans la cause n’est pas suffisant pour obtenir l’idée correcte de ce que l’objet représente par rapport à l’événement. C’est là qu’intervient NamedCause. Les causes nommées fournissent une méthode pour référencer des objets dans une cause avec un nom unique leur permettant d’être facilement identifié et demandé. Quelques exemples de cas d’utilisation pour des causes nommées est le Notifier d’un ChangeBlockEvent.Grow ou la Source d’un DamageEntityEvent.

Récupération d’une entrée nommée à partir d’une cause

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

Cet exemple utilise Cause#get(String, Class<T>) qui peut être utilisé pour récupérer l’objet associé à un nom s’il est présent dans la chaîne de cause. En outre, Cause#getNamedCauses() fournit une Map<String, Object> qui permet de trouver tous les noms présents et leurs objets associés.

Note

Certrains noms communs d’identification pour NamedCause sont présents en tant que variables statiques dans la classe NamedCause. Les identifieurs qui sont spécifiques à certains événements peuvent souvent être trouvés en tant que variables statiques dans la classe de l’événement, par exemple DamageEntityEvent#SOURCE.

Création de Causes personnalisées

Créer une cause à utiliser lors de l’appel d’un événement est extrêmement simple. La partie la plus difficile est de décider quelles informations inclure dans la cause. Si vous appelez un événement depuis votre plugin qui est habituellement déclenché par d’autres moyens, peut-être que vous souhaiterez inclure votre plugin pour que les autres plugins sachent que l’événement vient de votre plugin. Ou si vous appelez un événement au nom d’un joueur en raison d’une action c’est habituellement une bonne idée d’inclure ce joueur dans la cause.

Note

Les objets Cause sont immuables donc il ne peuvent pas être modifiés une fois créés.

À l’aide de Cause#of(NamedCause) vous pouvez construire une cause d’une série d’objets. Les objets seront ajoutés à la chaîne de cause à l’ordre dans lequel ils sont passés à la méthode, alors que le premier paramètre de l’objet va devenir la cause de racine. N’oubliez pas qu’une Cause ne peut pas être vide, donc au moins un paramètre non null est toujours requis.

Si vous avez déjà un Objet Cause et souhaiteriez y ajouter d’autres objets vous pouvez utiliser Cause#with(NamedCause, NamedCause…). Cela construit un Objet Cause qui contient en premier lieu les Objets présents dans l’Objet Cause originel et ensuite les Objets additionnels que vous avez fourni.

Finalement, si vous souhaitez ajouter un objet à une cause avec un nom défini appelé d’abord NamedCause#of(String, Object) et puis passer l’instance reoutnrée de NamedCause à la chaîne de cause comme vous le feriez avec un objet normal.