Now before I start to show you what I have to show you, I personally don't have/can't find a purpose to use this and I must warn you that you can seriously mess with plugins unless you are 100% sure of what you know you want. The question that I've seen occasionally on Bukkit: Pretty much everybody's answer is "you can't". That got me thinking though because I honestly never tried to see if the usual answer is right and the truth is that you actually can cancel events with certain priorities. Now there is usually a better alternative that the OP of the question can take, but as I was playing around with this, I also realized that you can have event priorities below LOWEST and higher than MONITOR. Some of you may have noticed that Bukkit has a RegisteredListener class. You might have guessed it by now, but this event priority manipulation can be accomplished with that class. The class provides these methods right here: callEvent(Event) getListener() getPlugin() getPriority() isIgnoringCancelled() Here is a basic example showing the event priorities in action. Code: public class EventPriorityTest extends JavaPlugin implements Listener { @Override public void onEnable() { Bukkit.getPluginManager().registerEvents(this, this); } @EventHandler(priority = EventPriority.LOWEST) public void lowestEvent(PlayerMoveEvent event) { eventTest(event, ChatColor.RED + "Lowest"); } @EventHandler(priority = EventPriority.LOW) public void lowEvent(PlayerMoveEvent event) { eventTest(event, ChatColor.GOLD + "Low"); } //Default @EventHandler(priority = EventPriority.NORMAL) public void normalEvent(PlayerMoveEvent event) { eventTest(event, ChatColor.YELLOW + "Normal"); } @EventHandler(priority = EventPriority.HIGH) public void highEvent(PlayerMoveEvent event) { eventTest(event, ChatColor.GREEN + "High"); } @EventHandler(priority = EventPriority.HIGHEST) public void highestEvent(PlayerMoveEvent event) { eventTest(event, ChatColor.AQUA + "Highest"); } @EventHandler(priority = EventPriority.MONITOR) public void monitorEvent(PlayerMoveEvent event) { eventTest(event, ChatColor.LIGHT_PURPLE + "Monitor"); } private void eventTest(PlayerMoveEvent event, String s) { if (!event.getTo().toVector().equals(event.getFrom().toVector())) { Bukkit.broadcastMessage(s); } } } Now when the event gets called, the messages get sent in this order (like it should): Lowest Low Normal High Highest Monitor If we want to start to mix things up a bit, it's time to make our own RegisteredListener wrapper class. Here is one. Code: public class RegisteredListenerWrapper extends RegisteredListener { private RegisteredListener registeredListener; public RegisteredListenerWrapper(RegisteredListener registeredListener) { //Filling in bogus info because it's required super(null, null, null, null, false); this.registeredListener = registeredListener; } @Override public Listener getListener() { return registeredListener.getListener(); } @Override public Plugin getPlugin() { return registeredListener.getPlugin(); } @Override public EventPriority getPriority() { return registeredListener.getPriority(); } @Override public void callEvent(Event event) throws EventException { registeredListener.callEvent(event); } @Override public boolean isIgnoringCancelled() { return registeredListener.isIgnoringCancelled(); } } You may replace Bukkit's RegisteredListeners with the wrapper by doing something like this: Code: //If you want to replace all listeners with the wrapper for(RegisteredListener rl : PlayerMoveEvent.getHandlerList().getRegisteredListeners()) { //Unregister the current registered one so we don't have duplicates PlayerMoveEvent.getHandlerList().unregister(rl); //Stuffing in your wrapper RegisteredListener PlayerMoveEvent.getHandlerList().register(new RegisteredListenerWrapper(rl)); } Now that we have full control in what goes on in the RegisteredListener, we could do something like this in the class: Code: @Override public EventPriority getPriority() { if(registeredListener.getPriority() == EventPriority.MONITOR) return EventPriority.HIGH; return registeredListener.getPriority(); } Now if we call the events from the basic example plugin, the messages are now sent in this order: Lowest Low Normal High Monitor Highest Notice anything weird? If you want to have an above MONITOR or below LOWEST event priority, you could do something like this: Code: @Override public void callEvent(Event event) throws EventException { //Below LOWEST event priority code here registeredListener.callEvent(event); //Above MONITOR event priority code here } If you want to completely remove a plugin's event or a certain priority, you might do something like this: Code: for (RegisteredListener rl : <Event of choice>.getHandlerList().getRegisteredListeners()) { if (rl.getPlugin().getName().equals("plugin name here") && rl.getPriority() == EventPriority.MONITOR) { <Event of choice>.getHandlerList().unregister(rl); } } There is a lot you can do with this and I have just shown a few examples of what you can do. To tell you the truth, as I was writing this, I realized that it is entirely possible to create a plugin that can make events on MONITOR truly unmodifiable.
@teej107 This is certainly an interesting concept. I could see it being useful for logging plugin (post monitor), and perhaps for creating a framework with additional priorities.
@teej107 Very interesting ideas in here! It opened my eyes to the fact that we can extend the Events API. What you can do with this: a better Events API? I could: Use numeric event priorities (instead of enum). Add a better way to unregister certain handlers (make sure users don't need to deal at all with the HandlersList mess). Add a non-reflective way of handling events (for example, have a EventHandler2<E extends Event> interface). As you pointed out, prevent monitor handlers from modifying an event (e.g. it throws an exception if you try to). I have seen many custom commands APIs, but can't say the same for events. I'd definitely switch to any API that offers what I listed above.