Custom events

Discussion in 'Plugin Development' started by matejdro, Feb 21, 2011.

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

    matejdro

    I saw getServer().getPluginManager().registerEvent. Do that means that we can register custom events? Is there any documentation about that?
     
  2. Offline

    PrivateAlpha

    Bump!

    I want to know this too!
     
  3. Offline

    Cheesier

    I'd love to register custom events as it will be a big part of my plugin.
     
  4. Offline

    Raphfrk

    There is a slight inefficiency in that you will receive all custom events and can't register for specific ones. You must check the event name

    I added a pull that allows you to register for specific events, but it hasn't been pulled yet.
    --- merged: Feb 22, 2011 11:25 AM ---
    Hmm, auto-merge ate my previous post.

    This is an example of a custom event:

    Code:
    public class RunnableEvent extends Event {
    
    	Runnable runnable;
    
        public RunnableEvent(final Runnable runnable) {
            super("ServerPortRunnableEvent");
            this.runnable = runnable;
        }
    
    }
    
    This is an example of the listener:

    Code:
    public class ServerPortCustomListener extends CustomEventListener implements Listener {
    
        JavaPlugin serverPort = null;
    
        ServerPortListenerCommon serverPortListenerCommon;
    
        ServerPortCustomListener( ServerPortBukkit serverPort ) {
            this.serverPort = serverPort;
            this.serverPortListenerCommon = serverPort.serverPortListenerCommon;
        }
    
        public void onCustomEvent(Event event) {
    
            if( !event.getType().equals(Type.CUSTOM_EVENT) ) {
                return;
            }
    
            if( !event.getEventName().equals("ServerPortRunnableEvent")) {
                return;
            }
    
            ((RunnableEvent)event).runnable.run();
    
        }
    }
    
     
  5. Offline

    matejdro

    Wow, thanks. I will definitely check that out.
     
  6. Offline

    Cheesier

    I don't really get this, could you post an example file using all this, I'm very confused :)
     
  7. Offline

    Raphfrk

    Those 2 pieces of code are the class files.

    The only thing missing is how to trigger the event

    You do that with

    Code:
    RunnableEvent runnableEvent = new RunnableEvent(runnable)
    
    getServer().getPluginManager().callEvent(runnableEvent);
    
    In this case, you pass a Runnable to the constructor, but in practice, you can create the custom event so that it does whatever you want.
     
  8. Wait, I think I know this one.
    *started coding*
     
  9. Offline

    Cheesier

    Okay but passing information to the onCustomEvent, how is that done?

    Would be fantastic ! :)
     
  10. Listener:
    Code:
    import org.bukkit.event.CustomEventListener;
    import org.bukkit.event.Event;
    
    public class CustomListener extends CustomEventListener{
    
        public void onCustomEvent(CustomEvent event){
            onCustomEvent(event);
        }
        public void onCustomEvent(Event ev){
            CustomEvent event = (CustomEvent)ev;
            CustomEvent.Reason Reason = event.getReason();
    
            if(Reason == CustomEvent.Reason.RIGHTCLICK){
                //TO-DO when you right clicked something
            } else
            if(Reason == CustomEvent.Reason.OTHER_REASON){
                //TO-DO when ... something else?
            }
        }
    }
    The Event:
    Code:
    import org.bukkit.event.Event;
    import org.bukkit.event.Cancellable;
    
    @SuppressWarnings("serial")
    public class CustomEvent extends Event implements Cancellable{
        private Reason reason;
        private boolean isCancelled = false;
    
        protected CustomEvent(Reason reason) {
            super(Event.Type.CUSTOM_EVENT);
            this.reason = reason;
        }
    
        @Override
        public boolean isCancelled() {
            return isCancelled;
        }
    
        @Override
        public void setCancelled(boolean arg0){
            isCancelled = arg0;
        }
    
        public Reason getReason(){
            return this.reason;
        }
    
        public enum Reason{
            RIGHTCLICK,
            OTHER_REASON
        }
    
    }
    To call the event
    Code:
    CustomEvent event = new CustomEvent(CustomEvent.Reason.RIGHTCLICK);
    CustomListener.onCustomEvent(event);

    Haven't tested it, but you all know what I mean with it right?? :p
    --- merged: Mar 5, 2011 5:33 PM ---
    I tought it would work if you extended the Event class but the onCustomEvent can only call the Event class
    --- merged: Mar 5, 2011 5:34 PM ---
    BTW: I know it isn't working with the
    getServer().getPluginManager().callEvent(runnableEvent);
    But who cares?
     
  11. Offline

    Cheesier

    Thank you, now i just need to sort out what is what :)
    --- merged: Mar 5, 2011 5:47 PM ---
    Will this work for others plugin trying to catch the event ? I need a way to call all the plugins listening to my event
     
  12. I don't know yet how to do that. It will only call the event for the plugin itself
     
  13. Offline

    Raphfrk

    That sends the event to all plugins that are listening to the custom event type. (This is in fact, pretty inefficient, ideally they should be able to register for specific custom events).
     
  14. Offline

    Cheesier

    Hmm, getting an error
    Code:
    java.lang.IllegalArgumentException: use Event(String) to make custom events
    Error located at my CustomEvent constructor, error on this line:
    Code:
    super(Event.Type.CUSTOM_EVENT);
    And also, how can i trigger the event in another plugin ?
     
  15. I´m sorry, to be honest I have no idea. Never really worked with the custom event. Sorry

    BTW: Try to rename "Event.Type.CUSTOM_EVENT" to a String type ("Custom Event" or something)
     
  16. Offline

    Raphfrk

    A custom event is created using the String type constructor.

    You would use

    super("The name of the custom event");
     
  17. Offline

    Cheesier

    Imma test it out, hold yer thumbs fer me will ye ? :)

    Edit: It dosen't give out errors anymore :) Thanks!
    --- merged: Mar 6, 2011 12:14 PM ---
    Eh, one more thing, now that i have a working Event. Do I really need to have the Listener in my plugin? I just want to give other plugins the event.
    --- merged: Mar 6, 2011 12:39 PM ---
    Calling onCustomEvent(CustomEvent event) will get you stuck in a loop, as it calls itself

    Im still confused about triggering the event, as i think this way will only call my Event ? In a static way too... Correct me if I'm wrong
     
  18. Offline

    Raphfrk

    You call events using
    getServer().getPluginManager().callEvent(event);

    Note:
    this doesn't do resyncing to the main thread, if you call an event from another thread, it could cause problems.

    Also, if you are only sending custom events, then you don't need the listener.
     
  19. Offline

    Cheesier

    Fantastic! Off to test this now! :)
    --- merged: Mar 6, 2011 1:52 PM ---
    Hmm, the listener don't seem to get the event being triggered, i know that the event is sent but its not recived, sending my event to lets say the playerListerner gives me errors as i expected, sending it to the customListerner wont do a thing...

    Probably something wrong in CustomListener.java
    Code:
    public class CustomListener extends CustomEventListener {
    
        public void onCustomEvent(RoomyEvent event) {
            onCustomEvent(event);
            System.out.println("Event was done!");
        }
        public void onCustomEvent(Event ev) {
            System.out.println("Event was done!");
            RoomyEvent event = (RoomyEvent)ev;
            RoomyEvent.Reason Reason = event.getReason();
    
            if(Reason == RoomyEvent.Reason.ROOM_CHANGE) {
                //Player entered the room
                event.getPlayer().sendMessage("Entered/Left a room! :)");
            }
        }
    }
    Edit: the sender and the listeners are in different .JAR files, but ive included the Event Jar file into the other Listener.
     
  20. Offline

    Raphfrk

    Normally the way to include the other classes is to specify that include the other .jar file like you include the bukkit jar file.

    Have you registered the event in the receiver plugin?

    getServer().getPluginManager().registerEvent(Type.CUSTOM_EVENT, customEventListener, Priority.Normal, this)

    Also, you might have an infinite loop there. If you pass a RoomyEvent, then it will call the first function over and over.
    --- merged: Mar 6, 2011 4:19 PM ---
    Also, it might be worth using the @Override to make sure it is working properly.
     
  21. Offline

    Cheesier

    Yes i know about the infinite loop, i comented it away when i ran the code

    Code:
    // Changing this
    public class CustomListener extends CustomEventListener {
    
    // To this
    public class CustomListener extends CustomEventListener implemets listener {
    Forgot to tell that it worked like 10 minutes after my last post.
     
  22. Offline

    Raphfrk

    Great
     
  23. Offline

    amkeyte

    Not always useful, but in my case I was able to use an abstract class to start out the sorting process, and create methods that would seem more useful:

    Code:
    /**
     * abstract because it should not be instanciated. 
     * methods are not abstract because overriding event methods should be optional.
     * This allows you to choose which to respond to.
     * @author Aaron
     *
     */
    public abstract class PermsReceptacleEventListener extends CustomEventListener {
        /**
         * main event handler. filter out non-PermsReceptacleEvent events
         * return unhandled for filtered events.
         */
        @Override
        public void onCustomEvent(Event event) {
            if (event instanceof PermsReceptacleEvent) {
                onPermsReceptacleEvent((PermsReceptacleEvent) event);
            }
        }
    
        /**
         * sort by event reason.
         * override to handle non-sorted events (optional)
         * @param event
         */
        public void onPermsReceptacleEvent(PermsReceptacleEvent event) {
            switch (event.getReason()) {
            case ALLOW:
                onPermsReceptacleAllowEvent(event);
                break;
            case DENY:
                onPermsReceptacleDenyEvent(event);
                break;
            case DEFAULT:
                onPermsReceptacleDefaultEvent(event);
            }
        }
    
        /**
         * named event handler for extended listener
         * @param event
         */
        public void onPermsReceptacleDefaultEvent(PermsReceptacleEvent event) {
            // place holder for override -- do nothing
        }
        /**
         * named event handler for extended listener
         * @param event
         */
        public void onPermsReceptacleDenyEvent(PermsReceptacleEvent event) {
            // place holder for override -- do nothing
        }
        /**
         * named event handler for extended listener
         * @param event
         */
        public void onPermsReceptacleAllowEvent(PermsReceptacleEvent event) {
            // place holder for override -- do nothing
        }
    }
    
    }
    After, I extent this base class for use in my plugin:

    Code:
    public class ShirtsAndSkinsPermissionListener extends PermsReceptacleEventListener {
    
        @SuppressWarnings("unused")
        private final ShirtsAndSkins plugin;
    
        public ShirtsAndSkinsPermissionListener(ShirtsAndSkins plugin) {
            this.plugin = plugin;
        }
    
        @Override
        public void onPermsReceptacleDenyEvent(PermsReceptacleEvent event) {
            Player player = (Player) event.getSender();
            String eventName = event.getLockName().toPermissionString();
    
            ShirtsAndSkins.log(Level.INFO, "Permission was denied: " + player.getName() + " : " + eventName);
        }
    
        @Override
        public void onPermsReceptacleAllowEvent(PermsReceptacleEvent event) {
            String permissionString = event.getLockName().toPermissionString();
            CommandSender sender = event.getSender();
            String playerName = null;
    
            if (sender instanceof Player){
                playerName = ((Player) event.getSender()).getName();
            } else if (sender instanceof ConsoleCommandSender){
                playerName = "Console";
            } else {
                playerName = "Unkown Sender";
            }
                
            ShirtsAndSkins.log(Level.INFO, "Permission was allowed: " + playerName + " : " + permissionString);
        }
    }
    
    If you supply a non-generic listener class for extension then your custom event can act like a non-custom event.

    A question arises, however... Is it possible to assign several CustomEventListeners to a single plugin and have it work? Or would it only push the event to one of my listeners? (does that make sense?)


    Anyway... Thanks all for this thread as it helped me understand how to use the custom events.
    Hope my input helps someone else...
     
Thread Status:
Not open for further replies.

Share This Page