NoCheatPlus/NCPCore/src/main/java/fr/neatmonster/nocheatplus/event/mini/EventRegistryBukkit.java

240 lines
9.1 KiB
Java

/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.event.mini;
import java.lang.reflect.Method;
import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin;
import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName;
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder;
/**
* A MultiListenerRegistry that registers Bukkit types with a Spigot/CraftBukkit
* server.
*
* <br>
* Listener registration for {@link org.bukkit.event.Listener}, checking methods
* for {@link org.bukkit.event.EventHandler}. <br>
* <br>
* Supports passing a defaultOrder, as well as the per-class annotation
* {@link fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterEventsWithOrder},
* and the per-method annotation
* {@link fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder}.
* <br>
* Priority (FCFS): RegisterMethodWithOrder, RegisterEventsWithOrder,
* defaultOrder
*
* <br>
* <br>
* For alternatives and more details and conventions see:
* {@link fr.neatmonster.nocheatplus.event.mini.MiniListenerRegistry}<br>
*
*
* @author asofold
*
*/
public class EventRegistryBukkit extends MultiListenerRegistry<Event, EventPriority> {
/**
* Node for events that implement the Cancellable interface (Bukkit).
*
* @author asofold
*
* @param <E>
*/
protected static class CancellableNodeBukkit<E> extends MiniListenerNode<E, EventPriority> {
public CancellableNodeBukkit(EventPriority basePriority) {
super(basePriority);
}
// TODO: Future java: E extends Cancellable ?
@Override
protected boolean isCancelled(E event) {
return ((Cancellable) event).isCancelled();
}
}
private final Plugin plugin;
/**
* Pass this listener with each event registration to the
* {@link org.bukkit.plugin.PluginManager}.
*/
private final Listener dummyListener = new Listener() {}; // TODO: Get from NCP ?
public EventRegistryBukkit(Plugin plugin) {
this.plugin = plugin;
nodeFactory = new NodeFactory<Event, EventPriority>() {
@Override
public <E extends Event> MiniListenerNode<E, EventPriority> newNode(Class<E> eventClass, EventPriority basePriority) {
if (Cancellable.class.isAssignableFrom(eventClass)) {
// TODO: Check if order is right (eventClass extends Cancellable).
// TODO: Future java (see above) ?
return new CancellableNodeBukkit<E>(basePriority);
} else {
return new MiniListenerNode<E, EventPriority>(basePriority);
}
}
};
// Auto register for plugin disable.
// TODO: Ensure the ignoreCancelled setting is correct (do listeners really not unregister if the event is cancelled).
register(new MiniListener<PluginDisableEvent>() {
@Override
public void onEvent(PluginDisableEvent event) {
unregisterAttached(event.getPlugin());
}
}, EventPriority.MONITOR, new RegistrationOrder("nocheatplus.system.registry", null, ".*"), true);
}
@Override
protected <E extends Event> void registerNode(final Class<E> eventClass,
final MiniListenerNode<E, EventPriority> node, final EventPriority basePriority) {
Bukkit.getPluginManager().registerEvent(eventClass,
dummyListener,
basePriority, new EventExecutor() {
@SuppressWarnings("unchecked")
@Override
public void execute(Listener dummy, Event event) throws EventException {
if (eventClass.isAssignableFrom(event.getClass())) {
node.onEvent((E) event);
}
}
}, plugin, false);
}
/**
* Convenience method to have a listener unregister with disabling a plugin.
*
* @param listener
* Do not call with a plugin class being the listener, use the
* other register method instead!
* @param plugin
*/
public void register(Listener listener, Plugin plugin) {
register(listener, null, plugin);
}
/**
* Convenience method to have a listener unregister with disabling a certain
* other plugin.
*
* @param listener
* Do not call with a plugin class being the listener, use the
* other register method instead!
* @param defaultOrder
* @param plugin
* @see {@link #register(Listener, RegistrationOrder)}
*/
public void register(Listener listener, RegistrationOrder defaultOrder, Plugin plugin) {
attach(internalRegister(listener, defaultOrder), plugin);
}
/**
* Register the given listener similar to
* {@link org.bukkit.plugin.PluginManager#registerEvents(Listener, Plugin)}.
* <br>
* All events are registered for the plugin that was passed upon creation of
* this registry (supposedly NoCheatPlus).
*
* @param listener
* @see {@link #register(Listener, RegistrationOrder)}
*/
public void register(Listener listener) {
register(listener, (RegistrationOrder) null);
}
/**
* Register the given listener similar to
* {@link org.bukkit.plugin.PluginManager#registerEvents(Listener, Plugin)}.
* <br>
* All events are registered for the plugin that was passed upon creation of
* this registry (supposedly NoCheatPlus). Methods are selected by presence
* of the annotation {@link org.bukkit.event.EventHandler}.
* <hr>
* Supports passing a defaultOrder, as well as the per-class annotation
* {@link fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterEventsWithOrder},
* and the per-method annotation
* {@link fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder}.
* <br>
* Priority (FCFS): RegisterMethodWithOrder, RegisterEventsWithOrder,
* defaultOrder
*
* <br>
* <br>
* If no order is given, but the listener implements ComponentWithName, a
* RegistrationOrder with the component name as tag is created. <br>
* <br>
* <br>
* For alternatives and more details and conventions see:
* {@link fr.neatmonster.nocheatplus.event.mini.MiniListenerRegistry}<br>
*
* @param listener
* @param defaultOrder
*/
public void register(Listener listener, RegistrationOrder defaultOrder) {
internalRegister(listener, defaultOrder);
}
private Collection<MiniListener<? extends Event>> internalRegister(Listener listener,
RegistrationOrder defaultOrder) {
// Note: default ignoreCancelled and priority should have no effect, as EventHandler sets the defaults anyway.
// NCP for convenience: tag by component name, if no order is given.
if (defaultOrder == null && listener instanceof ComponentWithName) {
defaultOrder = new RegistrationOrder(((ComponentWithName) listener).getComponentName());
}
return super.register((Object) listener, EventPriority.NORMAL, defaultOrder, false);
}
@Override
protected boolean shouldBeEventHandler(Method method) {
return method.getAnnotation(EventHandler.class) != null;
}
@Override
protected boolean getIgnoreCancelled(Method method, boolean defaultIgnoreCancelled) {
EventHandler info = method.getAnnotation(EventHandler.class);
if (info == null) {
return defaultIgnoreCancelled;
}
else {
return info.ignoreCancelled();
}
}
@Override
protected EventPriority getPriority(Method method, EventPriority defaultPriority) {
EventHandler info = method.getAnnotation(EventHandler.class);
if (info == null) {
return defaultPriority;
}
else {
return info.priority();
}
}
}