New Event System

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

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


    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.
    1. package com.md_5.noclip.listeners;
    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;
    10. public class NoClipPlayerListener extends PlayerListener{
    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. }

    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:

    1. package com.md_5.noclip.listeners;
    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;
    9. public class NoClipPlayerListener implements Listener {
    11. public NoClipPlayerListener() {
    12. Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
    13. }
    15. @EventHandler(priority = EventPriority.LOW)
    16. public void onPlayerJoin(final PlayerJoinEvent event) {
    17. }
    18. }

    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:
    The syntax goes like this:
        @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:
    1. @EventHandler(priority = EventPriority.LOW)
    2. public void whenThePlayerMoves(final PlayerMoveEvent event) {
    3. }

    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


    Snapshots? No. Maven is not a build tool.
    Or do you mean the repo contents? They should be getting updated everytime you start eclipse (by default). Propably you need to repull the git repo, if you are using maven with git.
  3. Offline


    Never mind. I don't know why i even bother trying sometimes.
  4. Offline


    Why shouldn't you try? Are you already aware of this?
  5. Offline




    Clean and Build your project to update the (local) maven repo
  6. Offline


    Irony being that the pull request came from Spout. ;)
  7. Cool, thank ya. This makes things ALOT better and easier!
  8. Offline


    Strange. I keep getting "IncompleteAnnotationException: org.bukkit.event.EventHandler missing element event". Im using the latest build from here:
    Show Spoiler
    17:13:31 [SCHWERWIEGEND] Error occurred while enabling CHDistantFarm v1.04 (Is i
    t up to date?): org.bukkit.event.EventHandler missing element event
    java.lang.annotation.IncompleteAnnotationException: org.bukkit.event.EventHandle
    r missing element event
            at sun.reflect.annotation.AnnotationInvocationHandler.invoke(Unknown Sou
            at $Proxy12.event(Unknown Source)
            at org.bukkit.plugin.SimplePluginManager.registerEvents(SimplePluginMana
            at me.zacherl.distantfarm.DistantFarm.onEnable(
            at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManage
            at org.bukkit.craftbukkit.CraftServer.loadPlugin(
            at org.bukkit.craftbukkit.CraftServer.enablePlugins(
            at net.minecraft.server.MinecraftServer.t(
            at net.minecraft.server.MinecraftServer.a(
            at net.minecraft.server.MinecraftServer.init(

    It seems like the api is updated, but the latest build still needs the deprecated event annotation parameter.

    md_5: Any suggestions?
  9. Offline


    Any information on doing custom events with this?
  10. Offline


  11. Offline


    I can't figure out how to fetch variables in this new version, because this works:
    public void playerChat(PlayerChatEvent event) {
    //some code   
    But this doesn't:
    public void playerChat(PlayerChatEvent event, Player player) {
    //some code   
    [SEVERE] Wrong method arguments used for event type registered
  12. Offline


  13. Offline


    You need to get the objects you need from the event. For example, for player events you'd do event.getPlayer() to get the player.
  14. Offline


    Does onCommand still work the same way? :D
  15. Offline


    Love, you! :3
  16. Offline


    It seems to work, but the bukkit doesn't do any actions with the config file(s)?
    The config doesn't work at all, its generating the folder, and writtes the nodes into it, but does not do any actions with them in-game..

    EDIT: I got it.. bukkit doesn't support the if (plugin.config.getBoolean(...), true) anylonger..
    You have to type, if (plugin.getConfig().getBoolean(...), true) now..

    EDIT 2: wow, that seems to stop working to.. wtf is going on?

  17. Offline


    Okay, I got a problem with the new Eventsystem.

    What I've done with the last Eventsystem:
    1. My plugin reads the event-priority out of a config (this helps to be compatible to other plugins)
    2. Now it registers the events with the given priority

    With the new system, I can't find a way to do this without using Java-Reflections.. Did I miss anything, or is there simply no way to read the Priorities out of a config and change the level with the given priority?

    Using reflections should NOT be the goal of the new system :/
  18. To be honest I liked the old system.
    Technius, GeMoschen and MrMag518 like this.
  19. Offline


    GeMoschen: The only way i see, is registering a method for each priority. But i see no valid reason for reading the priorities out of a config file.
  20. Offline


    The reason is, that serverowners can adjust the event-level if they have compatibility-problems with other plugins.

    Not every plugin-dev is using "event.isCancelled()" (although they should) and this 'causes the incompatibilty sometimes. When you save the level in a config, you can adjust it.
  21. Offline

    Liam Allan

    This new system seem's good, but I think I'll keep to the old one for now (Seeing as it still works)...
  22. Offline


    I'll put up a bleeding branch with a registration option that forces all listeners in a class that will be registered to a specific priority some time in the next few days. That should resolve your issue once it is merged.
  23. Offline


    This is GREAT! [diamond]
  24. Offline


    I find myself loving this new event system.
  25. Offline


    Forcing an entire class to the same priority seems like a workaround rather than a proper solution. So instead of being able to merge a variety of events with a variety of run-time defined priorities, I need to create separate classes once again. This seems to be walking away from a primary goal of the redesign.

    While I do like the simplicity of this new system, annotations seem to be a form of meta-coding and this problem underlines my concern. Why were annotations chosen and not simply a standard method like before but with the local instance handler tracking approach? Is all this being overthought? Are annotations simply being used because of their perceived novelty, or is there some other benefit to them that I'm overlooking?
  26. Offline


    I know a lot of people that are a bit irritated about this change, but personally I like the new system. It'll be nice to not have to make 10-line classes just to cancel a single event.
  27. Offline


    Wow I love this new feature, thanks Afforess and Spout for making this.

    Now that the new RB is out I was finally able to throw away the old junk, and instead of having 5 classes, I know have just 2 :)

    This is best for TrainCarts, since I can now add new events very easily without supplying custom listener classes or other weird shenanigans.

    ONE question.

    Could you allow this annotation to be added in the class body?
    @EventHandler(priority = EventPriority.MONITOR)
    public class PlayerListener implements Listener {
    I get this error:
    Or is this simply not possible to do?
  28. Offline


    Should the old system still work perfectly fine?
  29. Offline


    It's depracted and will be removed by time, It's recommended to change to the new system immediately.
  30. Offline


    Reflection allows analytical analysis of metadata for classes, methods, and fields. The event priority is metadata to the event callback method, therefore using reflection is logical, not wrong.

    I agree. The solution is to leave the system as is.

    Annotations provide metadata to classes, methods and fields. This is a logical extension of such a system.
  31. Offline


    Afforess - Any method's parameters are metadata to the method. We could just define annotations for all method parameters and use annotations exclusively for everything with that logic.

    Metadata for coding seems a role that fits much better for compiler type interactions, not for the needs of a Plugin Developer's plugin. It's logical for things like @Override or @Deprecated as it assists the developer's efforts within the IDE. Forcing a metadata dependency for code logic seems counter intuitive at the minimum.

    I'm still not clear why a more conventional programming pattern isn't being employed here. I know Java is not the most concise when it comes to a callback design. My assumption is this annotation approach is being used to circumvent the standard approach of creating an individual class for each event callback. Is there no standard design pattern for event callbacks that would be appropriate here?

    All said and done creating individual callback classes for each event really shouldn't be considered as bad as most people seem to think it is. I even started programming Java myself trying to avoid creating classes wherever possible. I've since learned that is akin to trying to make as few methods as possible. Both are ignorant approachs to well-designed object oriented programming.

    I don't mean to stir the pot too much here, but at the same time if a new system is being tested, no time like the present to question it in detail.
Thread Status:
Not open for further replies.

Share This Page