From 10b4800ac9183d28fe1fe816fc69cb78ef383ed7 Mon Sep 17 00:00:00 2001 From: carm Date: Sat, 25 Jun 2022 04:50:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(api):=20=E6=8F=90=E4=BE=9Bfunctional?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=96=B9=E5=BC=8F=EF=BC=8C=E9=A2=84=E8=AE=BE?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=8F=90=E4=BE=9B=E6=96=B9=E5=BC=8F=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: 大部分API的实现方式发生变革,与先前版本并不兼容。 --- README.md | 33 +-- pom.xml | 2 +- .../carm/lib/easylistener/EasyListener.java | 251 +++++++++--------- .../lib/easylistener/ListenerManager.java | 103 ------- .../defaults/CommonListeners.java | 123 +++++++++ .../easylistener/defaults/EventFilters.java | 82 ++++++ .../easylistener/defaults/EventHandlers.java | 34 +++ .../handler/BaseEventHandler.java | 50 ++++ .../handler/BundleEventHandler.java | 117 ++++++++ .../handler/MultiEventHandler.java | 58 ++++ .../handler/SingleEventHandler.java | 42 +++ src/test/java/DemoPlugin.java | 56 ++-- 12 files changed, 677 insertions(+), 274 deletions(-) delete mode 100644 src/main/java/cc/carm/lib/easylistener/ListenerManager.java create mode 100644 src/main/java/cc/carm/lib/easylistener/defaults/CommonListeners.java create mode 100644 src/main/java/cc/carm/lib/easylistener/defaults/EventFilters.java create mode 100644 src/main/java/cc/carm/lib/easylistener/defaults/EventHandlers.java create mode 100644 src/main/java/cc/carm/lib/easylistener/handler/BaseEventHandler.java create mode 100644 src/main/java/cc/carm/lib/easylistener/handler/BundleEventHandler.java create mode 100644 src/main/java/cc/carm/lib/easylistener/handler/MultiEventHandler.java create mode 100644 src/main/java/cc/carm/lib/easylistener/handler/SingleEventHandler.java diff --git a/README.md b/README.md index b9ed228..c2ed7d8 100644 --- a/README.md +++ b/README.md @@ -12,43 +12,18 @@ ### [开发示例](src/test/java/DemoPlugin.java) -您可以点击这里访问项目的 [JavaDoc](https://carmjos.github.io/EasyListener) 。 +相关开发示例请 [点击这里](src/test/java/DemoPlugin.java),您也可以直接访问项目的 [JavaDoc](https://carmjos.github.io/EasyListener) 。 ```java public class DemoPlugin extends JavaPlugin { - protected final EasyListener listeners = EasyListener.create(this); - @Override public void onEnable() { - listeners // 基本用法 - .handle(PlayerInteractAtEntityEvent.class, (event) -> { - Entity clicked = event.getRightClicked(); - Player player = event.getPlayer(); - - if (clicked instanceof Player) { - player.sendMessage("你点了 " + clicked.getName() + " 一下!"); - } - - }) // 处理一个事件 - .cancel(PlayerPickupArrowEvent.class) // 取消一个事件 - .cancel( - EntityDamageEvent.class, EventPriority.HIGHEST, - (event) -> event.getCause() != EntityDamageEvent.DamageCause.ENTITY_ATTACK - ); // 有条件的取消一个事件 - - listeners // 额外提供的快捷方法 - .cancelDeath(null) // 所有玩家取消死亡 - .cancelBreak(player -> !player.isOp()) // 禁止非OP玩家破坏方块/接水或岩浆 - .cancelPlace(player -> !player.isOp()) // 禁止非OP玩家放置方块/放水或岩浆 - .cancelPVP((attacker, victim) -> !attacker.isOp()) // 禁止非op玩家PVP - .cancelWeatherChange() // 取消天气变更 - .cancelJoinMessage() // 取消加入消息 -// .cancelQuitMessage() -// .handleJoinMessage(player -> "玩家 " + player.getName() + " 加入了服务器。") - .handleQuitMessage(player -> "玩家 " + player.getName() + " 退出了服务器。"); // 设定退出消息 + EasyListener listeners = EasyListener.create(this); + // listeners...; // Do something... } + } ``` diff --git a/pom.xml b/pom.xml index b337927..e2d8754 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ cc.carm.lib easylistener - 1.2.0 + 2.0.0 jar EasyListener diff --git a/src/main/java/cc/carm/lib/easylistener/EasyListener.java b/src/main/java/cc/carm/lib/easylistener/EasyListener.java index 61702a1..5fcea80 100644 --- a/src/main/java/cc/carm/lib/easylistener/EasyListener.java +++ b/src/main/java/cc/carm/lib/easylistener/EasyListener.java @@ -1,27 +1,17 @@ package cc.carm.lib.easylistener; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; +import cc.carm.lib.easylistener.handler.BundleEventHandler; +import cc.carm.lib.easylistener.handler.MultiEventHandler; +import cc.carm.lib.easylistener.handler.SingleEventHandler; +import org.bukkit.Bukkit; import org.bukkit.event.*; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntitySpawnEvent; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.PlayerBucketEmptyEvent; -import org.bukkit.event.player.PlayerBucketFillEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.weather.WeatherChangeEvent; -import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Method; import java.util.Optional; -import java.util.function.BiPredicate; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; /** @@ -29,7 +19,13 @@ import java.util.function.Predicate; * * @author CarmJos */ -public interface EasyListener extends Listener { +public class EasyListener implements Listener { + + protected final Plugin plugin; + + public EasyListener(Plugin plugin) { + this.plugin = plugin; + } /** * 创建一个新的 {@link EasyListener} 实例 @@ -37,18 +33,35 @@ public interface EasyListener extends Listener { * @param plugin {@link Plugin}插件实例 * @return {@link EasyListener} 实例 */ - static @NotNull ListenerManager create(@NotNull Plugin plugin) { - return new ListenerManager(plugin); + public static @NotNull EasyListener create(@NotNull Plugin plugin) { + return new EasyListener(plugin); } /** * 注销本监听器内的全部监听器。 *
也可以通过 {@link HandlerList#unregister(Listener)} 方法注销本监听器。 */ - default void unregisterAll() { + public void unregisterAll() { HandlerList.unregisterAll(this); } + public @NotNull SingleEventHandler handleEvent(@NotNull Class eventClass) { + return new SingleEventHandler<>(this, eventClass); + } + + public @NotNull MultiEventHandler handleEvents(@NotNull Class eventType) { + return new MultiEventHandler<>(this, eventType); + } + + public @NotNull BundleEventHandler handleBundle(@NotNull Class elementClass) { + return handleBundle(elementClass, Event.class); + } + + public @NotNull BundleEventHandler handleBundle(@NotNull Class elementClass, + @NotNull Class eventType) { + return new BundleEventHandler<>(this, elementClass, eventType); + } + /** * 处理一个事件。 * @@ -59,9 +72,40 @@ public interface EasyListener extends Listener { * @param {@link Event} 事件的类型 * @return 本实例 */ - EasyListener handle(@NotNull Class eventClass, - @Nullable EventPriority priority, boolean ignoreCancelled, - @NotNull Consumer eventConsumer); + public EasyListener handle(@NotNull Class eventClass, + @Nullable EventPriority priority, boolean ignoreCancelled, + @NotNull Consumer eventConsumer) { + register(eventClass, eventConsumer, Optional.ofNullable(priority).orElse(EventPriority.NORMAL), ignoreCancelled); + return this; + } + + /** + * 有条件地取消一个事件。 + *
本方法在条件满足时对事件进行取消,不会改变事件取消的状态。 + *
因此,已经被取消的事件将不再进行判断和取消。。 + * + * @param eventClass {@link Event} 事件类 + * @param priority {@link EventPriority} 事件处理优先级 + * @param eventPredicate 判断事件是否可以取消的条件 + * @param afterCancelled 当事件被取消后执行的方法 + * @param {@link Event} 事件的类型,必须实现 {@link Cancellable} 。 + * @return 本实例 + * @throws IllegalArgumentException 如果事件没有实现 {@link Cancellable} 则抛出此异常 + */ + public EasyListener cancel(@NotNull Class eventClass, + @Nullable EventPriority priority, + @Nullable Predicate eventPredicate, + @Nullable Consumer afterCancelled) { + requireType(Cancellable.class, eventClass, "Event class " + eventClass.getName() + " is not cancellable"); + + final Predicate predicate = Optional.ofNullable(eventPredicate).orElse(t -> true); + return handle(eventClass, priority, true, (event) -> { + if (predicate.test(event)) { + ((Cancellable) event).setCancelled(true); + if (afterCancelled != null) afterCancelled.accept(event); + } + }); + } /** * 有条件地取消一个事件。 @@ -75,9 +119,11 @@ public interface EasyListener extends Listener { * @return 本实例 * @throws IllegalArgumentException 如果事件没有实现 {@link Cancellable} 则抛出此异常 */ - EasyListener cancel(@NotNull Class eventClass, - @Nullable EventPriority priority, - @Nullable Predicate eventPredicate); + public EasyListener cancel(@NotNull Class eventClass, + @Nullable EventPriority priority, + @Nullable Predicate eventPredicate) { + return cancel(eventClass, priority, eventPredicate, null); + } /** * 处理一个事件。 @@ -87,8 +133,8 @@ public interface EasyListener extends Listener { * @param {@link Event} 事件的类型 * @return 本实例 */ - default EasyListener handle(@NotNull Class eventClass, - @NotNull Consumer eventConsumer) { + public EasyListener handle(@NotNull Class eventClass, + @NotNull Consumer eventConsumer) { return handle(eventClass, null, eventConsumer); } @@ -101,9 +147,9 @@ public interface EasyListener extends Listener { * @param {@link Event} 事件的类型 * @return 本实例 */ - default EasyListener handle(@NotNull Class eventClass, - boolean ignoreCancelled, - @NotNull Consumer eventConsumer) { + public EasyListener handle(@NotNull Class eventClass, + boolean ignoreCancelled, + @NotNull Consumer eventConsumer) { return handle(eventClass, null, ignoreCancelled, eventConsumer); } @@ -116,9 +162,9 @@ public interface EasyListener extends Listener { * @param {@link Event} 事件的类型 * @return 本实例 */ - default EasyListener handle(@NotNull Class eventClass, - @Nullable EventPriority priority, - @NotNull Consumer eventConsumer) { + public EasyListener handle(@NotNull Class eventClass, + @Nullable EventPriority priority, + @NotNull Consumer eventConsumer) { return handle(eventClass, priority, false, eventConsumer); } @@ -130,7 +176,7 @@ public interface EasyListener extends Listener { * @return 本实例 * @throws IllegalArgumentException 如果事件没有实现 {@link Cancellable} 则抛出此异常 */ - default EasyListener cancel(@NotNull Class eventClass) { + public EasyListener cancel(@NotNull Class eventClass) { return cancel(eventClass, null, null); } @@ -143,115 +189,70 @@ public interface EasyListener extends Listener { * @return 本实例 * @throws IllegalArgumentException 如果事件没有实现 {@link Cancellable} 则抛出此异常 */ - default EasyListener cancel(@NotNull Class eventClass, - @Nullable Predicate eventPredicate) { + public EasyListener cancel(@NotNull Class eventClass, + @Nullable Predicate eventPredicate) { return cancel(eventClass, null, eventPredicate); } - // >--------------------------- - // 预设快捷操作方法 - - default EasyListener cancelJoinMessage() { - return handleJoinMessage(null); - } - - default EasyListener handleJoinMessage(@Nullable Function joinMessage) { - final Function message = Optional.ofNullable(joinMessage).orElse(t -> ""); - return handle(PlayerJoinEvent.class, (event) -> event.setJoinMessage(message.apply(event.getPlayer()))); - } - - default EasyListener cancelQuitMessage() { - return handleQuitMessage(null); - } - - default EasyListener handleQuitMessage(@Nullable Function quitMessage) { - final Function message = Optional.ofNullable(quitMessage).orElse(t -> ""); - return handle(PlayerQuitEvent.class, (event) -> event.setQuitMessage(message.apply(event.getPlayer()))); - } - - default EasyListener cancelWeatherChange() { - return cancelWeatherChange(null); - } - - default EasyListener cancelWeatherChange(@Nullable Predicate weatherPredicate) { - return cancel(WeatherChangeEvent.class, weatherPredicate); - } - - default EasyListener cancelBreak(@Nullable Predicate player) { - final Predicate predicate = Optional.ofNullable(player).orElse(t -> true); - return cancelBreak( - (event) -> predicate.test(event.getPlayer()), - (event) -> predicate.test(event.getPlayer()) - ); - } - - default EasyListener cancelBreak(@Nullable Predicate blockBreakPredicate, - @Nullable Predicate bucketFillPredicate) { - return cancel(BlockBreakEvent.class, blockBreakPredicate) - .cancel(PlayerBucketFillEvent.class, bucketFillPredicate); - } - - default EasyListener cancelPlace(@Nullable Predicate player) { - final Predicate predicate = Optional.ofNullable(player).orElse(t -> true); - return cancelPlace( - (event) -> predicate.test(event.getPlayer()), - (event) -> predicate.test(event.getPlayer()) - ); - } - - default EasyListener cancelPlace(@Nullable Predicate blockBreakPredicate, - @Nullable Predicate bucketEmptyPredicate) { - return cancel(BlockPlaceEvent.class, blockBreakPredicate) - .cancel(PlayerBucketEmptyEvent.class, bucketEmptyPredicate); + public Plugin getPlugin() { + return plugin; } /** - * 有条件的取消玩家PVP。 + * 通过 {@link SimplePluginManager} 获取到一个事件类的 {@link HandlerList} 。 * - * @param predicate 判断器,返回true则取消事件。两参数分别为 attacker 与 victim 。 - * @return 当前实例 + * @param eventClass 事件类 + * @return 事件类的 {@link HandlerList} */ - default EasyListener cancelPVP(@Nullable BiPredicate predicate) { - final BiPredicate p = Optional.ofNullable(predicate).orElse((attacker, victim) -> true); - return cancelAttack((attacker, damager) -> { - if (!(attacker instanceof Player) || !(damager instanceof Player)) return false; - else return p.test((Player) attacker, (Player) damager); - }); + private @NotNull HandlerList getEventListeners(@NotNull Class eventClass) { + try { + Method method = SimplePluginManager.class.getDeclaredMethod("getEventListeners", Class.class); + method.setAccessible(true); + return (HandlerList) method.invoke(Bukkit.getPluginManager(), eventClass); + } catch (Exception e) { + throw new IllegalPluginAccessException(e.toString()); + } } /** - * 有条件的取消两个实体间的伤害。 + * 创建一个事件的执行器实例。 * - * @param predicate 判断器,返回true则取消事件。两参数分别为 attacker 与 victim 。 - * @return 当前实例 + * @param eventClass 事件类 + * @param eventConsumer 事件执行内容 + * @param 事件类型 + * @return 事件的执行器实例 */ - default EasyListener cancelAttack(@Nullable BiPredicate predicate) { - final BiPredicate p = Optional.ofNullable(predicate).orElse((attacker, victim) -> true); - return cancel(EntityDamageByEntityEvent.class, (event) -> p.test(event.getDamager(), event.getEntity())); + protected EventExecutor createExecutor(@NotNull Class eventClass, + @NotNull Consumer eventConsumer) { + return (listener, event) -> { + try { + if (!eventClass.isAssignableFrom(event.getClass())) return; + eventConsumer.accept(eventClass.cast(event)); + } catch (Throwable t) { + throw new EventException(t); + } + }; } - default EasyListener cancelDeath(@Nullable Predicate predicate) { - return cancelDeath(predicate, (event) -> { - event.setDeathMessage(null); - event.setKeepInventory(true); - event.setKeepLevel(true); - }); + protected void requireType(@NotNull Class target, @NotNull Class value, + @Nullable String message) throws IllegalArgumentException { + if (target.isAssignableFrom(value)) return; + if (message == null) throw new IllegalArgumentException(); + else throw new IllegalArgumentException(message); } - @SuppressWarnings("deprecation") - default EasyListener cancelDeath(@Nullable Predicate predicate, - @Nullable Consumer handler) { - final Predicate p = Optional.ofNullable(predicate).orElse((player) -> true); - return handle(PlayerDeathEvent.class, (event) -> { - if (!p.test(event.getEntity())) return; - event.getEntity().setHealth(event.getEntity().getMaxHealth()); - Optional.ofNullable(handler).ifPresent(consumer -> consumer.accept(event)); - }); + protected void register(@NotNull Class eventClass, @NotNull RegisteredListener listener) { + getEventListeners(eventClass).register(listener); } - default EasyListener cancelSpawn(@Nullable BiPredicate predicate) { - final BiPredicate p = Optional.ofNullable(predicate).orElse((entity, location) -> !(entity instanceof Player)); - return cancel(EntitySpawnEvent.class, (event) -> p.test(event.getEntity(), event.getLocation())); + protected void register(@NotNull Class eventClass, @NotNull EventExecutor executor, + @NotNull EventPriority priority, boolean ignoreCancelled) { + register(eventClass, new RegisteredListener(this, executor, priority, getPlugin(), ignoreCancelled)); + } + + protected void register(@NotNull Class eventClass, @NotNull Consumer eventConsumer, + @NotNull EventPriority priority, boolean ignoreCancelled) { + register(eventClass, createExecutor(eventClass, eventConsumer), priority, ignoreCancelled); } } diff --git a/src/main/java/cc/carm/lib/easylistener/ListenerManager.java b/src/main/java/cc/carm/lib/easylistener/ListenerManager.java deleted file mode 100644 index 1b71f4f..0000000 --- a/src/main/java/cc/carm/lib/easylistener/ListenerManager.java +++ /dev/null @@ -1,103 +0,0 @@ -package cc.carm.lib.easylistener; - -import org.bukkit.Bukkit; -import org.bukkit.event.*; -import org.bukkit.plugin.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Method; -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Predicate; - -@SuppressWarnings("SameParameterValue") -public class ListenerManager implements EasyListener { - - protected final Plugin plugin; - - public ListenerManager(Plugin plugin) { - this.plugin = plugin; - } - - public Plugin getPlugin() { - return plugin; - } - - /** - * 通过 {@link SimplePluginManager} 获取到一个事件类的 {@link HandlerList} 。 - * - * @param eventClass 事件类 - * @return 事件类的 {@link HandlerList} - */ - private @NotNull HandlerList getEventListeners(@NotNull Class eventClass) { - try { - Method method = SimplePluginManager.class.getDeclaredMethod("getEventListeners", Class.class); - method.setAccessible(true); - return (HandlerList) method.invoke(Bukkit.getPluginManager(), eventClass); - } catch (Exception e) { - throw new IllegalPluginAccessException(e.toString()); - } - } - - /** - * 创建一个事件的执行器实例。 - * - * @param eventClass 事件类 - * @param eventConsumer 事件执行内容 - * @param 事件类型 - * @return 事件的执行器实例 - */ - protected EventExecutor createExecutor(@NotNull Class eventClass, - @NotNull Consumer eventConsumer) { - return (listener, event) -> { - try { - if (!eventClass.isAssignableFrom(event.getClass())) return; - eventConsumer.accept(eventClass.cast(event)); - } catch (Throwable t) { - throw new EventException(t); - } - }; - } - - protected void requireType(@NotNull Class target, @NotNull Class value, - @Nullable String message) throws IllegalArgumentException { - if (target.isAssignableFrom(value)) return; - if (message == null) throw new IllegalArgumentException(); - else throw new IllegalArgumentException(message); - } - - protected void register(@NotNull Class eventClass, @NotNull RegisteredListener listener) { - getEventListeners(eventClass).register(listener); - } - - protected void register(@NotNull Class eventClass, @NotNull EventExecutor executor, - @NotNull EventPriority priority, boolean ignoreCancelled) { - register(eventClass, new RegisteredListener(this, executor, priority, getPlugin(), ignoreCancelled)); - } - - protected void register(@NotNull Class eventClass, @NotNull Consumer eventConsumer, - @NotNull EventPriority priority, boolean ignoreCancelled) { - register(eventClass, createExecutor(eventClass, eventConsumer), priority, ignoreCancelled); - } - - @Override - public EasyListener handle(@NotNull Class eventClass, - @Nullable EventPriority priority, boolean ignoreCancelled, - @NotNull Consumer eventConsumer) { - register(eventClass, eventConsumer, Optional.ofNullable(priority).orElse(EventPriority.NORMAL), ignoreCancelled); - return this; - } - - @Override - public EasyListener cancel(@NotNull Class eventClass, @Nullable EventPriority priority, - @Nullable Predicate eventPredicate) { - requireType(Cancellable.class, eventClass, "Event class " + eventClass.getName() + " is not cancellable"); - - final Predicate predicate = Optional.ofNullable(eventPredicate).orElse(t -> true); - return handle(eventClass, priority, true, (event) -> { - if (predicate.test(event)) ((Cancellable) event).setCancelled(true); - }); - } - -} diff --git a/src/main/java/cc/carm/lib/easylistener/defaults/CommonListeners.java b/src/main/java/cc/carm/lib/easylistener/defaults/CommonListeners.java new file mode 100644 index 0000000..436ccd2 --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/defaults/CommonListeners.java @@ -0,0 +1,123 @@ +package cc.carm.lib.easylistener.defaults; + +import cc.carm.lib.easylistener.EasyListener; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +public class CommonListeners { + + public static void cancelJoinMessage(@NotNull EasyListener source) { + handleJoinMessage(source, null); + } + + public static void handleJoinMessage(@NotNull EasyListener source, @Nullable Function joinMessage) { + final Function message = Optional.ofNullable(joinMessage).orElse(t -> ""); + source.handle(PlayerJoinEvent.class, (event) -> event.setJoinMessage(message.apply(event.getPlayer()))); + } + + public static void cancelQuitMessage(@NotNull EasyListener source) { + handleQuitMessage(source, null); + } + + public static void handleQuitMessage(@NotNull EasyListener source, @Nullable Function quitMessage) { + final Function message = Optional.ofNullable(quitMessage).orElse(t -> ""); + source.handle(PlayerQuitEvent.class, (event) -> event.setQuitMessage(message.apply(event.getPlayer()))); + } + + public static void cancelWeatherChange(@NotNull EasyListener source) { + cancelWeatherChange(source, null); + } + + public static void cancelWeatherChange(@NotNull EasyListener source, + @Nullable Predicate weatherPredicate) { + source.cancel(WeatherChangeEvent.class, weatherPredicate); + } + + public static void cancelBreak(@NotNull EasyListener source, @Nullable Predicate playerPredicate) { + source.handleBundle(Player.class) + .from(BlockBreakEvent.class, BlockBreakEvent::getPlayer) + .from(PlayerBucketFillEvent.class, PlayerBucketFillEvent::getPlayer) + .filter(playerPredicate).cancel(); + } + + public static void cancelPlace(@NotNull EasyListener source, @Nullable Predicate playerPredicate) { + source.handleBundle(Player.class) + .from(BlockPlaceEvent.class, BlockPlaceEvent::getPlayer) + .from(PlayerBucketEmptyEvent.class, PlayerBucketEmptyEvent::getPlayer) + .filter(playerPredicate).cancel(); + } + + /** + * 有条件的取消玩家PVP。 + * + * @param source 用于注册的源 {@link EasyListener} 对象。 + * @param predicate 判断器,返回true则取消事件。两参数分别为 attacker 与 victim 。 + */ + public static void cancelPVP(@NotNull EasyListener source, + @Nullable BiPredicate predicate) { + final BiPredicate p = Optional.ofNullable(predicate).orElse((attacker, victim) -> true); + cancelAttack(source, (attacker, damager) -> { + if (!(attacker instanceof Player) || !(damager instanceof Player)) return false; + else return p.test((Player) attacker, (Player) damager); + }); + } + + /** + * 有条件的取消两个实体间的伤害。 + * + * @param source 用于注册的源 {@link EasyListener} 对象。 + * @param predicate 判断器,返回true则取消事件。两参数分别为 attacker 与 victim 。 + */ + public static void cancelAttack(@NotNull EasyListener source, + @Nullable BiPredicate predicate) { + final BiPredicate p = Optional.ofNullable(predicate).orElse((attacker, victim) -> true); + source.cancel(EntityDamageByEntityEvent.class, (event) -> p.test(event.getDamager(), event.getEntity())); + } + + public static void cancelDeath(@NotNull EasyListener source, + @Nullable Predicate predicate) { + cancelDeath(source, predicate, event -> { + event.setDeathMessage(null); + event.setKeepInventory(true); + event.setKeepLevel(true); + }); + } + + @SuppressWarnings("deprecation") + public static void cancelDeath(@NotNull EasyListener source, + @Nullable Predicate predicate, + @Nullable Consumer handler) { + final Predicate p = Optional.ofNullable(predicate).orElse((player) -> true); + source.handle(PlayerDeathEvent.class, (event) -> { + if (!p.test(event.getEntity())) return; + event.getEntity().setHealth(event.getEntity().getMaxHealth()); + Optional.ofNullable(handler).ifPresent(consumer -> consumer.accept(event)); + }); + } + + public static void cancelSpawn(@NotNull EasyListener source, + @Nullable BiPredicate predicate) { + final BiPredicate p = Optional.ofNullable(predicate).orElse((entity, location) -> !(entity instanceof Player)); + source.cancel(EntitySpawnEvent.class, (event) -> p.test(event.getEntity(), event.getLocation())); + } + +} diff --git a/src/main/java/cc/carm/lib/easylistener/defaults/EventFilters.java b/src/main/java/cc/carm/lib/easylistener/defaults/EventFilters.java new file mode 100644 index 0000000..aae8855 --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/defaults/EventFilters.java @@ -0,0 +1,82 @@ +package cc.carm.lib.easylistener.defaults; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Cancellable; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockEvent; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.world.WorldEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Predicate; + +public class EventFilters { + + public Predicate isCancelled() { + return Cancellable::isCancelled; + } + + public Predicate notCancelled() { + return e -> !e.isCancelled(); + } + + public Predicate moveInSameBlock() { + return e -> { + if (e.getTo() == null) return false; + + World fromWorld = e.getFrom().getWorld(); + World toWorld = e.getTo().getWorld(); + if (!Objects.equals(fromWorld, toWorld)) return false; + + return e.getFrom().getBlockX() != e.getTo().getBlockX() || + e.getFrom().getBlockZ() != e.getTo().getBlockZ() || + e.getFrom().getBlockY() != e.getTo().getBlockY(); + }; + } + + public static Predicate interactAction(Action... actionType) { + return e -> Arrays.stream(actionType).anyMatch(a -> a == e.getAction()); + } + + public static Predicate invClickType(ClickType... clickTypes) { + return e -> Arrays.stream(clickTypes).anyMatch(a -> a == e.getClick()); + } + + public static Predicate playerIsOp() { + return e -> e.getPlayer().isOp(); + } + + public static Predicate playerHasPerm(@NotNull String permission) { + return e -> e.getPlayer().hasPermission(permission); + } + + public static Predicate playerInWorld(@NotNull String worldName) { + return e -> e.getPlayer().getWorld().getName().equals(worldName); + } + + public Predicate entityOf(@NotNull EntityType type) { + return e -> e.getEntityType() == type; + } + + public Predicate worldOf(@NotNull String worldName) { + return e -> e.getWorld().getName().equals(worldName); + } + + public Predicate blockOf(@NotNull Material material) { + return e -> e.getBlock().getType() == material; + } + + public Predicate blockInWorld(@NotNull String worldName) { + return e -> e.getBlock().getWorld().getName().equals(worldName); + } + +} diff --git a/src/main/java/cc/carm/lib/easylistener/defaults/EventHandlers.java b/src/main/java/cc/carm/lib/easylistener/defaults/EventHandlers.java new file mode 100644 index 0000000..b4c16f5 --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/defaults/EventHandlers.java @@ -0,0 +1,34 @@ +package cc.carm.lib.easylistener.defaults; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.function.Consumer; + +public class EventHandlers { + + private EventHandlers() { + } + + public static final Consumer SET_CANCELLED = event -> event.setCancelled(true); + public static final Consumer UNSET_CANCELLED = event -> event.setCancelled(false); + + public static final Consumer CANCEL_MOVE_BY_TELEPORT = event -> event.getPlayer().teleport(event.getFrom()); + + public static Consumer setCancelled() { + return SET_CANCELLED; + } + + public static Consumer unsetCancelled() { + return UNSET_CANCELLED; + } + + public static Consumer setCancelled(boolean cancelled) { + return cancelled ? SET_CANCELLED : UNSET_CANCELLED; + } + + public static Consumer cancelMoveByTeleport() { + return CANCEL_MOVE_BY_TELEPORT; + } + +} diff --git a/src/main/java/cc/carm/lib/easylistener/handler/BaseEventHandler.java b/src/main/java/cc/carm/lib/easylistener/handler/BaseEventHandler.java new file mode 100644 index 0000000..e8126db --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/handler/BaseEventHandler.java @@ -0,0 +1,50 @@ +package cc.carm.lib.easylistener.handler; + +import cc.carm.lib.easylistener.EasyListener; +import org.bukkit.event.EventPriority; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Predicate; + +public abstract class BaseEventHandler> { + + protected final @NotNull EasyListener source; + + protected EventPriority priority = null; + protected boolean ignoreCancelled = false; + + protected Predicate predicate; + + public BaseEventHandler(@NotNull EasyListener source) { + this.source = source; + } + + protected abstract S getThis(); + + public S priority(@Nullable EventPriority priority) { + this.priority = priority; + return getThis(); + } + + public S setIgnoreCancelled(boolean ignore) { + this.ignoreCancelled = ignore; + return getThis(); + } + + public S acceptCancelled() { + return setIgnoreCancelled(false); + } + + public S ignoreCancelled() { + return setIgnoreCancelled(true); + } + + public S filter(@Nullable Predicate predicate) { + if (predicate == null) return getThis(); + this.predicate = Optional.ofNullable(this.predicate).map(p -> p.and(predicate)).orElse(predicate); + return getThis(); + } + +} diff --git a/src/main/java/cc/carm/lib/easylistener/handler/BundleEventHandler.java b/src/main/java/cc/carm/lib/easylistener/handler/BundleEventHandler.java new file mode 100644 index 0000000..dac2e79 --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/handler/BundleEventHandler.java @@ -0,0 +1,117 @@ +package cc.carm.lib.easylistener.handler; + +import cc.carm.lib.easylistener.EasyListener; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.*; + +public class BundleEventHandler { + + protected final EasyListener source; + + protected final Class eventType; + protected final Class handleClass; + protected final Map, EventWrapper> wrappers = new HashMap<>(); + + protected BiPredicate predicate; + + public BundleEventHandler(EasyListener source, Class handleClass, Class eventType) { + this.source = source; + this.eventType = eventType; + this.handleClass = handleClass; + } + + public BundleEventHandler from(@NotNull Class eventClass, + @NotNull Function wrapFunction) { + return from(eventClass, null, wrapFunction); + } + + public BundleEventHandler from(@NotNull Class eventClass, + @Nullable EventPriority priority, + @NotNull Function wrapFunction) { + this.wrappers.put(eventClass, new EventWrapper<>(eventClass, priority, wrapFunction)); + return this; + } + + public BundleEventHandler filter(@Nullable BiPredicate predicate) { + if (predicate == null) return this; + + this.predicate = Optional.ofNullable(this.predicate).map(p -> p.and(predicate)).orElse(predicate); + return this; + } + + public BundleEventHandler filter(@Nullable Predicate predicate) { + if (predicate == null) return this; + BiPredicate append = (t, e) -> predicate.test(t); + this.predicate = Optional.ofNullable(this.predicate).map(p -> p.and(append)).orElse(append); + return this; + } + + public EasyListener handle(@NotNull BiConsumer consumer) { + BiPredicate predicate = Optional.ofNullable(this.predicate).orElse((t, e) -> true); + this.wrappers.values().forEach(wrapper -> wrapper.handle(source, predicate, consumer)); + return source; + } + + public EasyListener handle(@NotNull Consumer consumer) { + return handle((t, e) -> consumer.accept(t)); + } + + public EasyListener cancel() { + return cancel((BiConsumer) null); + } + + public EasyListener cancel(@Nullable BiConsumer afterCancelled) { + BiConsumer consumer = Optional.ofNullable(afterCancelled).orElse((t, e) -> { + //Do nothing + }); + this.wrappers.values().forEach(wrapper -> wrapper.cancel(source, predicate, consumer)); + return source; + } + + public EasyListener cancel(@Nullable Consumer afterCancelled) { + return cancel((t, e) -> Optional.ofNullable(afterCancelled).ifPresent(c -> c.accept(t))); + } + + protected static class EventWrapper { + + protected final @NotNull Class eventClass; + protected final @NotNull Function wrapper; + + protected final EventPriority priority; + + public EventWrapper(@NotNull Class eventClass, EventPriority priority, + @NotNull Function wrapper) { + this.eventClass = eventClass; + this.wrapper = wrapper; + this.priority = priority; + } + + public void handle(@NotNull EasyListener source, + @NotNull BiPredicate predicate, @NotNull BiConsumer consumer) { + source.handle(this.eventClass, this.priority, event -> { + T wrapper = this.wrapper.apply(event); + if (predicate.test(wrapper, event)) consumer.accept(wrapper, event); + }); + } + + public void cancel(@NotNull EasyListener source, + @NotNull BiPredicate predicate, + @NotNull BiConsumer afterCancelled) { + source.cancel( + this.eventClass, this.priority, + event -> predicate.test(this.wrapper.apply(event), event), + event -> afterCancelled.accept(this.wrapper.apply(event), event) + ); + } + + } + + +} diff --git a/src/main/java/cc/carm/lib/easylistener/handler/MultiEventHandler.java b/src/main/java/cc/carm/lib/easylistener/handler/MultiEventHandler.java new file mode 100644 index 0000000..be2b01e --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/handler/MultiEventHandler.java @@ -0,0 +1,58 @@ +package cc.carm.lib.easylistener.handler; + +import cc.carm.lib.easylistener.EasyListener; +import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class MultiEventHandler extends BaseEventHandler> { + + protected final Class eventType; + + protected final Set> eventClasses = new HashSet<>(); + protected Predicate eventPredicate; + + public MultiEventHandler(EasyListener source, Class eventType) { + super(source); + this.eventType = eventType; + } + + @Override + protected MultiEventHandler getThis() { + return this; + } + + public MultiEventHandler from(@NotNull Class eventClass) { + this.eventClasses.add(eventClass); + return this; + } + + public EasyListener handle(@NotNull Consumer eventConsumer) { + + for (Class clazz : this.eventClasses) { + source.handle(clazz, priority, ignoreCancelled, (event) -> { + Predicate predicate = Optional.ofNullable(eventPredicate).orElse(t -> true); + if (predicate.test(event)) eventConsumer.accept(event); + }); + } + + return source; + } + + public EasyListener cancel() { + return cancel(null); + } + + public EasyListener cancel(@Nullable Consumer afterCancelled) { + this.eventClasses.forEach(clazz -> source.cancel(clazz, priority, eventPredicate, afterCancelled)); + return source; + } + + +} diff --git a/src/main/java/cc/carm/lib/easylistener/handler/SingleEventHandler.java b/src/main/java/cc/carm/lib/easylistener/handler/SingleEventHandler.java new file mode 100644 index 0000000..44a9c24 --- /dev/null +++ b/src/main/java/cc/carm/lib/easylistener/handler/SingleEventHandler.java @@ -0,0 +1,42 @@ +package cc.carm.lib.easylistener.handler; + +import cc.carm.lib.easylistener.EasyListener; +import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class SingleEventHandler extends BaseEventHandler> { + + protected final Class eventClass; + + public SingleEventHandler(EasyListener source, Class eventClass) { + super(source); + this.eventClass = eventClass; + } + + @Override + protected SingleEventHandler getThis() { + return this; + } + + public EasyListener handle(@NotNull Consumer eventConsumer) { + return source.handle(eventClass, priority, ignoreCancelled, (event) -> { + Predicate predicate = Optional.ofNullable(this.predicate).orElse(t -> true); + if (predicate.test(event)) eventConsumer.accept(event); + }); + } + + public EasyListener cancel() { + return cancel(null); + } + + public EasyListener cancel(@Nullable Consumer afterCancelled) { + return source.cancel(eventClass, priority, predicate, afterCancelled); + } + + +} diff --git a/src/test/java/DemoPlugin.java b/src/test/java/DemoPlugin.java index dfcdf0d..83270a4 100644 --- a/src/test/java/DemoPlugin.java +++ b/src/test/java/DemoPlugin.java @@ -1,21 +1,21 @@ import cc.carm.lib.easylistener.EasyListener; +import cc.carm.lib.easylistener.defaults.CommonListeners; +import cc.carm.lib.easylistener.defaults.EventFilters; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerPickupArrowEvent; +import org.bukkit.event.player.*; import org.bukkit.plugin.java.JavaPlugin; public class DemoPlugin extends JavaPlugin { - protected final EasyListener listeners = EasyListener.create(this); + protected final EasyListener source = EasyListener.create(this); @Override public void onEnable() { - - listeners // 基本用法 - .handle(PlayerInteractAtEntityEvent.class, (event) -> { + // 基本用法 + source.handle(PlayerInteractAtEntityEvent.class, (event) -> { Entity clicked = event.getRightClicked(); Player player = event.getPlayer(); @@ -30,16 +30,40 @@ public class DemoPlugin extends JavaPlugin { (event) -> event.getCause() != EntityDamageEvent.DamageCause.ENTITY_ATTACK ); // 有条件的取消一个事件 - listeners // 额外提供的快捷方法 - .cancelDeath(null) // 所有玩家取消死亡 - .cancelBreak(player -> !player.isOp()) // 禁止非OP玩家破坏方块/接水或岩浆 - .cancelPlace(player -> !player.isOp()) // 禁止非OP玩家放置方块/放水或岩浆 - .cancelPVP((attacker, victim) -> !attacker.isOp()) // 禁止非op玩家PVP - .cancelWeatherChange() // 取消天气变更 - .cancelJoinMessage() // 取消加入消息 -// .cancelQuitMessage() -// .handleJoinMessage(player -> "玩家 " + player.getName() + " 加入了服务器。") - .handleQuitMessage(player -> "玩家 " + player.getName() + " 退出了服务器。"); // 设定退出消息 + + // Functional 用法 + source.handleEvent(PlayerInteractAtEntityEvent.class) + .filter(e -> e.getRightClicked() instanceof Player) + .filter(EventFilters.playerHasPerm("yc.admin")) + .handle(e -> { + Player player = e.getPlayer(); + player.sendMessage("你点了 " + e.getRightClicked().getName() + " 一下!"); + }); + + source.handleEvents(PlayerEvent.class) + .from(PlayerJoinEvent.class) + .from(PlayerQuitEvent.class) + .filter(EventFilters.playerHasPerm("yc.admin")) + .handle(playerEvent -> System.out.println(playerEvent.getPlayer().getName())); + + source.handleBundle(Player.class) + .from(PlayerJoinEvent.class, PlayerEvent::getPlayer) + .from(PlayerInteractEvent.class, PlayerEvent::getPlayer) + .filter(p -> p.hasPermission("yc.admin")) + .handle((p, e) -> p.sendMessage("hi!")); + + + // 预设的快捷方法 + CommonListeners.cancelDeath(source, null); // 所有玩家取消死亡 + CommonListeners.cancelBreak(source, player -> !player.isOp()); // 禁止非OP玩家破坏方块/接水或岩浆 + CommonListeners.cancelPlace(source, player -> !player.isOp()); // 禁止非OP玩家建造方块/接水或岩浆 + + CommonListeners.cancelPVP(source, (attacker, victim) -> !attacker.isOp()); // 禁止非op玩家攻击别人 + CommonListeners.cancelWeatherChange(source); // 取消天气变化 + CommonListeners.cancelJoinMessage(source); // 取消加入消息 +// CommonListeners.cancelQuitMessage(listeners); +// CommonListeners.handleJoinMessage(listeners, player -> "玩家 " + player.getName() + " 加入了服务器。"); + CommonListeners.handleQuitMessage(source, player -> "玩家 " + player.getName() + " 退出了服务器。"); // 设定退出消息 }