From 576103a85cbf4c5b6e04483900e54d4c0b6547a4 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 28 Jan 2021 16:49:37 +0100 Subject: [PATCH 01/35] KelpPlayerLoginEvent is now a KelpPlayerEvent instead of PlayerEvent --- .../event/kelpevent/KelpPlayerLoginEvent.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerLoginEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerLoginEvent.java index 36df3e8d..3945bc52 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerLoginEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerLoginEvent.java @@ -17,12 +17,9 @@ * the {@link KelpPlayer} instances calls this event after it has finished so that * it is safe to use the kelp player object. * - * All methods (except {@link #getKelpPlayer()}) are the same as those from the normal - * bukkit event, so you can look for more detailed information there. - * * @author pxav */ -public class KelpPlayerLoginEvent extends PlayerEvent { +public class KelpPlayerLoginEvent extends KelpPlayerEvent { // list of all event handlers listening for this event private static final HandlerList handlers = new HandlerList(); @@ -30,21 +27,12 @@ public class KelpPlayerLoginEvent extends PlayerEvent { private String hostname; private PlayerLoginEvent.Result result; private String message; - private KelpPlayer kelpPlayer; - public KelpPlayerLoginEvent(Player who, KelpPlayer kelpPlayer, String hostname, PlayerLoginEvent.Result result, String message) { + public KelpPlayerLoginEvent(KelpPlayer who, String hostname, PlayerLoginEvent.Result result, String message) { super(who); this.hostname = hostname; this.result = result; this.message = message; - this.kelpPlayer = kelpPlayer; - } - - /** - * @return The {@link KelpPlayer} instance of the player who logged in. - */ - public KelpPlayer getKelpPlayer() { - return kelpPlayer; } public String getHostname() { From 8a36677d77898a23ff01e9c2ab27ab28686e8864 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 28 Jan 2021 16:49:50 +0100 Subject: [PATCH 02/35] KelpPlayerUpdateSettingsEvent is now a KelpPlayerEvent instead of PlayerEvent --- .../KelpPlayerUpdateSettingsEvent.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerUpdateSettingsEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerUpdateSettingsEvent.java index 3e00baea..8a741d9d 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerUpdateSettingsEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpPlayerUpdateSettingsEvent.java @@ -13,14 +13,11 @@ * * @author pxav */ -public class KelpPlayerUpdateSettingsEvent extends PlayerEvent { +public class KelpPlayerUpdateSettingsEvent extends KelpPlayerEvent { // list of all event handlers listening for this event private static final HandlerList handlers = new HandlerList(); - // the player whose settings changed. - private KelpPlayer who; - // the stage when the settings changed private SettingsUpdateStage updateStage; @@ -42,8 +39,7 @@ public KelpPlayerUpdateSettingsEvent(KelpPlayer who, int viewDistance, PlayerChatVisibility playerChatVisibility, boolean chatColorEnabled) { - super(who.getBukkitPlayer()); - this.who = who; + super(who); this.updateStage = updateStage; this.language = language; this.viewDistance = viewDistance; @@ -64,7 +60,7 @@ public String getLanguage() { } public boolean hasLanguageChanged() { - return !this.language.equalsIgnoreCase(who.getClientLanguage()); + return !this.language.equalsIgnoreCase(player.getClientLanguage()); } public int getViewDistance() { @@ -72,7 +68,7 @@ public int getViewDistance() { } public boolean hasViewDistanceChanged() { - return viewDistance != who.getClientViewDistance(); + return viewDistance != player.getClientViewDistance(); } public boolean getChatColorEnabled() { @@ -84,7 +80,7 @@ public boolean getChatColorEnabled() { * @return if the chat color setting has changed. */ public boolean hasChatColorChanged() { - return chatColorEnabled != who.isPlayerChatColorEnabled(); + return chatColorEnabled != player.isPlayerChatColorEnabled(); } /** @@ -100,7 +96,7 @@ public PlayerChatVisibility getChatVisibility() { * @return if the chat visibility settings have changed. */ public boolean hasChatVisibilityChanged() { - return playerChatVisibility != who.getPlayerChatVisibility(); + return playerChatVisibility != player.getPlayerChatVisibility(); } /** @@ -108,7 +104,7 @@ public boolean hasChatVisibilityChanged() { * @return the kelp player instance of the player whose settings have changed. */ public KelpPlayer getKelpPlayer() { - return who; + return player; } @Override From 33ce76aee35f904e3de043bbc167adfca4f1f5dd Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 28 Jan 2021 16:50:09 +0100 Subject: [PATCH 03/35] Inventory events are now KelpPlayer events --- .../kelp/core/event/kelpevent/KelpInventoryCloseEvent.java | 5 +++-- .../kelp/core/event/kelpevent/KelpInventoryOpenEvent.java | 5 +++-- .../kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java index 04c3895a..898ef549 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java @@ -1,6 +1,7 @@ package de.pxav.kelp.core.event.kelpevent; import de.pxav.kelp.core.inventory.type.KelpInventory; +import de.pxav.kelp.core.player.KelpPlayer; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.player.PlayerEvent; @@ -10,13 +11,13 @@ * * @author pxav */ -public class KelpInventoryCloseEvent extends PlayerEvent { +public class KelpInventoryCloseEvent extends KelpPlayerEvent { private static final HandlerList handlers = new HandlerList(); private KelpInventory inventory; private boolean animated; - public KelpInventoryCloseEvent(Player who, KelpInventory inventory, boolean isAnimated) { + public KelpInventoryCloseEvent(KelpPlayer who, KelpInventory inventory, boolean isAnimated) { super(who); this.inventory = inventory; this.animated = isAnimated; diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java index bdf23053..0649344e 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java @@ -1,6 +1,7 @@ package de.pxav.kelp.core.event.kelpevent; import de.pxav.kelp.core.inventory.type.KelpInventory; +import de.pxav.kelp.core.player.KelpPlayer; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.player.PlayerEvent; @@ -10,13 +11,13 @@ * * @author pxav */ -public class KelpInventoryOpenEvent extends PlayerEvent { +public class KelpInventoryOpenEvent extends KelpPlayerEvent { private static final HandlerList handlers = new HandlerList(); private KelpInventory inventory; private boolean animatedInventory; - public KelpInventoryOpenEvent(Player who, KelpInventory inventory, boolean isAnimated) { + public KelpInventoryOpenEvent(KelpPlayer who, KelpInventory inventory, boolean isAnimated) { super(who); this.inventory = inventory; this.animatedInventory = isAnimated; diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java index 1f7eb7ba..219e156f 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java @@ -1,6 +1,7 @@ package de.pxav.kelp.core.event.kelpevent; import de.pxav.kelp.core.inventory.type.KelpInventory; +import de.pxav.kelp.core.player.KelpPlayer; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.player.PlayerEvent; @@ -10,12 +11,12 @@ * * @author pxav */ -public class KelpInventoryUpdateEvent extends PlayerEvent { +public class KelpInventoryUpdateEvent extends KelpPlayerEvent { private static final HandlerList handlers = new HandlerList(); private KelpInventory inventory; - public KelpInventoryUpdateEvent(Player who, KelpInventory inventory) { + public KelpInventoryUpdateEvent(KelpPlayer who, KelpInventory inventory) { super(who); this.inventory = inventory; } From 6db7ec55714af4342b77834c5d56099ebb484a26 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 28 Jan 2021 16:50:31 +0100 Subject: [PATCH 04/35] Fix bug that inventory events were not called correctly --- .../pxav/kelp/core/inventory/KelpInventoryRepository.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/inventory/KelpInventoryRepository.java b/core/src/main/java/de/pxav/kelp/core/inventory/KelpInventoryRepository.java index 5b2e5faf..5b8fae1b 100644 --- a/core/src/main/java/de/pxav/kelp/core/inventory/KelpInventoryRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/inventory/KelpInventoryRepository.java @@ -74,7 +74,7 @@ public void openInventory(KelpInventory inventory, KelpPlayer player) { playerAnimations.put(player.getUUID(), animatedInventory); } - Bukkit.getPluginManager().callEvent(new KelpInventoryOpenEvent(player.getBukkitPlayer(), inventory, animated)); + Bukkit.getPluginManager().callEvent(new KelpInventoryOpenEvent(player, inventory, animated)); playerInventories.put(player.getUUID(), inventory); } @@ -97,7 +97,7 @@ public void closeInventory(KelpPlayer player) { animatedInventory.stopUpdater(); } - Bukkit.getPluginManager().callEvent(new KelpInventoryCloseEvent(player.getBukkitPlayer(), inventory, animated)); + Bukkit.getPluginManager().callEvent(new KelpInventoryCloseEvent(player, inventory, animated)); this.playerInventories.remove(player.getUUID()); this.playerAnimations.remove(player.getUUID()); this.kelpListenerRepository.unregisterListeners(player.getUUID()); @@ -113,7 +113,7 @@ public void closeInventory(KelpPlayer player) { public void updateInventory(KelpPlayer player) { KelpInventory kelpInventory = playerInventories.get(player.getUUID()); kelpInventory.update(player); - Bukkit.getPluginManager().callEvent(new KelpInventoryUpdateEvent(player.getBukkitPlayer(), kelpInventory)); + Bukkit.getPluginManager().callEvent(new KelpInventoryUpdateEvent(player, kelpInventory)); } public Map> getPlayerPages() { From ce4d592e0076d04e9c8daad47c4cedb31c2c1497 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 28 Jan 2021 16:50:53 +0100 Subject: [PATCH 05/35] Fix KelpPlayerLoginEvent trigger --- .../kelp/implementation1_8/player/PlayerCreationListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java b/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java index c8cc1117..028b3808 100644 --- a/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java +++ b/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java @@ -50,7 +50,6 @@ public void handlePlayerLogin(PlayerLoginEvent event) { KelpPlayer kelpPlayer = kelpPlayerRepository.newKelpPlayer(event.getPlayer()); kelpPlayerRepository.addOrUpdatePlayer(kelpPlayer.getUUID(), kelpPlayer); Bukkit.getPluginManager().callEvent(new KelpPlayerLoginEvent( - event.getPlayer(), kelpPlayer, event.getHostname(), event.getResult(), From 3974d1751f3c450357f6bef0dadf5907ff20887f Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 15:32:46 +0100 Subject: [PATCH 06/35] Dynamic listeners now support generic events --- .../event/listener/KelpEventRepository.java | 105 +++++++----------- .../core/event/listener/KelpListener.java | 100 +++++++++++------ 2 files changed, 109 insertions(+), 96 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index 29cc0ef3..cb7fe717 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; /** @@ -37,7 +38,7 @@ public class KelpEventRepository { private Injector injector; private KelpLogger logger; - private Map kelpListeners; + private Map> kelpListeners; private Map timesCalled; @Inject @@ -82,62 +83,47 @@ public void detectSubscriptions(String... packageNames) { }); } - public KelpListener listen() { - return new KelpListener(this); - } - - UUID addListener(KelpListener kelpListener) { + UUID addListener(KelpListener kelpListener) { UUID uuid = UUID.randomUUID(); - for (Class listenedEvent : kelpListener.getListenedEvents()) { - Listener listenerInstance = new Listener() {}; - kelpListener.addBukkitListener(listenerInstance); - Bukkit.getPluginManager() - .registerEvent( - (listenedEvent), - listenerInstance, - EventPriority.NORMAL, - (listener, event) -> { - boolean execute = true; - for (Map.Entry> entry : kelpListener.getConditionalExpires().entrySet()) { - if (entry.getKey() != ConditionalExpiryTestStage.BEFORE_HANDLER && entry.getKey() != ConditionalExpiryTestStage.ALWAYS) { - continue; - } - if (!entry.getValue().test(event)) { - execute = false; - removeListener(uuid); - break; - } - } - - if (!execute) { - return; - } - - kelpListener.getHandler().accept(event); - int timesCalled = this.timesCalled.getOrDefault(uuid, 0); - if ((timesCalled + 1) >= kelpListener.getMaxExecutions() && kelpListener.getMaxExecutions() != -1) { - removeListener(uuid); - return; - } - this.timesCalled.put(uuid, timesCalled + 1); - - for (Map.Entry> entry : kelpListener.getConditionalExpires().entrySet()) { - if (entry.getKey() != ConditionalExpiryTestStage.AFTER_HANDLER && entry.getKey() != ConditionalExpiryTestStage.ALWAYS) { - continue; - } + Listener listenerInstance = new Listener() {}; + kelpListener.setBukkitListener(listenerInstance); - if (!entry.getValue().test(event)) { - execute = false; - removeListener(uuid); - break; - } - } + Bukkit.getPluginManager() + .registerEvent( + (kelpListener.getEventClass()), + listenerInstance, + EventPriority.NORMAL, + (listener, event) -> { + + boolean expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.BEFORE_HANDLER); + + if (expire) { + removeListener(uuid); + return; + } + + kelpListener.triggerHandler(event); + + expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.AFTER_HANDLER); + + if (expire) { + removeListener(uuid); + return; + } + + int timesCalled = this.timesCalled.getOrDefault(uuid, 0); + if ((timesCalled + 1) >= kelpListener.getMaxExecutions() && kelpListener.getMaxExecutions() != -1) { + removeListener(uuid); + return; + } + + this.timesCalled.put(uuid, timesCalled + 1); + + }, + javaPlugin, + false); - }, - javaPlugin, - false); - } this.kelpListeners.put(uuid, kelpListener); return uuid; } @@ -149,21 +135,14 @@ public void removeListener(UUID listenerId) { } KelpListener kelpListener = this.kelpListeners.get(listenerId); - kelpListener.getListenedEvents().forEach((eventClass) -> { - try { - Method method = eventClass.getMethod("getHandlerList"); + try { + Method method = kelpListener.getEventClass().getMethod("getHandlerList"); HandlerList handlerList = (HandlerList) method.invoke(null); - kelpListener.getBukkitListeners().forEach(handlerList::unregister); + handlerList.unregister(kelpListener.getBukkitListener()); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } - }); - this.kelpListeners.remove(listenerId); } - public void detectKelpEvents(String... packageNames) { - - } - } diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index 16689ba8..1ec53c39 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -1,81 +1,115 @@ package de.pxav.kelp.core.event.listener; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import de.pxav.kelp.core.KelpPlugin; import org.bukkit.event.Event; import org.bukkit.event.Listener; -import java.util.Collection; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.function.Consumer; import java.util.function.Predicate; -/** - * A class description goes here. - * - * @author pxav - */ -public class KelpListener { +public class KelpListener { - private Collection> listenedEvents = Lists.newArrayList(); private int maxExecutions = -1; - private ConcurrentMap> conditionalExpires = Maps.newConcurrentMap(); - private Consumer handler; + //TODO: min executions + private ConcurrentMap> conditionalExpires; + private Consumer handler; - private Collection bukkitListeners = Lists.newArrayList(); + private Listener bukkitListener; private KelpEventRepository kelpEventRepository; - ConcurrentMap> getConditionalExpires() { - return this.conditionalExpires; + private Class eventClass; + + public KelpListener(Class eventClass, KelpEventRepository eventRepository) { + this.eventClass = eventClass; + this.kelpEventRepository = eventRepository; + this.conditionalExpires = Maps.newConcurrentMap(); } - Collection> getListenedEvents() { - return listenedEvents; + public static KelpListener listen(Class event) { + return new KelpListener<>(event, KelpPlugin.getInjector().getInstance(KelpEventRepository.class)); } - Consumer getHandler() { - return this.handler; + ConcurrentMap> getConditionalExpires() { + return this.conditionalExpires; } - Collection getBukkitListeners() { - return bukkitListeners; + public void triggerHandler(Event event) { + T type = (T) event; + this.handler.accept(type); } - int getMaxExecutions() { - return this.maxExecutions; + Listener getBukkitListener() { + return bukkitListener; } - KelpListener(KelpEventRepository kelpEventRepository) { - this.kelpEventRepository = kelpEventRepository; + public void setBukkitListener(Listener bukkitListener) { + this.bukkitListener = bukkitListener; } - void addBukkitListener(Listener listener) { - this.bukkitListeners.add(listener); + public Class getEventClass() { + return eventClass; } - public KelpListener to(Class event) { - this.listenedEvents.add(event); - return this; + int getMaxExecutions() { + return this.maxExecutions; + } + + /** + * Tests all conditions set that would let the listener expire. + * + * @param eventPost The event to check the conditions against. + * @param currentStage The current stage of the testing process. When the event is handled + * by the {@link KelpEventRepository}, + * @return {@code true} if all tests have passed and the listener may be executed. + * {@code false} if at least one test has failed and the listener has to be unregistered. + */ + public boolean testConditions(Event eventPost, ConditionalExpiryTestStage currentStage) { + boolean output = true; + + // check whether the given event is really handled by this listener + if (eventPost.getClass() != eventClass) { + return true; + } + + T toCheck = (T) eventPost; + + for (Map.Entry> entry : conditionalExpires.entrySet()) { + ConditionalExpiryTestStage testStage = entry.getKey(); + + // if the current condition is not checked in the given stage, let the test pass. + if (currentStage != testStage && testStage != ConditionalExpiryTestStage.ALWAYS) { + return false; + } + + // check the condition. If it is false, let all the following tests fail as well. + if (!entry.getValue().test(toCheck)) { + return true; + } + } + return false; } - public KelpListener expireIf(Predicate conditionalExpiry) { + public KelpListener expireIf(Predicate conditionalExpiry) { this.conditionalExpires.put(ConditionalExpiryTestStage.BEFORE_HANDLER, conditionalExpiry); return this; } - public KelpListener expireIf(Predicate conditionalExpiry, ConditionalExpiryTestStage conditionalExpiryTestStage) { + public KelpListener expireIf(Predicate conditionalExpiry, ConditionalExpiryTestStage conditionalExpiryTestStage) { this.conditionalExpires.put(conditionalExpiryTestStage, conditionalExpiry); return this; } - public KelpListener expireAfterExecutions(int maxExecutions) { + public KelpListener expireAfterExecutions(int maxExecutions) { this.maxExecutions = maxExecutions; return this; } - public UUID handle(Consumer handler) { + public UUID handle(Consumer handler) { this.handler = handler; return kelpEventRepository.addListener(this); } From 8b45813074a26f502d35a727bb0d8ab21758adad Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 16:07:05 +0100 Subject: [PATCH 07/35] You can now define a minimal amount of executions per listener --- .../event/listener/KelpEventRepository.java | 29 +++++++++++-------- .../core/event/listener/KelpListener.java | 17 ++++++++--- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index cb7fe717..fdb5b613 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -96,30 +96,35 @@ UUID addListener(KelpListener kelpListener) { EventPriority.NORMAL, (listener, event) -> { - boolean expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.BEFORE_HANDLER); + int timesCalled = this.timesCalled.getOrDefault(uuid, 0); - if (expire) { - removeListener(uuid); - return; + // if it has to be executed according to the minimal execution times, ignore the + // expire conditions. + + // if min executions are ignored or min executions are not relevant + if (kelpListener.getMinExecutions() == -1 || timesCalled >= kelpListener.getMinExecutions()) { + boolean expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.BEFORE_HANDLER); + + if (expire) { + removeListener(uuid); + return; + } } kelpListener.triggerHandler(event); - expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.AFTER_HANDLER); - - if (expire) { + if ((timesCalled + 1) >= kelpListener.getMaxExecutions() && kelpListener.getMaxExecutions() != -1) { removeListener(uuid); return; } + this.timesCalled.put(uuid, timesCalled + 1); - int timesCalled = this.timesCalled.getOrDefault(uuid, 0); - if ((timesCalled + 1) >= kelpListener.getMaxExecutions() && kelpListener.getMaxExecutions() != -1) { + boolean expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.AFTER_HANDLER); + + if (expire) { removeListener(uuid); - return; } - this.timesCalled.put(uuid, timesCalled + 1); - }, javaPlugin, false); diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index 1ec53c39..1a0db30e 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -14,7 +14,7 @@ public class KelpListener { private int maxExecutions = -1; - //TODO: min executions + private int minExecutions = -1; private ConcurrentMap> conditionalExpires; private Consumer handler; @@ -59,21 +59,25 @@ int getMaxExecutions() { return this.maxExecutions; } + int getMinExecutions() { + return minExecutions; + } + /** * Tests all conditions set that would let the listener expire. * * @param eventPost The event to check the conditions against. * @param currentStage The current stage of the testing process. When the event is handled * by the {@link KelpEventRepository}, - * @return {@code true} if all tests have passed and the listener may be executed. - * {@code false} if at least one test has failed and the listener has to be unregistered. + * @return {@code true} if at least one test has failed and the listener has to be unregistered. + * {@code false} if all tests have passed and the listener may remain. */ public boolean testConditions(Event eventPost, ConditionalExpiryTestStage currentStage) { boolean output = true; // check whether the given event is really handled by this listener if (eventPost.getClass() != eventClass) { - return true; + return false; } T toCheck = (T) eventPost; @@ -109,6 +113,11 @@ public KelpListener expireAfterExecutions(int maxExecutions) { return this; } + public KelpListener minimalExecutions(int minExecutions) { + this.minExecutions = minExecutions; + return this; + } + public UUID handle(Consumer handler) { this.handler = handler; return kelpEventRepository.addListener(this); From 295193a0a3e1a5dce3cfb76a8319449547a2f1d9 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 17:08:11 +0100 Subject: [PATCH 08/35] Fix bug that conditional expiry was not handled correctly --- .../de/pxav/kelp/core/event/listener/KelpEventRepository.java | 2 +- .../java/de/pxav/kelp/core/event/listener/KelpListener.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index fdb5b613..a09ff3fe 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -113,7 +113,7 @@ UUID addListener(KelpListener kelpListener) { kelpListener.triggerHandler(event); - if ((timesCalled + 1) >= kelpListener.getMaxExecutions() && kelpListener.getMaxExecutions() != -1) { + if ((timesCalled + 1) >= kelpListener.getMaxExecutions()) { removeListener(uuid); return; } diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index 1a0db30e..32179fe0 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -91,7 +91,7 @@ public boolean testConditions(Event eventPost, ConditionalExpiryTestStage curren } // check the condition. If it is false, let all the following tests fail as well. - if (!entry.getValue().test(toCheck)) { + if (entry.getValue().test(toCheck)) { return true; } } From c29239355f298645abc27be7804b276064f926d4 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 17:23:13 +0100 Subject: [PATCH 09/35] Add documentation to inventory events --- .../event/kelpevent/KelpInventoryCloseEvent.java | 13 ++++++++++++- .../event/kelpevent/KelpInventoryOpenEvent.java | 10 +++++++++- .../event/kelpevent/KelpInventoryUpdateEvent.java | 8 +++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java index 898ef549..39cf20d4 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryCloseEvent.java @@ -7,7 +7,8 @@ import org.bukkit.event.player.PlayerEvent; /** - * A class description goes here. + * This event is called when a player closes their {@link KelpInventory} + * or it is closed by a plugin. * * @author pxav */ @@ -23,10 +24,20 @@ public KelpInventoryCloseEvent(KelpPlayer who, KelpInventory inventory, boolean this.animated = isAnimated; } + /** + * Gets the inventory that has been closed. + * + * @return The closed inventory + */ public KelpInventory getInventory() { return this.inventory; } + /** + * Checks whether the closed inventory has an animated title. + * + * @return {@code true} if the title was animated. + */ public boolean isAnimated() { return animated; } diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java index 0649344e..dae00b51 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryOpenEvent.java @@ -7,7 +7,9 @@ import org.bukkit.event.player.PlayerEvent; /** - * A class description goes here. + * This event is triggered when a player opens a {@link KelpInventory} or + * the inventory is opened by a plugin. This does not include opening the player's + * personal inventory, which is opened by pressing {@code 'E'}. * * @author pxav */ @@ -27,6 +29,12 @@ public KelpInventory getInventory() { return inventory; } + /** + * Checks if the inventory is a subclass of {@link de.pxav.kelp.core.inventory.type.AnimatedInventory}, + * which would mean that the title is animated. + * + * @return {@code true} if the inventory's title is animated. + */ public boolean isAnimatedInventory() { return animatedInventory; } diff --git a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java index 219e156f..f4ed295c 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java +++ b/core/src/main/java/de/pxav/kelp/core/event/kelpevent/KelpInventoryUpdateEvent.java @@ -7,7 +7,8 @@ import org.bukkit.event.player.PlayerEvent; /** - * A class description goes here. + * This event is called when a {@link KelpInventory} is updated. This does not + * include title updates of animated inventories. * * @author pxav */ @@ -21,6 +22,11 @@ public KelpInventoryUpdateEvent(KelpPlayer who, KelpInventory inventory) { this.inventory = inventory; } + /** + * Gets the inventory that has been updated. + * + * @return the updated inventory + */ public KelpInventory getInventory() { return inventory; } From dd48e9c2175382c355f5aa9305c77ca0670cf20e Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 17:25:49 +0100 Subject: [PATCH 10/35] Add auto-inject mode for @Subscribes annotation --- .../event/listener/KelpEventRepository.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index a09ff3fe..0ff56dbd 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -4,17 +4,21 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; +import de.pxav.kelp.core.event.kelpevent.KelpPlayerEvent; import de.pxav.kelp.core.logger.KelpLogger; import de.pxav.kelp.core.logger.LogLevel; import de.pxav.kelp.core.player.KelpPlayer; +import de.pxav.kelp.core.player.KelpPlayerRepository; import de.pxav.kelp.core.reflect.MethodCriterion; import de.pxav.kelp.core.reflect.MethodFinder; import de.pxav.kelp.core.reflect.TypeFinder; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerEvent; import org.bukkit.plugin.java.JavaPlugin; import java.lang.reflect.InvocationTargetException; @@ -32,18 +36,18 @@ @Singleton public class KelpEventRepository { - private TypeFinder typeFinder; private MethodFinder methodFinder; private JavaPlugin javaPlugin; private Injector injector; private KelpLogger logger; + private KelpPlayerRepository playerRepository; private Map> kelpListeners; private Map timesCalled; @Inject - public KelpEventRepository(TypeFinder typeFinder, MethodFinder methodFinder, JavaPlugin javaPlugin, Injector injector, KelpLogger logger) { - this.typeFinder = typeFinder; + public KelpEventRepository(KelpPlayerRepository playerRepository, MethodFinder methodFinder, JavaPlugin javaPlugin, Injector injector, KelpLogger logger) { + this.playerRepository = playerRepository; this.methodFinder = methodFinder; this.javaPlugin = javaPlugin; this.injector = injector; @@ -67,8 +71,27 @@ public void detectSubscriptions(String... packageNames) { try { if (current.getParameters().length == 0) { current.invoke(injector.getInstance(current.getDeclaringClass())); - } else if (current.getParameters().length == 1 && current.getParameterTypes()[0].isAssignableFrom(KelpPlayer.class)) { - // invoke with event player as parameter + return; + } + + // auto inject for specific parameters: + + if (current.getParameters().length == 1 + && current.getParameterTypes()[0].isAssignableFrom(KelpPlayer.class)) { + if (event instanceof PlayerEvent) { + PlayerEvent playerEvent = (PlayerEvent) event; + KelpPlayer kelpPlayer = playerRepository.getKelpPlayer(playerEvent.getPlayer()); + current.invoke(injector.getInstance(current.getDeclaringClass()), kelpPlayer); + } else if (event instanceof KelpPlayerEvent) { + KelpPlayerEvent playerEvent = (KelpPlayerEvent) event; + current.invoke(injector.getInstance(current.getDeclaringClass()), playerEvent.getPlayer()); + } + } + if (event instanceof PlayerEvent + && current.getParameters().length == 1 + && current.getParameterTypes()[0].isAssignableFrom(Player.class)) { + PlayerEvent playerEvent = (PlayerEvent) event; + current.invoke(injector.getInstance(current.getDeclaringClass()), playerEvent.getPlayer()); } } catch (IllegalAccessException | InvocationTargetException e) { From 289175d018980901ebe428b7ca79f726593bbc49 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 17:58:56 +0100 Subject: [PATCH 11/35] You can now add filters to dynamic events --- .../event/listener/KelpEventRepository.java | 6 ++++ .../core/event/listener/KelpListener.java | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index 0ff56dbd..10957427 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -134,8 +134,14 @@ UUID addListener(KelpListener kelpListener) { } } + // if one or more filters do not match + if (!kelpListener.testFilters(event)) { + return; + } + kelpListener.triggerHandler(event); + if ((timesCalled + 1) >= kelpListener.getMaxExecutions()) { removeListener(uuid); return; diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index 32179fe0..c02fd448 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -1,10 +1,12 @@ package de.pxav.kelp.core.event.listener; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import de.pxav.kelp.core.KelpPlugin; import org.bukkit.event.Event; import org.bukkit.event.Listener; +import java.util.Collection; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentMap; @@ -16,6 +18,7 @@ public class KelpListener { private int maxExecutions = -1; private int minExecutions = -1; private ConcurrentMap> conditionalExpires; + private Collection> filters; private Consumer handler; private Listener bukkitListener; @@ -28,6 +31,7 @@ public KelpListener(Class eventClass, KelpEventRepository eventRepository) { this.eventClass = eventClass; this.kelpEventRepository = eventRepository; this.conditionalExpires = Maps.newConcurrentMap(); + this.filters = Lists.newArrayList(); } public static KelpListener listen(Class event) { @@ -98,6 +102,26 @@ public boolean testConditions(Event eventPost, ConditionalExpiryTestStage curren return false; } + /** + * Tests all the given filters of the listener and checks whether + * the event should be handled right now. + * + * @param eventPost The event to check the filters against. + * @return {@code true} if all filters match and the event can be handled. + * {@code false} if at least one filter does not match. + */ + public boolean testFilters(Event eventPost) { + T eventCheck = (T) eventPost; + + for (Predicate filter : filters) { + if (!filter.test(eventCheck)) { + return false; + } + } + + return true; + } + public KelpListener expireIf(Predicate conditionalExpiry) { this.conditionalExpires.put(ConditionalExpiryTestStage.BEFORE_HANDLER, conditionalExpiry); return this; @@ -108,6 +132,11 @@ public KelpListener expireIf(Predicate conditionalExpiry, Conditio return this; } + public KelpListener filter(Predicate condition) { + this.filters.add(condition); + return this; + } + public KelpListener expireAfterExecutions(int maxExecutions) { this.maxExecutions = maxExecutions; return this; From 1f93b328c954d090aa92fe62f6c8def9385be218 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 18:13:23 +0100 Subject: [PATCH 12/35] Add #getName() method to KelpPlayer --- core/src/main/java/de/pxav/kelp/core/player/KelpPlayer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/player/KelpPlayer.java b/core/src/main/java/de/pxav/kelp/core/player/KelpPlayer.java index 4f6da573..82f2eabe 100644 --- a/core/src/main/java/de/pxav/kelp/core/player/KelpPlayer.java +++ b/core/src/main/java/de/pxav/kelp/core/player/KelpPlayer.java @@ -347,6 +347,10 @@ public UUID getUUID() { return playerVersionTemplate.getUniqueId(bukkitPlayer); } + public String getName() { + return bukkitPlayer.getName(); + } + // @Override // public KelpPlayer teleport(Location location) { // playerVersionTemplate.teleport(bukkitPlayer, location); From 3da2c586afa164c9e06e200662e7d234e53171d5 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 18:13:39 +0100 Subject: [PATCH 13/35] Add some default event criteria --- .../core/event/listener/EventCriteria.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java b/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java new file mode 100644 index 00000000..106df6c0 --- /dev/null +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java @@ -0,0 +1,31 @@ +package de.pxav.kelp.core.event.listener; + +import de.pxav.kelp.core.event.kelpevent.KelpPlayerEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import java.util.function.Predicate; + +public class EventCriteria { + + public static Predicate playerHasPermission(String permission) { + return event -> event.getPlayer().hasPermission(permission); + } + + public static Predicate playerName(String name) { + return event -> event.getPlayer().getName().equalsIgnoreCase(name); + } + + public static Predicate playerIsOperator() { + return event -> event.getPlayer().isOperator(); + } + + public static Predicate messageStartsWith(String prefix) { + return event -> event.getMessage().startsWith(prefix); + } + + public static Predicate commandStartsWith(String prefix) { + return event -> event.getMessage().startsWith(prefix); + } + +} From aa3208de2f9ed6deca16c861863476a2f3b65ca3 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 18:15:29 +0100 Subject: [PATCH 14/35] Rename event filters to criteria --- .../event/listener/KelpEventRepository.java | 7 ++---- .../core/event/listener/KelpListener.java | 22 +++++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index 10957427..1ffcafb1 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -11,7 +11,6 @@ import de.pxav.kelp.core.player.KelpPlayerRepository; import de.pxav.kelp.core.reflect.MethodCriterion; import de.pxav.kelp.core.reflect.MethodFinder; -import de.pxav.kelp.core.reflect.TypeFinder; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -25,8 +24,6 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; /** * A class description goes here. @@ -134,8 +131,8 @@ UUID addListener(KelpListener kelpListener) { } } - // if one or more filters do not match - if (!kelpListener.testFilters(event)) { + // if one or more criteria do not match, don't handle the event. + if (!kelpListener.testCriteria(event)) { return; } diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index c02fd448..3e5d654a 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -18,7 +18,7 @@ public class KelpListener { private int maxExecutions = -1; private int minExecutions = -1; private ConcurrentMap> conditionalExpires; - private Collection> filters; + private Collection> criteria; private Consumer handler; private Listener bukkitListener; @@ -31,7 +31,7 @@ public KelpListener(Class eventClass, KelpEventRepository eventRepository) { this.eventClass = eventClass; this.kelpEventRepository = eventRepository; this.conditionalExpires = Maps.newConcurrentMap(); - this.filters = Lists.newArrayList(); + this.criteria = Lists.newArrayList(); } public static KelpListener listen(Class event) { @@ -103,18 +103,18 @@ public boolean testConditions(Event eventPost, ConditionalExpiryTestStage curren } /** - * Tests all the given filters of the listener and checks whether + * Tests all the given criteria of the listener and checks whether * the event should be handled right now. * - * @param eventPost The event to check the filters against. - * @return {@code true} if all filters match and the event can be handled. - * {@code false} if at least one filter does not match. + * @param eventPost The event to check the criteria against. + * @return {@code true} if all criteria match and the event can be handled. + * {@code false} if at least one criterion does not match. */ - public boolean testFilters(Event eventPost) { + public boolean testCriteria(Event eventPost) { T eventCheck = (T) eventPost; - for (Predicate filter : filters) { - if (!filter.test(eventCheck)) { + for (Predicate criterion : criteria) { + if (!criterion.test(eventCheck)) { return false; } } @@ -132,8 +132,8 @@ public KelpListener expireIf(Predicate conditionalExpiry, Conditio return this; } - public KelpListener filter(Predicate condition) { - this.filters.add(condition); + public KelpListener criterion(Predicate condition) { + this.criteria.add(condition); return this; } From b59ff75fec9b3d11cda7fa9549a232ccea1b595e Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 18:37:07 +0100 Subject: [PATCH 15/35] Add static factory to KelpConsoleSender --- .../de/pxav/kelp/core/command/KelpConsoleSender.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/command/KelpConsoleSender.java b/core/src/main/java/de/pxav/kelp/core/command/KelpConsoleSender.java index fb166b2b..3d2c4be9 100644 --- a/core/src/main/java/de/pxav/kelp/core/command/KelpConsoleSender.java +++ b/core/src/main/java/de/pxav/kelp/core/command/KelpConsoleSender.java @@ -1,6 +1,8 @@ package de.pxav.kelp.core.command; +import de.pxav.kelp.core.KelpPlugin; import de.pxav.kelp.core.command.version.KelpConsoleSenderVersionTemplate; +import de.pxav.kelp.core.player.KelpPlayer; import org.bukkit.command.CommandSender; /** @@ -31,6 +33,13 @@ public class KelpConsoleSender { this.versionTemplate = versionTemplate; } + public static KelpConsoleSender create(CommandSender bukkitSender) { + return new KelpConsoleSender( + bukkitSender, + KelpPlugin.getInjector().getInstance(KelpConsoleSenderVersionTemplate.class) + ); + } + /** * Sends a message to the console sender. * @param message The message you want to send (may contain color codes using §) From 84a23961f6a6bd3d76dc407f7160db3ac9b2dd83 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 18:41:17 +0100 Subject: [PATCH 16/35] You can now delegate onCommand methods to console sender --- .../java/de/pxav/kelp/core/command/KelpCommand.java | 11 +++++++++++ .../command/VersionedCommandRegistry.java | 12 ++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java b/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java index c04dc345..92f2dd4a 100644 --- a/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java +++ b/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java @@ -54,6 +54,8 @@ public class KelpCommand { // resets the argument count for sub commands to 0 again. private boolean argumentsStartFromZero; + private boolean delegatePlayerToConsole; + /** * This method is executed by the command registry, when the command * is executed by a player and {@code PLAYER_ONLY} is set as executor type. @@ -99,6 +101,10 @@ public Map getSubCommands() { return subCommands; } + public void delegatePlayerToConsole(boolean delegate) { + this.delegatePlayerToConsole = delegate; + } + /** * Sets the description of the command, which can later be used * to display in help commands, etc. @@ -406,4 +412,9 @@ public boolean shouldArgumentsStartFromZero() { public Collection getAliases() { return aliases; } + + public boolean shouldDelegateToConsole() { + return this.delegatePlayerToConsole; + } + } diff --git a/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/command/VersionedCommandRegistry.java b/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/command/VersionedCommandRegistry.java index d8be7f19..0f3d9629 100644 --- a/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/command/VersionedCommandRegistry.java +++ b/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/command/VersionedCommandRegistry.java @@ -157,7 +157,11 @@ private boolean checkPlayerPermissionsAndExecute(CommandSender sender, String[] if (command.getPermission() != null) { if (bukkitPlayer.hasPermission(command.getPermission())) { if (executorType == ExecutorType.PLAYER_AND_CONSOLE) { - command.onCommand(player, args); + if (command.shouldDelegateToConsole()) { + command.onCommand(KelpConsoleSender.create(player.getBukkitPlayer()), args); + } else { + command.onCommand(player, args); + } } else if (executorType == ExecutorType.PLAYER_ONLY) { command.onCommand(player, args); } @@ -170,7 +174,11 @@ private boolean checkPlayerPermissionsAndExecute(CommandSender sender, String[] return false; } else { if (executorType == ExecutorType.PLAYER_AND_CONSOLE) { - command.onCommand(player, args); + if (command.shouldDelegateToConsole()) { + command.onCommand(KelpConsoleSender.create(player.getBukkitPlayer()), args); + } else { + command.onCommand(player, args); + } } else if (executorType == ExecutorType.PLAYER_ONLY) { command.onCommand(player, args); } From a863bee97afda5ba76fa6ca19d18a8850b37576e Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 19:03:09 +0100 Subject: [PATCH 17/35] Sub commands can now inherit properties from their main commands --- .../pxav/kelp/core/command/KelpCommand.java | 10 +++++++++ .../core/command/KelpCommandRepository.java | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java b/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java index 92f2dd4a..dee08306 100644 --- a/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java +++ b/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java @@ -56,6 +56,8 @@ public class KelpCommand { private boolean delegatePlayerToConsole; + private boolean inheritFromMainCommand; + /** * This method is executed by the command registry, when the command * is executed by a player and {@code PLAYER_ONLY} is set as executor type. @@ -105,6 +107,10 @@ public void delegatePlayerToConsole(boolean delegate) { this.delegatePlayerToConsole = delegate; } + public void inheritFromMainCommand(boolean inherit) { + this.inheritFromMainCommand = inherit; + } + /** * Sets the description of the command, which can later be used * to display in help commands, etc. @@ -417,4 +423,8 @@ public boolean shouldDelegateToConsole() { return this.delegatePlayerToConsole; } + public boolean shouldInheritFromMainCommand() { + return this.inheritFromMainCommand; + } + } diff --git a/core/src/main/java/de/pxav/kelp/core/command/KelpCommandRepository.java b/core/src/main/java/de/pxav/kelp/core/command/KelpCommandRepository.java index 5c8daa83..7b255bc2 100644 --- a/core/src/main/java/de/pxav/kelp/core/command/KelpCommandRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/command/KelpCommandRepository.java @@ -88,6 +88,28 @@ public void loadCommands(String... packages) { commandClass.onCommandRegister(); + // inherit properties from main command to sub commands if needed. + commandClass.getSubCommands().forEach((subCommand, subCommandAnnotation) -> { + if (!subCommand.shouldInheritFromMainCommand()) { + return; + } + if (subCommand.getNoPermissionMessage() == null) { + subCommand.noPermissionMessage(commandClass.getNoPermissionMessage()); + } + if (subCommand.getNoConsoleMessage() == null) { + subCommand.noConsoleMessage(commandClass.getNoConsoleMessage()); + } + if (subCommand.getNoPlayerMessage() == null) { + subCommand.noPlayerMessage(commandClass.getNoPlayerMessage()); + } + if (subCommand.getPermission() == null) { + subCommand.permission(commandClass.getPermission()); + } + if (subCommand.getDescription() == null) { + subCommand.description(commandClass.getDescription()); + } + }); + // add command to bukkit registry registryVersionTemplate.registerCommand(commandClass, commandAnnotation); logger.log(LogLevel.DEBUG, "[COMMAND] Registered main command " From cd6ada9b59d267d7bcd41927188dbb8e8755590d Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 22:36:45 +0100 Subject: [PATCH 18/35] Add method picking any random formatting code (either style or color) --- .../pxav/kelp/core/command/KelpCommand.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java b/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java index dee08306..d1f9ba20 100644 --- a/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java +++ b/core/src/main/java/de/pxav/kelp/core/command/KelpCommand.java @@ -54,8 +54,14 @@ public class KelpCommand { // resets the argument count for sub commands to 0 again. private boolean argumentsStartFromZero; + // if 'true' the onCommand() method for console will be + // used although a player executes the command (if executor + // type is set to PLAYER_AND_CONSOLE) private boolean delegatePlayerToConsole; + // whether basic properties such as error messages should be taken + // from the parent command, so that they don't have to be defined + // manually each time. private boolean inheritFromMainCommand; /** @@ -96,6 +102,8 @@ public void onCommand(KelpConsoleSender consoleSender, String[] args) {} public void onCommandRegister() {} /** + * Gets a collection of all sub commands associated with this command. + * * @return A map of all sub commands, where the key is the command class * of the command and the value is the sub command annotation. */ @@ -103,10 +111,41 @@ public Map getSubCommands() { return subCommands; } + /** + * Delegates the command executor from the player to a console. Normally, if executor type + * is set to {@link ExecutorType#PLAYER_AND_CONSOLE} and a player executes the command, + * the {@link #onCommand(KelpPlayer, String[])} method is called. But if you want the same + * command structure to be executed for both types of users, you might not want to copy the + * methods for player and console. That's why you can use this method to create a kind of + * redirection. If this is enabled, the player will be converted to a console sender and + * the {@link #onCommand(KelpConsoleSender, String[])} method will be executed so that + * you only have to maintain one command method. + * + * @param delegate {@code true} if the described redirection/delegation + * of commands should be done. + */ public void delegatePlayerToConsole(boolean delegate) { this.delegatePlayerToConsole = delegate; } + /** + * Makes the current command inherit certain properties of the parent command. + * This includes: + *
    + *
  • Command description
  • + *
  • Command permission
  • + *
  • No permission message
  • + *
  • No player message
  • + *
  • No console message
  • + *
+ * + * You can of course inherit properties from the parent command and overwrite + * them manually later, while keeping the values for the other strings. So if + * you only want to change the description you can inherit all properties and overwrite + * the description yourself. + * + * @param inherit {@code true} if you want the listed properties to be inherited from the main command. + */ public void inheritFromMainCommand(boolean inherit) { this.inheritFromMainCommand = inherit; } @@ -362,6 +401,9 @@ public KelpCommand argumentsStartFromZero(boolean argumentsStartFromZero) { } /** + * Gets the command's description used in the Kelp command + * overview for example. + * * @return The description of the command. */ public String getDescription() { @@ -369,6 +411,9 @@ public String getDescription() { } /** + * Gets the custom message that is sent to a player when they do not + * have sufficient permissions to execute the command. + * * @return The message which is sent to players, if they do not have enough * permissions. */ @@ -377,6 +422,11 @@ public String getNoPermissionMessage() { } /** + * Gets the custom message set by this command which is sent when + * a console tries to execute the command, although it is made + * for players only. If this is null, the default message of + * Kelp will be used. + * * @return The message which is sent to the console, when it * executes a command, which is meant for players only. */ @@ -385,6 +435,10 @@ public String getNoPlayerMessage() { } /** + * Gets the custom message set by this command which is sent when + * a player executes the command although it is meant for consoles + * only. If this is null, the default message will be used. + * * @return The message which is sent to players when they execute a console command. */ public String getNoConsoleMessage() { @@ -392,6 +446,9 @@ public String getNoConsoleMessage() { } /** + * Gets the permission that is needed by a player to execute the command. + * A console does not need this permission. + * * @return Returns the permission string, which is needed for this command. */ public String getPermission() { @@ -399,6 +456,10 @@ public String getPermission() { } /** + * Checks whether custom parameters other than sub commands are + * accepted by the command. If this is false, you won't be able to + * handle such custom user inputs. + * * @return {@code true} if custom parameters are allowed in this command. */ public boolean customParametersAllowed() { @@ -406,6 +467,9 @@ public boolean customParametersAllowed() { } /** + * Checks whether the arguments should be reset when queried in a sub command. + * For more information see {@link #argumentsStartFromZero(boolean)} + * * @return {@code true} if the argument count should be reset to 0. */ public boolean shouldArgumentsStartFromZero() { @@ -413,12 +477,19 @@ public boolean shouldArgumentsStartFromZero() { } /** + * Gets a collection of all aliases defined for this command. + * * @return A collection of all aliases the command has. */ public Collection getAliases() { return aliases; } + /** + * Checks if the command + * + * @return + */ public boolean shouldDelegateToConsole() { return this.delegatePlayerToConsole; } From b0f6bfa97b55ba0ac3adc09b7bbdca8084e54461 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 22:37:04 +0100 Subject: [PATCH 19/35] Add method picking any random formatting code (either style or color) --- core/src/main/java/de/pxav/kelp/core/common/StringUtils.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java b/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java index aaeb728d..bc47ecc2 100644 --- a/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java +++ b/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java @@ -303,6 +303,10 @@ public char randomStyleCode() { return styleCodes[ThreadLocalRandom.current().nextInt(colorCodes.length - 1)]; } + public char randomFormattingCode() { + return ThreadLocalRandom.current().nextBoolean() ? randomColorCode() : randomStyleCode(); + } + /** * @param indicator The indicator of the code you want to check. * @return {@code true} if the either a color code or a style code. From 2a42cdcb0b0702a504e74c90500da782bb883c43 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 22:37:20 +0100 Subject: [PATCH 20/35] Add documentation to text animation main interface --- .../de/pxav/kelp/core/animation/TextAnimation.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/pxav/kelp/core/animation/TextAnimation.java b/core/src/main/java/de/pxav/kelp/core/animation/TextAnimation.java index 267814b1..a2d1ceea 100644 --- a/core/src/main/java/de/pxav/kelp/core/animation/TextAnimation.java +++ b/core/src/main/java/de/pxav/kelp/core/animation/TextAnimation.java @@ -3,12 +3,24 @@ import java.util.List; /** - * A class description goes here. + * This interface represents the basis of every text animation + * used within the Kelp framework. A text animation basically takes + * a string and optionally some additional data and converts it to + * an animation. The animation consists of a collection of multiple + * strings. If you play those strings with a regular interval + * it will look like an animation. * * @author pxav */ public interface TextAnimation { + /** + * This method calculates the given data from the animation class + * to a final animation. The list contains all animation states that - if played + * one by one - make up the final animation. + * + * @return The final collection of all states of the animation in a chronological order. + */ List states(); } From 15ff469f7ff6108a87ac6e2e105e79fe27d9d6ca Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 22:37:28 +0100 Subject: [PATCH 21/35] Add documentation to TextAnimationFactory --- .../de/pxav/kelp/core/animation/TextAnimationFactory.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/pxav/kelp/core/animation/TextAnimationFactory.java b/core/src/main/java/de/pxav/kelp/core/animation/TextAnimationFactory.java index fee83743..7d1bb7f5 100644 --- a/core/src/main/java/de/pxav/kelp/core/animation/TextAnimationFactory.java +++ b/core/src/main/java/de/pxav/kelp/core/animation/TextAnimationFactory.java @@ -5,7 +5,13 @@ import de.pxav.kelp.core.common.StringUtils; /** - * A class description goes here. + * This factory class is used to produce instances of + * new {@link TextAnimation}s. + * + * This is useful if you fully follow an object-oriented and dependency- + * injecting design approach. For most cases, it would probably also clean + * to use static factory methods of the different text animation types such + * as {@link BuildingTextAnimation}. * * @author pxav */ From ae8f40a6405334f8417711747dbeeedf212e3f66 Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 22:37:39 +0100 Subject: [PATCH 22/35] Add documentation to StaticTextAnimation --- .../kelp/core/animation/StaticTextAnimation.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/pxav/kelp/core/animation/StaticTextAnimation.java b/core/src/main/java/de/pxav/kelp/core/animation/StaticTextAnimation.java index 34e9325b..814b67bf 100644 --- a/core/src/main/java/de/pxav/kelp/core/animation/StaticTextAnimation.java +++ b/core/src/main/java/de/pxav/kelp/core/animation/StaticTextAnimation.java @@ -4,7 +4,11 @@ import java.util.List; /** - * A class description goes here. + * This text animation is used to display static texts where a + * {@link TextAnimation} object is required by design. If you have + * an animated sidebar for example and you want to display a static + * text for example for debugging purposes, you can use this animation + * type. * * @author pxav */ @@ -22,6 +26,12 @@ public static StaticTextAnimation create() { return new StaticTextAnimation(); } + /** + * Sets the text to be displayed in the static animation. + * + * @param text The text to be displayed. + * @return Instance of the current animation object. + */ public StaticTextAnimation text(String text) { this.text = text; return this; From 3632f78d094023ee9666d10b602afca5f1bbb2da Mon Sep 17 00:00:00 2001 From: pxav Date: Sun, 31 Jan 2021 22:56:16 +0100 Subject: [PATCH 23/35] Add documentation to StringUtils --- .../de/pxav/kelp/core/common/StringUtils.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java b/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java index bc47ecc2..1949a8f3 100644 --- a/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java +++ b/core/src/main/java/de/pxav/kelp/core/common/StringUtils.java @@ -243,18 +243,46 @@ public boolean isStyleCode(char indicator) { return false; } + /** + * Takes a formatting code char (without the {@code '§'} in front) + * and converts it to a {@link ChatColor} object of the md_5 library. + * If there could be no chat color found, {@link ChatColor#WHITE WHITE} + * will be returned. + * + * @param formattingCode The formatting code to be converted. + * @return The corresponding md_5 chat color. + */ public ChatColor getChatColor(char formattingCode) { return isFormattingCode(formattingCode) ? ChatColor.getByChar(formattingCode) : ChatColor.WHITE; } + /** + * Takes a formatting code char (without the {@code '§'} in front) + * and converts it to a {@link org.bukkit.ChatColor} object of the bukkit library. + * If there could be no chat color found, {@link org.bukkit.ChatColor#WHITE WHITE} + * will be returned. + * + * @param formattingCode The formatting code to be converted. + * @return The corresponding bukkit chat color. + */ public org.bukkit.ChatColor getBukkitChatColor(char formattingCode) { return isFormattingCode(formattingCode) ? org.bukkit.ChatColor.getByChar(formattingCode) : org.bukkit.ChatColor.WHITE; } + /** + * Takes a formatting code with syntax {@code '§x'} and converts + * it to a {@link ChatColor} object of spigot/md_5 library. If the + * given code could not be found, {@link org.bukkit.ChatColor#WHITE WHITE} + * is returned. + * + * @param formattingCode The formatting code to be converted. + * @return The final {@link ChatColor} to be returned. {@code null} if the + * color was not found. + */ public ChatColor getChatColor(String formattingCode) { char code = formattingCode.charAt(1); return isFormattingCode(code) && formattingCode.charAt(0) == '§' @@ -262,6 +290,15 @@ public ChatColor getChatColor(String formattingCode) { : ChatColor.WHITE; } + /** + * Takes a formatting code with syntax {@code '§x'} and converts + * it to a {@link org.bukkit.ChatColor} object of bukkit. If the + * given code could not be found, {@link org.bukkit.ChatColor#WHITE WHITE} + * is returned. + * + * @param formattingCode The formatting code to be converted. + * @return The final {@link org.bukkit.ChatColor} to be returned. + */ public org.bukkit.ChatColor getBukkitChatColor(String formattingCode) { char code = formattingCode.charAt(1); return isFormattingCode(code) && formattingCode.charAt(0) == '§' @@ -269,6 +306,14 @@ public org.bukkit.ChatColor getBukkitChatColor(String formattingCode) { : org.bukkit.ChatColor.WHITE; } + /** + * Checks whether the given text ends with a color code. + * This does not check for style codes. + * + * @param text The text to be checked for color codes. + * @return The last color code of the text. {@code null} if there + * was no color code to be detected. + */ public String endsWithColorCode(String text) { if (text.length() < 2) { return null; @@ -282,7 +327,17 @@ public String endsWithColorCode(String text) { return null; } + /** + * Checks whether the given text ends with any formatting code + * (no matter if style or color). + * + * @param text The text to be checked for formatting codes. + * @return The last formatting code of the text. {@code null} if there + * was no color code to be detected. + */ public String endsWithFormattingCode(String text) { + // if the text is less than 2 chars long there can + // be no formatting code, so return immediately. if (text.length() < 2) { return null; } @@ -295,14 +350,32 @@ public String endsWithFormattingCode(String text) { return null; } + /** + * Picks a random color code id. This means the result will only be + * something like {@code '1', 'b', ...} without a {@code '§'} in front. + * + * @return Any random bukkit color code. + */ public char randomColorCode() { return colorCodes[ThreadLocalRandom.current().nextInt(colorCodes.length - 1)]; } + /** + * Picks a random style code. This means the result will only be + * something like {@code 'k', 'o', ...} without a {@code '§'} in front. + * + * @return + */ public char randomStyleCode() { return styleCodes[ThreadLocalRandom.current().nextInt(colorCodes.length - 1)]; } + /** + * Picks any random formatting code from the list. This can either be + * a result of {@link #randomStyleCode()} or {@link #randomColorCode()}. + * + * @return Any random foramtting code without {@code '§'} in front. + */ public char randomFormattingCode() { return ThreadLocalRandom.current().nextBoolean() ? randomColorCode() : randomStyleCode(); } From 499cfc620d3d4863d5989d8fcc34d0353c4f488f Mon Sep 17 00:00:00 2001 From: pxav Date: Tue, 2 Feb 2021 21:07:26 +0100 Subject: [PATCH 24/35] Remove unneeded getter from KelpListener --- .../java/de/pxav/kelp/core/event/listener/KelpListener.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index 3e5d654a..d9c8b6b6 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -38,10 +38,6 @@ public static KelpListener listen(Class event) { return new KelpListener<>(event, KelpPlugin.getInjector().getInstance(KelpEventRepository.class)); } - ConcurrentMap> getConditionalExpires() { - return this.conditionalExpires; - } - public void triggerHandler(Event event) { T type = (T) event; this.handler.accept(type); From f1a79e1f37b73649a04daf7968ddf4966edc093a Mon Sep 17 00:00:00 2001 From: pxav Date: Tue, 2 Feb 2021 22:03:02 +0100 Subject: [PATCH 25/35] Add documentation to KelpListener --- .../core/event/listener/KelpListener.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index d9c8b6b6..4e7cacc2 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -13,6 +13,19 @@ import java.util.function.Consumer; import java.util.function.Predicate; +/** + * This class provides a way to create dynamic, functional listeners + * at runtime. You don't have to predefine specific event handlers using + * {@link org.bukkit.event.EventHandler} methods, but you can register + * and unregister those listeners at runtime, while benefiting from + * features such as criteria or minimum executions, etc. + * + * Listeners can be created via static factory method {@link KelpListener#listen(Class)} + * and unregistered via their {@code listenerId} using {@link KelpEventRepository#removeListener(UUID)} + * + * @param The type of event you are listening to. + * @author pxav + */ public class KelpListener { private int maxExecutions = -1; @@ -34,31 +47,77 @@ public KelpListener(Class eventClass, KelpEventRepository eventRepository) { this.criteria = Lists.newArrayList(); } + /** + * Registers a new dynamic listener for the given event. + * + * @param event The class of the event to listen for. + * @param The event type used to adjust the class to your event. + * @return An instance of the current listener for fluent builder design. + */ public static KelpListener listen(Class event) { return new KelpListener<>(event, KelpPlugin.getInjector().getInstance(KelpEventRepository.class)); } + /** + * Calls the code that has been defined in the {@link #handle(Consumer)} + * + * @param event The instance of the event that has been + * called and should be handled now. + */ public void triggerHandler(Event event) { T type = (T) event; this.handler.accept(type); } + /** + * Gets the instance of the bukkit listener, which calls this dynamic listener. + * + * + * @return The instance of the bukkit listener, which is responsible for this dynamic listener. + */ Listener getBukkitListener() { return bukkitListener; } + /** + * Sets the internal bukkit listener instance. When registering this dynamic listener, + * + * + * @param bukkitListener The instance of the bukkit listener under + * which the event is registered. + */ public void setBukkitListener(Listener bukkitListener) { this.bukkitListener = bukkitListener; } + /** + * Gets the class of the event, which is handled by this + * listener. If the listener is handling {@link de.pxav.kelp.core.event.kelpevent.KelpPlayerLoginEvent}, + * this method will return {@code KelpPlayerLoginEvent.class} + * + * @return The class of the event, which is handled by this listener. + */ public Class getEventClass() { return eventClass; } + /** + * Gets the maximum amount of times this event should be handled. + * It won't be handled after the listener code has been executed + * this specific amount of times. + * + * @return The maximum amount of event handles. + */ int getMaxExecutions() { return this.maxExecutions; } + /** + * Gets the minimal amount of times this event should be handled. + * It won't expire until this number of executions has been reached. + * + * @return The amount of minimal executions/handles of this listener. + */ int getMinExecutions() { return minExecutions; } @@ -118,31 +177,90 @@ public boolean testCriteria(Event eventPost) { return true; } + /** + * Adds an expiry condition to the listener. This method automatically selects + * {@link ConditionalExpiryTestStage#BEFORE_HANDLER}, which means that the condition is always + * checked before the event is handled. It won't be checked afterwards. + * + * If the condition is true the listener will be unregistered and not executed in the future. + * + * @param conditionalExpiry The condition to check for each time before the actual handler is called. + * @return An instance of the current listener for fluent builder design. + */ public KelpListener expireIf(Predicate conditionalExpiry) { this.conditionalExpires.put(ConditionalExpiryTestStage.BEFORE_HANDLER, conditionalExpiry); return this; } + /** + * Adds an expiry condition to the listener. Depending on which {@code conditionalExpiryTestStage} you have + * selected, the given condition is checked before and after the event is handled. + * If the condition is true the listener will be unregistered and not executed in the future. + * + * @param conditionalExpiry The condition to check for before/after each event. + * @param conditionalExpiryTestStage When the condition should be checked (before, after, always?) + * @return An instance of the current listener for fluent builder design. + */ public KelpListener expireIf(Predicate conditionalExpiry, ConditionalExpiryTestStage conditionalExpiryTestStage) { this.conditionalExpires.put(conditionalExpiryTestStage, conditionalExpiry); return this; } + /** + * Adds a criterion to the listener. The listener will only be triggered + * if all the given criteria added by this method are fulfilled. In + * this criteria you can check basic things such as that the item + * of an interaction is not null or a player has a specific permission, + * etc. + * + * if you have criteria to check for a listener it is recommended to + * use this method instead of cluttering all your criteria in the + * handle method as this increases readability. + * + * @param condition The condition to check for before handling the event. + * @return An instance of the current listener for fluent builder design. + */ public KelpListener criterion(Predicate condition) { this.criteria.add(condition); return this; } + /** + * Makes the listener expire after a specific amount of executions. + * That means that if you set {@code maxExecutions} to 5, the event + * will be handled 5 times and then expire. If it expires before + * due to a conditional expiry for example, the amount provided here + * will be ignored. + * + * @param maxExecutions The maximum amount of times the event should + * be handled by this listener. + * @return An instance of the current listener for fluent builder design. + */ public KelpListener expireAfterExecutions(int maxExecutions) { this.maxExecutions = maxExecutions; return this; } + /** + * Sets the minimal amount of times this event should be handled. + * This ignores all expire-conditions that are set (except timed expires). + * + * @param minExecutions The minimal amount of times this event should be handled. + * @return An instance of the current listener for fluent builder design. + */ public KelpListener minimalExecutions(int minExecutions) { this.minExecutions = minExecutions; return this; } + /** + * Provides the code that should be executed to handle the given event. + * This code is only executed if all criteria match and the listener has + * not expired before. + * + * @param handler The consumer consuming the event to handle. + * @return The {@code listenerId}, which can be used later to unregister the listener from the {@link KelpEventRepository}. + */ public UUID handle(Consumer handler) { this.handler = handler; return kelpEventRepository.addListener(this); From 75193386c3eb6f0c567d61aac935f8e6376517a6 Mon Sep 17 00:00:00 2001 From: pxav Date: Tue, 2 Feb 2021 22:03:11 +0100 Subject: [PATCH 26/35] Add documentation to EventCriteria --- .../core/event/listener/EventCriteria.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java b/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java index 106df6c0..53f013a0 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/EventCriteria.java @@ -6,24 +6,75 @@ import java.util.function.Predicate; +/** + * Contains basic pre-defined criteria for the dynamic event library. + * Instead of creating a predicate yourself every time, you can use the + * shortcuts from this class. Example: + * + * {@code .criterion({@link EventCriteria#playerHasPermission(String)})} + * + * @author pxav + */ public class EventCriteria { + /** + * Checks whether the event player has the given permission. This method uses the normal + * {@link de.pxav.kelp.core.player.KelpPlayer#hasPermission(String)} check so it + * does not matter from which permission plugin the permission comes from. + * + * @param permission The permission you want to check. + * @param The type of event you are using. Must be a subtype of {@link KelpPlayerEvent}. + * @return The final predicate representing the criterion. + */ public static Predicate playerHasPermission(String permission) { return event -> event.getPlayer().hasPermission(permission); } + /** + * Checks whether the event player has a specific name. + * + * @param name The name you want to check the player for. + * @param The type of event you are using. Must be a subtype of {@link KelpPlayerEvent}. + * @return The final predicate representing the criterion. + */ public static Predicate playerName(String name) { return event -> event.getPlayer().getName().equalsIgnoreCase(name); } + /** + * Checks if the player of the event is a server operator. This + * does not check for {@code '*'-Permissions}, but only if the player + * has an entry in the server's {@code ops.json} + * + * @param The type of event you are using. Must be a subtype of {@link KelpPlayerEvent}. + * @return The final predicate representing the criterion. + */ public static Predicate playerIsOperator() { return event -> event.getPlayer().isOperator(); } + /** + * Checks whether the message of an {@link AsyncPlayerChatEvent} starts with a given + * prefix. If you are doing chat commands for example, this might become useful to + * check if the message is a command you want to check for. + * + * @param prefix The prefix the message should have. + * @param The type of event you are using. Must be {@link AsyncPlayerChatEvent}. + * @return The final predicate representing the criterion. + */ public static Predicate messageStartsWith(String prefix) { return event -> event.getMessage().startsWith(prefix); } + /** + * Checks if the command passed by a {@link PlayerCommandPreprocessEvent} starts with a given + * prefix. This is useful if you want to handle sub commands via this event and you want to + * check if the player is using a command that you handle ({@code /yourCommand}) + * + * @param prefix The prefix the command message should have. + * @param The type of event you are using. Must be {@link PlayerCommandPreprocessEvent}. + * @return The final predicate representing the criterion. + */ public static Predicate commandStartsWith(String prefix) { return event -> event.getMessage().startsWith(prefix); } From 5fd9b5ed76732c2615206047d0e9fe753cdc1965 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 11:38:47 +0100 Subject: [PATCH 27/35] Fix bug that maximum executions of dynamic listeners could not be disabled --- .../pxav/kelp/core/event/listener/KelpEventRepository.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index 1ffcafb1..e064a28e 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -139,9 +139,10 @@ UUID addListener(KelpListener kelpListener) { kelpListener.triggerHandler(event); - if ((timesCalled + 1) >= kelpListener.getMaxExecutions()) { - removeListener(uuid); - return; + if (kelpListener.getMaxExecutions() != -1 + && (timesCalled + 1) >= kelpListener.getMaxExecutions()) { + removeListener(uuid); + return; } this.timesCalled.put(uuid, timesCalled + 1); From e91130a630c0e23086dc1982867c4aae27783b56 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 11:39:47 +0100 Subject: [PATCH 28/35] You can now set timed expires for dynamic listeners --- .../event/listener/KelpEventRepository.java | 14 +++++++ .../core/event/listener/KelpListener.java | 39 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index e064a28e..28a3c923 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -11,6 +11,7 @@ import de.pxav.kelp.core.player.KelpPlayerRepository; import de.pxav.kelp.core.reflect.MethodCriterion; import de.pxav.kelp.core.reflect.MethodFinder; +import de.pxav.kelp.core.scheduler.type.DelayedScheduler; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -156,6 +157,19 @@ UUID addListener(KelpListener kelpListener) { javaPlugin, false); + // scheduled expiry if enabled + if (kelpListener.getExpireTime() != -1) { + DelayedScheduler.create() + .async() + .withDelayOf(kelpListener.getExpireTime()) + .timeUnit(kelpListener.getExpireTimeUnit()) + .run(taskId -> { + if (this.kelpListeners.containsKey(uuid)) { + removeListener(uuid); + } + }); + } + this.kelpListeners.put(uuid, kelpListener); return uuid; } diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java index 4e7cacc2..7e69c61b 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpListener.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; @@ -30,8 +31,13 @@ public class KelpListener { private int maxExecutions = -1; private int minExecutions = -1; + + private int expireTime = -1; + private TimeUnit expireTimeUnit; + private ConcurrentMap> conditionalExpires; private Collection> criteria; + private Consumer handler; private Listener bukkitListener; @@ -122,6 +128,25 @@ int getMinExecutions() { return minExecutions; } + /** + * Gets the time after which the listener will expire automatically. + * The unit for this time is provided in {@link #getExpireTimeUnit()} + * + * @return The amount of time to pass until the listener expires. + */ + public int getExpireTime() { + return expireTime; + } + + /** + * Gets the time unit of {@link #getExpireTime()}. + * + * @return The time unit after which the listener will expire. + */ + public TimeUnit getExpireTimeUnit() { + return expireTimeUnit; + } + /** * Tests all conditions set that would let the listener expire. * @@ -241,6 +266,20 @@ public KelpListener expireAfterExecutions(int maxExecutions) { return this; } + /** + * Makes the listener expire after a given amount of time. + * The time is counted from the moment the listener is registered. + * + * @param time The time to wait before letting the event handler expire. + * @param timeUnit The unit of the given {@code time} attribute. + * @return An instance of the current listener for fluent builder design. + */ + public KelpListener expireAfter(int time, TimeUnit timeUnit) { + this.expireTime = time; + this.expireTimeUnit = timeUnit; + return this; + } + /** * Sets the minimal amount of times this event should be handled. * This ignores all expire-conditions that are set (except timed expires). From 6118a5f3ee4ed92b507377581cfb1e064a54d1b5 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 11:40:07 +0100 Subject: [PATCH 29/35] Create static factories for schedulers --- .../de/pxav/kelp/core/scheduler/type/DelayedScheduler.java | 6 ++++++ .../pxav/kelp/core/scheduler/type/RepeatingScheduler.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/scheduler/type/DelayedScheduler.java b/core/src/main/java/de/pxav/kelp/core/scheduler/type/DelayedScheduler.java index 0cd21a67..812fe709 100644 --- a/core/src/main/java/de/pxav/kelp/core/scheduler/type/DelayedScheduler.java +++ b/core/src/main/java/de/pxav/kelp/core/scheduler/type/DelayedScheduler.java @@ -59,6 +59,12 @@ public class DelayedScheduler { this.timeUnit = TimeUnit.SECONDS; } + public static DelayedScheduler create() { + return new DelayedScheduler( + KelpPlugin.getInjector().getInstance(KelpSchedulerRepository.class) + ); + } + /** * Tells the scheduler to execute the given code on a separate thread. * Async schedulers use {@link ScheduledExecutorService} instead of the diff --git a/core/src/main/java/de/pxav/kelp/core/scheduler/type/RepeatingScheduler.java b/core/src/main/java/de/pxav/kelp/core/scheduler/type/RepeatingScheduler.java index 9577ef04..50ed07cc 100644 --- a/core/src/main/java/de/pxav/kelp/core/scheduler/type/RepeatingScheduler.java +++ b/core/src/main/java/de/pxav/kelp/core/scheduler/type/RepeatingScheduler.java @@ -73,6 +73,12 @@ public class RepeatingScheduler { this.waitForTaskCompletion = false; } + public static RepeatingScheduler create() { + return new RepeatingScheduler( + KelpPlugin.getInjector().getInstance(KelpSchedulerRepository.class) + ); + } + /** * Tells the scheduler to execute the given code on a separate thread. * Async schedulers use {@link ScheduledExecutorService} instead of the From 06792bf06716261e03b6b335217319c491146e63 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 11:48:56 +0100 Subject: [PATCH 30/35] Add documentation to KelpEventRepository --- .../event/listener/KelpEventRepository.java | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java index 28a3c923..50eb42f0 100644 --- a/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/event/listener/KelpEventRepository.java @@ -25,6 +25,8 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Predicate; /** * A class description goes here. @@ -104,7 +106,20 @@ public void detectSubscriptions(String... packageNames) { }); } + /** + * Adds/Registers a new dynamic listener. This method automatically + * creates the bukkit event handler, which then checks for expires + * or criteria of the listener. This method is non-api. The listener + * id is also returned by {@link KelpListener#handle(Consumer)} if you need + * it. + * + * A listener can be unregistered with {@link KelpEventRepository#removeListener(UUID)} + * + * @param kelpListener The listener you want to register. + * @return The id of the listener, which can be used later to remove it. + */ UUID addListener(KelpListener kelpListener) { + // generate listener id UUID uuid = UUID.randomUUID(); Listener listenerInstance = new Listener() {}; @@ -137,9 +152,10 @@ UUID addListener(KelpListener kelpListener) { return; } + // if all criteria match and the listener did not expire, call the handler. kelpListener.triggerHandler(event); - + // check if max executions are enabled and have been reached if (kelpListener.getMaxExecutions() != -1 && (timesCalled + 1) >= kelpListener.getMaxExecutions()) { removeListener(uuid); @@ -147,6 +163,7 @@ UUID addListener(KelpListener kelpListener) { } this.timesCalled.put(uuid, timesCalled + 1); + // test post-handler conditions and let the listener expire eventually. boolean expire = kelpListener.testConditions(event, ConditionalExpiryTestStage.AFTER_HANDLER); if (expire) { @@ -174,14 +191,26 @@ UUID addListener(KelpListener kelpListener) { return uuid; } + /** + * Removes/unregisters a dynamic listener with a specific listener id. + * When registering a new dynamic listener using either {@link KelpListener#listen(Class)} + * or {@link KelpEventRepository#addListener(KelpListener)}, you are returned + * an id. This id can be used to unregister the listener, so that it won't be + * called again. This method is called automatically if the listener expires due to + * timeout or certain conditions you set using {@link KelpListener#expireIf(Predicate)} for example. + * + * @param listenerId The id of the listener you want to remove. + */ public void removeListener(UUID listenerId) { + // check if there is anything to rremove. if (!this.kelpListeners.containsKey(listenerId)) { logger.log(LogLevel.ERROR, "Cannot remove non-existing listener (id: " + listenerId + ")"); return; } - KelpListener kelpListener = this.kelpListeners.get(listenerId); + KelpListener kelpListener = this.kelpListeners.get(listenerId); try { + // remove the listener instance saved in the KelpListener object from the event's handler list. Method method = kelpListener.getEventClass().getMethod("getHandlerList"); HandlerList handlerList = (HandlerList) method.invoke(null); handlerList.unregister(kelpListener.getBukkitListener()); From 217969423770509d248f0094331fe8d63867620d Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 11:51:11 +0100 Subject: [PATCH 31/35] Bump plugin version to 0.1.1 --- core/src/main/java/de/pxav/kelp/core/KelpPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/de/pxav/kelp/core/KelpPlugin.java b/core/src/main/java/de/pxav/kelp/core/KelpPlugin.java index 1dca462b..a7ba0d2f 100644 --- a/core/src/main/java/de/pxav/kelp/core/KelpPlugin.java +++ b/core/src/main/java/de/pxav/kelp/core/KelpPlugin.java @@ -35,7 +35,7 @@ * * @author pxav */ -@Plugin(name = "Kelp", version = "0.1.0") +@Plugin(name = "Kelp", version = "0.1.1") @Author("pxav") @Description("A cross version spigot framework.") @Singleton From b5f15dbe2c4ec832e9124886690b6fcb1e148708 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 11:51:35 +0100 Subject: [PATCH 32/35] Bump project version to 0.1.1 --- core/pom.xml | 2 +- kelp-sql/pom.xml | 4 ++-- pom.xml | 2 +- testing-module/pom.xml | 4 ++-- v1_8_implementation/pom.xml | 4 ++-- v_1_14_implementation/pom.xml | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 0d5a39d2..32e9d4e7 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -5,7 +5,7 @@ com.github.pxav.kelp parent - 0.1.0 + 0.1.1 4.0.0 diff --git a/kelp-sql/pom.xml b/kelp-sql/pom.xml index b1a3bd0f..54091094 100644 --- a/kelp-sql/pom.xml +++ b/kelp-sql/pom.xml @@ -5,7 +5,7 @@ parent com.github.pxav.kelp - 0.1.0 + 0.1.1 4.0.0 @@ -20,7 +20,7 @@ com.github.pxav.kelp core - 0.1.0 + 0.1.1 provided diff --git a/pom.xml b/pom.xml index b8301a6a..cf4cf101 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.github.pxav.kelp parent pom - 0.1.0 + 0.1.1 Kelp A cross-version spigot framework to avoid boilerplate code and make your plugin compatible with multiple spigot versions easily diff --git a/testing-module/pom.xml b/testing-module/pom.xml index 67fdd6c4..3fb2a163 100644 --- a/testing-module/pom.xml +++ b/testing-module/pom.xml @@ -5,7 +5,7 @@ parent com.github.pxav.kelp - 0.1.0 + 0.1.1 4.0.0 @@ -45,7 +45,7 @@ com.github.pxav.kelp core - 0.1.0 + 0.1.1 provided diff --git a/v1_8_implementation/pom.xml b/v1_8_implementation/pom.xml index 96997378..abc50809 100644 --- a/v1_8_implementation/pom.xml +++ b/v1_8_implementation/pom.xml @@ -5,7 +5,7 @@ com.github.pxav.kelp parent - 0.1.0 + 0.1.1 4.0.0 @@ -90,7 +90,7 @@ com.github.pxav.kelp core - 0.1.0 + 0.1.1 provided diff --git a/v_1_14_implementation/pom.xml b/v_1_14_implementation/pom.xml index f6f9a39a..fff19fb3 100644 --- a/v_1_14_implementation/pom.xml +++ b/v_1_14_implementation/pom.xml @@ -5,7 +5,7 @@ parent com.github.pxav.kelp - 0.1.0 + 0.1.1 4.0.0 @@ -57,7 +57,7 @@ com.github.pxav.kelp core - 0.1.0 + 0.1.1 org.spigotmc From f20c8dd96f2f24656d1475155b6871ec5201d881 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 12:03:55 +0100 Subject: [PATCH 33/35] Fix NullPointerException when player quit during reload --- .../java/de/pxav/kelp/core/sidebar/SidebarRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/de/pxav/kelp/core/sidebar/SidebarRepository.java b/core/src/main/java/de/pxav/kelp/core/sidebar/SidebarRepository.java index 9f46547a..76e83511 100755 --- a/core/src/main/java/de/pxav/kelp/core/sidebar/SidebarRepository.java +++ b/core/src/main/java/de/pxav/kelp/core/sidebar/SidebarRepository.java @@ -113,6 +113,11 @@ public void stopAllClusters() { @EventHandler public void handleClusterRemove(PlayerQuitEvent event) { KelpPlayer player = playerRepository.getKelpPlayer(event.getPlayer()); + + if (player == null) { + return; + } + if (animationStates.containsKey(player.getUUID())) { removeAnimatedSidebar(player); } From f8276224a75cd9948d888d35d458c8af8e3f50f4 Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 12:04:31 +0100 Subject: [PATCH 34/35] Complete documentation of PlayerCreationListener --- .../player/PlayerCreationListener.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java b/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java index 028b3808..e2e7fd97 100644 --- a/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java +++ b/v1_8_implementation/src/main/java/de/pxav/kelp/implementation1_8/player/PlayerCreationListener.java @@ -4,6 +4,8 @@ import de.pxav.kelp.core.event.kelpevent.KelpPlayerLoginEvent; import de.pxav.kelp.core.event.kelpevent.KelpPlayerUpdateSettingsEvent; import de.pxav.kelp.core.event.kelpevent.SettingsUpdateStage; +import de.pxav.kelp.core.logger.KelpLogger; +import de.pxav.kelp.core.logger.LogLevel; import de.pxav.kelp.core.player.KelpPlayer; import de.pxav.kelp.core.player.KelpPlayerRepository; import de.pxav.kelp.core.player.PlayerChatVisibility; @@ -19,7 +21,9 @@ /** * This class is responsible for keeping player instances over * the server lifetime. When the kelp plugin instance is disabled - * (by a reload for example), then + * (by a reload for example), then {@link #createOnStartup()} can be + * called to restore all player instances and continue working safely + * with them. * * @author pxav */ @@ -27,11 +31,15 @@ public class PlayerCreationListener { private KelpPlayerRepository kelpPlayerRepository; private GlobalPacketListener globalPacketListener; + private KelpLogger logger; @Inject - public PlayerCreationListener(KelpPlayerRepository kelpPlayerRepository, GlobalPacketListener globalPacketListener) { + public PlayerCreationListener(KelpPlayerRepository kelpPlayerRepository, + GlobalPacketListener globalPacketListener, + KelpLogger logger) { this.kelpPlayerRepository = kelpPlayerRepository; this.globalPacketListener = globalPacketListener; + this.logger = logger; } /** @@ -74,6 +82,7 @@ public void handlePlayerQuit(PlayerQuitEvent event) { * would lead to {@code null pointers}. */ public void createOnStartup() { + logger.log(LogLevel.DEBUG, "[VERSION-1.8] Restoring player instances..."); Bukkit.getOnlinePlayers().forEach(current -> { // catches NoSuchElementException which occurs when a player quits // the server during a reload, because the server does not recognize @@ -99,6 +108,7 @@ public void createOnStartup() { kelpPlayerRepository.removeKelpPlayer(current.getUniqueId()); } }); + logger.log(LogLevel.DEBUG, "[VERSION-1.8] All players have been successfully created internally."); } } From d8ced83f801aa74db946c5bc54b08fc5afc4e41c Mon Sep 17 00:00:00 2001 From: pxav Date: Thu, 4 Feb 2021 12:56:08 +0100 Subject: [PATCH 35/35] Add CHANGELOG for release 0.1.1 --- CHANGELOG/kelp-v0.1.1.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 CHANGELOG/kelp-v0.1.1.md diff --git a/CHANGELOG/kelp-v0.1.1.md b/CHANGELOG/kelp-v0.1.1.md new file mode 100644 index 00000000..93883257 --- /dev/null +++ b/CHANGELOG/kelp-v0.1.1.md @@ -0,0 +1,26 @@ +# v0.1.1 +> Release date: 04.02.2021 + +**Events & commands changes**: +* Rework dynamic listener system: + * Dynamic listeners are now built with generic types, meaning that they can adjust to your event, and you don't have to cast your event anymore when handling it. + * Add timed/scheduled expires to dynamic listeners: You can now give a specific time in which the listener will expire. + * Add minimal executions: You can now give a specific amount of minimal executions of the listener, which means that it has to be executed `n` amount of times, before it expires, even though other conditional expiry checks would lead to an expiry. Scheduled expires have a higher priority and will unregister the listener even though the event has not been handled `n` times. + * Add event criteria: You can now add unlimited criteria to an event. Only if all criteria are fulfilled, the event will be handled. Those criteria can be used to check whether the action of a specific interaction is valid, etc. + * Add default event criteria in `EventCriteria`. Common criteria such as checking if the player has a specific permissions are included here to avoid typing the predicates yourself every time. +* Custom Kelp events now use the new event supertype `KelpPlayerEvent` added in the last release: + * `KelpInventoryCloseEvent` + * `KelpInventoryOpenEvent` + * `KelpInventoryUpdateEvent` + * `KelpInventoryCloseEvent` + * `KelpPlayerLoginEvent` + * `KelpPlayerUpdateSettingsEvent` + * `KelpInventoryCloseEvent` + * `KelpInventoryCloseEvent` + * `KelpInventoryCloseEvent` +* Add 'smart inject' to listeners using the `@Subscribes` annotation. If your event is a `PlayerEvent` or `KelpPlayerEvent` and has a single parameter with the player of this event, the player parameter will be injected automatically. +* Documentation improvements for text animation classes +* Add `delegatePlayerToConsole(bool)` method to `KelpCommand`, which is a command property that can be assigned in `onCommandRegister`. It executes the `onCommand` method of the console sender if the executor type is set to `PLAYER_AND_CONSOLE` and a player executes the command. If your command has the same behaviour for players and consoles, this is useful to avoid duplicated command handlers. +* Add `inheritFromMainCommand(bool)` property to `KelpCommand`, which can be used in sub commands to inherit basic properties such as permission and messages from the main command (`@CreateCommand`) to the sub command (`@CreateSubCommand`). So you don't have to assign the properties manually for every command anymore. +* Fix bug in sidebar cluster system that caused a `NullPointerException` when a player quit during a server reload. +* Schedulers can now be produced via static factories \ No newline at end of file