New Event System

Discussion in 'Resources' started by md_5, Jan 17, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    md_5

    Some of you may have noticed that we have introduced a new way of handling events in Bukkit. Those of you that haven't noticed sure will when you next open your IDE and find a bunch of big yellow deprecation warnings :p
    Anyway lets start with the old way of using listeners, or more specifically how I do it in all of my projects.
    Code:java
    1. package com.md_5.noclip.listeners;
    2.  
    3. import org.bukkit.Bukkit;
    4. import org.bukkit.event.Event;
    5. import org.bukkit.event.EventHandler;
    6. import org.bukkit.event.EventPriority;
    7. import org.bukkit.event.player.PlayerJoinEvent;
    8. import org.bukkit.event.player.PlayerListener;
    9.  
    10. public class NoClipPlayerListener extends PlayerListener{
    11.  
    12. public NoClipPlayerListener() {
    13. Bukkit.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_JOIN, this, Event.Priority.Normal, plugin);
    14. }
    15. @Override
    16. public void onPlayerJoin(final PlayerJoinEvent event) {
    17. }
    18. }
    19.  

    Looking at the code we have a listening class that extends PlayerListener, we then have a constructor which registers the events and some methods to execute the events. The way I use this class is to simply call: new NoClipPlayerListener() : In my onEnable() method. But now how do we replace this with the new event system you ask? Well lets take a look at the same method again:

    Code:java
    1. package com.md_5.noclip.listeners;
    2.  
    3. import org.bukkit.Bukkit;
    4. import org.bukkit.event.EventHandler;
    5. import org.bukkit.event.EventPriority;
    6. import org.bukkit.event.Listener;
    7. import org.bukkit.event.player.PlayerJoinEvent;
    8.  
    9. public class NoClipPlayerListener implements Listener {
    10.  
    11. public NoClipPlayerListener() {
    12. Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
    13. }
    14.  
    15. @EventHandler(priority = EventPriority.LOW)
    16. public void onPlayerJoin(final PlayerJoinEvent event) {
    17. }
    18. }
    19.  

    Well aside from the lack of big warnings several things have changed. The first being we no longer extend PlayerListener, instead all Listeners, no matter what their type implement Listener. Now instead of registering each event individually in the constructor we can simply call registerEvents() and get all the events we use registered for us. Another bonus of this system is you can name your methods anything you like. Now how do we actually go about registering these new events? Well instead of using the @Override tag to replace the listening methods you add a new tag:
    @EventHandler();
    The syntax goes like this:
    Code:
        @EventHandler(event = NAMEOFEVENT.class, priority = EventPriority.WHATPRIORITY)
    So say I wanted to add a new event, say playermove it is as simple as adding this method:
    Code:java
    1. @EventHandler(priority = EventPriority.LOW)
    2. public void whenThePlayerMoves(final PlayerMoveEvent event) {
    3. }
    4.  

    Notice here how I can call the method anything I like. Using these new listeners in your plugin is exactly the same as before: new MYListener();

    I hope this is a brief tutorial on how to upgrade your plugins to the new event system.
     
  2. Offline

    Afforess


    Incorrect. A function can not operate correctly without its parameters, but can operate correctly w/o metadata.

    It's actually quite common. Scala, for example, will not compile w/o specific override notations.
     
  3. Offline

    EdGruberman

    Maybe I'm missing your point, but it's possible to define an annotation to manage parameter input for a method just as this solution is using an annotation to define parameters for the event callback. Your logic is seemingly conflicting. You indicate priority is metadata to the callback. You also indicate a method should operate correctly without metadata. How would these new event callback methods operate without defining priority?

    That is a compiler requirement to ensure proper syntax, not code/implementation logic. Event callbacks don't seem to be related to compiler functionality as I see things. This is my point I'm trying to make.
     
  4. Offline

    Afforess

    Lack of use does not mean the function is broken.

    Java will allow you to add new compile errors based on annotations. Would you like to have that added?
     
  5. Offline

    ZNickq

    Afforess
    Hmm, the formatting in that post looks odd :confused:
     
  6. Offline

    Captain Chaos

    Is this new event registration system more efficient or better performing than the previous way? In other words, is there any reason to update my plugins just to use this new event registration system, or can I wait until I'm releasing a new version anyway?
     
  7. Offline

    Afforess

    It is significantly faster in terms of performance.
     
  8. Offline

    Captain Chaos

    Ah OK, good to know. Thx.
     
  9. Offline

    EdGruberman

    You said "event priority is metadata to the event callback method". If priority is not defined, the event will not be called. That is a broken callback from an implementation view. I think we are bouncing back and forth between interface definitions and implementation definitions. I would think the goal of an API is to make things intuitive for the implementation.

    I'm not sure what you are suggesting here. Is there some way to have the compiler indicate there is a callback function that is not properly registered?

    Eh, maybe I just need to accept that this new system will simply require annotations and reflection to effectively implement and that is what Bukkit is going to encourage.
     
  10. Offline

    Afforess

    yes, exactly that.
     
  11. Offline

    Don Redhorse

    hmmm I did use:

    EntityDamageEvent damageEvent = event.getEntity().getLastDamageCause();
    log.debug("damageEvent", damageEvent.getType());

    but getType() is now deprecated. There is also no reference to a new way to accomplish something like this.

    Any idea? I'm still looking at the code but I'm not the fasted.
     
  12. Offline

    EdGruberman

    Are you suggesting tying compiler requirements directly to event callbacks? Wouldn't that just place another implementation restriction on the new system?

    Annotations, reflection, and compiler errors based on implementation all make me shudder, but again, if that is the direction of Bukkit, I'll adapt.
     
  13. Offline

    bergerkiller

    Afforess Just a redirection to here
    Shouldn't certain events also get a property or implemented interface to set if they can be used cross-threaded, and block cross-thread access natively? It doesn't make sense I have to manually check (from a plugin) to shield my and other plugins from 'roque' plugins as they are described now...
     
  14. Offline

    Sekonda

    So what would I need to do to change this

    Code:
    pm.registerEvent(Event.Type.PLAYER_CHANGED_WORLD, this.playerListener, Event.Priority.Normal, this);
    confused.com - new bukkit developer btw.
     
  15. Offline

    TheFieldZy

    Code:java
    1.  
    2. pm.registerEvents(playerListener, this);
    3.  

    Don't forget to do everything else in the actual listener class, like adding the annotation befor your listener method:
    Code:
    @EventHandler(priority = EventPriority.NORMAL)
    
    And to implement Listener rather than extending the deprecated classes.
     
  16. Offline

    Lolmewn

    in
    Code:
    @EventHandler(event = NAMEOFEVENT.class, priority = EventPriority.WHATPRIORITY)
    event is deprecated.
    Also, it's whining that the method is never locally used.. quite annoying.
    This is my code:[/FONT]
    Code:
    public void onEnable() {[/FONT][/FONT]
    [FONT=Consolas][FONT=Consolas]getServer().getPluginManager().registerEvents(new Listener(){[/FONT][/FONT]
    [FONT=Consolas][FONT=Consolas]@EventHandler(priority = EventPriority.NORMAL)[/FONT][/FONT]
    [FONT=Consolas][FONT=Consolas]public void onPlayerJoin(final PlayerJoinEvent event){[/FONT][/FONT]
     
    [FONT=Consolas][FONT=Consolas]}[/FONT][/FONT]
    [FONT=Consolas][FONT=Consolas]}, this);[/FONT][/FONT]
    [FONT=Consolas][FONT=Consolas]}
    [/code][/FONT][/code]

    -.- it's just impossible to remove those [fon t] thingies -.- [/FONT][/code][/FONT]

    I also have another question. How do you create your own events with the new system?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  17. Offline

    DiddiZ

    Is there a way to just register some events of a listener, or do I now have to put all events in seperate listeners if I still want to be able to toggle each?
     
  18. Offline

    EdGruberman

    Each in a separate listener, or I would assume you'd have to employ reflection to somehow disable individual annotations at run-time before you call the registerEvents method.

    The separate listener design is not so bad though as that actually mirrors the standard Observer pattern for event callbacks. It's definitely a lot of inbetween reflection and annotation infrastructure to get back to something so basic, but at least this new system doesn't prevent you from employing that standard design pattern in your implementation. You will still be forced to use reflection if you wish to change priority at runtime however. (Unless zml2008 pushes through on his idea of a new override for registration forcing EventPriority for the class also.)
     
  19. Offline

    Dudeman241

    How would I put something that says only one person can use this command. I am making a starterkit and was just wondering how I would do that and also what would I put for the registerEvent?
     
  20. Offline

    DiddiZ

    I see, ty.
    You check the player name in the command, but very wrong thread.
     
  21. Offline

    Dudeman241

    Sorry I got cut off at the "the" I did not finish. What would I put for the registerEvent thingy?
     
  22. Offline

    DiddiZ

    Nothing, as you're about to register a command, not an event.
     
  23. Offline

    Dudeman241

  24. Offline

    Tauryuu

    I'm so confuzzled. D:
     
  25. Offline

    drampelt

    I'm getting a NullPointerException using this and not sure what I'm doing wrong :confused:
    Error:
    Code:
    16:56:10 [SEVERE] Error occurred while enabling Daisy v2.0 (Is it up to date?): null
    java.lang.NullPointerException
            at org.bukkit.plugin.SimplePluginManager.registerEvents(SimplePluginManager.java:563)
            at ca.drmc.daisy.DaisyPlayerListener.<init>(DaisyPlayerListener.java:17)
            at ca.drmc.daisy.Daisy.onEnable(Daisy.java:28)
            at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:231)
            at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:1057)
            at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:379)
            at org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:191)
            at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:174)
            at net.minecraft.server.MinecraftServer.t(MinecraftServer.java:356)
            at net.minecraft.server.MinecraftServer.a(MinecraftServer.java:343)
            at net.minecraft.server.MinecraftServer.init(MinecraftServer.java:175)
            at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:407)
            at net.minecraft.server.ThreadServerApplication.run(SourceFile:465)
    
    Source file:
    Code:
    package ca.drmc.daisy;
     
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
     
    public class DaisyPlayerListener implements Listener{
    private Daisy plugin;
     
    public DaisyPlayerListener(){
    ---> Bukkit.getServer().getPluginManager().registerEvents(this, plugin); <-- NPE Right here (line 17)
    }
     
    @EventHandler(priority = EventPriority.NORMAL)
    public void onPlayerJoin(final PlayerJoinEvent event){
    <blah blah blah>
    }
    }
    }
    
     
  26. you didn't setted your plugin variable.
     
  27. Offline

    drampelt

    private Daisy plugin;
    Correct me please if I'm wrong, but I set it fine I believe
     
  28. yeah, but you didn't setted a value to it. sorry if you misunderstood.
     
  29. Offline

    drampelt

    How would I do that then? Not sure what you mean :/
     
  30. Offline

    Sagacious_Zed Bukkit Docs

Thread Status:
Not open for further replies.

Share This Page