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

    obnoxint

    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

    croxis

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

    obnoxint

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

    feildmaster Retired Staff

    What?

    EDIT:

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

    Afforess

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

    Zacherl

    Strange. I keep getting "IncompleteAnnotationException: org.bukkit.event.EventHandler missing element event". Im using the latest build from here:
    http://forums.bukkit.org/threads/jenkins-temporarily-unavailable.55174/#post-916651
    Show Spoiler
    Code:
    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
    rce)
            at $Proxy12.event(Unknown Source)
            at org.bukkit.plugin.java.JavaPluginLoader.createRegisteredListeners(Jav
    aPluginLoader.java:990)
            at org.bukkit.plugin.SimplePluginManager.registerEvents(SimplePluginMana
    ger.java:432)
            at me.zacherl.distantfarm.DistantFarm.onEnable(DistantFarm.java:443)
            at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:232)
            at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader
    .java:1034)
            at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManage
    r.java:252)
            at org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:190)
            at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:173
    )
            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)

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

    md_5: Any suggestions?
     
  9. Offline

    hatstand

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

    Zacherl

  11. Offline

    K_Cin

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

    hatstand

  13. Offline

    zml2008

    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

    ItsHarry

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

    ArcheCane

    Love, you! :3
     
  16. Offline

    MrMag518

    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?

    EDIT 3: AND NOW ITS WORKING AGAIN, WTH IS GOING ON BUKKIT?!
     
  17. Offline

    GeMoschen

    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

    Zacherl

    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

    GeMoschen

    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

    zml2008

    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

    GeMoschen

    This is GREAT! [diamond]
     
  24. Offline

    WizzleDonker

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

    EdGruberman Retired Staff

    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

    AmoebaMan

    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

    bergerkiller

    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?
    Code:
    @EventHandler(priority = EventPriority.MONITOR)
    public class PlayerListener implements Listener {
    I get this error:
    Or is this simply not possible to do?
     
  28. Offline

    blainicus

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

    MrMag518

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

    Afforess

    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

    EdGruberman Retired Staff

    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