Welcome to Bukkit France

Inscrivez-vous maintenant pour profiter d'un accès total à tout le contenu offert par la meilleur communauté Bukkit française ! Une fois inscrit et connecté, vous pourrez contribuez à la communauté en postant vos propres sujets et questions ou en répondant à ceux existants. Vous pourrez aussi customiser votre profil, recevoir des points de réputations, communiquer avec les autres membres via le chat, et plus encore! 

  • Annonces

    • Pskyco

      Bukkit France passe sous Discord !   02/20/16

      Bukkit France est désormais passé sur Discord, au revoir donc notre vieux Teamspeak ! Téléchargez le client et venez nous rejoindre sur notre salon en suivant les instructions suivantes.
      M-à-j du 25/02/2017 : Désormais, seuls les comptes actifs sur le forum se verront donner l'accès au Discord, ce dernier n'est pas une plateforme d'aide de la même manière que le chat.
  • billets
    47
  • commentaires
    40
  • vues
    31974

Chapitre 4 : Events && Listeners

ilicos

1072 vues

blog-0436006001446747183.jpg

Bonjour tout le monde,

 

Jackblue semblant être bien trop occupé pour avancer les cours de spigot actuellement, je me suis décidé à m'y mettre et contribuer à l'avancement du programme! :)

Étant programmeur étudiant dans le domaine du jeux-vidéo, je risque de généraliser un peu des concepts avant d'aborder le développement craftbukkit/spigot.

 

I - Introduction

 

Listener, écouteur en français... mais à quoi servent-il donc? à écouter, certes mais quoi? Des événements.

Les listeners vont capter un événement puis exécuter une callBack (fonction).

Un joueur ouvre son inventaire, l'événement InventoryOpenEvent va être dispatché et les listeners qui écouteront cet événement vont le capter et exécuter leurs fonctions.

 

II - Pourquoi utiliser des listeners && events

 

Imaginons que je programme un plateformer... mon joueur meurt, je pourrais lui faire appeler une fonction public de mon HUD pour changer le nombre de vies restantes.

Cependant, imaginons que plus tard je veuille que tout les ennemis aux alentours se réjouissent de la mort de mon héros. Je vais être contraint de rajouter cela sur mon joueur et de rajouter des fonctions publiques sur mes ennemis. Est-ce vraiment à un élément de mon jeu d'appliquer à tout les autres éléments les comportements qu'ils devraient avoir? Non, c'est plutôt à eux d'observer // d'écouter un événement PlayerDieEvent et de changer leurs animations en conséquence.

 

En supplément, utiliser un événement permet de simplifier le travail en équipe.

Je m'occupe du Player, JeremGamer des ennemis, mon player meurt:

- Dans le cas où je décide d'appeler une fonction publics des ennemis : "Hey jerem', tu pourrais rajouter cette fonction publique?"

- Dans le cas d'un événement, JeremGamer rajoute un listener et fait ce qu'il veut avec.

 

Cela permet d'avoir plus de liberté en séparant mieux les causes et les conséquences.

 

III - En pratique, les listeners

 

Avec bukkit, il faut créer sa propre class Listener qui va écouter un ou plusieurs événements et attacher cette class au pluginManager.

On commence par la création de la classe:

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperListener implements Listener { 
}

 

La méthode pour attacher la class au pluginManager prend en paramètre un Listener d'où la nécessité d'implémenter Listener à votre Listener

 

Pour l'exemple, nous allons envoyer un message au joueur quand il se connecte.

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperListener implements Listener {
    @EventHandler
    public void onPlayerConnection(PlayerJoinEvent event){        
        event.getPlayer().sendMessage("Bienvenue à toi! :D");    
    }
}

 

@EventHandler est une annotation permettant de signaler la fonction qui suit comme étant une callBack de listener. Le type d'event passé en paramètre déterminera quel événement est écouté. Le nom de la fonction importe peu, toujours est-il qu'il est préférable qu'elle soit compréhensible.

La documentation vous permettra de trouver l’événement qui correspond à ce que vous souhaitez écouter.

Ce même objet passé en paramètre contient différent informations et méthodes pour les récupérer. Certains événements peuvent être annulé par exemple BlockBreakEvent.

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperListener implements Listener {    
    @EventHandler    
    public void onBlockBreak(BlockBreakEvent event){        
        event.setCancelled(true);    
    }
}

 

Le joueur va casser un block, l'évènement va être dispatché, intercepté par le listener, mon callBack va annuler l’événement et donc le bloc va ré-apparaître.

 

Faites attention, là j'écris qu'une seule fonction à chaque fois, mais je peux en mettre plusieurs, par contre il doit y avoir toujours @EventHandler devant chaque fonction. Sinon elles ne seront pas prise en compte comme callback.

 

Maintenant que l'on a créé un belle classe Listener, il va falloir l'ajouter au plugin manager, sinon, ça ne risque pas de fonctionner.

Pour ce faire, on récupère le pluginManager, on lui assigne le listener et on lui passe en second paramètre le plugin qui ajoute ce listener:

 
monInstanceDePlugin.getServer().getPluginManager().registerEvents(monInstanceDeListener, monInstanceDePlugin);

// - ou -

Bukkit.getPluginManager().registerEvents(monInstanceDeListener, monInstanceDePlugin);

// - ou -

Bukkit.getServer().getPluginManager().registerEvents(monInstanceDeListener, monInstanceDePlugin);

 

J'aurais tendance à conseiller le 2ème, le chemin de fonctions étant le plus cours.

 

Vous pouvez également supprimer un Listener

 
HandlerList.unregisterAll(monInstanceDeListener);

 

ou supprimer l'écoute d'un événement particulier sur un listener;

 
PlayerJoinEvent.getHandlerList().unregister(monInstanceDeListener);

 

Attention! L'instance doit être la même entre l'ajout et la suppression.

 

Il est bon de savoir que l'annotation @EventHandler peut prendre un paramètre: la priorité:

il y a 6 étapes:

  • EventPriority.LOWEST
  • EventPriority.LOW
  • EventPriority.NORMAL
  • EventPriority.HIGH
  • EventPriority.HIGHEST
  • EventPriority.MONITOR

 

 

Lorsqu'un évènement survient, Craftbukkit appelle les méthodes d'écoute qui ont une faible priorité en premier, et celle qui ont une forte priorité en dernier, afin que ces dernières aient le dernier mot sur le sort de l'évènement (notamment s'il est annulé ou pas). Par défaut la priorité est NORMAL.

 

Attention : La priorité MONITOR existe pour de l'observation, il ne faut pas l'utiliser pour avoir le dernier mot sur une modification//annulation d'événement.

Pour déclarer une propriété, au lieu d'écrire:

 
@EventHandler

 

on écrit:

 
@EventHandler(priority = EventPriority.HIGH)

 

Bien entendu, vous choisissez la propriété qui vous convient et vous utilisé une propriété seulement si vous en avez besoin. (Plusieurs plugins qui écoutent le même événement)

 

IV - Création d'événements

 

Vous pouvez également ajouter vos propres événements, pour cela, il faut créer sa classe qui étends Event.

 
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; 

public class MonSuperEvent extends Event {    
    private static final HandlerList handlers = new HandlerList();     
  
    @Override    
    public HandlerList getHandlers() {        
        return handlers;    
    }     
  
    public static HandlerList getHandlerList() {        
        return handlers;    
    }
}

 

Attention, il faut conserver ces méthodes et cette propriété. C'est elle qui contient tout les listeners.

Je peux rajouter d'autres méthodes et d'autres propriétés.

Je peux aussi implémenter Cancellable qui m'obligera à implémenter les méthodes

 
public boolean isCancelled()
public void setCancelled(boolean cancel)

 

J'aurais alors à les compléter pour les rendre fonctionnelles

 
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; 

public class MonSuperEvent extends Event implements Cancellable{    
    private static final HandlerList handlers = new HandlerList();     

    @Override    
    public HandlerList getHandlers() {        
        return handlers;    
    }     

    public static HandlerList getHandlerList() {        
        return handlers;    
    }    

    public boolean isCancelled() {       
        return cancelled;    
    }     

    public void setCancelled(boolean cancel) {       
        this.cancelled = cancel;    
    }
}

 

Maintenant que j'ai créé mon Event, je peux tout à fait l'écouter comme un Evenement classique. Cependant, faut-il encore le dispatcher pour que mes Listener reçoivent l'événement.

Pour ce faire:

 
MonSuperEvent event = new MonSuperEvent();
Bukkit.getPluginManager().callEvent(event); 
//Je dispatche l'événement, tout mes listeners qui écoute l'évènement le captent et agissent éventuellement dessus, décident éventuellement de l'annuler...

if (event.isCancelled()){    
// Par conséquent, si mon évènement est annulé, J'annule l'action.
}

 

Rien ne m'empêche de rajouter des paramètres au constructeur de l’événement pour y ajouter des informations.

Je pourrais créer l'événement TeamWinEvent, et avoir des méthodes .getTeam() ou .getPlayersTeam() qui me renvoient des informations importantes et qui sont intéressantes.

 

V - Une chose à savoir mais pas forcément à faire

Au lieu de créer une class pour votre listener, vous pouvez directement implémenter Listener à votre plugin et utiliser votre propre classe plugin comme listener

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperPlugin extends JavaPlugin implements Listener {    
    @Override    
    public void onEnable(){        
        getServer().getPluginManager().registerEvents(this, this);    
    }    

    @EventHandler    
    public void onPlayerJoin(PlayerJoinEvent event){        
        event.getPlayer().sendMessage("Koukou twa ! :D");    
    }
}

 

C'est bien si c'est juste pour tester quelque chose rapidement... mais ça devient vite le foutoir sur votre classe principale.

 

Résumé:

  • Événements et listeners offrent une plus grande liberté d'action en séparant cause et conséquences.
  • Une fois notre classe listener créée, on lui ajoute les méthodes d'écoutes sans oublier l'annotation @EventHandler et on enregistre notre listener auprès du PluginManager
  • Possibilité d'annuler certains événements : setCancelled(true);
  • Possibilité de créer ses propres événements, de les dispatcher quand on veut et de les écouter comme les événements classiques

 

JeremGamer a également créé des cours sur les évènements et les listeners relatifs aux guis pour javax.swing et java.awt.

http://www.bukkit.fr/blog/3/entry-61-chapitre-28-les-%C3%A9v%C3%A8nements-partie-1/

http://www.bukkit.fr/blog/3/entry-62-chapitre-29-les-%C3%A9v%C3%A8nements-partie-2/

 

ilicos


4 personnes aiment ça


8 Commentaires


Petit problème avec les syntaxes ! ...

Partager ce commentaire


Lien vers le commentaire
Partager sur d’autres sites
il y a 42 minutes, Kwizzy a dit :

Petit problème avec les syntaxes ! ...

Oui on sait, c'est du au récent portage IPB. On y travaille

Partager ce commentaire


Lien vers le commentaire
Partager sur d’autres sites

Dans les jeux, ils utilisent un système d'évent ? Du moins, est-ce que c'est mieux ou useless ?

Perso je trouve ça spécial d'écouter ses propres events.

1 personne aime ça

Partager ce commentaire


Lien vers le commentaire
Partager sur d’autres sites
Il y a 10 heures, SkyBeast a dit :

Dans les jeux, ils utilisent un système d'évent ? Du moins, est-ce que c'est mieux ou useless ?

Perso je trouve ça spécial d'écouter ses propres events.

Oui les jeux spécialement utilisent les systèmes d'events. Un des gros avantages est que du coup, quand tu veux rajouter une fonctionnalité, pas besoin d'aller fouiller dans le code et le modifier au risque de tout casser! Il suffit d'écouter l'event. ;)

Je t'invite à lire les deux chapitres cités à la fin de celui-ci. Tu comprendra peut-être un peu mieux l'utilité de faire ça :)

(edit: au passage, désolé pour la syntaxe du code, je vais m'occuper de corriger ça quand je pourrais)

2 personnes aiment ça

Partager ce commentaire


Lien vers le commentaire
Partager sur d’autres sites
Le 2/17/2016 à 09:32, Kwizzy a dit :

Petit problème avec les syntaxes ! ...

 

Plus besoin de t'embêter Jerem, j'ai corrigé :) 

Modifié par ilicos

Partager ce commentaire


Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !


Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.


Connectez-vous maintenant