From d0ec585cde5445806e1ae9a5974d110464db614d Mon Sep 17 00:00:00 2001 From: Manere <133597204+Manered@users.noreply.github.com> Date: Tue, 19 Dec 2023 20:19:08 +0100 Subject: [PATCH] v3.2.0 Honestly don't even ask me why I wasted a week on working on a library :sob: --- .gitignore | 3 +- pom.xml | 29 +- .../dev/manere/utils/cachable/Cachable.java | 171 +++++++ .../utils/cachable/CachableSnapshot.java | 45 ++ .../utils/cachable/impl/CachableImpl.java | 147 ++++++ .../cachable/impl/CachableSnapshotImpl.java | 69 +++ ...ommandSettings.java => CommandConfig.java} | 42 +- .../dev/manere/utils/command/CommandType.java | 22 - .../manere/utils/command/CommandTypes.java | 77 ++++ .../dev/manere/utils/command/Commander.java | 18 +- .../command/annotation/AutoRegister.java | 4 +- .../annotation/AutoRegisterHandler.java | 15 +- .../manere/utils/command/args/Argument.java | 4 +- .../command/args/custom/CustomArgument.java | 3 +- .../args/custom/CustomListArgument.java | 11 +- .../entity/CachedOfflinePlayerArgument.java | 2 +- .../args/entity/EntityTypeArgument.java | 2 +- .../args/entity/OfflinePlayerArgument.java | 2 +- .../command/args/entity/PlayerArgument.java | 2 +- .../args/exception/ArgumentExType.java | 10 +- .../exception/ArgumentParseException.java | 2 +- .../command/args/misc/GamemodeArgument.java | 2 +- .../args/primitive/BooleanArgument.java | 2 +- .../args/primitive/DoubleArgument.java | 2 +- .../command/args/primitive/FloatArgument.java | 2 +- .../args/primitive/IntegerArgument.java | 31 +- .../command/args/primitive/LongArgument.java | 2 +- .../command/args/text/ComponentArgument.java | 2 +- .../args/text/ComponentListArgument.java | 44 ++ .../command/args/text/StringArgument.java | 2 +- .../command/args/text/StringListArgument.java | 4 +- .../utils/command/args/text/TextArgument.java | 2 +- .../command/args/text/TextListArgument.java | 43 ++ .../utils/command/builder/CommandBuilder.java | 237 ---------- .../utils/command/impl/CommandInfo.java | 86 ++++ .../manere/utils/command/impl/Commands.java | 422 ++++++++++++++++++ .../CommandsRegistrar.java} | 15 +- .../alias/CommandAliasBuilder.java | 38 +- .../dispatcher/CommandContext.java | 80 +++- .../dispatcher/CommandDispatcher.java | 3 +- .../dispatcher/SuggestionDispatcher.java | 3 +- .../permission/CommandPermission.java | 3 +- .../permission/CommandPermissionBuilder.java | 26 +- .../java/dev/manere/utils/config/Config.java | 1 - .../utils/config/section/ConfigSection.java | 2 +- .../utils/config/section/ConfigSelection.java | 9 +- .../config/setter/ConfigSectionSetter.java | 1 - .../utils/config/setter/ConfigSetter.java | 1 - .../manere/utils/config/val/ConfigList.java | 1 - .../manere/utils/config/val/ConfigVal.java | 10 +- .../manere/utils/consumers/PairConsumer.java | 18 + .../utils/consumers/TripleConsumer.java | 20 + .../dev/manere/utils/context/Context.java | 36 ++ src/main/java/dev/manere/utils/elo/ELO.java | 1 - .../java/dev/manere/utils/elo/Ratings.java | 2 +- .../java/dev/manere/utils/elo/Winner.java | 11 +- .../utils/event/builder/EventBuilder.java | 17 +- .../utils/event/builder/EventCallback.java | 12 +- .../utils/event/builder/EventHandler.java | 29 +- .../event/crystal/PlayerAnchorDeathEvent.java | 125 ++++++ ...vent.java => PlayerCrystalDeathEvent.java} | 21 +- .../impl/SpigotAnchorEventListener.java | 75 ++++ .../SpigotCrystalEventListener.java} | 28 +- .../dev/manere/utils/item/ItemBuilder.java | 143 +++++- .../dev/manere/utils/item/PotionBuilder.java | 12 +- .../java/dev/manere/utils/library/Utils.java | 12 +- .../utils/library/event/PluginEvents.java | 98 ++++ .../utils/library/wrapper/PluginWrapper.java | 250 +++++++++++ .../manere/utils/location/LocationUtils.java | 1 - .../manere/utils/logger/AdventureLogger.java | 1 - .../java/dev/manere/utils/logger/Loggers.java | 14 +- .../java/dev/manere/utils/menu/MenuBase.java | 3 +- .../java/dev/manere/utils/menu/MenuUtils.java | 1 - .../menu/{ => listener}/CloseListener.java | 4 +- .../menu/{ => listener}/DragListener.java | 4 +- .../menu/{ => listener}/MenuListener.java | 26 +- .../dev/manere/utils/menu/normal/Menu.java | 78 ++-- .../utils/menu/paginated/PaginatedMenu.java | 121 ++--- .../utils/menu/paginated/PaginatedSlot.java | 4 + .../utils/message/ActionBarMessager.java | 4 +- .../dev/manere/utils/message/Messagers.java | 1 - .../java/dev/manere/utils/misc/Buildable.java | 12 + .../dev/manere/utils/misc/FluentBuilder.java | 16 + .../dev/manere/utils/misc/ObjectUtils.java | 156 +++++++ .../java/dev/manere/utils/misc/Storable.java | 23 + .../utils/model/{Duo.java => Tuple.java} | 12 +- .../utils/papi/PlaceholderAPIBuilder.java | 9 +- .../dev/manere/utils/pdc/UUIDDataType.java | 79 ++++ .../manere/utils/player/cache/CacheInfo.java | 27 -- .../manere/utils/player/cache/CacheKey.java | 39 -- .../manere/utils/player/cache/CacheVal.java | 102 ----- .../utils/player/cache/PlayerCache.java | 142 ------ .../manere/utils/prettify/ListPrettify.java | 1 - .../utils/reflection/ReflectionUtils.java | 5 +- .../manere/utils/registration/Registrar.java | 25 +- .../utils/resource/ResourceBuilder.java | 127 ++++++ .../manere/utils/resource/ResourceFile.java | 212 +++++++++ .../utils/resource/ResourceOptions.java | 115 +++++ .../utils/resource/format/ResourceFormat.java | 47 ++ .../resource/format/ResourceFormats.java | 24 + .../utils/resource/path/ResourcePath.java | 42 ++ .../utils/resource/path/ResourcePaths.java | 40 ++ .../resource/yaml/ResourceConfiguration.java | 336 ++++++++++++++ .../utils/returnable/PairReturnable.java | 15 + .../manere/utils/returnable/Returnable.java | 13 + .../utils/returnable/TripleReturnable.java | 17 + .../utils/scheduler/AsyncScheduler.java | 75 ---- .../manere/utils/scheduler/SchedulerBase.java | 118 +++++ .../manere/utils/scheduler/Schedulers.java | 85 +++- .../manere/utils/scheduler/SyncScheduler.java | 75 ---- .../dev/manere/utils/scheduler/TickTimes.java | 4 +- .../utils/scheduler/async/AsyncScheduler.java | 77 ++++ .../scheduler/builder/SchedulerBuilder.java | 245 +++++----- .../scheduler/builder/SchedulerConfig.java | 103 +++++ .../builder/SchedulerThreadType.java | 16 + .../utils/scheduler/builder/TaskType.java | 22 - .../scheduler/builder/task/SchedulerTask.java | 99 ++++ .../scheduler/stacker/SchedulerStacker.java | 167 ++----- .../utils/scheduler/sync/SyncScheduler.java | 71 +++ .../dev/manere/utils/scoreboard/Sidebar.java | 11 +- .../utils/scoreboard/SidebarHandler.java | 46 +- .../utils/serializers/Base64Serializer.java | 1 - .../utils/serializers/ByteSerializer.java | 105 +++++ .../manere/utils/serializers/Serializers.java | 14 +- .../dev/manere/utils/server/ServerUtils.java | 1 - .../utils/sql/connection/SQLConnector.java | 1 - .../dev/manere/utils/tablist/Tablist.java | 116 +++++ src/main/java/dev/manere/utils/text/Text.java | 19 +- .../manere/utils/text/color/TextStyle.java | 34 +- .../dev/manere/utils/text/font/SmallFont.java | 1 - .../utils/tierlist/data/PlayerInfo.java | 1 - .../manere/utils/tierlist/data/TierList.java | 1 - .../java/dev/manere/utils/update/Updater.java | 1 - .../java/dev/manere/utils/world/Worlds.java | 55 ++- .../utils/worldedit/AsyncWorldEditor.java | 1 - .../utils/worldedit/SyncWorldEditor.java | 1 - .../manere/utils/worldedit/WorldEditor.java | 1 - 137 files changed, 4753 insertions(+), 1378 deletions(-) create mode 100644 src/main/java/dev/manere/utils/cachable/Cachable.java create mode 100644 src/main/java/dev/manere/utils/cachable/CachableSnapshot.java create mode 100644 src/main/java/dev/manere/utils/cachable/impl/CachableImpl.java create mode 100644 src/main/java/dev/manere/utils/cachable/impl/CachableSnapshotImpl.java rename src/main/java/dev/manere/utils/command/{CommandSettings.java => CommandConfig.java} (65%) delete mode 100644 src/main/java/dev/manere/utils/command/CommandType.java create mode 100644 src/main/java/dev/manere/utils/command/CommandTypes.java create mode 100644 src/main/java/dev/manere/utils/command/args/text/ComponentListArgument.java create mode 100644 src/main/java/dev/manere/utils/command/args/text/TextListArgument.java delete mode 100644 src/main/java/dev/manere/utils/command/builder/CommandBuilder.java create mode 100644 src/main/java/dev/manere/utils/command/impl/CommandInfo.java create mode 100644 src/main/java/dev/manere/utils/command/impl/Commands.java rename src/main/java/dev/manere/utils/command/{builder/CommandBuilderHandler.java => impl/CommandsRegistrar.java} (88%) rename src/main/java/dev/manere/utils/command/{builder => impl}/alias/CommandAliasBuilder.java (66%) rename src/main/java/dev/manere/utils/command/{builder => impl}/dispatcher/CommandContext.java (72%) rename src/main/java/dev/manere/utils/command/{builder => impl}/dispatcher/CommandDispatcher.java (89%) rename src/main/java/dev/manere/utils/command/{builder => impl}/dispatcher/SuggestionDispatcher.java (91%) rename src/main/java/dev/manere/utils/command/{builder => impl}/permission/CommandPermission.java (78%) rename src/main/java/dev/manere/utils/command/{builder => impl}/permission/CommandPermissionBuilder.java (80%) create mode 100644 src/main/java/dev/manere/utils/consumers/PairConsumer.java create mode 100644 src/main/java/dev/manere/utils/consumers/TripleConsumer.java create mode 100644 src/main/java/dev/manere/utils/context/Context.java create mode 100644 src/main/java/dev/manere/utils/event/crystal/PlayerAnchorDeathEvent.java rename src/main/java/dev/manere/utils/event/crystal/{PlayerDeathByPlayerWithCrystalEvent.java => PlayerCrystalDeathEvent.java} (92%) create mode 100644 src/main/java/dev/manere/utils/event/crystal/impl/SpigotAnchorEventListener.java rename src/main/java/dev/manere/utils/event/crystal/{SpigotEventListener.java => impl/SpigotCrystalEventListener.java} (66%) create mode 100644 src/main/java/dev/manere/utils/library/event/PluginEvents.java create mode 100644 src/main/java/dev/manere/utils/library/wrapper/PluginWrapper.java rename src/main/java/dev/manere/utils/menu/{ => listener}/CloseListener.java (90%) rename src/main/java/dev/manere/utils/menu/{ => listener}/DragListener.java (90%) rename src/main/java/dev/manere/utils/menu/{ => listener}/MenuListener.java (87%) create mode 100644 src/main/java/dev/manere/utils/misc/Buildable.java create mode 100644 src/main/java/dev/manere/utils/misc/FluentBuilder.java create mode 100644 src/main/java/dev/manere/utils/misc/ObjectUtils.java create mode 100644 src/main/java/dev/manere/utils/misc/Storable.java rename src/main/java/dev/manere/utils/model/{Duo.java => Tuple.java} (84%) create mode 100644 src/main/java/dev/manere/utils/pdc/UUIDDataType.java delete mode 100644 src/main/java/dev/manere/utils/player/cache/CacheInfo.java delete mode 100644 src/main/java/dev/manere/utils/player/cache/CacheKey.java delete mode 100644 src/main/java/dev/manere/utils/player/cache/CacheVal.java delete mode 100644 src/main/java/dev/manere/utils/player/cache/PlayerCache.java create mode 100644 src/main/java/dev/manere/utils/resource/ResourceBuilder.java create mode 100644 src/main/java/dev/manere/utils/resource/ResourceFile.java create mode 100644 src/main/java/dev/manere/utils/resource/ResourceOptions.java create mode 100644 src/main/java/dev/manere/utils/resource/format/ResourceFormat.java create mode 100644 src/main/java/dev/manere/utils/resource/format/ResourceFormats.java create mode 100644 src/main/java/dev/manere/utils/resource/path/ResourcePath.java create mode 100644 src/main/java/dev/manere/utils/resource/path/ResourcePaths.java create mode 100644 src/main/java/dev/manere/utils/resource/yaml/ResourceConfiguration.java create mode 100644 src/main/java/dev/manere/utils/returnable/PairReturnable.java create mode 100644 src/main/java/dev/manere/utils/returnable/Returnable.java create mode 100644 src/main/java/dev/manere/utils/returnable/TripleReturnable.java delete mode 100644 src/main/java/dev/manere/utils/scheduler/AsyncScheduler.java create mode 100644 src/main/java/dev/manere/utils/scheduler/SchedulerBase.java delete mode 100644 src/main/java/dev/manere/utils/scheduler/SyncScheduler.java create mode 100644 src/main/java/dev/manere/utils/scheduler/async/AsyncScheduler.java create mode 100644 src/main/java/dev/manere/utils/scheduler/builder/SchedulerConfig.java create mode 100644 src/main/java/dev/manere/utils/scheduler/builder/SchedulerThreadType.java delete mode 100644 src/main/java/dev/manere/utils/scheduler/builder/TaskType.java create mode 100644 src/main/java/dev/manere/utils/scheduler/builder/task/SchedulerTask.java create mode 100644 src/main/java/dev/manere/utils/scheduler/sync/SyncScheduler.java create mode 100644 src/main/java/dev/manere/utils/serializers/ByteSerializer.java create mode 100644 src/main/java/dev/manere/utils/tablist/Tablist.java diff --git a/.gitignore b/.gitignore index 1c12ecd..85ec936 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ replay_pid* /target/ target/ target -/target \ No newline at end of file +/target +dependency-reduced-pom.xml \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4d1a73e..503e789 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ dev.manere utils - 3.1.0 + 3.2.0 jar Utils @@ -27,6 +27,27 @@ 17 + + org.apache.maven.plugins + maven-shade-plugin + 3.5.0 + + + + com.jeff_media.customblockdata + dev.manere.utils.customblockdata + + + + + + package + + shade + + + + @@ -86,6 +107,12 @@ + + com.jeff-media + custom-block-data + 2.2.2 + compile + diff --git a/src/main/java/dev/manere/utils/cachable/Cachable.java b/src/main/java/dev/manere/utils/cachable/Cachable.java new file mode 100644 index 0000000..8907459 --- /dev/null +++ b/src/main/java/dev/manere/utils/cachable/Cachable.java @@ -0,0 +1,171 @@ +package dev.manere.utils.cachable; + +import dev.manere.utils.cachable.impl.CachableImpl; +import dev.manere.utils.consumers.PairConsumer; +import dev.manere.utils.model.Tuple; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +/** + * The {@code Cachable} interface defines methods for a caching mechanism that associates keys with values. + * + * @param The type of keys in the cache. + * @param The type of values in the cache. + */ +public interface Cachable { + /** + * Creates and returns a Cachable instance. + * + * @param The key type + * @param The value type + * @return A new Cachable instance + */ + static CachableImpl of() { + return new CachableImpl<>(); + } + + /** + * Creates and returns a Cachable instance initialized with the given entries. + * + * @param The key type + * @param The value type + * @param entries The initial entries to cache + * @return A Cachable instance with the given initial entries + */ + static CachableImpl of(Collection> entries) { + CachableImpl cachable = new CachableImpl<>(); + cachable.cacheAll(entries); + + return cachable; + } + + /** + * Creates and returns a Cachable instance initialized with the given entries. + * + * @param The key type + * @param The value type + * @param entries The initial entries to cache + * @return A Cachable instance with the given initial entries + */ + static CachableImpl of(Map entries) { + CachableImpl cachable = new CachableImpl<>(); + cachable.cacheAll(entries); + + return cachable; + } + + /** + * Creates and returns a Cachable instance initialized with the given entries. + * + * @param The key type + * @param The value type + * @param entries The initial entries to cache + * @return A Cachable instance with the given initial entries + */ + @SafeVarargs + static CachableImpl of(Tuple... entries) { + return Cachable.of(Arrays.asList(entries)); + } + + /** + * Retrieves the value associated with the given key. + * + * @param key The key whose associated value is to be returned. + * @return The value associated with the given key, or null if the key is not present in the cache. + */ + V val(K key); + + /** + * Retrieves the key associated with the given value. + * + * @param val The value whose associated key is to be returned. + * @return The key associated with the given value, or null if the value is not present in the cache. + */ + K key(V val); + + /** + * Returns true if the cachable contains a key + * @param key The key to check for + * @return true if exists, false otherwise + */ + boolean hasKey(K key); + + /** + * Returns true if the cachable contains a value + * @param val The val to check for + * @return true if exists, false otherwise + */ + boolean hasVal(V val); + + /** + * Caches the specified key-value pair. + * + * @param key The key to be cached. + * @param val The value to be cached. + */ + void cache(K key, V val); + + /** + * Removes the specified key-value pair from the cache. + * + * @param key The key to be removed. + * @param val The value to be removed. + */ + void del(K key, V val); + + /** + * Removes the entry associated with the specified key from the cache. + * + * @param key The key to be removed. + */ + void del(K key); + + /** + * Caches multiple key-value pairs. + * + * @param entries A collection of key-value pairs to be cached. + */ + void cacheAll(Collection> entries); + + /** + * Caches a key-value map. + * + * @param entries A key-value map to be cached. + */ + void cacheAll(Map entries); + + /** + * Removes multiple entries from the cache based on the specified keys. + * + * @param keys A collection of keys to be removed. + */ + void delAll(Collection keys); + + /** + * Performs the given action for each entry in the cache. + * + * @param forEach The action to be performed for each entry. + */ + void forEach(PairConsumer forEach); + + /** + * Returns the number of entries currently cached. + * + * @return The number of entries in the cache. + */ + int cached(); + + /** + * Clears all entries from the cache. + */ + void clear(); + + /** + * Creates and returns a snapshot of the current state of the cache. + * + * @return A snapshot of the cache. + */ + CachableSnapshot snapshot(); +} diff --git a/src/main/java/dev/manere/utils/cachable/CachableSnapshot.java b/src/main/java/dev/manere/utils/cachable/CachableSnapshot.java new file mode 100644 index 0000000..a5b4a71 --- /dev/null +++ b/src/main/java/dev/manere/utils/cachable/CachableSnapshot.java @@ -0,0 +1,45 @@ +package dev.manere.utils.cachable; + +import dev.manere.utils.model.Tuple; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * The {@code CachableSnapshot} interface represents a snapshot or view of a cache's current state. + * It provides methods to access the cached entries as a map, list, or collection of key-value pairs. + *

+ * WARNING: THIS DOES NOT UPDATE! ONCE CREATED YOUR VALUES WILL BE OLD VALUES IF UPDATED AFTER YOU MADE A SNAPSHOT + * @param The type of keys in the cache. + * @param The type of values in the cache. + */ +public interface CachableSnapshot { + /** + * Returns the cached entries as an unmodifiable map. + * + * @return An unmodifiable map view of the cached entries + */ + Map asMap(); + + /** + * Returns the cached entries as an unmodifiable list. + * + * @return An unmodifiable list view of the cached entries + */ + List> asList(); + + /** + * Returns the cached entries as an unmodifiable collection. + * + * @return An unmodifiable collection view of the cached entries + */ + Collection> asCollection(); + + /** + * Returns the cached entries as an array of tuples. + * + * @return An array view of the cached entries + */ + Tuple[] asTupleArray(); +} diff --git a/src/main/java/dev/manere/utils/cachable/impl/CachableImpl.java b/src/main/java/dev/manere/utils/cachable/impl/CachableImpl.java new file mode 100644 index 0000000..5dafd22 --- /dev/null +++ b/src/main/java/dev/manere/utils/cachable/impl/CachableImpl.java @@ -0,0 +1,147 @@ +package dev.manere.utils.cachable.impl; + +import dev.manere.utils.cachable.Cachable; +import dev.manere.utils.cachable.CachableSnapshot; +import dev.manere.utils.consumers.PairConsumer; +import dev.manere.utils.model.Tuple; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class CachableImpl implements Cachable { + /** + * Internal {@link ConcurrentHashMap}. + */ + final Map cache = new ConcurrentHashMap<>(); + + /** + * {@inheritDoc} + */ + @Override + public V val(K key) { + return cache.get(key); + } + + /** + * {@inheritDoc} + */ + @Override + public K key(V val) { + for (Map.Entry entry : cache.entrySet()) { + if (entry.getValue().equals(val)) { + return entry.getKey(); + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasKey(K key) { + return cache.containsKey(key); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasVal(V val) { + return cache.containsValue(val); + } + + /** + * {@inheritDoc} + */ + @Override + public void cache(K key, V val) { + cache.put(key, val); + } + + /** + * {@inheritDoc} + */ + @Override + public void del(K key, V val) { + if (cache.get(key).equals(val)) { + cache.remove(key); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void del(K key) { + cache.remove(key); + } + + /** + * {@inheritDoc} + */ + @Override + public void cacheAll(Collection> entries) { + for (Tuple entry : entries) { + cache(entry.key(), entry.val()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void cacheAll(Map entries) { + for (Map.Entry entry : entries.entrySet()) { + K key = entry.getKey(); + V val = entry.getValue(); + + cache(key, val); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void delAll(Collection keys) { + for (K key : keys) { + cache.remove(key); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void forEach(PairConsumer forEach) { + cache.forEach(forEach::execute); + } + + /** + * {@inheritDoc} + */ + @Override + public int cached() { + return cache.size(); + } + + /** + * {@inheritDoc} + */ + @Override + public void clear() { + cache.clear(); + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull CachableSnapshot snapshot() { + return new CachableSnapshotImpl<>(this); + } +} diff --git a/src/main/java/dev/manere/utils/cachable/impl/CachableSnapshotImpl.java b/src/main/java/dev/manere/utils/cachable/impl/CachableSnapshotImpl.java new file mode 100644 index 0000000..e4249aa --- /dev/null +++ b/src/main/java/dev/manere/utils/cachable/impl/CachableSnapshotImpl.java @@ -0,0 +1,69 @@ +package dev.manere.utils.cachable.impl; + +import dev.manere.utils.cachable.CachableSnapshot; +import dev.manere.utils.model.Tuple; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class CachableSnapshotImpl implements CachableSnapshot { + /** + * Internal {@link CachableImpl} + */ + private final CachableImpl cachable; + + CachableSnapshotImpl(CachableImpl cachable) { + this.cachable = cachable; + } + + /** + * {@inheritDoc} + */ + @Override + public Map asMap() { + return cachable.cache; + } + + /** + * {@inheritDoc} + */ + @Override + public List> asList() { + List> list = new ArrayList<>(); + + for (K key : cachable.cache.keySet()) { + for (V val : cachable.cache.values()) { + list.add(Tuple.duo(key, val)); + } + } + + return list; + } + + /** + * {@inheritDoc} + */ + @Override + public Collection> asCollection() { + return asList(); + } + + /** + * {@inheritDoc} + */ + @Override + public Tuple[] asTupleArray() { + @SuppressWarnings("unchecked") + Tuple[] tuples = (Tuple[]) Array.newInstance(Tuple.class, asList().size()); + + int i = 0; + for (Tuple tuple : asList()) { + tuples[i++] = tuple; + } + + return tuples; + } +} diff --git a/src/main/java/dev/manere/utils/command/CommandSettings.java b/src/main/java/dev/manere/utils/command/CommandConfig.java similarity index 65% rename from src/main/java/dev/manere/utils/command/CommandSettings.java rename to src/main/java/dev/manere/utils/command/CommandConfig.java index ec472ff..a78f2c2 100644 --- a/src/main/java/dev/manere/utils/command/CommandSettings.java +++ b/src/main/java/dev/manere/utils/command/CommandConfig.java @@ -1,27 +1,27 @@ package dev.manere.utils.command; -import dev.manere.utils.command.builder.dispatcher.CommandDispatcher; -import dev.manere.utils.command.builder.dispatcher.SuggestionDispatcher; +import dev.manere.utils.command.impl.dispatcher.CommandDispatcher; +import dev.manere.utils.command.impl.dispatcher.SuggestionDispatcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.ArrayList; /** * Class representing settings for a {@link Commander} command. */ -public class CommandSettings { +public class CommandConfig { private CommandDispatcher executes; private SuggestionDispatcher completes; - private CommandType type; + private CommandTypes type; /** * Creates settings with default executor and completer. */ - public CommandSettings() { - this.type = CommandType.PLUGIN_YML; + public CommandConfig() { + this.type = CommandTypes.PLUGIN_YML; this.executes = context -> true; - this.completes = context -> List.of(); + this.completes = context -> new ArrayList<>(); } /** @@ -30,8 +30,8 @@ public CommandSettings() { * @param executes The execute dispatcher * @param completes The complete dispatcher */ - public CommandSettings(CommandDispatcher executes, SuggestionDispatcher completes) { - this.type = CommandType.PLUGIN_YML; + public CommandConfig(CommandDispatcher executes, SuggestionDispatcher completes) { + this.type = CommandTypes.PLUGIN_YML; this.executes = executes; this.completes = completes; } @@ -43,7 +43,7 @@ public CommandSettings(CommandDispatcher executes, SuggestionDispatcher complete * @param executes The execute dispatcher * @param completes The complete dispatcher */ - public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionDispatcher completes) { + public CommandConfig(CommandTypes type, CommandDispatcher executes, SuggestionDispatcher completes) { this.type = type; this.executes = executes; this.completes = completes; @@ -54,8 +54,8 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * * @return The default settings */ - public static @NotNull CommandSettings settings() { - return new CommandSettings(); + public static @NotNull CommandConfig settings() { + return new CommandConfig(); } /** @@ -65,8 +65,8 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * @param completes The complete dispatcher * @return The settings */ - public static @NotNull CommandSettings settings(@Nullable CommandDispatcher executes, @Nullable SuggestionDispatcher completes) { - return new CommandSettings(executes, completes); + public static @NotNull CommandConfig settings(@Nullable CommandDispatcher executes, @Nullable SuggestionDispatcher completes) { + return new CommandConfig(executes, completes); } /** @@ -77,8 +77,8 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * @param completes The complete dispatcher * @return The settings */ - public static @NotNull CommandSettings settings(@NotNull CommandType type, @Nullable CommandDispatcher executes, @Nullable SuggestionDispatcher completes) { - return new CommandSettings(type, executes, completes); + public static @NotNull CommandConfig settings(@NotNull CommandTypes type, @Nullable CommandDispatcher executes, @Nullable SuggestionDispatcher completes) { + return new CommandConfig(type, executes, completes); } /** @@ -96,7 +96,7 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * @param executes The new dispatcher * @return This settings instance */ - public @NotNull CommandSettings executes(@Nullable CommandDispatcher executes) { + public @NotNull CommandConfig executes(@Nullable CommandDispatcher executes) { this.executes = executes; return this; } @@ -116,7 +116,7 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * @param completes The new dispatcher * @return This settings instance */ - public @NotNull CommandSettings completes(@Nullable SuggestionDispatcher completes) { + public @NotNull CommandConfig completes(@Nullable SuggestionDispatcher completes) { this.completes = completes; return this; } @@ -126,7 +126,7 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * * @return The type */ - public @NotNull CommandType type() { + public @NotNull CommandTypes type() { return type; } @@ -136,7 +136,7 @@ public CommandSettings(CommandType type, CommandDispatcher executes, SuggestionD * @param type The new type * @return This settings instance */ - public @NotNull CommandSettings type(@NotNull CommandType type) { + public @NotNull CommandConfig type(@NotNull CommandTypes type) { this.type = type; return this; } diff --git a/src/main/java/dev/manere/utils/command/CommandType.java b/src/main/java/dev/manere/utils/command/CommandType.java deleted file mode 100644 index 9ffca0f..0000000 --- a/src/main/java/dev/manere/utils/command/CommandType.java +++ /dev/null @@ -1,22 +0,0 @@ -package dev.manere.utils.command; - -import org.bukkit.command.CommandMap; -import org.bukkit.plugin.java.JavaPlugin; - -/** - * An enumeration representing the registration system to use. - */ -public enum CommandType { - - /** - * Self-explanatory. Uses the plugin.yml file - * and {@link JavaPlugin#getCommand(String)} to retrieve and register the command. - */ - PLUGIN_YML, - - /** - * Used for registering commands via the {@link CommandMap} - * Does not require the command to be in the plugin.yml of your project. - */ - COMMAND_MAP, -} diff --git a/src/main/java/dev/manere/utils/command/CommandTypes.java b/src/main/java/dev/manere/utils/command/CommandTypes.java new file mode 100644 index 0000000..a00dbcb --- /dev/null +++ b/src/main/java/dev/manere/utils/command/CommandTypes.java @@ -0,0 +1,77 @@ +package dev.manere.utils.command; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandMap; +import org.bukkit.plugin.java.JavaPlugin; + +/** + * An enumeration representing the registration system to use. + */ +public class CommandTypes { + private final int type; + + private CommandTypes(int type) { + this.type = type; + } + + /** + * Self-explanatory. Uses the plugin.yml file + * and {@link JavaPlugin#getCommand(String)} to retrieve and register the command. + */ + public static final CommandTypes PLUGIN_YML = CommandTypes.type(0); + + /** + * Used for registering commands via the {@link CommandMap} + * Does not require the command to be in the plugin.yml of your project. + *

+ * If you have a command of {@code /hello} and your plugin's name is HelloPlugin + * then it will register with the default namespace of your plugin: {@code /helloplugin:hello} + *

+ * Access to the command map is provided via the {@link Bukkit#getCommandMap()} method. + */ + public static final CommandTypes COMMAND_MAP = CommandTypes.type(1); + + public static CommandTypes pluginYml() { + return PLUGIN_YML; + } + + public static CommandTypes plugin() { + return pluginYml(); + } + + public static CommandTypes descriptionFile() { + return pluginYml(); + } + + public static CommandTypes descFile() { + return pluginYml(); + } + + public static CommandTypes pluginMeta() { + return pluginYml(); + } + + public static CommandTypes meta() { + return pluginYml(); + } + + public static CommandTypes commandMap() { + return COMMAND_MAP; + } + + public static CommandTypes map() { + return commandMap(); + } + + public static CommandTypes paper() { + return commandMap(); + } + + public int type() { + return type; + } + + public static CommandTypes type(int type) { + return new CommandTypes(type); + } +} diff --git a/src/main/java/dev/manere/utils/command/Commander.java b/src/main/java/dev/manere/utils/command/Commander.java index f6bfd75..0471f14 100644 --- a/src/main/java/dev/manere/utils/command/Commander.java +++ b/src/main/java/dev/manere/utils/command/Commander.java @@ -1,21 +1,21 @@ package dev.manere.utils.command; import dev.manere.utils.command.annotation.AutoRegister; -import dev.manere.utils.command.builder.CommandBuilder; -import dev.manere.utils.command.builder.dispatcher.CommandDispatcher; -import dev.manere.utils.command.builder.dispatcher.SuggestionDispatcher; +import dev.manere.utils.command.impl.Commands; +import dev.manere.utils.command.impl.dispatcher.CommandDispatcher; +import dev.manere.utils.command.impl.dispatcher.SuggestionDispatcher; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; /** - * Bukkit-like wrapper for a command, uses {@link CommandBuilder}. - * @see CommandBuilder + * Bukkit-like wrapper for a command, uses {@link Commands}. + * @see Commands * @see AutoRegister */ public abstract class Commander implements CommandDispatcher, SuggestionDispatcher { - private CommandSettings settings; + private CommandConfig settings; private String name; private final List aliases = new ArrayList<>(); private String description; @@ -27,7 +27,7 @@ public abstract class Commander implements CommandDispatcher, SuggestionDispatch * @param name The name of the command to use for registration. */ public Commander(String name) { - this.settings = CommandSettings.settings(); + this.settings = CommandConfig.settings(); this.name = name; } @@ -36,7 +36,7 @@ public Commander(String name) { * * @return The command settings */ - public @NotNull CommandSettings settings() { + public @NotNull CommandConfig settings() { return settings; } @@ -55,7 +55,7 @@ public Commander(String name) { * @param settings The new settings * @return This commander instance */ - public @NotNull Commander settings(@NotNull CommandSettings settings) { + public @NotNull Commander settings(@NotNull CommandConfig settings) { this.settings = settings; return this; } diff --git a/src/main/java/dev/manere/utils/command/annotation/AutoRegister.java b/src/main/java/dev/manere/utils/command/annotation/AutoRegister.java index 9f30ff6..da50d8f 100644 --- a/src/main/java/dev/manere/utils/command/annotation/AutoRegister.java +++ b/src/main/java/dev/manere/utils/command/annotation/AutoRegister.java @@ -16,6 +16,4 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface AutoRegister { - -} +public @interface AutoRegister {} diff --git a/src/main/java/dev/manere/utils/command/annotation/AutoRegisterHandler.java b/src/main/java/dev/manere/utils/command/annotation/AutoRegisterHandler.java index 698191a..89268d0 100644 --- a/src/main/java/dev/manere/utils/command/annotation/AutoRegisterHandler.java +++ b/src/main/java/dev/manere/utils/command/annotation/AutoRegisterHandler.java @@ -1,11 +1,11 @@ package dev.manere.utils.command.annotation; -import dev.manere.utils.command.CommandType; +import dev.manere.utils.command.CommandTypes; import dev.manere.utils.command.Commander; import dev.manere.utils.event.EventListener; import dev.manere.utils.library.Utils; import dev.manere.utils.logger.Loggers; -import dev.manere.utils.model.Duo; +import dev.manere.utils.model.Tuple; import dev.manere.utils.registration.Registrar; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @@ -25,7 +25,6 @@ * @see AutoRegister */ public class AutoRegisterHandler { - /** * Scans the project using this library and then * attempts to register the class as an event listener or command. @@ -59,7 +58,7 @@ public static void scanAndRegister() { } } - private static @NotNull Duo findInstance(@NotNull Class clazz) { + private static @NotNull Tuple findInstance(@NotNull Class clazz) { Constructor[] constructors = clazz.getDeclaredConstructors(); Object instance = null; @@ -101,12 +100,12 @@ else if (Modifier.isPrivate(modifiers)) { } - return new Duo<>(mode, instance); + return new Tuple<>(mode, instance); } private static void autoRegister(@NotNull Class clazz) { JavaPlugin plugin = Utils.plugin(); - Duo tuple = findInstance(clazz); + Tuple tuple = findInstance(clazz); Object instance = tuple.val(); @@ -128,7 +127,7 @@ private static void autoRegister(@NotNull Class clazz) { } else if (Commander.class.isAssignableFrom(clazz)) { Commander commander = (Commander) instance; - if (commander.settings().type() == CommandType.PLUGIN_YML) { + if (commander.settings().type() == CommandTypes.PLUGIN_YML) { Registrar.command(commander); } else { Registrar.command( @@ -183,7 +182,7 @@ private static void autoRegister(@NotNull Class clazz) { return classes; } - private static @NotNull File src() { + public static @NotNull File src() { try { JavaPlugin plugin = (JavaPlugin) Utils.plugin().getServer().getPluginManager().getPlugin(Utils.plugin().getName()); Method getFileMethod = JavaPlugin.class.getDeclaredMethod("getFile"); diff --git a/src/main/java/dev/manere/utils/command/args/Argument.java b/src/main/java/dev/manere/utils/command/args/Argument.java index 7cd448c..f05fb9b 100644 --- a/src/main/java/dev/manere/utils/command/args/Argument.java +++ b/src/main/java/dev/manere/utils/command/args/Argument.java @@ -2,8 +2,8 @@ import dev.manere.utils.command.args.custom.CustomArgument; import dev.manere.utils.command.args.exception.ArgumentExType; -import dev.manere.utils.command.builder.dispatcher.CommandContext; -import dev.manere.utils.command.builder.dispatcher.SuggestionDispatcher; +import dev.manere.utils.command.impl.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.SuggestionDispatcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/custom/CustomArgument.java b/src/main/java/dev/manere/utils/command/args/custom/CustomArgument.java index d916ba1..f846a65 100644 --- a/src/main/java/dev/manere/utils/command/args/custom/CustomArgument.java +++ b/src/main/java/dev/manere/utils/command/args/custom/CustomArgument.java @@ -1,7 +1,7 @@ package dev.manere.utils.command.args.custom; import dev.manere.utils.command.args.exception.ArgumentParseException; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,7 +11,6 @@ * @param The type to which the argument will be parsed. */ public interface CustomArgument { - /** * Parses the given argument into the specified type. * diff --git a/src/main/java/dev/manere/utils/command/args/custom/CustomListArgument.java b/src/main/java/dev/manere/utils/command/args/custom/CustomListArgument.java index b0419c3..3d5310c 100644 --- a/src/main/java/dev/manere/utils/command/args/custom/CustomListArgument.java +++ b/src/main/java/dev/manere/utils/command/args/custom/CustomListArgument.java @@ -1,7 +1,7 @@ package dev.manere.utils.command.args.custom; import dev.manere.utils.command.args.exception.ArgumentParseException; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,8 +10,7 @@ /** * Represents a custom argument that deals with a list of string arguments. */ -public abstract class CustomListArgument implements CustomArgument> { - +public abstract class CustomListArgument implements CustomArgument> { /** * Parses a list of string arguments into a specific type. * @@ -20,7 +19,7 @@ public abstract class CustomListArgument implements CustomArgument> { * @throws ArgumentParseException If an error occurs during the parsing process. */ @Nullable - public abstract String parse(@Nullable List args) throws ArgumentParseException; + public abstract T parse(@Nullable List args) throws ArgumentParseException; /** * Parses a specific string argument at the given index into a specific type. @@ -31,7 +30,7 @@ public abstract class CustomListArgument implements CustomArgument> { * @throws ArgumentParseException If an error occurs during the parsing process. */ @Nullable - public abstract String parse(@NotNull CommandContext ctx, int indexStart) throws ArgumentParseException; + public abstract T parse(@NotNull CommandContext ctx, int indexStart) throws ArgumentParseException; /** * Parses a string argument into a list of a specific type. @@ -41,7 +40,7 @@ public abstract class CustomListArgument implements CustomArgument> { * @return The parsed list, or null if parsing fails. */ @Nullable - public List parse(@NotNull CommandContext ctx, @Nullable String arg) { + public List parse(@NotNull CommandContext ctx, @Nullable String arg) { return null; } } diff --git a/src/main/java/dev/manere/utils/command/args/entity/CachedOfflinePlayerArgument.java b/src/main/java/dev/manere/utils/command/args/entity/CachedOfflinePlayerArgument.java index 83b524e..83cdf6f 100644 --- a/src/main/java/dev/manere/utils/command/args/entity/CachedOfflinePlayerArgument.java +++ b/src/main/java/dev/manere/utils/command/args/entity/CachedOfflinePlayerArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import dev.manere.utils.server.ServerUtils; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/dev/manere/utils/command/args/entity/EntityTypeArgument.java b/src/main/java/dev/manere/utils/command/args/entity/EntityTypeArgument.java index bd8fb7c..0a294c6 100644 --- a/src/main/java/dev/manere/utils/command/args/entity/EntityTypeArgument.java +++ b/src/main/java/dev/manere/utils/command/args/entity/EntityTypeArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/entity/OfflinePlayerArgument.java b/src/main/java/dev/manere/utils/command/args/entity/OfflinePlayerArgument.java index 54efc30..63a6f12 100644 --- a/src/main/java/dev/manere/utils/command/args/entity/OfflinePlayerArgument.java +++ b/src/main/java/dev/manere/utils/command/args/entity/OfflinePlayerArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import dev.manere.utils.server.ServerUtils; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/dev/manere/utils/command/args/entity/PlayerArgument.java b/src/main/java/dev/manere/utils/command/args/entity/PlayerArgument.java index bf42ffc..fbc8e02 100644 --- a/src/main/java/dev/manere/utils/command/args/entity/PlayerArgument.java +++ b/src/main/java/dev/manere/utils/command/args/entity/PlayerArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import dev.manere.utils.player.PlayerUtils; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/dev/manere/utils/command/args/exception/ArgumentExType.java b/src/main/java/dev/manere/utils/command/args/exception/ArgumentExType.java index 2e12e57..d04715b 100644 --- a/src/main/java/dev/manere/utils/command/args/exception/ArgumentExType.java +++ b/src/main/java/dev/manere/utils/command/args/exception/ArgumentExType.java @@ -1,5 +1,7 @@ package dev.manere.utils.command.args.exception; +import dev.manere.utils.command.args.primitive.IntegerArgument; + /** * Enum representing different types of argument parsing exceptions. */ @@ -17,5 +19,11 @@ public enum ArgumentExType { /** * Indicates that the syntax of the command is invalid. (Incorrect Usage) */ - INVALID_SYNTAX + INVALID_SYNTAX, + + /** + * Indicates that the argument provided is not within the expected integer range. + * @see IntegerArgument + */ + INVALID_RANGE } diff --git a/src/main/java/dev/manere/utils/command/args/exception/ArgumentParseException.java b/src/main/java/dev/manere/utils/command/args/exception/ArgumentParseException.java index 377deb6..a374f15 100644 --- a/src/main/java/dev/manere/utils/command/args/exception/ArgumentParseException.java +++ b/src/main/java/dev/manere/utils/command/args/exception/ArgumentParseException.java @@ -3,7 +3,7 @@ /** * Exception thrown when there is an issue parsing command arguments. */ -public class ArgumentParseException extends Exception { +public class ArgumentParseException extends RuntimeException { private final ArgumentExType type; /** diff --git a/src/main/java/dev/manere/utils/command/args/misc/GamemodeArgument.java b/src/main/java/dev/manere/utils/command/args/misc/GamemodeArgument.java index 1bc8322..8fffa41 100644 --- a/src/main/java/dev/manere/utils/command/args/misc/GamemodeArgument.java +++ b/src/main/java/dev/manere/utils/command/args/misc/GamemodeArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.bukkit.GameMode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/primitive/BooleanArgument.java b/src/main/java/dev/manere/utils/command/args/primitive/BooleanArgument.java index 0c04a0d..8220893 100644 --- a/src/main/java/dev/manere/utils/command/args/primitive/BooleanArgument.java +++ b/src/main/java/dev/manere/utils/command/args/primitive/BooleanArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/primitive/DoubleArgument.java b/src/main/java/dev/manere/utils/command/args/primitive/DoubleArgument.java index ef27566..8549e78 100644 --- a/src/main/java/dev/manere/utils/command/args/primitive/DoubleArgument.java +++ b/src/main/java/dev/manere/utils/command/args/primitive/DoubleArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/primitive/FloatArgument.java b/src/main/java/dev/manere/utils/command/args/primitive/FloatArgument.java index e03d289..7011069 100644 --- a/src/main/java/dev/manere/utils/command/args/primitive/FloatArgument.java +++ b/src/main/java/dev/manere/utils/command/args/primitive/FloatArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/primitive/IntegerArgument.java b/src/main/java/dev/manere/utils/command/args/primitive/IntegerArgument.java index e2e8364..cd39c48 100644 --- a/src/main/java/dev/manere/utils/command/args/primitive/IntegerArgument.java +++ b/src/main/java/dev/manere/utils/command/args/primitive/IntegerArgument.java @@ -3,15 +3,32 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class IntegerArgument implements CustomArgument { + private final @Nullable Integer max; + private final @Nullable Integer min; + + public IntegerArgument(int min, int max) { + this.max = max; + this.min = min; + } + + public IntegerArgument() { + this.min = null; + this.max = null; + } + public static IntegerArgument arg() { return new IntegerArgument(); } + public static IntegerArgument arg(@Nullable Integer min, @Nullable Integer max) { + return new IntegerArgument(min, max); + } + /** * {@inheritDoc} */ @@ -22,7 +39,17 @@ public static IntegerArgument arg() { } try { - return Integer.parseInt(arg); + int value = Integer.parseInt(arg); + + if (min != null && value < min) { + throw new ArgumentParseException("Value must be greater than " + min, ArgumentExType.INVALID_RANGE); + } + + if (max != null && value > max) { + throw new ArgumentParseException("Value must be less than " + max, ArgumentExType.INVALID_RANGE); + } + + return value; } catch (NumberFormatException e) { throw new ArgumentParseException("Invalid Integer/Number provided.", ArgumentExType.INVALID_SYNTAX); } diff --git a/src/main/java/dev/manere/utils/command/args/primitive/LongArgument.java b/src/main/java/dev/manere/utils/command/args/primitive/LongArgument.java index 9b116bc..b6562b8 100644 --- a/src/main/java/dev/manere/utils/command/args/primitive/LongArgument.java +++ b/src/main/java/dev/manere/utils/command/args/primitive/LongArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/text/ComponentArgument.java b/src/main/java/dev/manere/utils/command/args/text/ComponentArgument.java index 02f7514..7bd7e85 100644 --- a/src/main/java/dev/manere/utils/command/args/text/ComponentArgument.java +++ b/src/main/java/dev/manere/utils/command/args/text/ComponentArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import dev.manere.utils.text.color.TextStyle; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/dev/manere/utils/command/args/text/ComponentListArgument.java b/src/main/java/dev/manere/utils/command/args/text/ComponentListArgument.java new file mode 100644 index 0000000..399fd84 --- /dev/null +++ b/src/main/java/dev/manere/utils/command/args/text/ComponentListArgument.java @@ -0,0 +1,44 @@ +package dev.manere.utils.command.args.text; + +import dev.manere.utils.command.args.custom.CustomListArgument; +import dev.manere.utils.command.args.exception.ArgumentExType; +import dev.manere.utils.command.args.exception.ArgumentParseException; +import dev.manere.utils.command.impl.dispatcher.CommandContext; +import dev.manere.utils.text.color.TextStyle; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ComponentListArgument extends CustomListArgument { + public static ComponentListArgument arg() { + return new ComponentListArgument(); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable Component parse(@Nullable List args) throws ArgumentParseException { + if (args == null || args.isEmpty()) { + throw new ArgumentParseException("CustomArgument list cannot be null or empty", ArgumentExType.ARG_IS_NULL); + } + + return TextStyle.style(String.join(" ", args)); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable Component parse(@NotNull CommandContext ctx, int indexStart) throws ArgumentParseException { + List rawArgs = ctx.rawArgs(); + + if (indexStart < 0 || indexStart >= rawArgs.size()) { + throw new ArgumentParseException("Invalid indexStart value", ArgumentExType.INVALID_SYNTAX); + } + + return parse(rawArgs.subList(indexStart, rawArgs.size())); + } +} diff --git a/src/main/java/dev/manere/utils/command/args/text/StringArgument.java b/src/main/java/dev/manere/utils/command/args/text/StringArgument.java index ebf3c55..72a222f 100644 --- a/src/main/java/dev/manere/utils/command/args/text/StringArgument.java +++ b/src/main/java/dev/manere/utils/command/args/text/StringArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/text/StringListArgument.java b/src/main/java/dev/manere/utils/command/args/text/StringListArgument.java index d868921..4d0e5c3 100644 --- a/src/main/java/dev/manere/utils/command/args/text/StringListArgument.java +++ b/src/main/java/dev/manere/utils/command/args/text/StringListArgument.java @@ -3,13 +3,13 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomListArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -public class StringListArgument extends CustomListArgument { +public class StringListArgument extends CustomListArgument { public static StringListArgument arg() { return new StringListArgument(); } diff --git a/src/main/java/dev/manere/utils/command/args/text/TextArgument.java b/src/main/java/dev/manere/utils/command/args/text/TextArgument.java index 570d784..e8049ca 100644 --- a/src/main/java/dev/manere/utils/command/args/text/TextArgument.java +++ b/src/main/java/dev/manere/utils/command/args/text/TextArgument.java @@ -3,7 +3,7 @@ import dev.manere.utils.command.args.exception.ArgumentParseException; import dev.manere.utils.command.args.exception.ArgumentExType; import dev.manere.utils.command.args.custom.CustomArgument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import dev.manere.utils.text.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/manere/utils/command/args/text/TextListArgument.java b/src/main/java/dev/manere/utils/command/args/text/TextListArgument.java new file mode 100644 index 0000000..f5c8329 --- /dev/null +++ b/src/main/java/dev/manere/utils/command/args/text/TextListArgument.java @@ -0,0 +1,43 @@ +package dev.manere.utils.command.args.text; + +import dev.manere.utils.command.args.custom.CustomListArgument; +import dev.manere.utils.command.args.exception.ArgumentExType; +import dev.manere.utils.command.args.exception.ArgumentParseException; +import dev.manere.utils.command.impl.dispatcher.CommandContext; +import dev.manere.utils.text.Text; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class TextListArgument extends CustomListArgument { + public static TextListArgument arg() { + return new TextListArgument(); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable Text parse(@Nullable List args) throws ArgumentParseException { + if (args == null || args.isEmpty()) { + throw new ArgumentParseException("CustomArgument list cannot be null or empty", ArgumentExType.ARG_IS_NULL); + } + + return Text.text(String.join(" ", args)); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable Text parse(@NotNull CommandContext ctx, int indexStart) throws ArgumentParseException { + List rawArgs = ctx.rawArgs(); + + if (indexStart < 0 || indexStart >= rawArgs.size()) { + throw new ArgumentParseException("Invalid indexStart value", ArgumentExType.INVALID_SYNTAX); + } + + return parse(rawArgs.subList(indexStart, rawArgs.size())); + } +} diff --git a/src/main/java/dev/manere/utils/command/builder/CommandBuilder.java b/src/main/java/dev/manere/utils/command/builder/CommandBuilder.java deleted file mode 100644 index 1782e17..0000000 --- a/src/main/java/dev/manere/utils/command/builder/CommandBuilder.java +++ /dev/null @@ -1,237 +0,0 @@ -package dev.manere.utils.command.builder; - -import dev.manere.utils.command.CommandType; -import dev.manere.utils.command.args.Argument; -import dev.manere.utils.command.builder.alias.CommandAliasBuilder; -import dev.manere.utils.command.builder.dispatcher.CommandContext; -import dev.manere.utils.command.builder.dispatcher.CommandDispatcher; -import dev.manere.utils.command.builder.dispatcher.SuggestionDispatcher; -import dev.manere.utils.command.builder.permission.CommandPermissionBuilder; -import dev.manere.utils.text.color.TextStyle; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Predicate; - -/** - * A utility class for building and configuring Bukkit plugin commands. - */ -public class CommandBuilder { - private final String name; - private final CommandType type; - private CommandDispatcher dispatcher; - private SuggestionDispatcher suggestionDispatcher; - private final Command command; - private final List> requirements; - private final List> args; - - /** - * Constructs a new CommandBuilder with the specified name and type. - * - * @param name The name of the command. - * @param type The type of the command. - */ - public CommandBuilder(@NotNull String name, @NotNull CommandType type) { - this.name = name; - this.type = type; - this.requirements = new ArrayList<>(); - this.args = new ArrayList<>(); - this.command = new Command(name) { - @Override - public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - return true; - } - }; - } - - /** - * Create a new CommandBuilder with the specified name and type. - * - * @param name The name of the command. - * @param type The type of the command. - * @return A new CommandBuilder instance. - */ - public static @NotNull CommandBuilder command(@NotNull String name, @NotNull CommandType type) { - return new CommandBuilder(name, type); - } - - /** - * Create a new CommandBuilder with the specified name and default (PLUGIN_YML) type. - * - * @param name The name of the command. - * @return A new CommandBuilder instance. - */ - public static @NotNull CommandBuilder command(@NotNull String name) { - return CommandBuilder.command(name, CommandType.PLUGIN_YML); - } - - /** - * Adds a predicate/filter to the command. - * Return true if you want to stop the execution - * of the command. - * - * @param predicate What to run. - * @return This CommandBuilder instance for method chaining. - */ - public @NotNull CommandBuilder requirement(@NotNull Predicate predicate) { - requirements().add(predicate); - return this; - } - - /** - * Returns the list of filters. - * - * @return The list of filters. - */ - public @NotNull List> requirements() { - return this.requirements; - } - - /** - * Returns the underlying Bukkit Command associated with this CommandBuilder. - * - * @return The Bukkit Command object. - */ - public @NotNull Command command() { - return command; - } - - /** - * Gets the description of the command. - * - * @return The description of the command. - */ - public @NotNull String description() { - return command.getDescription(); - } - - /** - * Sets the description of the command. - * - * @param description The new description for the command. - * @return This CommandBuilder instance for method chaining. - */ - public @NotNull CommandBuilder description(@NotNull String description) { - this.command.setDescription(description); - return this; - } - - /** - * Returns a CommandPermissionBuilder instance for setting custom permissions for the command. - * - * @return A CommandPermissionBuilder instance. - */ - public @NotNull CommandPermissionBuilder permission() { - return new CommandPermissionBuilder(this); - } - - /** - * Sets the usage description for the command. - * - * @param usage The usage description for the command. - * @return This CommandBuilder instance for method chaining. - */ - public @NotNull CommandBuilder usage(@NotNull String usage) { - this.command.setUsage(TextStyle.legacy(usage)); - return this; - } - - /** - * Returns the usage message associated with this CommandBuilder. - * - * @return The usage message associated with this CommandBuilder. - */ - public @NotNull String usage() { - return this.command.getUsage(); - } - - /** - * Returns a CommandAliasBuilder instance for managing command aliases. - * - * @return A CommandAliasBuilder instance. - */ - public @NotNull CommandAliasBuilder aliases() { - return new CommandAliasBuilder(this); - } - - /** - * Sets the CommandDispatcher for executing the command. - * - * @param dispatcher The CommandDispatcher for executing the command. - * @return This CommandBuilder instance for method chaining. - */ - public @NotNull CommandBuilder executes(@NotNull CommandDispatcher dispatcher) { - this.dispatcher = dispatcher; - return this; - } - - /** - * Returns the CommandDispatcher associated with this CommandBuilder. - * - * @return The CommandDispatcher for executing the command. - */ - public @Nullable CommandDispatcher executes() { - return dispatcher; - } - - /** - * Sets the SuggestionDispatcher for handling command suggestions. - * - * @param suggestionDispatcher The SuggestionDispatcher for handling command suggestions. - * @return This CommandBuilder instance for method chaining. - */ - public @NotNull CommandBuilder completes(@Nullable SuggestionDispatcher suggestionDispatcher) { - this.suggestionDispatcher = suggestionDispatcher; - return this; - } - - /** - * Returns the SuggestionDispatcher associated with this CommandBuilder. - * - * @return The SuggestionDispatcher for handling command suggestions. - */ - public @Nullable SuggestionDispatcher completes() { - return suggestionDispatcher; - } - - /** - * Gets the name of the command. - * - * @return The name of the command. - */ - public @NotNull String name() { - return name; - } - - /** - * Gets the type of the command. - * - * @return The type of the command - */ - public @NotNull CommandType type() { - return type; - } - - - public @NotNull CommandBuilder argument(@NotNull Argument arg) { - this.args.add(arg); - return this; - } - - public @NotNull List> args() { - return args; - } - - /** - * Builds and returns a CommandBuilderHandler for handling the command. - * - * @return A CommandBuilderHandler for handling the command. - */ - public @NotNull CommandBuilderHandler build() { - return new CommandBuilderHandler(this); - } -} diff --git a/src/main/java/dev/manere/utils/command/impl/CommandInfo.java b/src/main/java/dev/manere/utils/command/impl/CommandInfo.java new file mode 100644 index 0000000..88d19e6 --- /dev/null +++ b/src/main/java/dev/manere/utils/command/impl/CommandInfo.java @@ -0,0 +1,86 @@ +package dev.manere.utils.command.impl; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; + +public class CommandInfo { + final @NotNull Commands builder; + private @Nullable String namespace; + private @Nullable String description; + private @Nullable String permission; + private @Nullable Component permissionMessage; + private @Nullable String usage; + private @Nullable List aliases; + + public CommandInfo(@NotNull Commands builder) { + this.builder = builder; + } + + public String namespace() { + return namespace; + } + + public CommandInfo namespace(String namespace) { + this.namespace = namespace; + return this; + } + + public String description() { + return description; + } + + public CommandInfo description(String description) { + this.description = description; + return this; + } + + public String permission() { + return permission; + } + + public CommandInfo permission(String permission) { + this.permission = permission; + return this; + } + + public CommandInfo permission(String prefix, String suffix) { + this.permission = prefix + "." + suffix; + return this; + } + + public Component permissionMessage() { + return permissionMessage; + } + + public CommandInfo permissionMessage(Component permissionMessage) { + this.permissionMessage = permissionMessage; + return this; + } + + public String usage() { + return usage; + } + + public CommandInfo usage(String usage) { + this.usage = usage; + return this; + } + + public List aliases() { + return aliases; + } + + public CommandInfo aliases(List aliases) { + this.aliases = aliases; + return this; + } + + public CommandInfo aliases(String... aliases) { + this.aliases = Arrays.asList(aliases); + return this; + } +} diff --git a/src/main/java/dev/manere/utils/command/impl/Commands.java b/src/main/java/dev/manere/utils/command/impl/Commands.java new file mode 100644 index 0000000..24fd87b --- /dev/null +++ b/src/main/java/dev/manere/utils/command/impl/Commands.java @@ -0,0 +1,422 @@ +package dev.manere.utils.command.impl; + +import dev.manere.utils.command.CommandTypes; +import dev.manere.utils.command.args.Argument; +import dev.manere.utils.command.impl.alias.CommandAliasBuilder; +import dev.manere.utils.command.impl.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandDispatcher; +import dev.manere.utils.command.impl.dispatcher.SuggestionDispatcher; +import dev.manere.utils.command.impl.permission.CommandPermission; +import dev.manere.utils.command.impl.permission.CommandPermissionBuilder; +import dev.manere.utils.library.Utils; +import dev.manere.utils.text.color.TextStyle; +import net.kyori.adventure.text.Component; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * Allows you to easily create commands non-reliant on Brigadier, + * made very simple and easy to use, + * allows for a variety of options + * and a lot of customisable features. + *

+ * WARNING:

+ * When using {@code new Commands(Command command)} or {@link Commands#legacy(Command)} you will lose + * the Argument arguments. Don't use that unless you need to.

+ *

+ * REQUIREMENTS: + *

When adding a requirement using {@link Commands#requirement(Predicate)} you should return:

+ * - {@code true} if you want to stop execution of the command, + *

+ * - {@code false} if you want to continue execution of the command. + *

+ * COMMAND TYPES: + *

You will find documentation for Command Types in {@link CommandTypes}

+ * + * @see CommandDispatcher + * @see SuggestionDispatcher + * @see CommandTypes + * @see Argument + * @see CommandContext + */ +public class Commands { + private final String name; + private final CommandTypes type; + private CommandDispatcher dispatcher; + private SuggestionDispatcher suggestionDispatcher; + private final Command command; + private final List> requirements; + private final List> args; + private String namespace; + + /** + * Constructs a new Commands with the specified name and type. + * + * @param name The name of the command. + * @param type The type of the command. + */ + public Commands(@NotNull String name, @NotNull CommandTypes type) { + this.name = name; + this.type = type; + this.requirements = new ArrayList<>(); + this.args = new ArrayList<>(); + this.command = new Command(name) { + @Override + public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { + return true; + } + }; + } + + public Commands(@NotNull String name) { + this(name, CommandTypes.commandMap()); + } + + private Commands(Command command) { + CommandTypes commandType = Utils.plugin().getCommand(command.getName()) != null + ? CommandTypes.PLUGIN_YML + : CommandTypes.COMMAND_MAP; + + this.name = command.getName(); + this.type = commandType; + this.requirements = new ArrayList<>(); + this.args = new ArrayList<>(); + this.command = command; + + this.dispatcher = ctx -> this.command.execute( + ctx.sender(), + ctx.commandRan(), + ctx.rawArgs().toArray(new String[0]) + ); + + this.suggestionDispatcher = ctx -> this.command.tabComplete( + ctx.sender(), + ctx.commandRan(), + ctx.rawArgs().toArray(new String[0]) + ); + } + + @ApiStatus.Internal + public static @NotNull Commands legacy(Command command) { + return new Commands(command); + } + + /** + * Create a new Commands with the specified name and type. + * + * @param name The name of the command. + * @param type The type of the command. + * @return A new Commands instance. + */ + public static @NotNull Commands command(@NotNull String name, @NotNull CommandTypes type) { + return new Commands(name, type); + } + + /** + * Create a new Commands with the specified name and default (PLUGIN_YML) type. + * + * @param name The name of the command. + * @return A new Commands instance. + */ + public static @NotNull Commands command(@NotNull String name) { + return new Commands(name); + } + + void test() { + + } + + public Commands info(Consumer infoConsumer) { + CommandInfo info = new CommandInfo(this); + infoConsumer.accept(info); + + if (info.description() != null) description(info.description()); + if (info.namespace() != null) namespace(info.namespace()); + if (info.aliases() != null) aliases(info.aliases()); + if (info.permission() != null) permission(info.permission()); + if (info.permissionMessage() != null) permissionMessage(info.permissionMessage()); + if (info.usage() != null) usage(info.usage()); + + return this; + } + + /** + * Returns the command registration namespace. + * + * @return The command registration namespace. + */ + public @NotNull String namespace() { + return namespace == null ? Utils.plugin().getName() : namespace; + } + + /** + * Sets the command registration namespace. + * + * @param namespace The new the command registration namespace. + * @return This Commands instance for method chaining. + */ + public Commands namespace(@NotNull String namespace) { + this.namespace = namespace; + return this; + } + + /** + * Adds a predicate/filter to the command. + * Return true if you want to stop the execution + * of the command. + * + * @param predicate What to run. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands requirement(@NotNull Predicate predicate) { + requirements().add(predicate); + return this; + } + + /** + * Returns the list of filters. + * + * @return The list of filters. + */ + public @NotNull List> requirements() { + return this.requirements; + } + + /** + * Returns the underlying Bukkit Command associated with this command. + * + * @return The Bukkit Command object. + */ + public @NotNull Command command() { + return command; + } + + /** + * Gets the description of the command. + * + * @return The description of the command. + */ + public @NotNull String description() { + return command.getDescription(); + } + + /** + * Sets the description of the command. + * + * @param description The new description for the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands description(@NotNull String description) { + this.command.setDescription(description); + return this; + } + + /** + * Returns a CommandPermissionBuilder instance for setting custom permissions for the command. + * + * @return A CommandPermissionBuilder instance. + */ + public @NotNull CommandPermissionBuilder permission() { + return new CommandPermissionBuilder(this); + } + + /** + * Sets the required permission for the command. + * + * @param permission The permission to require for the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands permission(@NotNull String permission) { + return permission() + .type(CommandPermission.CUSTOM) + .custom(permission) + .build(); + } + + /** + * Sets the required permission for the command. + * + * @param prefix The permission prefix to require for the command. + * If your permission is `kits . kit` then the prefix + * is {@code kits} + * @param suffix The permission suffix to require for the command. + * If your permission is `kits . kit` then the suffix + * is {@code kit} + * + * @return This Commands instance for method chaining. + */ + public @NotNull Commands permission(@NotNull String prefix, @NotNull String suffix) { + return permission() + .type(CommandPermission.CUSTOM) + .custom(prefix, suffix) + .build(); + } + + /** + * Sets the 'insufficient permissions' message for the command. + * + * @param permissionMessage The 'insufficient permissions' message for the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands permissionMessage(@NotNull Component permissionMessage) { + command().permissionMessage(permissionMessage); + return this; + } + + /** + * Sets the usage description for the command. + * + * @param usage The usage description for the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands usage(@NotNull String usage) { + this.command.setUsage(TextStyle.legacy(usage)); + return this; + } + + /** + * Returns the usage message associated with this command. + * + * @return The usage message associated with this command. + */ + public @NotNull String usage() { + return this.command.getUsage(); + } + + /** + * Returns a CommandAliasBuilder instance for managing command aliases. + * + * @return A CommandAliasBuilder instance. + */ + public @NotNull CommandAliasBuilder aliases() { + return new CommandAliasBuilder(this); + } + + /** + * Sets the aliases for the command. + * + * @param aliases The aliases for the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands aliases(@NotNull String... aliases) { + return aliases(Arrays.asList(aliases)); + } + + /** + * Sets the aliases for the command. + * + * @param aliases The aliases for the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands aliases(@NotNull List aliases) { + return aliases().aliases(aliases).build(); + } + + /** + * Sets the CommandDispatcher for executing the command. + * + * @param dispatcher The CommandDispatcher for executing the command. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands executes(@NotNull CommandDispatcher dispatcher) { + this.dispatcher = dispatcher; + return this; + } + + /** + * Returns the CommandDispatcher associated with this command. + * + * @return The CommandDispatcher for executing the command. + */ + public @Nullable CommandDispatcher executes() { + return dispatcher; + } + + /** + * Sets the SuggestionDispatcher for handling command suggestions. + * + * @param suggestionDispatcher The SuggestionDispatcher for handling command suggestions. + * @return This Commands instance for method chaining. + */ + public @NotNull Commands completes(@Nullable SuggestionDispatcher suggestionDispatcher) { + this.suggestionDispatcher = suggestionDispatcher; + return this; + } + + /** + * Returns the SuggestionDispatcher associated with this command. + * + * @return The SuggestionDispatcher for handling command suggestions. + */ + public @Nullable SuggestionDispatcher completes() { + return suggestionDispatcher; + } + + /** + * Gets the name of the command. + * + * @return The name of the command. + */ + public @NotNull String name() { + return name; + } + + /** + * Gets the type of the command. + * + * @return The type of the command + */ + public @NotNull CommandTypes type() { + return type; + } + + /** + * Adds an argument to the command. + * @param argument The argument to add + * @return This Commands instance for method chaining. + */ + public @NotNull Commands argument(@NotNull Argument argument) { + this.args.add(argument); + return this; + } + + /** + * Adds an argument to the command. + * @param argument The argument to add + * @return This Commands instance for method chaining. + */ + public @NotNull Commands arg(@NotNull Argument argument) { + return argument(argument); + } + + @NotNull + public List> args() { + return args; + } + + /** + * Builds and returns a CommandsRegistrar for handling the command. + * + * @return A CommandsRegistrar for handling the command. + */ + public @NotNull CommandsRegistrar build() { + return new CommandsRegistrar(this); + } + + /** + * Attempts to register the command + * with the plugin obtained by {@link Utils#plugin()} + */ + public void register() { + build().register(); + } +} diff --git a/src/main/java/dev/manere/utils/command/builder/CommandBuilderHandler.java b/src/main/java/dev/manere/utils/command/impl/CommandsRegistrar.java similarity index 88% rename from src/main/java/dev/manere/utils/command/builder/CommandBuilderHandler.java rename to src/main/java/dev/manere/utils/command/impl/CommandsRegistrar.java index 61fb6c8..b90f24c 100644 --- a/src/main/java/dev/manere/utils/command/builder/CommandBuilderHandler.java +++ b/src/main/java/dev/manere/utils/command/impl/CommandsRegistrar.java @@ -1,7 +1,7 @@ -package dev.manere.utils.command.builder; +package dev.manere.utils.command.impl; import dev.manere.utils.command.args.Argument; -import dev.manere.utils.command.builder.dispatcher.CommandContext; +import dev.manere.utils.command.impl.dispatcher.CommandContext; import dev.manere.utils.library.Utils; import dev.manere.utils.registration.Registrar; import org.bukkit.plugin.java.JavaPlugin; @@ -11,11 +11,10 @@ import java.util.function.Predicate; /** - * Class related to finally registering a CommandBuilder. + * Class related to finally registering a Commands. * @param commandBuilder The command builder to handle. */ -public record CommandBuilderHandler(@NotNull CommandBuilder commandBuilder) { - +public record CommandsRegistrar(@NotNull Commands commandBuilder) { /** * Attempts to register the command * with the plugin obtained by {@link Utils#plugin()} @@ -31,8 +30,8 @@ public void register() { */ @SuppressWarnings("DataFlowIssue") public void register(@NotNull JavaPlugin plugin) { - switch (commandBuilder.type()) { - case PLUGIN_YML -> { + switch (commandBuilder.type().type()) { + case 0 -> { if (plugin.getCommand(commandBuilder.name()) == null) throw new NullPointerException( "The plugin.yml file is missing a definition for the command you are trying to register." + " Add the command definition to your plugin.yml to fix this." @@ -68,7 +67,7 @@ public void register(@NotNull JavaPlugin plugin) { } } - case COMMAND_MAP -> Registrar.commandMap(this); + case 1 -> Registrar.commandMap(this); } } } diff --git a/src/main/java/dev/manere/utils/command/builder/alias/CommandAliasBuilder.java b/src/main/java/dev/manere/utils/command/impl/alias/CommandAliasBuilder.java similarity index 66% rename from src/main/java/dev/manere/utils/command/builder/alias/CommandAliasBuilder.java rename to src/main/java/dev/manere/utils/command/impl/alias/CommandAliasBuilder.java index 39531e8..f048647 100644 --- a/src/main/java/dev/manere/utils/command/builder/alias/CommandAliasBuilder.java +++ b/src/main/java/dev/manere/utils/command/impl/alias/CommandAliasBuilder.java @@ -1,24 +1,24 @@ -package dev.manere.utils.command.builder.alias; +package dev.manere.utils.command.impl.alias; -import dev.manere.utils.command.builder.CommandBuilder; +import dev.manere.utils.command.impl.Commands; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; /** - * A builder class for managing aliases for a command associated with a CommandBuilder. + * A builder class for managing aliases for a command associated with a Commands. */ public class CommandAliasBuilder { - private final CommandBuilder commandBuilder; + private final Commands commandBuilder; private final List aliases; /** - * Constructs a new CommandAliasBuilder associated with the specified CommandBuilder. + * Constructs a new CommandAliasBuilder associated with the specified Commands. * - * @param commandBuilder The CommandBuilder associated with this CommandAliasBuilder. + * @param commandBuilder The Commands associated with this CommandAliasBuilder. */ - public CommandAliasBuilder(@NotNull CommandBuilder commandBuilder) { + public CommandAliasBuilder(@NotNull Commands commandBuilder) { this.commandBuilder = commandBuilder; this.aliases = commandBuilder.command().getAliases().isEmpty() ? new ArrayList<>() : commandBuilder.command().getAliases(); } @@ -43,7 +43,12 @@ public CommandAliasBuilder(@NotNull CommandBuilder commandBuilder) { return aliases; } - + /** + * Sets the aliases for the command. + * + * @param aliases The aliases for the command. + * @return This CommandAliasBuilder instance for method chaining. + */ public @NotNull CommandAliasBuilder aliases(@NotNull List aliases) { this.aliases.clear(); @@ -55,22 +60,13 @@ public CommandAliasBuilder(@NotNull CommandBuilder commandBuilder) { } /** - * Gets the associated CommandBuilder. - * - * @return The CommandBuilder associated with this CommandAliasBuilder. - */ - public @NotNull CommandBuilder commandBuilder() { - return commandBuilder; - } - - /** - * Builds and associates the list of aliases with the CommandBuilder. + * Builds and associates the list of aliases with the Commands. * - * @return The CommandBuilder with the associated aliases. + * @return The Commands with the associated aliases. */ - public @NotNull CommandBuilder build() { + public @NotNull Commands build() { if (!aliases.isEmpty()) { - commandBuilder().command().setAliases(aliases); + commandBuilder.command().setAliases(aliases); } return commandBuilder; diff --git a/src/main/java/dev/manere/utils/command/builder/dispatcher/CommandContext.java b/src/main/java/dev/manere/utils/command/impl/dispatcher/CommandContext.java similarity index 72% rename from src/main/java/dev/manere/utils/command/builder/dispatcher/CommandContext.java rename to src/main/java/dev/manere/utils/command/impl/dispatcher/CommandContext.java index 6e1bf7c..64f3421 100644 --- a/src/main/java/dev/manere/utils/command/builder/dispatcher/CommandContext.java +++ b/src/main/java/dev/manere/utils/command/impl/dispatcher/CommandContext.java @@ -1,4 +1,4 @@ -package dev.manere.utils.command.builder.dispatcher; +package dev.manere.utils.command.impl.dispatcher; import dev.manere.utils.command.args.Argument; import dev.manere.utils.command.args.custom.CustomArgument; @@ -204,7 +204,7 @@ public boolean senderIsPlayer() { if (rawArgs.size() <= index || rawArgAt(index) == null) { try { - if (argument.type() instanceof CustomListArgument arg) return arg.parse(this, 0); + if (argument.type() instanceof CustomListArgument arg) return arg.parse(this, 0); if (argument.defaultVal() == null) return null; return argument.type().parse(this, argument.defaultVal()); @@ -214,7 +214,7 @@ public boolean senderIsPlayer() { } } else if (rawArgAt(index) != null) { try { - if (argument.type() instanceof CustomListArgument arg) return arg.parse(this, index); + if (argument.type() instanceof CustomListArgument arg) return arg.parse(this, index); return argument.type().parse(this, rawArgAt(index)); } catch (ArgumentParseException e) { @@ -226,6 +226,62 @@ public boolean senderIsPlayer() { return null; } + /** + * Returns the argument of the identifier with the specified type. + * + * @param identifier The identifier of the argument. + * @param type The type parameter for the generic method. + * @param The type parameter for the generic method. + * @return The argument of the specified type. + */ + public @Nullable T argAt(@NotNull String identifier, @NotNull Class type) { + for (Argument arg : args) { + if (arg.identifier().equalsIgnoreCase(identifier)) { + return argAt(args.indexOf(arg), type); + } + } + + return null; + } + + /** + * Returns the argument at the specified index with the specified type. + * + * @param index The index of the argument. + * @param type The type parameter for the generic method. + * @param The type parameter for the generic method. + * @return The argument at the specified index with the specified type. + */ + @SuppressWarnings("unchecked") + public @Nullable T argAt(int index, @NotNull Class type) { + Argument argument = args.get(index); + + if (argument == null || rawArgs == null || rawArgs.isEmpty()) return null; + + if (rawArgs.size() <= index || rawArgAt(index) == null) { + try { + if (argument.type() instanceof CustomListArgument arg) return (T) arg.parse(this, 0); + if (argument.defaultVal() == null) return null; + + return type.cast(argument.type().parse(this, argument.defaultVal())); + } catch (ArgumentParseException err) { + if (argument.onError() != null) argument.onError().apply(this, err.type()); + else throw new RuntimeException(err.getMessage()); + } + } else if (rawArgAt(index) != null) { + try { + if (argument.type() instanceof CustomListArgument arg) return (T) arg.parse(this, index); + + return type.cast(argument.type().parse(this, rawArgAt(index))); + } catch (ArgumentParseException e) { + if (argument.onError() != null) argument.onError().apply(this, e.type()); + else throw new RuntimeException(e.getMessage()); + } + } + + return null; + } + public int argPos(String identifier) { for (Argument arg : args) { if (arg.identifier().equalsIgnoreCase(identifier)) { @@ -244,4 +300,22 @@ public int argPos(String identifier) { public @NotNull List> args() { return args; } + + /** + * Returns the size of all arguments. + * + * @return The size of all arguments. + */ + public int argSize() { + return rawArgs().size(); + } + + /** + * Returns the size of all arguments. + * + * @return The size of all arguments. + */ + public int size() { + return argSize(); + } } diff --git a/src/main/java/dev/manere/utils/command/builder/dispatcher/CommandDispatcher.java b/src/main/java/dev/manere/utils/command/impl/dispatcher/CommandDispatcher.java similarity index 89% rename from src/main/java/dev/manere/utils/command/builder/dispatcher/CommandDispatcher.java rename to src/main/java/dev/manere/utils/command/impl/dispatcher/CommandDispatcher.java index e9c2661..5b75d1f 100644 --- a/src/main/java/dev/manere/utils/command/builder/dispatcher/CommandDispatcher.java +++ b/src/main/java/dev/manere/utils/command/impl/dispatcher/CommandDispatcher.java @@ -1,4 +1,4 @@ -package dev.manere.utils.command.builder.dispatcher; +package dev.manere.utils.command.impl.dispatcher; import org.jetbrains.annotations.NotNull; @@ -6,7 +6,6 @@ * An interface for executing commands based on the provided command context. */ public interface CommandDispatcher { - /** * Executes a command based on the provided command context. * diff --git a/src/main/java/dev/manere/utils/command/builder/dispatcher/SuggestionDispatcher.java b/src/main/java/dev/manere/utils/command/impl/dispatcher/SuggestionDispatcher.java similarity index 91% rename from src/main/java/dev/manere/utils/command/builder/dispatcher/SuggestionDispatcher.java rename to src/main/java/dev/manere/utils/command/impl/dispatcher/SuggestionDispatcher.java index 889428f..a13ecd2 100644 --- a/src/main/java/dev/manere/utils/command/builder/dispatcher/SuggestionDispatcher.java +++ b/src/main/java/dev/manere/utils/command/impl/dispatcher/SuggestionDispatcher.java @@ -1,4 +1,4 @@ -package dev.manere.utils.command.builder.dispatcher; +package dev.manere.utils.command.impl.dispatcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,7 +9,6 @@ * An interface for providing command suggestions based on the provided command context. */ public interface SuggestionDispatcher { - /** * Generates a list of command suggestions based on the provided command context. * diff --git a/src/main/java/dev/manere/utils/command/builder/permission/CommandPermission.java b/src/main/java/dev/manere/utils/command/impl/permission/CommandPermission.java similarity index 78% rename from src/main/java/dev/manere/utils/command/builder/permission/CommandPermission.java rename to src/main/java/dev/manere/utils/command/impl/permission/CommandPermission.java index a271206..aedf1ed 100644 --- a/src/main/java/dev/manere/utils/command/builder/permission/CommandPermission.java +++ b/src/main/java/dev/manere/utils/command/impl/permission/CommandPermission.java @@ -1,10 +1,9 @@ -package dev.manere.utils.command.builder.permission; +package dev.manere.utils.command.impl.permission; /** * An enumeration representing different types of command permissions. */ public enum CommandPermission { - /** * Represents a custom command permission type. */ diff --git a/src/main/java/dev/manere/utils/command/builder/permission/CommandPermissionBuilder.java b/src/main/java/dev/manere/utils/command/impl/permission/CommandPermissionBuilder.java similarity index 80% rename from src/main/java/dev/manere/utils/command/builder/permission/CommandPermissionBuilder.java rename to src/main/java/dev/manere/utils/command/impl/permission/CommandPermissionBuilder.java index f2878fe..5c3af2e 100644 --- a/src/main/java/dev/manere/utils/command/builder/permission/CommandPermissionBuilder.java +++ b/src/main/java/dev/manere/utils/command/impl/permission/CommandPermissionBuilder.java @@ -1,25 +1,25 @@ -package dev.manere.utils.command.builder.permission; +package dev.manere.utils.command.impl.permission; -import dev.manere.utils.command.builder.CommandBuilder; +import dev.manere.utils.command.impl.Commands; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * A builder class for setting custom permissions for a command associated with a CommandBuilder. + * A builder class for setting custom permissions for a command associated with a Commands. */ public class CommandPermissionBuilder { - private final CommandBuilder commandBuilder; + private final Commands commandBuilder; private CommandPermission type; private String custom; private Component message; /** - * Constructs a new CommandPermissionBuilder associated with the specified CommandBuilder. + * Constructs a new CommandPermissionBuilder associated with the specified Commands. * - * @param commandBuilder The CommandBuilder associated with this CommandPermissionBuilder. + * @param commandBuilder The Commands associated with this CommandPermissionBuilder. */ - public CommandPermissionBuilder(@NotNull CommandBuilder commandBuilder) { + public CommandPermissionBuilder(@NotNull Commands commandBuilder) { this.commandBuilder = commandBuilder; } @@ -57,11 +57,11 @@ public CommandPermissionBuilder(@NotNull CommandBuilder commandBuilder) { } /** - * Gets the associated CommandBuilder. + * Gets the associated Commands. * - * @return The CommandBuilder associated with this CommandPermissionBuilder. + * @return The Commands associated with this CommandPermissionBuilder. */ - public @NotNull CommandBuilder commandBuilder() { + public @NotNull Commands commandBuilder() { return commandBuilder; } @@ -105,11 +105,11 @@ public CommandPermissionBuilder(@NotNull CommandBuilder commandBuilder) { } /** - * Builds and associates the command permission with the CommandBuilder. + * Builds and associates the command permission with the Commands. * - * @return The CommandBuilder with the associated command permission. + * @return The Commands with the associated command permission. */ - public @NotNull CommandBuilder build() { + public @NotNull Commands build() { commandBuilder().command().setPermission(custom()); if (message() != null) { diff --git a/src/main/java/dev/manere/utils/config/Config.java b/src/main/java/dev/manere/utils/config/Config.java index c0c0054..258f8ff 100644 --- a/src/main/java/dev/manere/utils/config/Config.java +++ b/src/main/java/dev/manere/utils/config/Config.java @@ -14,7 +14,6 @@ * Utility class for managing and interacting with configuration settings in a Bukkit plugin. */ public class Config { - /** * Retrieves the singleton instance of the Config class. * diff --git a/src/main/java/dev/manere/utils/config/section/ConfigSection.java b/src/main/java/dev/manere/utils/config/section/ConfigSection.java index c634f24..9f44218 100644 --- a/src/main/java/dev/manere/utils/config/section/ConfigSection.java +++ b/src/main/java/dev/manere/utils/config/section/ConfigSection.java @@ -11,7 +11,7 @@ * This class provides methods for creating, modifying, and retrieving values from the specified section. */ public class ConfigSection { - public final ConfigurationSection section; + final ConfigurationSection section; public final String sectionPath; /** diff --git a/src/main/java/dev/manere/utils/config/section/ConfigSelection.java b/src/main/java/dev/manere/utils/config/section/ConfigSelection.java index a8f360d..68d493b 100644 --- a/src/main/java/dev/manere/utils/config/section/ConfigSelection.java +++ b/src/main/java/dev/manere/utils/config/section/ConfigSelection.java @@ -2,7 +2,7 @@ import dev.manere.utils.config.ConfigKey; import dev.manere.utils.config.val.ConfigVal; -import dev.manere.utils.model.Duo; +import dev.manere.utils.model.Tuple; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; @@ -11,8 +11,7 @@ * Utility class for selecting and iterating over keys and values within a specific section of the plugin's configuration. */ public class ConfigSelection { - - private final ConfigSection section; + final ConfigSection section; /** * Constructs a ConfigSelection for the specified ConfigSection. @@ -38,10 +37,10 @@ public ConfigSelection(@NotNull ConfigSection section) { * * @param consumer The consumer to apply to each key-value pair. */ - public void forEach(@NotNull Consumer> consumer) { + public void forEach(@NotNull Consumer> consumer) { if (this.section.section != null) { for (String key : this.section.section.getKeys(false)) { - consumer.accept(new Duo<>(ConfigKey.key(key), ConfigKey.key(key).val())); + consumer.accept(Tuple.duo(ConfigKey.key(key), ConfigKey.key(key).val())); } } } diff --git a/src/main/java/dev/manere/utils/config/setter/ConfigSectionSetter.java b/src/main/java/dev/manere/utils/config/setter/ConfigSectionSetter.java index 038e0c7..cf45fb1 100644 --- a/src/main/java/dev/manere/utils/config/setter/ConfigSectionSetter.java +++ b/src/main/java/dev/manere/utils/config/setter/ConfigSectionSetter.java @@ -16,7 +16,6 @@ * Utility class for setting values in a specific section of the plugin's configuration. */ public class ConfigSectionSetter { - private final ConfigSection configSection; private Object val; private String key; diff --git a/src/main/java/dev/manere/utils/config/setter/ConfigSetter.java b/src/main/java/dev/manere/utils/config/setter/ConfigSetter.java index 701be5b..5162fec 100644 --- a/src/main/java/dev/manere/utils/config/setter/ConfigSetter.java +++ b/src/main/java/dev/manere/utils/config/setter/ConfigSetter.java @@ -16,7 +16,6 @@ * Utility class for setting values in the plugin's configuration. */ public class ConfigSetter { - private ConfigKey key; private Object val; private boolean defaultVal; diff --git a/src/main/java/dev/manere/utils/config/val/ConfigList.java b/src/main/java/dev/manere/utils/config/val/ConfigList.java index 6ecb094..3b64ed2 100644 --- a/src/main/java/dev/manere/utils/config/val/ConfigList.java +++ b/src/main/java/dev/manere/utils/config/val/ConfigList.java @@ -14,7 +14,6 @@ * Represents a list of values in the configuration associated with a specific ConfigVal. */ public record ConfigList(@NotNull ConfigVal val) { - /** * Creates a new ConfigList instance with the specified ConfigVal. * diff --git a/src/main/java/dev/manere/utils/config/val/ConfigVal.java b/src/main/java/dev/manere/utils/config/val/ConfigVal.java index 93db616..966d7dd 100644 --- a/src/main/java/dev/manere/utils/config/val/ConfigVal.java +++ b/src/main/java/dev/manere/utils/config/val/ConfigVal.java @@ -16,9 +16,9 @@ * Represents a value associated with a configuration key. */ public class ConfigVal { - public final ConfigKey key; - public final Object object; - public final String path; + private final ConfigKey key; + private final Object object; + final String path; /** * Constructs a ConfigVal with the specified ConfigKey. @@ -139,4 +139,8 @@ public boolean asBoolean() { public @Nullable ConfigList asListOf() { return ConfigList.list(this); } + + public ConfigKey key() { + return key; + } } diff --git a/src/main/java/dev/manere/utils/consumers/PairConsumer.java b/src/main/java/dev/manere/utils/consumers/PairConsumer.java new file mode 100644 index 0000000..deb0c29 --- /dev/null +++ b/src/main/java/dev/manere/utils/consumers/PairConsumer.java @@ -0,0 +1,18 @@ +package dev.manere.utils.consumers; + +/** + * The {@code PairConsumer} interface represents an entity capable of executing an operation + * that involves two parameters of different types. + * + * @param The type of the first parameter. + * @param The type of the second parameter. + */ +public interface PairConsumer { + /** + * Executes an operation with the given parameters. + * + * @param firstParam The first parameter of type A. + * @param secondParam The second parameter of type B. + */ + void execute(A firstParam, B secondParam); +} diff --git a/src/main/java/dev/manere/utils/consumers/TripleConsumer.java b/src/main/java/dev/manere/utils/consumers/TripleConsumer.java new file mode 100644 index 0000000..35b0620 --- /dev/null +++ b/src/main/java/dev/manere/utils/consumers/TripleConsumer.java @@ -0,0 +1,20 @@ +package dev.manere.utils.consumers; + +/** + * The {@code TripleConsumer} interface represents an entity capable of executing an operation + * that involves three parameters of different types. + * + * @param The type of the first parameter. + * @param The type of the second parameter. + * @param The type of the third parameter. + */ +public interface TripleConsumer { + /** + * Executes an operation with the given parameters. + * + * @param firstParam The first parameter of type A. + * @param secondParam The second parameter of type B. + * @param thirdParam The third parameter of type C. + */ + void execute(A firstParam, B secondParam, C thirdParam); +} diff --git a/src/main/java/dev/manere/utils/context/Context.java b/src/main/java/dev/manere/utils/context/Context.java new file mode 100644 index 0000000..409a6b4 --- /dev/null +++ b/src/main/java/dev/manere/utils/context/Context.java @@ -0,0 +1,36 @@ +package dev.manere.utils.context; + +import dev.manere.utils.command.impl.dispatcher.CommandContext; + +/** + * The {@code Context} interface represents a context associated with a specific type of source. + * It provides a method to retrieve the source associated with the context. + *

+ * A context should be a class to store multiple values and provide utility methods on them. + * An example is {@link CommandContext} which is a context class for commands. + * + * @param The type of the source associated with the context. + */ +public interface Context { + /** + * Retrieves the source associated with this context. + * + * @return The source associated with this context. + */ + S source(); + + /** + * The {@code Source} interface represents a wrapper for a specific type of source. + * It provides a method to unwrap and obtain the original source object. + * + * @param The type of the source object. + */ + interface Source { + /** + * Unwraps and obtains the original source object. + * + * @return The original source object. + */ + T unwrap(); + } +} diff --git a/src/main/java/dev/manere/utils/elo/ELO.java b/src/main/java/dev/manere/utils/elo/ELO.java index 0d442f6..8953233 100644 --- a/src/main/java/dev/manere/utils/elo/ELO.java +++ b/src/main/java/dev/manere/utils/elo/ELO.java @@ -8,7 +8,6 @@ * This class provides methods to calculate ELO ratings for two players after a match. */ public class ELO { - /** * Calculate the new ELO ratings for two players after a match. * diff --git a/src/main/java/dev/manere/utils/elo/Ratings.java b/src/main/java/dev/manere/utils/elo/Ratings.java index 3681eeb..cbb8c9e 100644 --- a/src/main/java/dev/manere/utils/elo/Ratings.java +++ b/src/main/java/dev/manere/utils/elo/Ratings.java @@ -27,7 +27,7 @@ public Ratings(int playerElo1, int playerElo2) { * @param playerElo1 The initial ELO rating of the first player. * @param playerElo2 The initial ELO rating of the second player. */ - public static Ratings ratings(int playerElo1, int playerElo2) { + public static Ratings of(int playerElo1, int playerElo2) { return new Ratings<>(playerElo1, playerElo2); } diff --git a/src/main/java/dev/manere/utils/elo/Winner.java b/src/main/java/dev/manere/utils/elo/Winner.java index 38c338d..50e842e 100644 --- a/src/main/java/dev/manere/utils/elo/Winner.java +++ b/src/main/java/dev/manere/utils/elo/Winner.java @@ -4,7 +4,6 @@ * An enumeration representing the winner of a match. */ public enum Winner { - /** * Represents that the first player (Player ONE) is the winner. */ @@ -13,5 +12,13 @@ public enum Winner { /** * Represents that the second player (Player TWO) is the winner. */ - TWO + TWO; + + public static Winner one() { + return Winner.ONE; + } + + public static Winner two() { + return Winner.TWO; + } } diff --git a/src/main/java/dev/manere/utils/event/builder/EventBuilder.java b/src/main/java/dev/manere/utils/event/builder/EventBuilder.java index 6c5c3a2..5add2ae 100644 --- a/src/main/java/dev/manere/utils/event/builder/EventBuilder.java +++ b/src/main/java/dev/manere/utils/event/builder/EventBuilder.java @@ -3,11 +3,11 @@ import dev.manere.utils.library.Utils; import org.bukkit.event.Event; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.util.Consumer; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; /** * The EventBuilder class is used to easily listen to events without @@ -16,9 +16,8 @@ * @param Any subclass of {@link Event} */ public class EventBuilder { - - public final List actionList; - public final Class eventType; + final List actionList; + final Class eventType; /** * Constructs a new EventBuilder with the specified event type. @@ -36,7 +35,7 @@ public class EventBuilder { * @param consumer The event consumer. * @return This EventBuilder instance, for chaining methods. */ - public @NotNull EventBuilder listener(@NotNull Consumer consumer) { + public @NotNull EventBuilder execute(@NotNull Consumer consumer) { actionList.add(consumer); return this; } @@ -80,4 +79,12 @@ public class EventBuilder { public @NotNull EventCallback register() { return build().register(Utils.plugin()); } + + public List actionList() { + return actionList; + } + + public Class eventType() { + return eventType; + } } diff --git a/src/main/java/dev/manere/utils/event/builder/EventCallback.java b/src/main/java/dev/manere/utils/event/builder/EventCallback.java index 24d09c3..9f8590b 100644 --- a/src/main/java/dev/manere/utils/event/builder/EventCallback.java +++ b/src/main/java/dev/manere/utils/event/builder/EventCallback.java @@ -22,12 +22,12 @@ public class EventCallback implements EventExecutor, Listener { public static final HandlerListCache HANDLER_LIST_CACHE = new HandlerListCache(); - public final Class eventType; - public final EventPriority eventPriority; - public final boolean ignoredCancelled; - public final Object[] handlerArray; - public final AtomicBoolean isRegistered; - public final JavaPlugin plugin; + private final Class eventType; + private final EventPriority eventPriority; + private final boolean ignoredCancelled; + private final Object[] handlerArray; + private final AtomicBoolean isRegistered; + private final JavaPlugin plugin; /** * Constructs an EventCallback. diff --git a/src/main/java/dev/manere/utils/event/builder/EventHandler.java b/src/main/java/dev/manere/utils/event/builder/EventHandler.java index 66315d0..d315fc8 100644 --- a/src/main/java/dev/manere/utils/event/builder/EventHandler.java +++ b/src/main/java/dev/manere/utils/event/builder/EventHandler.java @@ -15,10 +15,10 @@ * @param The type of event to handle. */ public class EventHandler { - public final List actionList; - public final Class eventType; - public EventPriority eventPriority; - public boolean ignoreCancelled; + final List actionList; + final Class eventType; + EventPriority eventPriority; + boolean ignoreCancelled; /** * Constructs an EventHandler with the specified EventBuilder. @@ -71,8 +71,27 @@ public class EventHandler { * @param eventPriority The EventPriority to set. * @return The modified EventHandler instance. */ - public @NotNull EventHandler eventPriority(@NotNull EventPriority eventPriority) { + public @NotNull EventHandler priority(@NotNull EventPriority eventPriority) { this.eventPriority = eventPriority; return this; } + + /** + * Sets the priority of the event. + * + * @param eventPriority The EventPriority identified via an integer to set. + * @return The modified EventHandler instance. + */ + public @NotNull EventHandler priority(int eventPriority) { + return switch (eventPriority) { + case 1000, 100, 10, 1 -> priority(EventPriority.MONITOR); + case 2000, 200, 20, 2 -> priority(EventPriority.HIGHEST); + case 3000, 300, 30, 3 -> priority(EventPriority.HIGH); + case 4000, 400, 40, 4 -> priority(EventPriority.NORMAL); + case 5000, 500, 50, 5 -> priority(EventPriority.LOW); + case 6000, 600, 60, 6 -> priority(EventPriority.LOWEST); + + default -> this; + }; + } } diff --git a/src/main/java/dev/manere/utils/event/crystal/PlayerAnchorDeathEvent.java b/src/main/java/dev/manere/utils/event/crystal/PlayerAnchorDeathEvent.java new file mode 100644 index 0000000..0077ea4 --- /dev/null +++ b/src/main/java/dev/manere/utils/event/crystal/PlayerAnchorDeathEvent.java @@ -0,0 +1,125 @@ +package dev.manere.utils.event.crystal; + +import org.bukkit.block.BlockState; +import org.bukkit.block.data.type.RespawnAnchor; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents an event triggered when a player dies from a detonated Respawn Anchor. + * This event provides information about the block of the Respawn Anchor, + * the victim player, the attacking player (the player who detonated the anchor), + * and the Respawn Anchor block itself (if the block is a Respawn Anchor). + */ +public class PlayerAnchorDeathEvent extends Event { + private static final HandlerList HANDLERS = new HandlerList(); + private final @NotNull BlockState block; + private final @NotNull Player victim; + private final @NotNull Player attacker; + private final @Nullable RespawnAnchor anchor; + + /** + * Constructs a new instance of the PlayerAnchorDeathEvent. + * + * @param block The block of the Respawn Anchor. + * @param victim The player who died near the Respawn Anchor. + * @param attacker The player who detonated the anchor. Shouldn't be nullable, but can be. + */ + public PlayerAnchorDeathEvent(@NotNull BlockState block, @NotNull Player victim, @NotNull Player attacker) { + this.block = block; + this.victim = victim; + this.attacker = attacker; + + if (this.block instanceof RespawnAnchor respawnAnchor) { + this.anchor = respawnAnchor; + } else { + this.anchor = null; + } + } + + /** + * Gets the HandlerList for this event. + * + * @return The HandlerList for this event. + */ + public static HandlerList getHandlerList() { + return HANDLERS; + } + + /** + * Gets the HandlerList for this event. + * + * @return The HandlerList for this event. + */ + @Override + public @NotNull HandlerList getHandlers() { + return HANDLERS; + } + + /** + * Gets the HandlerList for this event. + * + * @return The HandlerList for this event. + */ + public @NotNull HandlerList handlers() { + return getHandlers(); + } + + /** + * Gets the name of this event. + * + * @return The name of this event. + */ + @Override + public @NotNull String getEventName() { + return "PlayerAnchorDeathEvent"; + } + + /** + * Gets the name of this event. + * + * @return The name of this event. + */ + public @NotNull String eventName() { + return getEventName(); + } + + /** + * Gets the block of the Respawn Anchor involved in this event. + * + * @return The Respawn Anchor block. + */ + public @NotNull BlockState block() { + return block; + } + + /** + * Gets the player who died near the Respawn Anchor. + * + * @return The victim player. + */ + public @NotNull Player victim() { + return victim; + } + + /** + * Gets the player who attacked, if any. + * + * @return The attacking player, or null if the death was not caused by a player. + */ + public @NotNull Player attacker() { + return attacker; + } + + /** + * Gets the Respawn Anchor block, if the block is a Respawn Anchor. + * + * @return The Respawn Anchor block, or null if the block is not a Respawn Anchor. + */ + public @Nullable RespawnAnchor anchor() { + return anchor; + } +} diff --git a/src/main/java/dev/manere/utils/event/crystal/PlayerDeathByPlayerWithCrystalEvent.java b/src/main/java/dev/manere/utils/event/crystal/PlayerCrystalDeathEvent.java similarity index 92% rename from src/main/java/dev/manere/utils/event/crystal/PlayerDeathByPlayerWithCrystalEvent.java rename to src/main/java/dev/manere/utils/event/crystal/PlayerCrystalDeathEvent.java index c7f5c83..34b46d4 100644 --- a/src/main/java/dev/manere/utils/event/crystal/PlayerDeathByPlayerWithCrystalEvent.java +++ b/src/main/java/dev/manere/utils/event/crystal/PlayerCrystalDeathEvent.java @@ -13,10 +13,10 @@ import java.util.List; /** - * The {@code PlayerDeathByPlayerWithCrystalEvent} class represents an event that occurs when a player is killed by another player using an end crystal. + * The {@code PlayerCrystalDeathEvent} class represents an event that occurs when a player is killed by another player using an end crystal. * This event extends the Bukkit {@link Event} class and provides information about the involved players, the end crystal used, and the damage dealt. */ -public class PlayerDeathByPlayerWithCrystalEvent extends Event { +public class PlayerCrystalDeathEvent extends Event { private static final HandlerList HANDLERS = new HandlerList(); private final Player killer; private final Player victim; @@ -25,7 +25,7 @@ public class PlayerDeathByPlayerWithCrystalEvent extends Event { private final PlayerDeathEvent playerDeathEvent; /** - * Constructs a new {@code PlayerDeathByPlayerWithCrystalEvent}. + * Constructs a new {@code PlayerCrystalDeathEvent}. * * @param killer The player who initiated the kill. * @param victim The player who was killed. @@ -33,7 +33,7 @@ public class PlayerDeathByPlayerWithCrystalEvent extends Event { * @param playerDamageEvent The {@link EntityDamageByEntityEvent} associated with the kill. * @param playerDeathEvent The {@link PlayerDeathEvent} associated with the kill. */ - public PlayerDeathByPlayerWithCrystalEvent( + public PlayerCrystalDeathEvent( Player killer, Player victim, Entity crystal, @@ -48,11 +48,11 @@ public PlayerDeathByPlayerWithCrystalEvent( } /** - * Returns the list of event handlers for this event type. + * Returns the event handlers for this event type. * - * @return The list of event handlers. + * @return The event handlers. */ - public static HandlerList handlerList() { + public static HandlerList getHandlerList() { return HANDLERS; } @@ -66,6 +66,11 @@ public static HandlerList handlerList() { return HANDLERS; } + /** + * Returns the event handlers for this event type. + * + * @return The event handlers. + */ public @NotNull HandlerList handlers() { return getHandlers(); } @@ -75,7 +80,7 @@ public static HandlerList handlerList() { */ @Override public @NotNull String getEventName() { - return "PlayerDeathByPlayerWithCrystalEvent"; + return "PlayerCrystalDeathEvent"; } public @NotNull String eventName() { diff --git a/src/main/java/dev/manere/utils/event/crystal/impl/SpigotAnchorEventListener.java b/src/main/java/dev/manere/utils/event/crystal/impl/SpigotAnchorEventListener.java new file mode 100644 index 0000000..b62043e --- /dev/null +++ b/src/main/java/dev/manere/utils/event/crystal/impl/SpigotAnchorEventListener.java @@ -0,0 +1,75 @@ +package dev.manere.utils.event.crystal.impl; + +import dev.manere.utils.event.crystal.PlayerAnchorDeathEvent; +import dev.manere.utils.library.Utils; +import dev.manere.utils.player.PlayerUtils; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.type.RespawnAnchor; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByBlockEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class SpigotAnchorEventListener implements Listener { + private static final Map DETONATOR_MAP = new HashMap<>(); + + @EventHandler + public void onInteract(PlayerInteractEvent event) { + if (event.getClickedBlock() == null || !event.hasBlock() || event.getMaterial() != Material.RESPAWN_ANCHOR) return; + if (!(event.getClickedBlock().getBlockData() instanceof RespawnAnchor anchorBlock)) return; + + ItemStack itemHand = event.getItem() == null + ? new ItemStack(Material.AIR) + : event.getItem(); + + if (!(anchorBlock.getCharges() <= 3)) return; + if (itemHand.getType() == Material.GLOWSTONE && anchorBlock.getCharges() != 0) return; + + DETONATOR_MAP.put(event.getClickedBlock().getLocation(), event.getPlayer().getUniqueId()); + } + + @EventHandler + public void onAnchorDamage(EntityDamageByBlockEvent event) { + if (event.getCause() != EntityDamageEvent.DamageCause.BLOCK_EXPLOSION) return; + if (!(event.getEntity() instanceof Player victim) || event.getEntityType() != EntityType.PLAYER) return; + if (victim.getHealth() > event.getDamage()) return; + + if (victim.getInventory().getItemInMainHand().getType() == Material.TOTEM_OF_UNDYING) return; + if (victim.getInventory().getItemInOffHand().getType() == Material.TOTEM_OF_UNDYING) return; + + if (event.getDamagerBlockState() == null || event.getDamagerBlockState().getType() != Material.RESPAWN_ANCHOR) return; + + if (victim.getInventory().getItemInMainHand().getType() == Material.TOTEM_OF_UNDYING) return; + if (victim.getInventory().getItemInOffHand().getType() == Material.TOTEM_OF_UNDYING) return; + + UUID detonator = DETONATOR_MAP.get(new Location( + victim.getWorld(), + event.getDamagerBlockState().getX(), + event.getDamagerBlockState().getY(), + event.getDamagerBlockState().getZ()) + ); + + if (detonator == null) return; + + Player playerDetonator = PlayerUtils.player(detonator); + + if (playerDetonator == null) return; + + PlayerAnchorDeathEvent calledEvent = new PlayerAnchorDeathEvent( + event.getDamagerBlockState(), victim, playerDetonator + ); + + Utils.plugin().getServer().getPluginManager().callEvent(calledEvent); + + DETONATOR_MAP.remove(event.getDamagerBlockState().getLocation()); + } +} \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/event/crystal/SpigotEventListener.java b/src/main/java/dev/manere/utils/event/crystal/impl/SpigotCrystalEventListener.java similarity index 66% rename from src/main/java/dev/manere/utils/event/crystal/SpigotEventListener.java rename to src/main/java/dev/manere/utils/event/crystal/impl/SpigotCrystalEventListener.java index 33935b3..c20aa7e 100644 --- a/src/main/java/dev/manere/utils/event/crystal/SpigotEventListener.java +++ b/src/main/java/dev/manere/utils/event/crystal/impl/SpigotCrystalEventListener.java @@ -1,5 +1,6 @@ -package dev.manere.utils.event.crystal; +package dev.manere.utils.event.crystal.impl; +import dev.manere.utils.event.crystal.PlayerCrystalDeathEvent; import dev.manere.utils.library.Utils; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -9,18 +10,12 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.PlayerDeathEvent; -/** - * This class implements a Spigot event listener for various events related to player damage and death involving crystals. - */ -public class SpigotEventListener implements Listener { +public class SpigotCrystalEventListener implements Listener { private Entity crystal; private Player victim; private Player killer; private EntityDamageByEntityEvent playerDamageEvent; - /** - * Resets temporary data related to the events. - */ private void reset() { this.crystal = null; this.victim = null; @@ -28,11 +23,6 @@ private void reset() { this.playerDamageEvent = null; } - /** - * Listens for the crystal explosion event to determine the killer. - * - * @param event The EntityDamageByEntityEvent representing the crystal explosion event. - */ @EventHandler public void onCrystalExplode(EntityDamageByEntityEvent event) { if (event.getEntityType() != EntityType.ENDER_CRYSTAL) return; @@ -44,11 +34,6 @@ public void onCrystalExplode(EntityDamageByEntityEvent event) { this.killer = (Player) event.getDamager(); } - /** - * Listens for player damage events by crystals to determine the victim. - * - * @param event The EntityDamageByEntityEvent representing the player damage event. - */ @EventHandler public void onPlayerDamage(EntityDamageByEntityEvent event) { if (event.getEntityType() != EntityType.PLAYER) return; @@ -67,11 +52,6 @@ public void onPlayerDamage(EntityDamageByEntityEvent event) { this.playerDamageEvent = event; } - /** - * Listens for player death events to create a custom event for a player death involving a crystal. - * - * @param event The PlayerDeathEvent representing the player's death. - */ @EventHandler public void onPlayerDeath(PlayerDeathEvent event) { if (this.crystal == null || this.killer == null || victim == null || playerDamageEvent == null) { @@ -82,7 +62,7 @@ public void onPlayerDeath(PlayerDeathEvent event) { return; } - PlayerDeathByPlayerWithCrystalEvent calledEvent = new PlayerDeathByPlayerWithCrystalEvent( + PlayerCrystalDeathEvent calledEvent = new PlayerCrystalDeathEvent( this.killer, this.victim, this.crystal, this.playerDamageEvent, event ); diff --git a/src/main/java/dev/manere/utils/item/ItemBuilder.java b/src/main/java/dev/manere/utils/item/ItemBuilder.java index 8d3c101..0ba7a42 100644 --- a/src/main/java/dev/manere/utils/item/ItemBuilder.java +++ b/src/main/java/dev/manere/utils/item/ItemBuilder.java @@ -1,8 +1,11 @@ package dev.manere.utils.item; import dev.manere.utils.library.Utils; +import dev.manere.utils.misc.Storable; import dev.manere.utils.player.PlayerUtils; import dev.manere.utils.scheduler.Schedulers; +import dev.manere.utils.serializers.Serializers; +import dev.manere.utils.text.color.TextStyle; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.Color; @@ -15,17 +18,19 @@ import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.*; +import org.bukkit.persistence.PersistentDataContainer; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; +import java.util.function.Consumer; /** * Utility class for building customized {@link ItemStack}s. * Provides methods for setting display name, lore, enchantments, etc. */ -public class ItemBuilder { +public class ItemBuilder implements Storable { private final ItemStack itemStack; /** @@ -116,6 +121,10 @@ public ItemBuilder name(Component name) { return this; } + public ItemBuilder name(String name) { + return name(TextStyle.style(name)); + } + /** * Sets the display name of the ItemStack without automatically colorizing it. * @@ -166,7 +175,7 @@ public ItemBuilder skullOwner(String playerName){ SkullMeta itemMeta = (SkullMeta) itemStack.getItemMeta(); if (itemMeta != null) { - Schedulers.async().now(() -> itemMeta.setOwnerProfile(Bukkit.getOfflinePlayer(UUID.fromString(playerName)).getPlayerProfile())); + Schedulers.async().execute(() -> itemMeta.setOwnerProfile(Bukkit.getOfflinePlayer(UUID.fromString(playerName)).getPlayerProfile())); } itemStack.setItemMeta(itemMeta); @@ -184,7 +193,7 @@ public ItemBuilder skullOwner(Player player) { SkullMeta itemMeta = (SkullMeta) itemStack.getItemMeta(); if (itemMeta != null) { - Schedulers.async().now(() -> itemMeta.setOwnerProfile(player.getPlayerProfile())); + Schedulers.async().execute(() -> itemMeta.setOwnerProfile(player.getPlayerProfile())); } itemStack.setItemMeta(itemMeta); @@ -299,12 +308,12 @@ public ItemBuilder amount(int amount) { /** * Sets the durability of the ItemStack. * - * @param durability The durability to set + * @param damage The durability to set * @return This builder, for chaining */ - public ItemBuilder durability(int durability) { + public ItemBuilder durability(int damage) { if (itemStack.getItemMeta() instanceof Damageable damageable) { - damageable.setDamage(durability); + damageable.setDamage(damage); itemStack.setItemMeta(damageable); } else { throw new IllegalArgumentException("ItemMeta is required to be an instance of Damageable to set the durability!"); @@ -365,6 +374,7 @@ public ItemBuilder glow() { */ public ItemBuilder removeGlow() { removeEnchantment(Enchantment.LUCK); + removeFlag(ItemFlag.HIDE_ENCHANTS); return this; } @@ -384,6 +394,22 @@ public ItemBuilder unbreakable() { return this; } + /** + * Sets the ItemStack to be breakable. + * + * @return This builder, for chaining + */ + public ItemBuilder breakable() { + ItemMeta meta = itemStack.getItemMeta(); + + if (meta != null) { + meta.setUnbreakable(false); + } + + itemStack.setItemMeta(meta); + return this; + } + /** * Sets the custom model data of the ItemStack. * @@ -421,6 +447,48 @@ public ItemMeta meta() { return itemStack.getItemMeta(); } + /** + * Gets the {@link PersistentDataContainer} of the ItemStack. + * + * @return The PersistentDataContainer + */ + public PersistentDataContainer pdc() { + return itemStack.getItemMeta().getPersistentDataContainer(); + } + + /** + * Edits the ItemMeta of the ItemStack using the provided consumer. + * + * @param metaConsumer The consumer to apply modifications to the ItemMeta + * @return This builder, for chaining + */ + public ItemBuilder editMeta(Consumer metaConsumer) { + itemStack.editMeta(metaConsumer); + return this; + } + + /** + * Edits the ItemStack using the provided consumer. + * + * @param stackConsumer The consumer to apply modifications to the ItemStack + * @return This builder, for chaining + */ + public ItemBuilder editStack(Consumer stackConsumer) { + stackConsumer.accept(itemStack); + return this; + } + + /** + * Edits the PersistentDataContainer of the ItemStack using the provided consumer. + * + * @param pdcConsumer The consumer to apply modifications to the PersistentDataContainer + * @return This builder, for chaining + */ + public ItemBuilder editPdc(Consumer pdcConsumer) { + pdcConsumer.accept(itemStack.getItemMeta().getPersistentDataContainer()); + return this; + } + /** * Creates an ItemBuilder from an existing {@link ItemStack}. * @@ -431,16 +499,34 @@ public ItemBuilder from(ItemStack itemStack) { return new ItemBuilder(itemStack); } + /** + * Sets the book-related data for the ItemStack. + * + * @param bookMeta The BookMeta containing book-related data + * @return This builder, for chaining + */ public ItemBuilder bookData(BookMeta bookMeta) { itemStack.setItemMeta(bookMeta); return this; } + /** + * Sets the banner-related data for the ItemStack. + * + * @param bannerMeta The BannerMeta containing banner-related data + * @return This builder, for chaining + */ public ItemBuilder bannerData(BannerMeta bannerMeta) { itemStack.setItemMeta(bannerMeta); return this; } + /** + * Sets the color of the leather armor ItemStack. + * + * @param color The color to set for the leather armor + * @return This builder, for chaining + */ public ItemBuilder leatherArmorColor(Color color) { LeatherArmorMeta meta = (LeatherArmorMeta) itemStack.getItemMeta(); @@ -450,12 +536,25 @@ public ItemBuilder leatherArmorColor(Color color) { return this; } + /** + * Sets the firework-related data for the ItemStack. + * + * @param meta The FireworkMeta containing firework-related data + * @return This builder, for chaining + */ public ItemBuilder fireworkData(FireworkMeta meta) { itemStack.setItemMeta(meta); return this; } - public ItemBuilder addItemAttribute(Attribute attribute, AttributeModifier modifier) { + /** + * Adds an attribute to the ItemStack. + * + * @param attribute The attribute to add + * @param modifier The attribute modifier to apply + * @return This builder, for chaining + */ + public ItemBuilder addAttribute(Attribute attribute, AttributeModifier modifier) { ItemMeta meta = itemStack.getItemMeta(); if (meta != null) meta.addAttributeModifier(attribute, modifier); @@ -464,7 +563,12 @@ public ItemBuilder addItemAttribute(Attribute attribute, AttributeModifier modif return this; } - public ItemBuilder clearItemAttributes() { + /** + * Clears all attribute modifiers from the ItemStack. + * + * @return This builder, for chaining + */ + public ItemBuilder clearAttributes() { ItemMeta meta = itemStack.getItemMeta(); if (meta != null) Objects.requireNonNull(meta.getAttributeModifiers()) @@ -474,6 +578,11 @@ public ItemBuilder clearItemAttributes() { return this; } + /** + * Hides attributes from being displayed on the ItemStack. + * + * @return This builder, for chaining + */ public ItemBuilder hideAttributes() { ItemMeta meta = itemStack.getItemMeta(); @@ -490,7 +599,23 @@ public ItemBuilder hideAttributes() { * * @return The built ItemStack */ - public ItemStack build(){ + public ItemStack build() { return itemStack; } + + /** + * {@inheritDoc} + */ + @Override + public String serialize() { + return Serializers.base64().serializeItemBuilder(this); + } + + /** + * {@inheritDoc} + */ + @Override + public ItemBuilder deserialize(String serialized) { + return ItemBuilder.item(Serializers.base64().deserialize(serialized)); + } } \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/item/PotionBuilder.java b/src/main/java/dev/manere/utils/item/PotionBuilder.java index 7fefefd..9f05183 100644 --- a/src/main/java/dev/manere/utils/item/PotionBuilder.java +++ b/src/main/java/dev/manere/utils/item/PotionBuilder.java @@ -11,7 +11,6 @@ * A utility class for building custom potion items with different potion effects. */ public class PotionBuilder { - private final ItemStack item; private final PotionMeta potionMeta; @@ -30,10 +29,21 @@ public PotionBuilder(ItemStack item) { this.potionMeta = (PotionMeta) item.getItemMeta(); } + /** + * Constructs a PotionBuilder using an existing ItemStack. + * + * @param item The ItemStack to be used as a base for the potion. + * @throws IllegalArgumentException If the provided item's ItemMeta is not an instance of PotionMeta. + */ public static PotionBuilder potion(ItemStack item) { return new PotionBuilder(item); } + /** + * Constructs a PotionBuilder using a specified material for the potion item. + * + * @param material The material to be used for the potion. + */ public static PotionBuilder potion(Material material) { return potion(new ItemStack(material)); } diff --git a/src/main/java/dev/manere/utils/library/Utils.java b/src/main/java/dev/manere/utils/library/Utils.java index c5c65ef..ab89711 100644 --- a/src/main/java/dev/manere/utils/library/Utils.java +++ b/src/main/java/dev/manere/utils/library/Utils.java @@ -1,8 +1,10 @@ package dev.manere.utils.library; +import com.jeff_media.customblockdata.CustomBlockData; import dev.manere.utils.command.annotation.AutoRegisterHandler; -import dev.manere.utils.event.crystal.SpigotEventListener; -import dev.manere.utils.menu.MenuListener; +import dev.manere.utils.event.crystal.impl.SpigotAnchorEventListener; +import dev.manere.utils.event.crystal.impl.SpigotCrystalEventListener; +import dev.manere.utils.menu.listener.MenuListener; import dev.manere.utils.registration.Registrar; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @@ -11,7 +13,6 @@ * The {@code Utils} class provides utility methods and event registration for the Utils library. */ public class Utils { - public static JavaPlugin plugin; /** @@ -22,7 +23,10 @@ public class Utils { private Utils(@NotNull JavaPlugin plugin) { Utils.plugin = plugin; - Registrar.events(new SpigotEventListener()); + CustomBlockData.registerListener(plugin); + + Registrar.events(new SpigotAnchorEventListener()); + Registrar.events(new SpigotCrystalEventListener()); Registrar.events(new MenuListener()); AutoRegisterHandler.scanAndRegister(); diff --git a/src/main/java/dev/manere/utils/library/event/PluginEvents.java b/src/main/java/dev/manere/utils/library/event/PluginEvents.java new file mode 100644 index 0000000..e0d9228 --- /dev/null +++ b/src/main/java/dev/manere/utils/library/event/PluginEvents.java @@ -0,0 +1,98 @@ +package dev.manere.utils.library.event; + +import dev.manere.utils.event.builder.EventBuilder; +import dev.manere.utils.event.builder.EventCallback; +import dev.manere.utils.event.builder.EventHandler; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +/** + * Utility class for simplified event handling in Bukkit plugins. + */ +public class PluginEvents { + /** + * Registers an event with a callback to be executed on event occurrence with normal priority. + * + * @param The type of the event. + * @param eventClazz The class object representing the event. + * @param consumer The callback to be executed when the event occurs. + */ + public void register(@NotNull Class eventClazz, @NotNull Consumer consumer) { + register(eventClazz, consumer, EventPriority.NORMAL); + } + + /** + * Registers an event with a callback to be executed on event occurrence with the specified priority. + * + * @param The type of the event. + * @param eventClazz The class object representing the event. + * @param consumer The callback to be executed when the event occurs. + * @param priority The priority of the event registration. + */ + public void register( + @NotNull Class eventClazz, @NotNull Consumer consumer, @NotNull EventPriority priority + ) { + register(eventClazz, consumer, priority, false); + } + + /** + * Registers an event with a callback and additional settings. + * + * @param The type of the event. + * @param eventClazz The class object representing the event. + * @param consumer The callback to be executed when the event occurs. + * @param priority The priority of the event registration. + * @param ignoreCancelled Whether to ignore cancelled events. + */ + public void register( + @NotNull Class eventClazz, @NotNull Consumer consumer, @NotNull EventPriority priority, boolean ignoreCancelled + ) { + EventBuilder.event(eventClazz) + .execute(consumer) + .build() + .ignoreCancelled(ignoreCancelled) + .priority(priority) + .register(); + } + + /** + * Unregisters all event listeners associated with the provided listener. + * + * @param listener The listener to unregister. + */ + public void unregister(@NotNull Listener listener) { + HandlerList.unregisterAll(listener); + } + + /** + * Unregisters all event listeners associated with the provided EventBuilder. + * + * @param eventBuilder The EventBuilder whose listeners should be unregistered. + */ + public void unregister(@NotNull EventBuilder eventBuilder) { + HandlerList.unregisterAll(eventBuilder.build().register()); + } + + /** + * Unregisters all event listeners associated with the provided EventHandler. + * + * @param eventHandler The EventHandler whose listeners should be unregistered. + */ + public void unregister(@NotNull EventHandler eventHandler) { + HandlerList.unregisterAll(eventHandler.register()); + } + + /** + * Unregisters all event listeners associated with the provided EventCallback. + * + * @param eventCallback The EventCallback whose listeners should be unregistered. + */ + public void unregister(@NotNull EventCallback eventCallback) { + HandlerList.unregisterAll(eventCallback); + } +} diff --git a/src/main/java/dev/manere/utils/library/wrapper/PluginWrapper.java b/src/main/java/dev/manere/utils/library/wrapper/PluginWrapper.java new file mode 100644 index 0000000..817ae96 --- /dev/null +++ b/src/main/java/dev/manere/utils/library/wrapper/PluginWrapper.java @@ -0,0 +1,250 @@ +package dev.manere.utils.library.wrapper; + +import dev.manere.utils.command.CommandTypes; +import dev.manere.utils.command.impl.Commands; +import dev.manere.utils.library.Utils; +import dev.manere.utils.library.event.PluginEvents; +import dev.manere.utils.resource.ResourceFile; +import dev.manere.utils.resource.ResourceOptions; +import dev.manere.utils.resource.format.ResourceFormat; +import dev.manere.utils.resource.format.ResourceFormats; +import dev.manere.utils.resource.path.ResourcePath; +import dev.manere.utils.resource.path.ResourcePaths; +import org.bukkit.Server; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.ServerLoadEvent; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; +import java.util.logging.Level; + +/** + * An abstract base class for Paper/Bukkit/Spigot plugins providing common functionality and structure. + * Extends {@link JavaPlugin} and implements {@link Listener}. + *

+ * This class is intended to be used as a replacement for having to run {@link Utils#init(JavaPlugin)} in your onEnable() method of JavaPlugin. + * It does that for you. + *

+ * Here's the order of the abstract method calling (load(), start(), stop()): + *

+ * 1. load() -> 2. start() -> 3. stop() + *

+ * 1. Called when initializing the plugin (before enabling the plugin), before start(). + * You should avoid calling unsafe methods. + *

+ * 2. Called when your plugin gets enabled. + * Everything should be safe to execute. + *

+ * 3. Called when your plugin is disabling. + * Do not run any asynchronous methods. + * + * @see Utils + * @see JavaPlugin + */ +public abstract class PluginWrapper extends JavaPlugin implements Listener { + private boolean isReloading = false; + + /** + * Called when initializing the plugin (before enabling the plugin), before start(). + * You should avoid calling unsafe methods. + */ + protected void load() {} + + /** + * Called when your plugin gets enabled. + * Everything should be safe to execute. + */ + protected abstract void start(); + + /** + * Called when your plugin is disabling. + * Do not run any asynchronous methods. + */ + protected void stop() {} + + /** + * Event handler for server load events. Sets {@code isReloading} to true if the load type is RELOAD. + * + * @param event The ServerLoadEvent + */ + @EventHandler + public final void onServerLoadEvent(ServerLoadEvent event) { + if (event.getType() == ServerLoadEvent.LoadType.RELOAD) { + isReloading = true; + } + } + + @Override + public final void onLoad() { + getServer().getPluginManager().registerEvents(this, this); + + this.load(); + } + + @Override + public final void onDisable() { + Utils.init(this); + + this.stop(); + } + + @Override + public final void onEnable() { + this.start(); + this.isReloading = false; + } + + /** + * Logs a message with the specified priority level. + * + * @param priority The priority level + * @param text The log message + * @throws IllegalArgumentException if an invalid priority integer is provided + */ + public final void log(int priority, @NotNull String text) { + if (priority >= 0 && priority < 300) { + getLogger().log(Level.FINEST, text); + } else if (priority >= 300 && priority < 400) { + getLogger().log(Level.FINER, text); + } else if (priority >= 400 && priority < 500) { + getLogger().log(Level.FINE, text); + } else if (priority >= 500 && priority < 700) { + getLogger().log(Level.CONFIG, text); + } else if (priority >= 700 && priority < 800) { + getLogger().log(Level.INFO, text); + } else if (priority >= 800 && priority < 900) { + getLogger().log(Level.WARNING, text); + } else if (priority >= 900 && priority < 1000) { + getLogger().log(Level.SEVERE, text); + } else { + throw new IllegalArgumentException( + "Invalid priority integer: " + priority + ". Refer to the integer values of java.util.logging.Level" + ); + } + } + + /** + * Logs a message with the specified log level. + * + * @param level The log level + * @param text The log message + */ + public final void log(@NotNull Level level, @NotNull String text) { + getLogger().log(level, text); + } + + /** + * Creates a {@link ResourceFile} with the specified name, specified format, specified path, and specified options. + * + * @param name The name of the resource file + * @param format The format of the resource file + * @param path The path of the resource file + * @param options The resource file options + * @return The created ResourceFile + */ + public final @NotNull ResourceFile resource(String name, ResourceFormat format, ResourcePath path, Consumer options) { + return ResourceFile.builder() + .name(name) + .format(format) + .path(path) + .options(options) + .build(); + } + + /** + * Creates a {@link ResourceFile} with the specified name, default format, specified path, and specified options. + * + * @param name The name of the resource file + * @param path The path of the resource file + * @param options The resource file options + * @return The created ResourceFile + */ + public final @NotNull ResourceFile resource(String name, ResourcePath path, Consumer options) { + return resource(name, ResourceFormats.yaml(), path, options); + } + + /** + * Creates a {@link ResourceFile} with the specified name, default format, specified path, and default options. + * + * @param name The name of the resource file + * @param path The path of the resource file + * @return The created ResourceFile + */ + public final @NotNull ResourceFile resource(String name, ResourcePath path) { + return resource(name, ResourceFormats.yaml(), path, options -> {}); + } + + /** + * Creates a {@link ResourceFile} with the specified name, default format, default path, and default options. + * + * @param name The name of the resource file + * @return The created ResourceFile + */ + public final @NotNull ResourceFile resource(String name) { + return resource(name, ResourceFormats.yaml(), ResourcePaths.plugin(), options -> {}); + } + + /** + * Create a new Commands with the specified name and default (PLUGIN_YML) type. + * + * @param name The name of the command. + * @return A new Commands instance. + */ + public final @NotNull Commands command(String name) { + return Commands.command(name); + } + + /** + * Create a new Commands with the specified name and type. + * + * @param name The name of the command. + * @param type The type of the command. + * @return A new Commands instance. + */ + public final @NotNull Commands command(String name, CommandTypes type) { + return Commands.command(name, type); + } + + /** + * Returns the Server instance currently running this plugin + * @return Server running this plugin. + */ + public final @NotNull Server server() { + return this.getServer(); + } + + /** + * Executes a runnable if a player is reloading via the command {@code /bukkit:reload} + * @param toRunIfTrue The runnable to execute + */ + public final void ifReloadingRun(@NotNull Runnable toRunIfTrue) { + if (this.isReloading) toRunIfTrue.run(); + } + + /** + * Disables this plugin. + */ + public final void disable() { + plugins().disablePlugin(this); + } + + /** + * Gets the plugin manager for interfacing with plugins. + * @return a plugin manager for this Server instance + */ + public final @NotNull PluginManager plugins() { + return server().getPluginManager(); + } + + /** + * Gets the event handler of this plugin. + * @return the event handler of this plugin. + */ + public final @NotNull PluginEvents events() { + return new PluginEvents(); + } +} + diff --git a/src/main/java/dev/manere/utils/location/LocationUtils.java b/src/main/java/dev/manere/utils/location/LocationUtils.java index 05e6f0a..6720af7 100644 --- a/src/main/java/dev/manere/utils/location/LocationUtils.java +++ b/src/main/java/dev/manere/utils/location/LocationUtils.java @@ -16,7 +16,6 @@ * Utility class for performing operations and checks related to locations and coordinates. */ public class LocationUtils { - /** * Checks if a given integer value is between two other integer values. * diff --git a/src/main/java/dev/manere/utils/logger/AdventureLogger.java b/src/main/java/dev/manere/utils/logger/AdventureLogger.java index f587bdf..c1cb06e 100644 --- a/src/main/java/dev/manere/utils/logger/AdventureLogger.java +++ b/src/main/java/dev/manere/utils/logger/AdventureLogger.java @@ -9,7 +9,6 @@ * in Bukkit plugins using Kyori Adventure's component logger. */ public class AdventureLogger { - private static final ComponentLogger LOGGER = Utils.plugin().getComponentLogger(); /** diff --git a/src/main/java/dev/manere/utils/logger/Loggers.java b/src/main/java/dev/manere/utils/logger/Loggers.java index d5ed08a..762deb0 100644 --- a/src/main/java/dev/manere/utils/logger/Loggers.java +++ b/src/main/java/dev/manere/utils/logger/Loggers.java @@ -3,6 +3,9 @@ import dev.manere.utils.library.Utils; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import org.slf4j.LoggerFactory; + import java.util.logging.Logger; /** @@ -10,7 +13,6 @@ * in a Bukkit plugin, including Adventure loggers and prefixed loggers. */ public class Loggers { - /** * Returns an AdventureLogger instance for logging messages with Adventure components. * @@ -86,4 +88,14 @@ public static Logger server(JavaPlugin plugin) { public static Logger server(Plugin plugin) { return plugin.getServer().getLogger(); } + + /** + * Returns the class logger associated with the provided class. + * + * @param clazz The class. + * @return The class logger. + */ + public static org.slf4j.Logger logger(@NotNull Class clazz) { + return LoggerFactory.getLogger(clazz); + } } diff --git a/src/main/java/dev/manere/utils/menu/MenuBase.java b/src/main/java/dev/manere/utils/menu/MenuBase.java index 0e1a134..45eeba4 100644 --- a/src/main/java/dev/manere/utils/menu/MenuBase.java +++ b/src/main/java/dev/manere/utils/menu/MenuBase.java @@ -1,6 +1,8 @@ package dev.manere.utils.menu; import dev.manere.utils.item.ItemBuilder; +import dev.manere.utils.menu.listener.CloseListener; +import dev.manere.utils.menu.listener.DragListener; import dev.manere.utils.menu.paginated.PaginatedSlot; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -9,7 +11,6 @@ import org.jetbrains.annotations.Nullable; public interface MenuBase { - /** * Returns T, used for default values and for * miscalculation purposes. diff --git a/src/main/java/dev/manere/utils/menu/MenuUtils.java b/src/main/java/dev/manere/utils/menu/MenuUtils.java index 979462f..a818507 100644 --- a/src/main/java/dev/manere/utils/menu/MenuUtils.java +++ b/src/main/java/dev/manere/utils/menu/MenuUtils.java @@ -12,7 +12,6 @@ * Utility class for working with menus. */ public class MenuUtils { - /** * Gets the center slot index for a menu of the given size. * diff --git a/src/main/java/dev/manere/utils/menu/CloseListener.java b/src/main/java/dev/manere/utils/menu/listener/CloseListener.java similarity index 90% rename from src/main/java/dev/manere/utils/menu/CloseListener.java rename to src/main/java/dev/manere/utils/menu/listener/CloseListener.java index 9b429ea..62e11a5 100644 --- a/src/main/java/dev/manere/utils/menu/CloseListener.java +++ b/src/main/java/dev/manere/utils/menu/listener/CloseListener.java @@ -1,4 +1,4 @@ -package dev.manere.utils.menu; +package dev.manere.utils.menu.listener; import org.bukkit.event.inventory.InventoryCloseEvent; import org.jetbrains.annotations.NotNull; @@ -7,12 +7,10 @@ * Interface for listening to inventory close events. */ public interface CloseListener { - /** * Called when an inventory is closed. * * @param event The inventory close event. */ void onClose(@NotNull InventoryCloseEvent event); - } \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/menu/DragListener.java b/src/main/java/dev/manere/utils/menu/listener/DragListener.java similarity index 90% rename from src/main/java/dev/manere/utils/menu/DragListener.java rename to src/main/java/dev/manere/utils/menu/listener/DragListener.java index 04be748..f36924b 100644 --- a/src/main/java/dev/manere/utils/menu/DragListener.java +++ b/src/main/java/dev/manere/utils/menu/listener/DragListener.java @@ -1,4 +1,4 @@ -package dev.manere.utils.menu; +package dev.manere.utils.menu.listener; import org.bukkit.event.inventory.InventoryDragEvent; import org.jetbrains.annotations.NotNull; @@ -7,12 +7,10 @@ * Interface for listening to inventory drag events. */ public interface DragListener { - /** * Called when an inventory drag event occurs. * * @param event The inventory drag event. */ void onDrag(@NotNull InventoryDragEvent event); - } \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/menu/MenuListener.java b/src/main/java/dev/manere/utils/menu/listener/MenuListener.java similarity index 87% rename from src/main/java/dev/manere/utils/menu/MenuListener.java rename to src/main/java/dev/manere/utils/menu/listener/MenuListener.java index 2548dde..925c6f9 100644 --- a/src/main/java/dev/manere/utils/menu/MenuListener.java +++ b/src/main/java/dev/manere/utils/menu/listener/MenuListener.java @@ -1,6 +1,7 @@ -package dev.manere.utils.menu; +package dev.manere.utils.menu.listener; import dev.manere.utils.item.ItemBuilder; +import dev.manere.utils.menu.Button; import dev.manere.utils.menu.normal.Menu; import dev.manere.utils.menu.paginated.PaginatedMenu; import dev.manere.utils.menu.paginated.PaginatedSlot; @@ -18,7 +19,6 @@ * A listener class for handling click events in menus. */ public class MenuListener implements Listener { - /** * Handles click events in menus. * @@ -43,11 +43,11 @@ public void onClick(InventoryClickEvent event) { if (event.getInventory().getHolder() instanceof PaginatedMenu menu) { Button stickyButton = menu.stickyButton(event.getSlot()); - if (menu.currentPageItemEnabled && event.getSlot() == menu.currentPageSlot) { + if (menu.currentPageItemEnabled() && event.getSlot() == menu.currentPageSlot()) { event.setCancelled(true); } - for (Map.Entry entry : menu.previousButton.entrySet()) { + for (Map.Entry entry : menu.previousButton().entrySet()) { if (event.getSlot() == entry.getKey()) { event.setCancelled(true); @@ -57,7 +57,7 @@ public void onClick(InventoryClickEvent event) { } } - for (Map.Entry entry : menu.nextButton.entrySet()) { + for (Map.Entry entry : menu.nextButton().entrySet()) { if (event.getSlot() == entry.getKey()) { event.setCancelled(true); @@ -97,12 +97,12 @@ public void onClose(InventoryCloseEvent event) { Player player = (Player) event.getPlayer(); if (event.getInventory().getHolder() instanceof Menu menu) { - if (menu.onClose != null) { - menu.onClose.onClose(event); + if (menu.onClose() != null) { + menu.onClose().onClose(event); } } else if (event.getInventory().getHolder() instanceof PaginatedMenu menu) { - if (menu.onClose != null) { - menu.onClose.onClose(event); + if (menu.onClose() != null) { + menu.onClose().onClose(event); } } } @@ -117,12 +117,12 @@ public void onDrag(InventoryDragEvent event) { Player player = (Player) event.getWhoClicked(); if (event.getInventory().getHolder() instanceof Menu menu) { - if (menu.onDrag != null) { - menu.onDrag.onDrag(event); + if (menu.onDrag() != null) { + menu.onDrag().onDrag(event); } } else if (event.getInventory().getHolder() instanceof PaginatedMenu menu) { - if (menu.onDrag != null) { - menu.onDrag.onDrag(event); + if (menu.onDrag() != null) { + menu.onDrag().onDrag(event); } } } diff --git a/src/main/java/dev/manere/utils/menu/normal/Menu.java b/src/main/java/dev/manere/utils/menu/normal/Menu.java index 1c1e97a..9c88af7 100644 --- a/src/main/java/dev/manere/utils/menu/normal/Menu.java +++ b/src/main/java/dev/manere/utils/menu/normal/Menu.java @@ -3,11 +3,10 @@ import dev.manere.utils.item.ItemBuilder; import dev.manere.utils.library.Utils; import dev.manere.utils.menu.Button; -import dev.manere.utils.menu.CloseListener; -import dev.manere.utils.menu.DragListener; import dev.manere.utils.menu.MenuBase; -import dev.manere.utils.scheduler.builder.SchedulerBuilder; -import dev.manere.utils.scheduler.builder.TaskType; +import dev.manere.utils.menu.listener.CloseListener; +import dev.manere.utils.menu.listener.DragListener; +import dev.manere.utils.scheduler.Schedulers; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; @@ -20,18 +19,22 @@ import java.util.logging.Level; /** - * The Menu class allows you to create custom menus with buttons and items in Bukkit/Spigot. + * The Menu class allows you to create custom menus with buttons and items in Paper/Bukkit/Spigot. + *

* You can set buttons, items, borders, and fill patterns within the menu. + *

* Menus are displayed to players using the open(Player player) method. + *

+ * This implementation does not support pagination. */ public class Menu implements InventoryHolder, MenuBase

{ - public final Inventory inventory; - public final Component title; - public final int size; - public final Map buttons; - public final Map items; - public CloseListener onClose; - public DragListener onDrag; + private final Inventory inventory; + private final Component title; + private final int size; + private final Map buttons; + private final Map items; + private CloseListener onClose; + private DragListener onDrag; /** * Constructs a new Menu with the specified title and size. @@ -126,27 +129,26 @@ public void open(@NotNull Player player) { for (Button button : buttons.values()) { if (button.isRefreshingButton()) { - SchedulerBuilder.scheduler() - .type(TaskType.REPEATING) - .async(button.isRefreshingAsync()) - .after(button.refreshDelay()) - .every(button.refreshPeriod()) - .task(task -> { - if (player.getOpenInventory().getTopInventory() != getInventory()) { - task.cancel(); - return; - } - - int slot = slotByButton(button); - - getInventory().clear(slot); - getInventory().setItem(slot, button.item().build()); - - /* player.updateInventory(); - * This probably shouldn't be used. - */ - }) - .build(); + Schedulers.builder(task -> { + if (player.getOpenInventory().getTopInventory() != getInventory()) { + task.cancel(); + return; + } + + int slot = slotByButton(button); + + getInventory().clear(slot); + getInventory().setItem(slot, button.item().build()); + }).config(config -> { + if (button.isRefreshingAsync()) { + config.async(); + } else { + config.sync(); + } + + config.afterTicks((int) button.refreshDelay()); + config.everyTicks((int) button.refreshPeriod()); + }).execute(); } } } @@ -210,7 +212,7 @@ public void open(@NotNull Player player) { } else { int callersLineNumber = Thread.currentThread().getStackTrace()[2].getLineNumber(); Utils.plugin().getLogger().log(Level.WARNING, "You can not use Menu.fill(Object filler, String... pattern) with a object different than an ItemBuilder or Button!"); - Utils.plugin().getLogger().log(Level.WARNING, " Line: [" + callersLineNumber + "], File: [" + Thread.currentThread().getStackTrace()[2].getFileName() + "]"); + Utils.plugin().getLogger().log(Level.WARNING, " Line: [" + callersLineNumber + "], FileBuilder: [" + Thread.currentThread().getStackTrace()[2].getFileName() + "]"); } } } @@ -320,4 +322,12 @@ public Inventory inventory() { this.onDrag = onDrag; return this; } + + public CloseListener onClose() { + return onClose; + } + + public DragListener onDrag() { + return onDrag; + } } \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/menu/paginated/PaginatedMenu.java b/src/main/java/dev/manere/utils/menu/paginated/PaginatedMenu.java index cfee8d5..d614b9d 100644 --- a/src/main/java/dev/manere/utils/menu/paginated/PaginatedMenu.java +++ b/src/main/java/dev/manere/utils/menu/paginated/PaginatedMenu.java @@ -3,11 +3,10 @@ import dev.manere.utils.item.ItemBuilder; import dev.manere.utils.library.Utils; import dev.manere.utils.menu.Button; -import dev.manere.utils.menu.CloseListener; -import dev.manere.utils.menu.DragListener; import dev.manere.utils.menu.MenuBase; -import dev.manere.utils.scheduler.builder.SchedulerBuilder; -import dev.manere.utils.scheduler.builder.TaskType; +import dev.manere.utils.menu.listener.CloseListener; +import dev.manere.utils.menu.listener.DragListener; +import dev.manere.utils.scheduler.Schedulers; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -21,29 +20,27 @@ import java.util.logging.Level; /** - * A {@link PaginatedMenu} class for creating paginated menus in Bukkit/Spigot. - * This class allows you to build and manage paginated menus with customizable buttons, - * items, and pagination controls. + * A {@link PaginatedMenu} class for creating paginated menus in Paper/Bukkit/Spigot. + *

+ * This class allows you to build and manage paginated menus with customizable buttons, items, and pagination controls. */ - public class PaginatedMenu implements InventoryHolder, MenuBase { - - public final Inventory inventory; - public final Component title; - public final int size; - public final Map buttons; - public final Map items; - public int totalPages; - public int currentPage; - public final Map previousButton; - public final Map nextButton; - public final Map borderMap; - public final Map stickyButtons; - public boolean currentPageItemEnabled; - public ItemBuilder currentPageItem; - public int currentPageSlot; - public CloseListener onClose; - public DragListener onDrag; + private final Inventory inventory; + private final Component title; + private final int size; + private final Map buttons; + private final Map items; + private int totalPages; + private int currentPage; + private final Map previousButton; + private final Map nextButton; + private final Map borderMap; + private final Map stickyButtons; + private boolean currentPageItemEnabled; + private ItemBuilder currentPageItem; + private int currentPageSlot; + private CloseListener onClose; + private DragListener onDrag; /** * Constructs a new PaginatedMenu with the specified title and size. @@ -311,7 +308,7 @@ public int currentPage() { } else { int callersLineNumber = Thread.currentThread().getStackTrace()[2].getLineNumber(); Utils.plugin().getLogger().log(Level.WARNING, "You can not use PaginatedMenu.fill(Object filler, String... pattern) with a object different than an ItemBuilder or Button!"); - Utils.plugin().getLogger().log(Level.WARNING, " Line: [" + callersLineNumber + "], File: [" + Thread.currentThread().getStackTrace()[2].getFileName() + "]"); + Utils.plugin().getLogger().log(Level.WARNING, " Line: [" + callersLineNumber + "], FileBuilder: [" + Thread.currentThread().getStackTrace()[2].getFileName() + "]"); } } } @@ -376,30 +373,34 @@ public void open(@NotNull Player player, int page) { if (!button.isRefreshingButton()) { this.inventory.setItem(pageSlotHolderByButton(button).slot(), button.item().build()); } else { - SchedulerBuilder.scheduler() - .type(TaskType.REPEATING) - .async(button.isRefreshingAsync()) - .after(button.refreshDelay()) - .every(button.refreshPeriod()) - .task(task -> { - if (player.getOpenInventory().getTopInventory() != getInventory()) { - task.cancel(); - return; - } - - if (pageSlotHolderByButton(button).page() != currentPage) { - task.cancel(); - return; - } - - int slot = pageSlotHolderByButton(button).slot(); - - getInventory().clear(slot); - getInventory().setItem(slot, button.item().name(button.item().build().displayName()).build()); - - player.updateInventory(); - }) - .build(); + Schedulers.builder(task -> { + if (player.getOpenInventory().getTopInventory() != getInventory()) { + task.cancel(); + return; + } + + if (pageSlotHolderByButton(button).page() != currentPage) { + task.cancel(); + return; + } + + int slot = pageSlotHolderByButton(button).slot(); + + getInventory().clear(slot); + getInventory().setItem(slot, button.item().name(button.item().build().displayName()).build()); + + player.updateInventory(); + }).config(config -> { + if (button.isRefreshingAsync()) { + config.async(); + } else { + config.sync(); + } + + config.afterTicks((int) button.refreshDelay()); + config.everyTicks((int) button.refreshPeriod()); + }) + .execute(); } } } @@ -623,4 +624,24 @@ public Inventory inventory() { this.onDrag = onDrag; return this; } + + public CloseListener onClose() { + return onClose; + } + + public DragListener onDrag() { + return onDrag; + } + + public boolean currentPageItemEnabled() { + return currentPageItemEnabled; + } + + public ItemBuilder currentPageItem() { + return currentPageItem; + } + + public int currentPageSlot() { + return currentPageSlot; + } } \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/menu/paginated/PaginatedSlot.java b/src/main/java/dev/manere/utils/menu/paginated/PaginatedSlot.java index 698868a..4e7e634 100644 --- a/src/main/java/dev/manere/utils/menu/paginated/PaginatedSlot.java +++ b/src/main/java/dev/manere/utils/menu/paginated/PaginatedSlot.java @@ -5,6 +5,10 @@ /** * The PaginatedSlot record represents a holder for a slot and page number in a menu system. * It is used to associate a specific slot on a page within a menu. + *

+ * Slots start at 0 and end at the page slot size (usually 27/36/45/54). + *

+ * Pages start at 1. */ public record PaginatedSlot(int slot, int page) { public static @NotNull PaginatedSlot paginatedSlot(int slot, int page) { diff --git a/src/main/java/dev/manere/utils/message/ActionBarMessager.java b/src/main/java/dev/manere/utils/message/ActionBarMessager.java index 16fc558..38ec87b 100644 --- a/src/main/java/dev/manere/utils/message/ActionBarMessager.java +++ b/src/main/java/dev/manere/utils/message/ActionBarMessager.java @@ -55,8 +55,8 @@ public void clear() { * @param after The delay before the first message is sent (in ticks). * @param every The interval between subsequent messages (in ticks). */ - public void send(@NotNull Component text, long after, long every) { - Schedulers.async().repeating(task -> send(text), after, every); + public void send(@NotNull Component text, int after, int every) { + Schedulers.async().execute(task -> send(text), after, every); } /** diff --git a/src/main/java/dev/manere/utils/message/Messagers.java b/src/main/java/dev/manere/utils/message/Messagers.java index 56bff5e..4ebc048 100644 --- a/src/main/java/dev/manere/utils/message/Messagers.java +++ b/src/main/java/dev/manere/utils/message/Messagers.java @@ -7,7 +7,6 @@ * Utility class for obtaining instances of message senders. */ public class Messagers { - /** * Creates an instance of ActionBarMessager for a specific player. * diff --git a/src/main/java/dev/manere/utils/misc/Buildable.java b/src/main/java/dev/manere/utils/misc/Buildable.java new file mode 100644 index 0000000..cb6c33d --- /dev/null +++ b/src/main/java/dev/manere/utils/misc/Buildable.java @@ -0,0 +1,12 @@ +package dev.manere.utils.misc; + +/** + * The {@code Buildable} interface represents an object that can be built or constructed. + * Classes implementing this interface should provide a method to initiate the building process. + */ +public interface Buildable { + /** + * Initiates the building process for the object. + */ + void build(); +} diff --git a/src/main/java/dev/manere/utils/misc/FluentBuilder.java b/src/main/java/dev/manere/utils/misc/FluentBuilder.java new file mode 100644 index 0000000..e38d371 --- /dev/null +++ b/src/main/java/dev/manere/utils/misc/FluentBuilder.java @@ -0,0 +1,16 @@ +package dev.manere.utils.misc; + +/** + * The {@code FluentBuilder} class is an abstract class representing a fluent builder pattern. + * Classes extending this abstract class should implement the build method to create an object of a specified type. + * + * @param The type of object that the builder constructs. + */ +public abstract class FluentBuilder { + /** + * Constructs and returns an object of the specified type. + * + * @return The constructed object. + */ + public abstract R build(); +} diff --git a/src/main/java/dev/manere/utils/misc/ObjectUtils.java b/src/main/java/dev/manere/utils/misc/ObjectUtils.java new file mode 100644 index 0000000..dd6f4ef --- /dev/null +++ b/src/main/java/dev/manere/utils/misc/ObjectUtils.java @@ -0,0 +1,156 @@ +package dev.manere.utils.misc; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +/** + * Utility class for common object-related operations, including null checks and validation. + */ +public class ObjectUtils { + /** + * Ensures that the specified value is not null. + * + * @param value The value to check for null. + * @param The type of the value. + * @return The non-null value. + * @throws NullPointerException if the value is null. + */ + @CanIgnoreReturnValue + public static T nonNull(@Nullable T value) { + if (value == null) throw new NullPointerException(); + return value; + } + + /** + * Ensures that the specified value is not null. + * + * @param value The value to check for null. + * @param text The exception message if the value is null. + * @param The type of the value. + * @return The non-null value. + * @throws NullPointerException if the value is null. + */ + @CanIgnoreReturnValue + public static T nonNull(@Nullable T value, @NotNull String text) { + if (value == null) throw new NullPointerException(text); + return value; + } + + /** + * Provides a default value if the specified value is null. + * + * @param value The value to check for null. + * @param defaultValue The default value to return if the original value is null. + * @param The type of the value. + * @return The original value if not null, otherwise the default value. + */ + public static T defaultIfNull(@Nullable T value, T defaultValue) { + return (value != null) ? value : defaultValue; + } + + /** + * Executes the specified action if the value is not null. + * + * @param value The value to check for null. + * @param action The action to perform on the non-null value. + * @param The type of the value. + */ + public static void ifNonNull(@Nullable T value, Consumer action) { + if (value != null) { + action.accept(value); + } + } + + /** + * Ensures that the specified value is not null, throwing a custom exception if it is. + * + * @param value The value to check for null. + * @param exceptionSupplier A supplier providing the exception to be thrown if the value is null. + * @param The type of the value. + * @param The type of the exception. + * @return The non-null value. + * @throws E if the value is null. + */ + @CanIgnoreReturnValue + public static T nonNull(@Nullable T value, Supplier exceptionSupplier) { + if (value == null) throw exceptionSupplier.get(); + return value; + } + + /** + * Ensures that the specified collection is not null and does not contain null elements. + * + * @param collection The collection to check for null and null elements. + * @param The type of elements in the collection. + * @return The non-null and non-contain-null-elements collection. + * @throws NullPointerException if the collection is null or contains null elements. + */ + @CanIgnoreReturnValue + public static Collection nonNullElements(@Nullable Collection collection) { + if (collection == null || collection.contains(null)) throw new NullPointerException("Collection contains null elements"); + return collection; + } + + /** + * Ensures that the specified string is not null or empty. + * + * @param value The string to check for null or empty. + * @param fieldName The name of the field being checked. + * @return The non-null and non-empty string. + * @throws IllegalArgumentException if the string is null or empty. + */ + @CanIgnoreReturnValue + public static String nonEmpty(@Nullable String value, @NotNull String fieldName) { + if (value == null || value.trim().isEmpty()) throw new IllegalArgumentException(fieldName + " must not be empty"); + return value; + } + + /** + * Provides an empty collection if the specified collection is null. + * + * @param collection The collection to check for null. + * @param The type of elements in the collection. + * @return The original collection if not null, otherwise an empty collection. + */ + public static Collection emptyIfNull(@Nullable Collection collection) { + return (collection != null) ? collection : Collections.emptyList(); + } + + /** + * Checks the specified value against a predicate, throwing an exception if the check fails. + * + * @param value The value to check. + * @param predicate The predicate to test the value against. + * @param errorMessage The error message to include in the exception if the check fails. + * @param The type of the value. + * @return The original value if the check passes. + * @throws IllegalArgumentException if the check fails. + */ + @CanIgnoreReturnValue + public static T check(@Nullable T value, Predicate predicate, String errorMessage) { + if (!predicate.test(value)) throw new IllegalArgumentException(errorMessage); + return value; + } + + /** + * Ensures that the specified integer is non-negative. + * + * @param value The integer value to check. + * @param errorMessage The error message to include in the exception if the check fails. + * @return The original value if it is non-negative. + * @throws IllegalArgumentException if the value is negative. + */ + public static int requireNonNegative(int value, String errorMessage) { + if (value < 0) { + throw new IllegalArgumentException(errorMessage); + } + return value; + } +} \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/misc/Storable.java b/src/main/java/dev/manere/utils/misc/Storable.java new file mode 100644 index 0000000..00ea88a --- /dev/null +++ b/src/main/java/dev/manere/utils/misc/Storable.java @@ -0,0 +1,23 @@ +package dev.manere.utils.misc; + +/** + * The {@code Storable} interface defines methods for serializing an object to a string and deserializing from a string. + * + * @param The type of object to be serialized and deserialized. + */ +public interface Storable { + /** + * Serializes the object to a string representation. + * + * @return A string representation of the serialized object. + */ + String serialize(); + + /** + * Deserializes the object from a string representation. + * + * @param serialized the object to be deserialized. + * @return The deserialized object. + */ + T deserialize(String serialized); +} diff --git a/src/main/java/dev/manere/utils/model/Duo.java b/src/main/java/dev/manere/utils/model/Tuple.java similarity index 84% rename from src/main/java/dev/manere/utils/model/Duo.java rename to src/main/java/dev/manere/utils/model/Tuple.java index 8008f0f..4a6eb51 100644 --- a/src/main/java/dev/manere/utils/model/Duo.java +++ b/src/main/java/dev/manere/utils/model/Tuple.java @@ -9,7 +9,7 @@ * @param The key type * @param The value type */ -public class Duo { +public class Tuple { private K key; private V val; @@ -19,7 +19,7 @@ public class Duo { * @param key The key * @param val The value */ - public Duo(@Nullable K key, @Nullable V val) { + public Tuple(@Nullable K key, @Nullable V val) { this.key = key; this.val = val; } @@ -33,8 +33,8 @@ public Duo(@Nullable K key, @Nullable V val) { * @param val The value * @return A new tuple with the specified key and value */ - public static @NotNull Duo of(@Nullable K key, @Nullable V val) { - return new Duo<>(key, val); + public static @NotNull Tuple duo(@Nullable K key, @Nullable V val) { + return new Tuple<>(key, val); } /** @@ -55,7 +55,7 @@ public Duo(@Nullable K key, @Nullable V val) { * @param key The new key * @return This tuple instance */ - public @NotNull Duo key(@Nullable K key) { + public @NotNull Tuple key(@Nullable K key) { this.key = key; return this; } @@ -66,7 +66,7 @@ public Duo(@Nullable K key, @Nullable V val) { * @param val The new value * @return This tuple instance */ - public @NotNull Duo val(@Nullable V val) { + public @NotNull Tuple val(@Nullable V val) { this.val = val; return this; } diff --git a/src/main/java/dev/manere/utils/papi/PlaceholderAPIBuilder.java b/src/main/java/dev/manere/utils/papi/PlaceholderAPIBuilder.java index 8e8a706..dcde5c4 100644 --- a/src/main/java/dev/manere/utils/papi/PlaceholderAPIBuilder.java +++ b/src/main/java/dev/manere/utils/papi/PlaceholderAPIBuilder.java @@ -11,7 +11,6 @@ import java.util.function.BiFunction; public class PlaceholderAPIBuilder { - private final String prefix; private String author; private String version; @@ -23,7 +22,8 @@ public class PlaceholderAPIBuilder { * * @param prefix The identifier for the PlaceholderAPI expansion. */ - /* I hate you paper (why would you deprecate JavaPlugin#getDescription() and then make the alternative (PluginMeta) "unstable" */ + /* I hate you paper (why would you deprecate JavaPlugin#getDescription() + and then make the alternative (PluginMeta) "unstable" */ @SuppressWarnings("UnstableApiUsage") public PlaceholderAPIBuilder(@NotNull String prefix) { this.prefix = prefix; @@ -96,7 +96,10 @@ public PlaceholderAPIBuilder(@NotNull String prefix) { * @param offlineResult The function to handle placeholder requests for offline players. * @return The updated PlaceholderAPIBuilder instance. */ - public @NotNull PlaceholderAPIBuilder request(@Nullable BiFunction onlineResult, @Nullable BiFunction offlineResult) { + public @NotNull PlaceholderAPIBuilder request( + @Nullable BiFunction onlineResult, + @Nullable BiFunction offlineResult + ) { this.playerResult = onlineResult; this.offlinePlayerResult = offlineResult; return this; diff --git a/src/main/java/dev/manere/utils/pdc/UUIDDataType.java b/src/main/java/dev/manere/utils/pdc/UUIDDataType.java new file mode 100644 index 0000000..e944e6c --- /dev/null +++ b/src/main/java/dev/manere/utils/pdc/UUIDDataType.java @@ -0,0 +1,79 @@ +package dev.manere.utils.pdc; + +import org.bukkit.persistence.PersistentDataAdapterContext; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; + +import java.nio.ByteBuffer; +import java.util.UUID; + +/** + * A custom implementation of {@link PersistentDataType} for converting between byte arrays and UUIDs. + * This implementation is used for data persistence in Paper/Spigot/Bukkit plugins. + * + * @see PersistentDataType + */ +public class UUIDDataType implements PersistentDataType { + /** + * Creates a new instance of UUIDDataType. + * + * @return A new instance of UUIDDataType. + */ + public static UUIDDataType of() { + return new UUIDDataType(); + } + + /** + * Gets the primitive type associated with this data type. + * + * @return The primitive type (byte array). + */ + @Override + public @NotNull Class getPrimitiveType() { + return byte[].class; + } + + /** + * Gets the complex type associated with this data type. + * + * @return The complex type (UUID). + */ + @Override + public @NotNull Class getComplexType() { + return UUID.class; + } + + /** + * Converts a UUID to a byte array. + * + * @param complex The UUID to convert. + * @param context The PersistentDataAdapterContext. + * @return The byte array representation of the UUID. + */ + @Override + public byte @NotNull [] toPrimitive(UUID complex, @NotNull PersistentDataAdapterContext context) { + ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); + + byteBuffer.putLong(complex.getMostSignificantBits()); + byteBuffer.putLong(complex.getLeastSignificantBits()); + + return byteBuffer.array(); + } + + /** + * Converts a byte array to a UUID. + * + * @param primitive The byte array to convert. + * @param context The PersistentDataAdapterContext. + * @return The UUID representation of the byte array. + */ + @Override + public @NotNull UUID fromPrimitive(byte @NotNull [] primitive, @NotNull PersistentDataAdapterContext context) { + ByteBuffer byteBuffer = ByteBuffer.wrap(primitive); + + long firstLong = byteBuffer.getLong(); + long secondLong = byteBuffer.getLong(); + + return new UUID(firstLong, secondLong); + } +} \ No newline at end of file diff --git a/src/main/java/dev/manere/utils/player/cache/CacheInfo.java b/src/main/java/dev/manere/utils/player/cache/CacheInfo.java deleted file mode 100644 index 49e6819..0000000 --- a/src/main/java/dev/manere/utils/player/cache/CacheInfo.java +++ /dev/null @@ -1,27 +0,0 @@ -package dev.manere.utils.player.cache; - -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Represents information used for caching values in the player cache. - * - * @param target The player for whom the cache is created. - * @param identifier The identifier for the cached value. - * @param val The value to be cached. - */ -public record CacheInfo(@NotNull Player target, @NotNull CacheKey identifier, @Nullable Object val) { - - /** - * Creates a new CacheInfo instance with the specified player, identifier, and value. - * - * @param target The player for whom the cache is created. - * @param identifier The identifier for the cached value. - * @param val The value to be cached. - * @return A new CacheInfo instance. - */ - public static @NotNull CacheInfo of(@NotNull Player target, @NotNull CacheKey identifier, @Nullable Object val) { - return new CacheInfo(target, identifier, val); - } -} diff --git a/src/main/java/dev/manere/utils/player/cache/CacheKey.java b/src/main/java/dev/manere/utils/player/cache/CacheKey.java deleted file mode 100644 index 2383926..0000000 --- a/src/main/java/dev/manere/utils/player/cache/CacheKey.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.manere.utils.player.cache; - -import dev.manere.utils.library.Utils; -import org.jetbrains.annotations.NotNull; - -/** - * Represents a key used for identifying cached values in the player cache. - */ -public class CacheKey { - private final String name; - - /** - * Creates a new CacheKey instance with the specified name. - * - * @param name The name used to create the identifier for the cache key. - */ - public CacheKey(@NotNull String name) { - this.name = Utils.plugin().getName() + name.replaceAll(" ", "_").toUpperCase(); - } - - /** - * Creates a new CacheKey instance with the specified name. - * - * @param name The name used to create the identifier for the cache key. - * @return A new CacheKey instance. - */ - public static @NotNull CacheKey key(@NotNull String name) { - return new CacheKey(name); - } - - /** - * Gets the identifier generated based on the name. - * - * @return The identifier for the cache key. - */ - public @NotNull String identifier() { - return this.name; - } -} diff --git a/src/main/java/dev/manere/utils/player/cache/CacheVal.java b/src/main/java/dev/manere/utils/player/cache/CacheVal.java deleted file mode 100644 index ae1c4c2..0000000 --- a/src/main/java/dev/manere/utils/player/cache/CacheVal.java +++ /dev/null @@ -1,102 +0,0 @@ -package dev.manere.utils.player.cache; - -import dev.manere.utils.text.Text; - -/** - * Represents a cached value in the player cache. - * - * @param val The cached value. - */ -public record CacheVal(Object val) { - - /** - * Creates a new CacheVal instance with the specified value. - * - * @param val The value to be wrapped in a CacheVal instance. - * @return A new CacheVal instance. - */ - public static CacheVal cached(Object val) { - return new CacheVal(val); - } - - /** - * Returns the value stored as an Object. - * - * @return the value stored as an Object. - */ - public Object asObject() { - return val; - } - - /** - * Converts the cached value to a Text. - * - * @return A Text instance representing the cached value. - */ - public Text asText() { - return Text.text((String) val); - } - - /** - * Converts the cached value to a boolean. - * - * @return A boolean instance representing the cached value. - */ - public boolean asBoolean() { - return (boolean) val; - } - - /** - * Converts the cached value to a byte. - * - * @return A byte instance representing the cached value. - */ - public byte asByte() { - return (byte) val; - } - - /** - * Converts the cached value to a double. - * - * @return A double instance representing the cached value. - */ - public double asDouble() { - return (double) val; - } - - /** - * Converts the cached value to a float. - * - * @return A float instance representing the cached value. - */ - public float asFloat() { - return (float) val; - } - - /** - * Converts the cached value to an int. - * - * @return An int instance representing the cached value. - */ - public int asInt() { - return (int) val; - } - - /** - * Converts the cached value to a long. - * - * @return A long instance representing the cached value. - */ - public long asLong() { - return (long) val; - } - - /** - * Converts the cached value to a short. - * - * @return A short instance representing the cached value. - */ - public short asShort() { - return (short) val; - } -} diff --git a/src/main/java/dev/manere/utils/player/cache/PlayerCache.java b/src/main/java/dev/manere/utils/player/cache/PlayerCache.java deleted file mode 100644 index 6404c6b..0000000 --- a/src/main/java/dev/manere/utils/player/cache/PlayerCache.java +++ /dev/null @@ -1,142 +0,0 @@ -package dev.manere.utils.player.cache; - -import dev.manere.utils.library.Utils; -import org.bukkit.entity.Player; -import org.bukkit.metadata.FixedMetadataValue; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Represents a cache for player-related information using metadata in Bukkit. - * This class provides methods for caching, retrieving, and checking for specific values. - * - * @param target The player for whom the cache is created. - */ -public record PlayerCache(@NotNull Player target) { - - /** - * Creates a new PlayerCache instance for the specified player. - * - * @param player The player to create a cache for. - * @return A new PlayerCache instance. - */ - public static @NotNull PlayerCache cacheOf(Player player) { - return new PlayerCache(player); - } - - /** - * Caches a value for the specified player with a given identifier. - * - * @param target The player to cache the value for. - * @param identifier The identifier for the cached value. - * @param val The value to cache. - * @return True if the value was successfully cached, false otherwise. - */ - public static boolean cache(@NotNull Player target, @NotNull CacheKey identifier, @Nullable Object val) { - if (!target.getMetadata(identifier.identifier()).isEmpty()) { - return false; - } - - target.getMetadata(identifier.identifier()).add(new FixedMetadataValue(Utils.plugin(), val)); - return true; - } - - /** - * Caches a value for the specified player using information from a CacheInfo instance. - * - * @param info The CacheInfo instance containing target player, identifier, and value. - * @return True if the value was successfully cached, false otherwise. - */ - public static boolean cache(@NotNull CacheInfo info) { - return cache(info.target(), info.identifier(), info.val()); - } - - /** - * Retrieves a cached value for the specified player and identifier. - * - * @param target The player to retrieve the cached value for. - * @param identifier The identifier for the cached value. - * @return A CacheVal instance representing the cached value. - */ - public static CacheVal retrieve(@NotNull Player target, @NotNull CacheKey identifier) { - return CacheVal.cached(target.getMetadata(identifier.identifier()).get(0).value()); - } - - /** - * Checks if the specified player has a cached value with the given identifier and value. - * - * @param target The player to check for the cached value. - * @param identifier The identifier for the cached value. - * @param val The value to check for. - * @return True if the player has the specified cached value, false otherwise. - */ - public static boolean has(@NotNull Player target, @NotNull CacheKey identifier, @Nullable Object val) { - return target.getMetadata(identifier.identifier()).contains(new FixedMetadataValue(Utils.plugin(), val)); - } - - /** - * Checks if the specified player has a cached value using information from a CacheInfo instance. - * - * @param info The CacheInfo instance containing target player, identifier, and value. - * @return True if the player has the specified cached value, false otherwise. - */ - public static boolean has(@NotNull CacheInfo info) { - return has(info.target(), info.identifier(), info.val()); - } - - /** - * Caches a value for the current instance's player with a given identifier. - * - * @param identifier The identifier for the cached value. - * @param val The value to cache. - * @return True if the value was successfully cached, false otherwise. - */ - public boolean cache(@NotNull CacheKey identifier, @Nullable Object val) { - if (!target.getMetadata(identifier.identifier()).isEmpty()) { - return false; - } - - target.getMetadata(identifier.identifier()).add(new FixedMetadataValue(Utils.plugin(), val)); - return true; - } - - /** - * Retrieves a cached value for the current instance's player and identifier. - * - * @param identifier The identifier for the cached value. - * @return A CacheVal instance representing the cached value. - */ - public CacheVal retrieve(@NotNull CacheKey identifier) { - return CacheVal.cached(target.getMetadata(identifier.identifier()).get(0).value()); - } - - /** - * Checks if the current instance's player has a cached value with the given identifier and value. - * - * @param identifier The identifier for the cached value. - * @param val The value to check for. - * @return True if the player has the specified cached value, false otherwise. - */ - public boolean has(@NotNull CacheKey identifier, @Nullable Object val) { - return target.getMetadata(identifier.identifier()).contains(new FixedMetadataValue(Utils.plugin(), val)); - } - - /** - * Deletes a cached value for the specified player and identifier. - * - * @param target The player to delete the cached value for. - * @param identifier The identifier for the cached value to delete. - */ - public static void delete(@NotNull Player target, @NotNull CacheKey identifier) { - target.removeMetadata(identifier.identifier(), Utils.plugin()); - } - - /** - * Deletes a cached value for the current instance's player and identifier. - * - * @param identifier The identifier for the cached value to delete. - */ - public void delete(@NotNull CacheKey identifier) { - target.removeMetadata(identifier.identifier(), Utils.plugin()); - } -} diff --git a/src/main/java/dev/manere/utils/prettify/ListPrettify.java b/src/main/java/dev/manere/utils/prettify/ListPrettify.java index 67fd971..52d95ad 100644 --- a/src/main/java/dev/manere/utils/prettify/ListPrettify.java +++ b/src/main/java/dev/manere/utils/prettify/ListPrettify.java @@ -15,7 +15,6 @@ * To: a, b, c, d */ public class ListPrettify { - /** * Converts a List of Strings into a single comma-separated String. * diff --git a/src/main/java/dev/manere/utils/reflection/ReflectionUtils.java b/src/main/java/dev/manere/utils/reflection/ReflectionUtils.java index 5904b25..2c69567 100644 --- a/src/main/java/dev/manere/utils/reflection/ReflectionUtils.java +++ b/src/main/java/dev/manere/utils/reflection/ReflectionUtils.java @@ -13,7 +13,6 @@ * A utility class providing methods for reflection-related tasks. */ public class ReflectionUtils { - public static final String NM_PACKAGE = "net.minecraft"; public static final String CRAFTBUKKIT_PACKAGE = "org.bukkit.craftbukkit"; public static final String NMS_PACKAGE = NM_PACKAGE + ".server"; @@ -22,6 +21,10 @@ public class ReflectionUtils { private static final boolean NMS_REPACKAGED = optionalClass(NM_PACKAGE + ".network.protocol.Packet").isPresent(); private static volatile Object theUnsafe; + public static boolean compare(Class a, Class b) { + return a.getCanonicalName().equals(b.getCanonicalName()); + } + /** * Checks if the net.minecraft server package has been repackaged. * diff --git a/src/main/java/dev/manere/utils/registration/Registrar.java b/src/main/java/dev/manere/utils/registration/Registrar.java index c033507..004c5e7 100644 --- a/src/main/java/dev/manere/utils/registration/Registrar.java +++ b/src/main/java/dev/manere/utils/registration/Registrar.java @@ -1,12 +1,12 @@ package dev.manere.utils.registration; -import dev.manere.utils.command.CommandType; +import dev.manere.utils.command.CommandTypes; import dev.manere.utils.command.Commander; import dev.manere.utils.command.args.Argument; -import dev.manere.utils.command.builder.CommandBuilder; -import dev.manere.utils.command.builder.CommandBuilderHandler; -import dev.manere.utils.command.builder.dispatcher.CommandContext; -import dev.manere.utils.command.builder.permission.CommandPermission; +import dev.manere.utils.command.impl.Commands; +import dev.manere.utils.command.impl.CommandsRegistrar; +import dev.manere.utils.command.impl.dispatcher.CommandContext; +import dev.manere.utils.command.impl.permission.CommandPermission; import dev.manere.utils.library.Utils; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -25,7 +25,6 @@ * A utility class for registering various components in a Bukkit plugin. */ public class Registrar { - /** * Registers a listener with the provided plugin. * @@ -119,7 +118,7 @@ public static void commandMap(@NotNull String commandName, @NotNull Command comm */ @SuppressWarnings("DataFlowIssue") public static void command(@NotNull Commander commander) { - if (commander.settings().type() == CommandType.COMMAND_MAP) { + if (commander.settings().type().type() == CommandTypes.COMMAND_MAP.type()) { Registrar.command( commander, commander.aliases(), @@ -130,7 +129,9 @@ public static void command(@NotNull Commander commander) { return; } - if (commander.settings().type() == CommandType.PLUGIN_YML && Utils.plugin().getCommand(commander.name()) == null) { + if (commander.settings().type().type() == CommandTypes.PLUGIN_YML.type() + && Utils.plugin().getCommand(commander.name()) == null) + { throw new NullPointerException("You seem to have forgotten to provide the command '" + commander.name() + "' " + "in the plugin.yml file inside of your project."); } @@ -156,7 +157,7 @@ public static void command(@NotNull Commander commander) { * @see Commander */ public static void command(@NotNull Commander commander, @Nullable List aliases, @Nullable String description, @Nullable String permission, @Nullable String usage) { - CommandBuilder builder = CommandBuilder.command(commander.name(), commander.settings().type()); + Commands builder = Commands.command(commander.name(), commander.settings().type()); if (aliases != null && !aliases.isEmpty()) { builder.aliases().aliases(aliases).build(); @@ -184,8 +185,8 @@ public static void command(@NotNull Commander commander, @Nullable List } @SuppressWarnings("DataFlowIssue") - public static void commandMap(CommandBuilderHandler handler) { - CommandBuilder builder = handler.commandBuilder(); + public static void commandMap(CommandsRegistrar handler) { + Commands builder = handler.commandBuilder(); Command command = new Command(builder.name(), builder.description(), builder.usage(), builder.aliases().aliases()) { @@ -230,6 +231,6 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No command.permissionMessage(builder.command().permissionMessage()); } - Registrar.commandMap().register(builder.command().getName(), Utils.plugin().getName(), command); + Registrar.commandMap().register(builder.command().getName(), builder.namespace(), command); } } diff --git a/src/main/java/dev/manere/utils/resource/ResourceBuilder.java b/src/main/java/dev/manere/utils/resource/ResourceBuilder.java new file mode 100644 index 0000000..afe9f2a --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/ResourceBuilder.java @@ -0,0 +1,127 @@ +package dev.manere.utils.resource; + +import dev.manere.utils.resource.format.ResourceFormat; +import dev.manere.utils.resource.format.ResourceFormats; +import dev.manere.utils.resource.path.ResourcePath; +import dev.manere.utils.resource.path.ResourcePaths; + +import java.util.function.Consumer; + +/** + * A builder class for creating instances of {@link ResourceFile}. Allows customization + * of the resource file's format, options, name, and path before building the resource. + */ +public class ResourceBuilder { + private ResourceFormat format; + private final ResourceOptions options; + private ResourcePath path; + private String name; + + /** + * Constructs a new ResourceBuilder with default settings. + */ + public ResourceBuilder() { + this.format = ResourceFormats.yaml(); + this.options = new ResourceOptions(); + this.name = null; + this.path = ResourcePaths.plugin(); + } + + /** + * Returns a new instance of ResourceBuilder. + * + * @return A new ResourceBuilder instance. + */ + public static ResourceBuilder builder() { + return new ResourceBuilder(); + } + + /** + * Gets the current resource format. + * + * @return The current resource format. + */ + public ResourceFormat format() { + return format; + } + + /** + * Sets the resource format for the builder. + * + * @param format The desired resource format. + * @return The current ResourceBuilder instance for method chaining. + */ + public ResourceBuilder format(ResourceFormat format) { + this.format = format; + return this; + } + + /** + * Gets the current resource options. + * + * @return The current resource options. + */ + public ResourceOptions options() { + return options; + } + + /** + * Configures the resource options using the provided consumer. + * + * @param optionsConsumer A consumer for configuring resource options. + * @return The current ResourceBuilder instance for method chaining. + */ + public ResourceBuilder options(Consumer optionsConsumer) { + optionsConsumer.accept(this.options); + return this; + } + + /** + * Gets the current resource name. + * + * @return The current resource name. + */ + public String name() { + return name; + } + + /** + * Sets the resource name for the builder. + * + * @param name The desired resource name. + * @return The current ResourceBuilder instance for method chaining. + */ + public ResourceBuilder name(String name) { + this.name = name; + return this; + } + + /** + * Gets the current resource path. + * + * @return The current resource path. + */ + public ResourcePath path() { + return path; + } + + /** + * Sets the resource path for the builder. + * + * @param path The desired resource path. + * @return The current ResourceBuilder instance for method chaining. + */ + public ResourceBuilder path(ResourcePath path) { + this.path = path; + return this; + } + + /** + * Builds and returns a new instance of {@link ResourceFile} based on the builder's configuration. + * + * @return A new ResourceFile instance. + */ + public ResourceFile build() { + return ResourceFile.resource(this.name, this.format, this.options, this.path); + } +} diff --git a/src/main/java/dev/manere/utils/resource/ResourceFile.java b/src/main/java/dev/manere/utils/resource/ResourceFile.java new file mode 100644 index 0000000..03dde13 --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/ResourceFile.java @@ -0,0 +1,212 @@ +package dev.manere.utils.resource; + +import dev.manere.utils.library.Utils; +import dev.manere.utils.resource.format.ResourceFormat; +import dev.manere.utils.resource.format.ResourceFormats; +import dev.manere.utils.resource.path.ResourcePath; +import dev.manere.utils.resource.yaml.ResourceConfiguration; +import dev.manere.utils.scheduler.Schedulers; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +/** + * Represents a resource file with a specified format, options, path, and name. + */ +public class ResourceFile { + private ResourceFormat resourceFormat; + private final ResourceOptions recourseOptions; + private final ResourcePath resourcePath; + private final String name; + + /** + * Constructs a new ResourceFile with the specified name, format, options, and path. + * + * @param name The name of the resource file. + * @param format The format of the resource file. + * @param options The options for the resource file. + * @param path The path where the resource file is located. + */ + public ResourceFile(String name, ResourceFormat format, ResourceOptions options, ResourcePath path) { + this.resourceFormat = format; + this.recourseOptions = options; + this.resourcePath = path; + this.name = name; + + if (!this.resourceFormat.extension().contains(".")) { + this.resourceFormat = ResourceFormat.format("." + this.resourceFormat.extension()); + } + } + + /** + * Creates and returns a new instance of ResourceFile using the provided parameters. + * + * @param name The name of the resource file. + * @param format The format of the resource file. + * @param options The options for the resource file. + * @param path The path where the resource file is located. + * @return A new ResourceFile instance. + */ + public static ResourceFile resource(String name, ResourceFormat format, ResourceOptions options, ResourcePath path) { + return new ResourceFile(name, format, options, path); + } + + /** + * Returns a new instance of {@link ResourceBuilder} for building resource files. + * + * @return A new ResourceBuilder instance. + */ + public static ResourceBuilder builder() { + return ResourceBuilder.builder(); + } + + /** + * Returns a new instance of {@link ResourceConfiguration} for working with YAML configurations. + * + * @return A new ResourceConfiguration instance. + */ + public ResourceConfiguration yaml() { + return new ResourceConfiguration(this); + } + + /** + * Loads and returns the file configuration from the resource file asynchronously. + * + * @return The loaded FileConfiguration. + */ + public FileConfiguration loadYml() { + return (FileConfiguration) Schedulers.async().execute(() -> YamlConfiguration.loadConfiguration(file())); + } + + /** + * Reloads and returns the file configuration from the resource file asynchronously. + * + * @return The reloaded FileConfiguration. + */ + public FileConfiguration reloadYml() { + return loadYml(); + } + + /** + * Asynchronously saves the file configuration to the resource file. + */ + public void saveYml() { + if (Objects.equals(format(), ResourceFormats.yaml()) || Objects.equals(format(), ResourceFormats.yml())) { + Schedulers.async().execute(task -> { + try { + file().mkdirs(); + file().createNewFile(); + + FileConfiguration configuration = YamlConfiguration.loadConfiguration(file()); + configuration.save(file()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } else { + throw new UnsupportedOperationException("only yaml files are supported for saveOrLoad()"); + } + } + + /** + * Asynchronously saves or loads the resource file based on its existence and plugin resources. + * + * @return The current ResourceFile instance. + */ + public ResourceFile saveOrLoadYml() { + if (Objects.equals(format(), ResourceFormats.yaml()) || Objects.equals(format(), ResourceFormats.yml())) { + Schedulers.async().execute(task -> { + if (file().exists()) { + FileConfiguration configuration = YamlConfiguration.loadConfiguration(file()); + return; + } + + if (Utils.plugin().getResource(this.name + this.resourceFormat.extension()) != null) { + Utils.plugin().saveResource(this.resourcePath.path().replaceAll(Utils.plugin().getDataFolder().getPath(), "") + this.name + this.resourceFormat.extension(), false); + } + + try { + if (!file().createNewFile()) { + Utils.plugin().getLogger().severe("Failed to create resource: " + file().getPath()); + task.cancel(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + FileConfiguration configuration = YamlConfiguration.loadConfiguration(file()); + + configuration.options() + .copyDefaults(true) + .parseComments(true) + .pathSeparator('.'); + + if (recourseOptions.header() != null) { + configuration.options().setHeader(recourseOptions.header()); + } + + if (recourseOptions.footer() != null) { + configuration.options().setFooter(recourseOptions.footer()); + } + + try { + configuration.save(file()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } else { + throw new UnsupportedOperationException("only yaml files are supported for saveOrLoad()"); + } + + return this; + } + + /** + * Returns the file associated with the resource file. + * + * @return The file representing the resource file. + */ + public File file() { + return new File(new File(resourcePath.path()), name + resourceFormat.extension()); + } + + /** + * Gets the format of the resource file. + * + * @return The format of the resource file. + */ + public ResourceFormat format() { + return resourceFormat; + } + + /** + * Gets the options for the resource file. + * + * @return The options for the resource file. + */ + public ResourceOptions options() { + return recourseOptions; + } + + /** + * Gets the path where the resource file is located. + * + * @return The path of the resource file. + */ + public ResourcePath path() { + return resourcePath; + } + + /** + * Gets the name of the resource file. + * + * @return The name of the resource file. + */ + public String name() { + return name; + } +} diff --git a/src/main/java/dev/manere/utils/resource/ResourceOptions.java b/src/main/java/dev/manere/utils/resource/ResourceOptions.java new file mode 100644 index 0000000..caf39ae --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/ResourceOptions.java @@ -0,0 +1,115 @@ +package dev.manere.utils.resource; + +import java.util.Arrays; +import java.util.List; + +/** + * Represents options for configuring a resource file, including header, footer, and defaults. + */ +public class ResourceOptions { + private List header; + private List footer; + private boolean defaults; + + /** + * Constructs a new ResourceOptions with the specified header, footer, and defaults. + * + * @param header The header lines for the resource file. + * @param footer The footer lines for the resource file. + * @param defaults Whether to use default options. + */ + public ResourceOptions(List header, List footer, boolean defaults) { + this.header = header; + this.footer = footer; + this.defaults = defaults; + } + + /** + * Constructs a new ResourceOptions with default settings. + */ + public ResourceOptions() { + this.header = null; + this.footer = null; + this.defaults = false; + } + + /** + * Gets the header lines for the resource file. + * + * @return The header lines. + */ + public List header() { + return header; + } + + /** + * Gets the footer lines for the resource file. + * + * @return The footer lines. + */ + public List footer() { + return footer; + } + + /** + * Checks whether default options should be used. + * + * @return True if default options should be used, false otherwise. + */ + public boolean defaults() { + return defaults; + } + + /** + * Sets the header lines for the resource file. + * + * @param header The header lines to set. + * @return The current ResourceOptions instance for method chaining. + */ + public ResourceOptions header(List header) { + this.header = header; + return this; + } + + /** + * Sets the footer lines for the resource file. + * + * @param footer The footer lines to set. + * @return The current ResourceOptions instance for method chaining. + */ + public ResourceOptions footer(List footer) { + this.footer = footer; + return this; + } + + /** + * Sets the header lines for the resource file using varargs. + * + * @param header The header lines to set. + * @return The current ResourceOptions instance for method chaining. + */ + public ResourceOptions header(String... header) { + return header(Arrays.asList(header)); + } + + /** + * Sets the footer lines for the resource file using varargs. + * + * @param footer The footer lines to set. + * @return The current ResourceOptions instance for method chaining. + */ + public ResourceOptions footer(String... footer) { + return footer(Arrays.asList(footer)); + } + + /** + * Sets whether default options should be used. + * + * @param defaults True to use default options, false otherwise. + * @return The current ResourceOptions instance for method chaining. + */ + public ResourceOptions defaults(boolean defaults) { + this.defaults = defaults; + return this; + } +} diff --git a/src/main/java/dev/manere/utils/resource/format/ResourceFormat.java b/src/main/java/dev/manere/utils/resource/format/ResourceFormat.java new file mode 100644 index 0000000..f9fc514 --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/format/ResourceFormat.java @@ -0,0 +1,47 @@ +package dev.manere.utils.resource.format; + +/** + * Represents the format of a resource file, identified by its file extension. + */ +public class ResourceFormat { + private String extension; + + /** + * Constructs a ResourceFormat with the specified file extension. + * + * @param extension The file extension of the resource format. + */ + public ResourceFormat(String extension) { + this.extension = extension; + + if (!this.extension.contains(".")) { + this.extension = "." + extension; + } + } + + /** + * Constructs a ResourceFormat with a default file extension ".yml". + */ + public ResourceFormat() { + this.extension = ".yml"; + } + + /** + * Creates a new ResourceFormat with the specified file extension. + * + * @param extension The file extension of the resource format. + * @return A new ResourceFormat instance. + */ + public static ResourceFormat format(String extension) { + return new ResourceFormat(extension); + } + + /** + * Retrieves the file extension associated with this resource format. + * + * @return The file extension. + */ + public String extension() { + return extension; + } +} diff --git a/src/main/java/dev/manere/utils/resource/format/ResourceFormats.java b/src/main/java/dev/manere/utils/resource/format/ResourceFormats.java new file mode 100644 index 0000000..c2a19e5 --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/format/ResourceFormats.java @@ -0,0 +1,24 @@ +package dev.manere.utils.resource.format; + +/** + * Utility class for obtaining predefined ResourceFormats. + */ +public class ResourceFormats { + /** + * Retrieves a ResourceFormat instance for YAML files with the extension ".yml". + * + * @return A ResourceFormat instance for YAML files. + */ + public static ResourceFormat yml() { + return ResourceFormat.format(".yml"); + } + + /** + * Retrieves a ResourceFormat instance for YAML files with the extension ".yml". + * + * @return A ResourceFormat instance for YAML files. + */ + public static ResourceFormat yaml() { + return ResourceFormat.format(".yml"); + } +} diff --git a/src/main/java/dev/manere/utils/resource/path/ResourcePath.java b/src/main/java/dev/manere/utils/resource/path/ResourcePath.java new file mode 100644 index 0000000..c0a5db0 --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/path/ResourcePath.java @@ -0,0 +1,42 @@ +package dev.manere.utils.resource.path; + +import dev.manere.utils.library.Utils; + +public class ResourcePath { + private final String path; + + /** + * Constructs a ResourcePath with the specified path. + * + * @param path The path to the resource. + */ + public ResourcePath(String path) { + this.path = path; + } + + /** + * Constructs a ResourcePath with the default path derived from the plugin's data folder. + */ + public ResourcePath() { + this.path = Utils.plugin().getDataFolder().getPath(); + } + + /** + * Creates a new ResourcePath with the specified path. + * + * @param path The path to the resource. + * @return A new ResourcePath instance. + */ + public static ResourcePath path(String path) { + return new ResourcePath(path); + } + + /** + * Retrieves the path associated with this resource. + * + * @return The resource path. + */ + public String path() { + return path; + } +} diff --git a/src/main/java/dev/manere/utils/resource/path/ResourcePaths.java b/src/main/java/dev/manere/utils/resource/path/ResourcePaths.java new file mode 100644 index 0000000..6a0739b --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/path/ResourcePaths.java @@ -0,0 +1,40 @@ +package dev.manere.utils.resource.path; + +import dev.manere.utils.library.Utils; +import org.bukkit.plugin.java.JavaPlugin; + +/** + * Utility class for obtaining common ResourcePath instances. + */ +public class ResourcePaths { + /** + * Retrieves a ResourcePath instance representing the plugin's data folder path. + * + * @return A ResourcePath instance for the plugin's data folder. + */ + public static ResourcePath plugin() { + return ResourcePath.path(Utils.plugin().getDataFolder().getPath()); + } + + /** + * Retrieves a ResourcePath instance representing a plugin's data folder path. + * + * @param plugin The JavaPlugin instance whose data folder path is needed. + * @return A ResourcePath instance for the specified plugin's data folder. + */ + public static ResourcePath plugin(JavaPlugin plugin) { + return ResourcePath.path(plugin.getDataFolder().getPath()); + } + + /** + * Retrieves a ResourcePath instance representing the root path of the server. + * + * @return A ResourcePath instance for the root path. + */ + public static ResourcePath root() { + return ResourcePath.path(Utils.plugin() + .getDataFolder() + .getPath() + .replaceAll("plugins/" + Utils.plugin().getName() + "/", "")); + } +} diff --git a/src/main/java/dev/manere/utils/resource/yaml/ResourceConfiguration.java b/src/main/java/dev/manere/utils/resource/yaml/ResourceConfiguration.java new file mode 100644 index 0000000..33cc864 --- /dev/null +++ b/src/main/java/dev/manere/utils/resource/yaml/ResourceConfiguration.java @@ -0,0 +1,336 @@ +package dev.manere.utils.resource.yaml; + +import dev.manere.utils.cachable.Cachable; +import dev.manere.utils.item.ItemBuilder; +import dev.manere.utils.model.Tuple; +import dev.manere.utils.resource.ResourceFile; +import dev.manere.utils.text.color.TextStyle; +import net.kyori.adventure.text.Component; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public record ResourceConfiguration(ResourceFile resourceFile) { + /** + * Retrieves the value associated with the specified key as an Object. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public Object val(String key) { + return bukkit().get(key); + } + + /** + * Retrieves the value associated with the specified key as a String. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public String valAsString(String key) { + return bukkit().getString(key); + } + + /** + * Retrieves the value associated with the specified key as a boolean. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public boolean valAsBoolean(String key) { + return bukkit().getBoolean(key); + } + + /** + * Retrieves the value associated with the specified key as a list of booleans. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsBooleanList(String key) { + return bukkit().getBooleanList(key); + } + + /** + * Retrieves the value associated with the specified key as a list of bytes. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsByteList(String key) { + return bukkit().getByteList(key); + } + + /** + * Retrieves the value associated with the specified key as a list of characters. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsCharacterList(String key) { + return bukkit().getCharacterList(key); + } + + /** + * Retrieves the value associated with the specified key as a {@link Color}. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public Color valAsColor(String key) { + return bukkit().getColor(key); + } + + /** + * Retrieves the value associated with the specified key as a double. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public double valAsDouble(String key) { + return bukkit().getDouble(key); + } + + /** + * Retrieves the value associated with the specified key as a list of doubles. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsDoubleList(String key) { + return bukkit().getDoubleList(key); + } + + /** + * Retrieves the value associated with the specified key as a list of floats. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsFloatList(String key) { + return bukkit().getFloatList(key); + } + + /** + * Retrieves the value associated with the specified key as an int. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public int valAsInt(String key) { + return bukkit().getInt(key); + } + + /** + * Retrieves the value associated with the specified key as a list of ints. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsIntList(String key) { + return bukkit().getIntegerList(key); + } + + /** + * Retrieves the value associated with the specified key as an item stack. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public ItemStack valAsItemStack(String key) { + return bukkit().getItemStack(key); + } + + /** + * Retrieves the value associated with the specified key as a list of ? (any Object). + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsList(String key) { + return bukkit().getList(key); + } + + /** + * Retrieves the value associated with the specified key as a location. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public Location valAsLocation(String key) { + return bukkit().getLocation(key); + } + + /** + * Retrieves the value associated with the specified key as a long. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public long valAsLong(String key) { + return bukkit().getLong(key); + } + + /** + * Retrieves the value associated with the specified key as a list of longs. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsLongList(String key) { + return bukkit().getLongList(key); + } + + /** + * Retrieves the value associated with the specified key as a list of maps of ?, ? (Object, Object). + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List> valAsMapList(String key) { + return bukkit().getMapList(key); + } + + /** + * Retrieves the value associated with the specified key as an Object. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + @SuppressWarnings("unchecked") + public T val(String key, Class clazz) { + if (clazz.getCanonicalName().equals(Component.class.getCanonicalName())) { + return (T) valAsComponent(key); + } + + if (clazz.getCanonicalName().equals(ItemBuilder.class.getCanonicalName())) { + return (T) valAsItemBuilder(key); + } + + return bukkit().getObject(key, clazz); + } + + /** + * Retrieves the value associated with the specified key as an {@link OfflinePlayer}. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public OfflinePlayer valAsOfflinePlayer(String key) { + return bukkit().getOfflinePlayer(key); + } + + /** + * Retrieves the value associated with the specified key as a list of shorts. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsShortList(String key) { + return bukkit().getShortList(key); + } + + /** + * Retrieves the value associated with the specified key as a list of strings. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public List valAsStringList(String key) { + return bukkit().getStringList(key); + } + + /** + * Retrieves the value associated with the specified key as a vector. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public Vector valAsVector(String key) { + return bukkit().getVector(key); + } + + /** + * Retrieves the value associated with the specified key as an item builder. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public ItemBuilder valAsItemBuilder(String key) { + return ItemBuilder.item(valAsItemStack(key)); + } + + /** + * Retrieves the value associated with the specified key as a {@link Component}. + * + * @param key The key to retrieve the value for. + * @return The value associated with the key. + */ + public Component valAsComponent(String key) { + return TextStyle.style(valAsString(key)); + } + + /** + * Sets the value associated with the specified key in the configuration. + * + * @param key The key to set the value for. + * @param val The value to set. + */ + public void set(String key, Object val) { + bukkit().set(key, val); + resourceFile.saveYml(); + } + + /** + * Sets the value associated with the specified key in the configuration. + * + * @param tuple The Tuple to obtain the key and value from. + */ + public void set(Tuple tuple) { + if (tuple != null && tuple.key() != null) { + set(Objects.requireNonNull(tuple.key()), tuple.val()); + } + } + + /** + * Creates and returns a Cachable instance containing key-value pairs from the configuration. + * + * @return Cachable instance containing key-value pairs from the configuration. + */ + public Cachable keyVal() { + Cachable cachable = Cachable.of(); + + for (String key : keys()) { + Object val = bukkit().get(key); + cachable.cache(key, val); + } + + return cachable; + } + + /** + * Retrieves a collection of all keys in the configuration. + * + * @return Collection of all keys in the configuration. + */ + public Collection keys() { + return bukkit().getKeys(false); + } + + /** + * Loads the Bukkit YamlConfiguration associated with this resource file. + * + * @return The loaded YamlConfiguration. + */ + public YamlConfiguration bukkit() { + return (YamlConfiguration) resourceFile.loadYml(); + } +} diff --git a/src/main/java/dev/manere/utils/returnable/PairReturnable.java b/src/main/java/dev/manere/utils/returnable/PairReturnable.java new file mode 100644 index 0000000..aca1c35 --- /dev/null +++ b/src/main/java/dev/manere/utils/returnable/PairReturnable.java @@ -0,0 +1,15 @@ +package dev.manere.utils.returnable; + +/** + * An interface for a functional operation that takes one parameter and returns a value. + * @param the type of the return value + * @param the type of the first parameter + */ +public interface PairReturnable { + /** + * Computes a result based on the given parameter. + * @param firstParam the first parameter + * @return the result of the computation + */ + R returnVal(A firstParam); +} diff --git a/src/main/java/dev/manere/utils/returnable/Returnable.java b/src/main/java/dev/manere/utils/returnable/Returnable.java new file mode 100644 index 0000000..e4073c3 --- /dev/null +++ b/src/main/java/dev/manere/utils/returnable/Returnable.java @@ -0,0 +1,13 @@ +package dev.manere.utils.returnable; + +/** + * An interface for a functional operation that takes no parameters and returns a value. + * @param the type of the return value + */ +public interface Returnable { + /** + * Computes a result without any parameters. + * @return the result of the computation + */ + R returnVal(); +} diff --git a/src/main/java/dev/manere/utils/returnable/TripleReturnable.java b/src/main/java/dev/manere/utils/returnable/TripleReturnable.java new file mode 100644 index 0000000..a465fec --- /dev/null +++ b/src/main/java/dev/manere/utils/returnable/TripleReturnable.java @@ -0,0 +1,17 @@ +package dev.manere.utils.returnable; + +/** + * An interface for a functional operation that takes two parameters and returns a value. + * @param the type of the return value + * @param the type of the first parameter + * @param the type of the second parameter + */ +public interface TripleReturnable { + /** + * Computes a result based on the given parameters. + * @param firstParam the first parameter + * @param secondParam the second parameter + * @return the result of the computation + */ + R returnVal(A firstParam, B secondParam); +} diff --git a/src/main/java/dev/manere/utils/scheduler/AsyncScheduler.java b/src/main/java/dev/manere/utils/scheduler/AsyncScheduler.java deleted file mode 100644 index 0bf6587..0000000 --- a/src/main/java/dev/manere/utils/scheduler/AsyncScheduler.java +++ /dev/null @@ -1,75 +0,0 @@ -package dev.manere.utils.scheduler; - -import dev.manere.utils.library.Utils; -import dev.manere.utils.server.ServerUtils; -import org.bukkit.scheduler.BukkitTask; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -/** - * The AsyncScheduler class provides methods for scheduling tasks to run asynchronously. - * This class is designed for use in Spigot plugins. - */ -public class AsyncScheduler { - - /** - * Schedules a task to run asynchronously. - * - * @param task The task to be scheduled. - */ - public void now(@NotNull Consumer task) { - ServerUtils.scheduler().runTaskAsynchronously(Utils.plugin(), task); - } - - /** - * Schedules a runnable to run asynchronously. - * - * @param runnable The runnable to be scheduled. - */ - public void now(@NotNull Runnable runnable) { - ServerUtils.scheduler().runTaskAsynchronously(Utils.plugin(), runnable); - } - - /** - * Schedules a task to run asynchronously after a specified delay. - * - * @param runnable The task to be scheduled. - * @param after The delay (in ticks) before the task runs. - */ - public void later(@NotNull Consumer runnable, long after) { - ServerUtils.scheduler().runTaskLaterAsynchronously(Utils.plugin(), runnable, after); - } - - /** - * Schedules a runnable to run asynchronously after a specified delay. - * - * @param runnable The runnable to be scheduled. - * @param after The delay (in ticks) before the runnable runs. - */ - public void later(@NotNull Runnable runnable, long after) { - ServerUtils.scheduler().runTaskLaterAsynchronously(Utils.plugin(), runnable, after); - } - - /** - * Schedules a task to run asynchronously repeatedly, starting after a specified delay. - * - * @param task The task to be scheduled. - * @param after The delay (in ticks) before the first execution. - * @param every The interval (in ticks) between subsequent executions. - */ - public void repeating(@NotNull Consumer task, long after, long every) { - ServerUtils.scheduler().runTaskTimerAsynchronously(Utils.plugin(), task, after, every); - } - - /** - * Schedules a runnable to run asynchronously repeatedly, starting after a specified delay. - * - * @param runnable The runnable to be scheduled. - * @param after The delay (in ticks) before the first execution. - * @param every The interval (in ticks) between subsequent executions. - */ - public void repeating(@NotNull Runnable runnable, long after, long every) { - ServerUtils.scheduler().runTaskTimerAsynchronously(Utils.plugin(), runnable, after, every); - } -} diff --git a/src/main/java/dev/manere/utils/scheduler/SchedulerBase.java b/src/main/java/dev/manere/utils/scheduler/SchedulerBase.java new file mode 100644 index 0000000..5e5e66c --- /dev/null +++ b/src/main/java/dev/manere/utils/scheduler/SchedulerBase.java @@ -0,0 +1,118 @@ +package dev.manere.utils.scheduler; + +import dev.manere.utils.library.Utils; +import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; +import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * An abstract base class for custom schedulers. + * This class provides access to various Bukkit/Paper schedulers and Folia region-related schedulers. + */ +public abstract class SchedulerBase { + private final BukkitScheduler scheduler = Utils.plugin().getServer().getScheduler(); + private final RegionScheduler regionScheduler = Utils.plugin().getServer().getRegionScheduler(); + private final GlobalRegionScheduler globalRegionScheduler = Utils.plugin().getServer().getGlobalRegionScheduler(); + private final AsyncScheduler asyncFoliaScheduler = Utils.plugin().getServer().getAsyncScheduler(); + + /** + * Executes a task using the Bukkit scheduler. + * + * @param task The task to be executed. + */ + public abstract void execute(@NotNull Consumer task); + + /** + * Executes a runnable task using the Bukkit scheduler. + * + * @param runnable The runnable task to be executed. + */ + public abstract void execute(@NotNull Runnable runnable); + + /** + * Executes a task using the Bukkit scheduler after a specified number of ticks. + * + * @param task The task to be executed. + * @param afterTicks The number of ticks to wait before execution. + */ + public abstract void execute(@NotNull Consumer task, int afterTicks); + + /** + * Executes a runnable task using the Bukkit scheduler after a specified number of ticks. + * + * @param runnable The runnable task to be executed. + * @param afterTicks The number of ticks to wait before execution. + */ + public abstract void execute(@NotNull Runnable runnable, int afterTicks); + + /** + * Executes a task using the Bukkit scheduler after a specified number of ticks, + * and then repeats the task every specified number of ticks. + * + * @param task The task to be executed. + * @param afterTicks The number of ticks to wait before the first execution. + * @param everyTicks The number of ticks between each repeated execution. + */ + public abstract void execute(@NotNull Consumer task, int afterTicks, int everyTicks); + + /** + * Executes a runnable task using the Bukkit scheduler after a specified number of ticks, + * and then repeats the task every specified number of ticks. + * + * @param runnable The runnable task to be executed. + * @param afterTicks The number of ticks to wait before the first execution. + * @param everyTicks The number of ticks between each repeated execution. + */ + public abstract void execute(@NotNull Runnable runnable, int afterTicks, int everyTicks); + + /** + * Executes a supplier task and returns the result. + * + * @param supplier The supplier task to be executed. + * @return The result of the supplier task. + */ + public abstract @Nullable Object execute(@NotNull Supplier supplier); + + /** + * Retrieves the Bukkit scheduler associated with this scheduler. + * + * @return The Bukkit scheduler. + */ + public final @NotNull BukkitScheduler scheduler() { + return scheduler; + } + + /** + * Retrieves the region scheduler associated with this scheduler. + * + * @return The region scheduler. + */ + public final @NotNull RegionScheduler regionScheduler() { + return regionScheduler; + } + + /** + * Retrieves the global region scheduler associated with this scheduler. + * + * @return The global region scheduler. + */ + public final @NotNull GlobalRegionScheduler globalRegionScheduler() { + return globalRegionScheduler; + } + + /** + * Retrieves the asynchronous Folia scheduler associated with this scheduler. + * + * @return The asynchronous Folia scheduler. + */ + public final @NotNull AsyncScheduler asyncFoliaScheduler() { + return asyncFoliaScheduler; + } +} diff --git a/src/main/java/dev/manere/utils/scheduler/Schedulers.java b/src/main/java/dev/manere/utils/scheduler/Schedulers.java index 2aa7606..13e57ed 100644 --- a/src/main/java/dev/manere/utils/scheduler/Schedulers.java +++ b/src/main/java/dev/manere/utils/scheduler/Schedulers.java @@ -1,14 +1,20 @@ package dev.manere.utils.scheduler; +import dev.manere.utils.scheduler.async.AsyncScheduler; import dev.manere.utils.scheduler.builder.SchedulerBuilder; import dev.manere.utils.scheduler.stacker.SchedulerStacker; +import dev.manere.utils.scheduler.sync.SyncScheduler; +import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; /** * This class provides methods for retrieving scheduler types. */ public class Schedulers { - /** * Create and return a new instance of a synchronous scheduler. * @@ -46,20 +52,85 @@ public class Schedulers { } /** - * Creates a new instance of SchedulerBuilder. + * Create and return a new instance of a scheduler builder. * - * @return A new instance of SchedulerBuilder. + * @return A new instance of a scheduler builder. */ public static @NotNull SchedulerBuilder builder() { - return SchedulerBuilder.scheduler(); + return new SchedulerBuilder(); + } + + /** + * Create and return a new instance of a scheduler builder. + * + * @return A new instance of a scheduler builder. + */ + public static @NotNull SchedulerBuilder builder(@Nullable Runnable runnable) { + if (runnable != null) { + return new SchedulerBuilder(runnable); + } + + return new SchedulerBuilder(); + } + + /** + * Create and return a new instance of a scheduler builder. + * + * @return A new instance of a scheduler builder. + */ + public static @NotNull SchedulerBuilder builder(@Nullable Consumer task) { + if (task != null) { + return new SchedulerBuilder(task); + } + + return new SchedulerBuilder(); } /** - * Creates a new instance of SchedulerStacker. + * Create and return a new instance of a scheduler stacker. * - * @return A new instance of SchedulerStacker. + * @return A new instance of a scheduler stacker. */ public static @NotNull SchedulerStacker stacker() { - return SchedulerStacker.stacker(); + return new SchedulerStacker(); + } + + public static SchedulerBase base() { + return new SchedulerBase() { + @Override + public void execute(@NotNull Consumer task) { + Schedulers.sync().execute(task); + } + + @Override + public void execute(@NotNull Runnable runnable) { + Schedulers.sync().execute(runnable); + } + + @Override + public void execute(@NotNull Consumer task, int afterTicks) { + Schedulers.sync().execute(task, afterTicks); + } + + @Override + public void execute(@NotNull Runnable runnable, int afterTicks) { + Schedulers.sync().execute(runnable, afterTicks); + } + + @Override + public void execute(@NotNull Consumer task, int afterTicks, int everyTicks) { + Schedulers.sync().execute(task, afterTicks, everyTicks); + } + + @Override + public void execute(@NotNull Runnable runnable, int afterTicks, int everyTicks) { + Schedulers.sync().execute(runnable, afterTicks, everyTicks); + } + + @Override + public @Nullable Object execute(@NotNull Supplier supplier) { + return Schedulers.sync().execute(supplier); + } + }; } } diff --git a/src/main/java/dev/manere/utils/scheduler/SyncScheduler.java b/src/main/java/dev/manere/utils/scheduler/SyncScheduler.java deleted file mode 100644 index facc8cd..0000000 --- a/src/main/java/dev/manere/utils/scheduler/SyncScheduler.java +++ /dev/null @@ -1,75 +0,0 @@ -package dev.manere.utils.scheduler; - -import dev.manere.utils.library.Utils; -import dev.manere.utils.server.ServerUtils; -import org.bukkit.scheduler.BukkitTask; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -/** - * The SyncScheduler class provides methods for scheduling tasks to run synchronously. - * This class is designed for use in Spigot plugins. - */ -public class SyncScheduler { - - /** - * Schedules a task to run synchronously. - * - * @param task The task to be scheduled. - */ - public void now(@NotNull Consumer task) { - ServerUtils.scheduler().runTask(Utils.plugin(), task); - } - - /** - * Schedules a runnable to run synchronously. - * - * @param runnable The runnable to be scheduled. - */ - public void now(@NotNull Runnable runnable) { - ServerUtils.scheduler().runTask(Utils.plugin(), runnable); - } - - /** - * Schedules a task to run synchronously after a specified delay. - * - * @param runnable The task to be scheduled. - * @param after The delay (in ticks) before the task runs. - */ - public void later(Consumer runnable, long after) { - ServerUtils.scheduler().runTaskLater(Utils.plugin(), runnable, after); - } - - /** - * Schedules a runnable to run synchronously after a specified delay. - * - * @param runnable The runnable to be scheduled. - * @param after The delay (in ticks) before the runnable runs. - */ - public void later(@NotNull Runnable runnable, long after) { - ServerUtils.scheduler().runTaskLater(Utils.plugin(), runnable, after); - } - - /** - * Schedules a task to run synchronously repeatedly, starting after a specified delay. - * - * @param task The task to be scheduled. - * @param after The delay (in ticks) before the first execution. - * @param every The interval (in ticks) between subsequent executions. - */ - public void repeating(@NotNull Consumer task, long after, long every) { - ServerUtils.scheduler().runTaskTimer(Utils.plugin(), task, after, every); - } - - /** - * Schedules a runnable to run synchronously repeatedly, starting after a specified delay. - * - * @param runnable The runnable to be scheduled. - * @param after The delay (in ticks) before the first execution. - * @param every The interval (in ticks) between subsequent executions. - */ - public void repeating(@NotNull Runnable runnable, long after, long every) { - ServerUtils.scheduler().runTaskTimer(Utils.plugin(), runnable, after, every); - } -} diff --git a/src/main/java/dev/manere/utils/scheduler/TickTimes.java b/src/main/java/dev/manere/utils/scheduler/TickTimes.java index 8bb9b38..50310bc 100644 --- a/src/main/java/dev/manere/utils/scheduler/TickTimes.java +++ b/src/main/java/dev/manere/utils/scheduler/TickTimes.java @@ -1,6 +1,7 @@ package dev.manere.utils.scheduler; -import dev.manere.utils.scheduler.builder.SchedulerBuilder; +import dev.manere.utils.scheduler.async.AsyncScheduler; +import dev.manere.utils.scheduler.sync.SyncScheduler; import org.jetbrains.annotations.NotNull; import java.util.concurrent.TimeUnit; @@ -22,7 +23,6 @@ * @see Schedulers * @see AsyncScheduler * @see SyncScheduler - * @see SchedulerBuilder */ @SuppressWarnings("SameReturnValue") public class TickTimes { diff --git a/src/main/java/dev/manere/utils/scheduler/async/AsyncScheduler.java b/src/main/java/dev/manere/utils/scheduler/async/AsyncScheduler.java new file mode 100644 index 0000000..bc95924 --- /dev/null +++ b/src/main/java/dev/manere/utils/scheduler/async/AsyncScheduler.java @@ -0,0 +1,77 @@ +package dev.manere.utils.scheduler.async; + +import dev.manere.utils.library.Utils; +import dev.manere.utils.scheduler.SchedulerBase; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * An asynchronous scheduler wrapper for {@link SchedulerBase}. + */ +public class AsyncScheduler extends SchedulerBase { + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Consumer task) { + scheduler().runTaskAsynchronously(Utils.plugin(), task); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Runnable runnable) { + scheduler().runTaskAsynchronously(Utils.plugin(), runnable); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Consumer task, int afterTicks) { + scheduler().runTaskLaterAsynchronously(Utils.plugin(), task, afterTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Runnable runnable, int afterTicks) { + scheduler().runTaskLaterAsynchronously(Utils.plugin(), runnable, afterTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Consumer task, int afterTicks, int everyTicks) { + scheduler().runTaskTimerAsynchronously(Utils.plugin(), task, afterTicks, everyTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Runnable runnable, int afterTicks, int everyTicks) { + scheduler().runTaskTimerAsynchronously(Utils.plugin(), runnable, afterTicks, everyTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable Object execute(@NotNull Supplier supplier) { + try { + return CompletableFuture.supplyAsync(supplier).get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/dev/manere/utils/scheduler/builder/SchedulerBuilder.java b/src/main/java/dev/manere/utils/scheduler/builder/SchedulerBuilder.java index ff28953..5c1cc2c 100644 --- a/src/main/java/dev/manere/utils/scheduler/builder/SchedulerBuilder.java +++ b/src/main/java/dev/manere/utils/scheduler/builder/SchedulerBuilder.java @@ -1,177 +1,208 @@ package dev.manere.utils.scheduler.builder; -import dev.manere.utils.library.Utils; +import dev.manere.utils.scheduler.Schedulers; +import dev.manere.utils.scheduler.builder.task.SchedulerTask; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; /** - * Utility class for building Bukkit scheduler tasks. + * SchedulerBuilder is a class for building and executing scheduled tasks + * with customizable configurations using SchedulerConfig and SchedulerTask. + * It provides methods for configuring the task and execution details. */ public class SchedulerBuilder { - private boolean asynchronous; - private long delay; - private long period; - private Consumer task; - private TaskType type; + private SchedulerTask schedulerTask; + private final @NotNull SchedulerConfig config; /** - * Constructs a new @NotNull SchedulerBuilder with default settings. + * Constructs a new SchedulerBuilder with default values. */ public SchedulerBuilder() { - this.asynchronous = false; - this.delay = 0; - this.period = 0; - this.task = null; - this.type = TaskType.NORMAL; + this.config = new SchedulerConfig(); + this.schedulerTask = null; } /** - * Creates a new instance of SchedulerBuilder. + * Constructs a new SchedulerBuilder with a provided runnable. * - * @return A new instance of SchedulerBuilder. + * @param runnable The runnable task to be scheduled. */ - public static @NotNull SchedulerBuilder scheduler() { - return new SchedulerBuilder(); + public SchedulerBuilder(@NotNull Runnable runnable) { + this.config = new SchedulerConfig(); + this.schedulerTask = SchedulerTask.wrap(runnable); } /** - * Sets whether the task should be executed asynchronously. + * Constructs a new SchedulerBuilder with a provided task consumer. * - * @param async true if the task should be asynchronous, false otherwise. - * @return This @NotNull SchedulerBuilder for method chaining. + * @param task The task consumer to be scheduled. */ - public @NotNull SchedulerBuilder async(boolean async) { - this.asynchronous = async; - return this; + public SchedulerBuilder(@NotNull Consumer task) { + this.config = new SchedulerConfig(); + this.schedulerTask = SchedulerTask.wrap(task); } /** - * Sets the delay and period (in ticks) of the task. + * Configures the SchedulerConfig using a consumer. * - * @param delay The delay (in ticks). - * @param period The period (in ticks). - * @return This @NotNull SchedulerBuilder for method chaining. + * @param configConsumer The consumer for configuring SchedulerConfig. + * @return This SchedulerBuilder instance for method chaining. */ - public @NotNull SchedulerBuilder time(long delay, long period) { - this.delay = delay; - this.period = period; + public @NotNull SchedulerBuilder config(@NotNull Consumer configConsumer) { + configConsumer.accept(this.config); return this; } /** - * Sets the delay (in ticks) before the task starts. + * Sets the thread type to asynchronous. * - * @param delay The delay (in ticks). - * @return This @NotNull SchedulerBuilder for method chaining. + * @return This SchedulerBuilder instance for method chaining. */ - public @NotNull SchedulerBuilder after(long delay) { - this.delay = delay; + public @NotNull SchedulerBuilder async() { + this.config.async(); return this; } /** - * Sets the type of the task. + * Sets the thread type to synchronous. * - * @param type The type of the task. - * @return This @NotNull SchedulerBuilder for method chaining. + * @return This SchedulerBuilder instance for method chaining. */ - public @NotNull SchedulerBuilder type(TaskType type) { - this.type = type; + public @NotNull SchedulerBuilder sync() { + this.config.sync(); return this; } /** - * Sets the period (in ticks) between task executions for repeating tasks. + * Sets the interval between repeated executions in ticks. * - * @param period The period (in ticks). - * @return This @NotNull SchedulerBuilder for method chaining. + * @param everyTicks The number of ticks between each repeated execution. + * @return This SchedulerBuilder instance for method chaining. */ - public @NotNull SchedulerBuilder every(long period) { - this.period = period; + public @NotNull SchedulerBuilder everyTicks(int everyTicks) { + this.config.everyTicks(everyTicks); return this; } /** - * Sets the task to be executed. + * Sets the delay before the first execution in ticks. * - * @param task The task to be executed. - * @return This @NotNull SchedulerBuilder for method chaining. + * @param afterTicks The number of ticks to wait before the first execution. + * @return This SchedulerBuilder instance for method chaining. */ - public @NotNull SchedulerBuilder task(Consumer task) { - this.task = task; + public @NotNull SchedulerBuilder afterTicks(int afterTicks) { + this.config.afterTicks(afterTicks); return this; } /** - * Builds and schedules the task according to the provided settings. - * If the task is null, nothing is scheduled. - */ - public void build() { - if (task == null) return; - - if (type == TaskType.NORMAL) { - if (asynchronous) Utils.plugin().getServer().getScheduler().runTaskAsynchronously(Utils.plugin(), task); - - else Utils.plugin().getServer().getScheduler().runTask(Utils.plugin(), task); - } - - if (type == TaskType.LATER) { - if (asynchronous) Utils.plugin().getServer().getScheduler().runTaskLaterAsynchronously(Utils.plugin(), task, delay); - - else Utils.plugin().getServer().getScheduler().runTaskLater(Utils.plugin(), task, delay); - } - - if (type == TaskType.REPEATING) { - if (asynchronous) Utils.plugin().getServer().getScheduler().runTaskTimerAsynchronously(Utils.plugin(), task, delay, period); - - else Utils.plugin().getServer().getScheduler().runTaskTimer(Utils.plugin(), task, delay, period); - } - } - - /** - * Returns whether the task will be executed asynchronously. + * Sets the runnable task. * - * @return true if the task is asynchronous, false otherwise. + * @param runnable The runnable task to be scheduled. + * @return This SchedulerBuilder instance for method chaining. */ - public boolean isAsynchronous() { - return asynchronous; - } - - /** - * Returns the delay (in ticks) before the task starts. - * - * @return The delay (in ticks). - */ - public long delay() { - return delay; - } - - /** - * Returns the period (in ticks) between task executions for repeating tasks. - * - * @return The period (in ticks). - */ - public long period() { - return period; + public @NotNull SchedulerBuilder runnable(@NotNull Runnable runnable) { + this.schedulerTask = SchedulerTask.wrap(runnable); + return this; } /** - * Returns the task to be executed. + * Sets the task consumer. * - * @return The task to be executed. + * @param task The task consumer to be scheduled. + * @return This SchedulerBuilder instance for method chaining. */ - public Consumer task() { - return task; + public @NotNull SchedulerBuilder task(@NotNull Consumer task) { + this.schedulerTask = SchedulerTask.wrap(task); + return this; } /** - * Returns the type of the task. - * - * @return The type of the task. + * Executes the scheduled task based on the configured options. */ - public TaskType type() { - return type; + @SuppressWarnings("unchecked") + public void execute() { + switch (config.threadType()) { + case SYNC -> { + // Immediate, SYNC + if (config.everyTicks() == null && config.afterTicks() == null) { + if (schedulerTask.appropriate() instanceof Consumer consumer) { + Consumer taskConsumer = (Consumer) consumer; + Schedulers.sync().execute(taskConsumer); + } else if (schedulerTask.appropriate() instanceof Runnable runnable) { + Schedulers.sync().execute(runnable); + } + + break; + } + + // Delayed, SYNC + if (config.everyTicks() == null && config.afterTicks() != null) { + if (schedulerTask.appropriate() instanceof Consumer consumer) { + Consumer taskConsumer = (Consumer) consumer; + Schedulers.sync().execute(taskConsumer, config.afterTicks()); + } else if (schedulerTask.appropriate() instanceof Runnable runnable) { + Schedulers.sync().execute(runnable, config.afterTicks()); + } + + break; + } + + // Timer, SYNC + if (config.everyTicks() != null && config.afterTicks() != null) { + if (schedulerTask.appropriate() instanceof Consumer consumer) { + Consumer taskConsumer = (Consumer) consumer; + Schedulers.sync().execute(taskConsumer, config.afterTicks(), config.everyTicks()); + } else if (schedulerTask.appropriate() instanceof Runnable runnable) { + Schedulers.sync().execute(runnable, config.afterTicks(), config.everyTicks()); + } + + break; + } + + throw new UnsupportedOperationException("Not supported"); + } + case ASYNC -> { + // Immediate, SYNC + if (config.everyTicks() == null && config.afterTicks() == null) { + if (schedulerTask.appropriate() instanceof Consumer consumer) { + Consumer taskConsumer = (Consumer) consumer; + Schedulers.async().execute(taskConsumer); + } else if (schedulerTask.appropriate() instanceof Runnable runnable) { + Schedulers.async().execute(runnable); + } + + break; + } + + // Delayed, SYNC + if (config.everyTicks() == null && config.afterTicks() != null) { + if (schedulerTask.appropriate() instanceof Consumer consumer) { + Consumer taskConsumer = (Consumer) consumer; + Schedulers.async().execute(taskConsumer, config.afterTicks()); + } else if (schedulerTask.appropriate() instanceof Runnable runnable) { + Schedulers.async().execute(runnable, config.afterTicks()); + } + + break; + } + + // Timer, SYNC + if (config.everyTicks() != null && config.afterTicks() != null) { + if (schedulerTask.appropriate() instanceof Consumer consumer) { + Consumer taskConsumer = (Consumer) consumer; + Schedulers.async().execute(taskConsumer, config.afterTicks(), config.everyTicks()); + } else if (schedulerTask.appropriate() instanceof Runnable runnable) { + Schedulers.async().execute(runnable, config.afterTicks(), config.everyTicks()); + } + + break; + } + + throw new UnsupportedOperationException("Not supported"); + } + } } } diff --git a/src/main/java/dev/manere/utils/scheduler/builder/SchedulerConfig.java b/src/main/java/dev/manere/utils/scheduler/builder/SchedulerConfig.java new file mode 100644 index 0000000..313bb10 --- /dev/null +++ b/src/main/java/dev/manere/utils/scheduler/builder/SchedulerConfig.java @@ -0,0 +1,103 @@ +package dev.manere.utils.scheduler.builder; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * SchedulerConfig represents the configuration options for scheduling tasks. + * It includes parameters such as everyTicks, afterTicks, and threadType. + */ +public class SchedulerConfig { + private @Nullable Integer everyTicks; + private @Nullable Integer afterTicks; + private @NotNull SchedulerThreadType threadType; + + /** + * Constructs a new SchedulerConfig with default values. + */ + public SchedulerConfig() { + this.everyTicks = null; + this.afterTicks = null; + this.threadType = SchedulerThreadType.SYNC; + } + + /** + * Gets the value of everyTicks. + * + * @return The value of everyTicks. + */ + public @Nullable Integer everyTicks() { + return everyTicks; + } + + /** + * Sets the value of everyTicks. + * + * @param everyTicks The value to set for everyTicks. + * @return This SchedulerConfig instance for method chaining. + */ + public @NotNull SchedulerConfig everyTicks(@Nullable Integer everyTicks) { + this.everyTicks = everyTicks; + return this; + } + + /** + * Gets the value of afterTicks. + * + * @return The value of afterTicks. + */ + public @Nullable Integer afterTicks() { + return afterTicks; + } + + /** + * Sets the value of afterTicks. + * + * @param afterTicks The value to set for afterTicks. + * @return This SchedulerConfig instance for method chaining. + */ + public @NotNull SchedulerConfig afterTicks(@Nullable Integer afterTicks) { + this.afterTicks = afterTicks; + return this; + } + + /** + * Sets the thread type to asynchronous. + * + * @return This SchedulerConfig instance for method chaining. + */ + public @NotNull SchedulerConfig async() { + this.threadType = SchedulerThreadType.ASYNC; + return this; + } + + /** + * Sets the thread type to synchronous. + * + * @return This SchedulerConfig instance for method chaining. + */ + public @NotNull SchedulerConfig sync() { + this.threadType = SchedulerThreadType.SYNC; + return this; + } + + /** + * Gets the thread type. + * + * @return The thread type. + */ + public @NotNull SchedulerThreadType threadType() { + return threadType; + } + + /** + * Sets the thread type. + * + * @param threadType The thread type to set. + * @return This SchedulerConfig instance for method chaining. + */ + public @NotNull SchedulerConfig threadType(@NotNull SchedulerThreadType threadType) { + this.threadType = threadType; + return this; + } +} diff --git a/src/main/java/dev/manere/utils/scheduler/builder/SchedulerThreadType.java b/src/main/java/dev/manere/utils/scheduler/builder/SchedulerThreadType.java new file mode 100644 index 0000000..703f331 --- /dev/null +++ b/src/main/java/dev/manere/utils/scheduler/builder/SchedulerThreadType.java @@ -0,0 +1,16 @@ +package dev.manere.utils.scheduler.builder; + +/** + * An enumeration representing the types of threads for scheduling tasks. + */ +public enum SchedulerThreadType { + /** + * Synchronous execution on the main server thread. + */ + SYNC, + + /** + * Asynchronous execution on a separate thread. + */ + ASYNC +} diff --git a/src/main/java/dev/manere/utils/scheduler/builder/TaskType.java b/src/main/java/dev/manere/utils/scheduler/builder/TaskType.java deleted file mode 100644 index 530979a..0000000 --- a/src/main/java/dev/manere/utils/scheduler/builder/TaskType.java +++ /dev/null @@ -1,22 +0,0 @@ -package dev.manere.utils.scheduler.builder; - -/** - * Enumeration representing different types of scheduler tasks. - */ -public enum TaskType { - - /** - * Represents a normal, one-time execution task. - */ - NORMAL, - - /** - * Represents a task that repeats at a fixed interval. - */ - REPEATING, - - /** - * Represents a task that executes after a specified delay. - */ - LATER -} diff --git a/src/main/java/dev/manere/utils/scheduler/builder/task/SchedulerTask.java b/src/main/java/dev/manere/utils/scheduler/builder/task/SchedulerTask.java new file mode 100644 index 0000000..676cadf --- /dev/null +++ b/src/main/java/dev/manere/utils/scheduler/builder/task/SchedulerTask.java @@ -0,0 +1,99 @@ +package dev.manere.utils.scheduler.builder.task; + +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * SchedulerTask is a utility class representing a task to be scheduled. + * It can encapsulate either a runnable or a task consumer. + */ +public class SchedulerTask { + private final @Nullable Runnable runnable; + private final @Nullable Consumer task; + + /** + * Constructs a new SchedulerTask with default values. + */ + public SchedulerTask() { + this.runnable = null; + this.task = null; + } + + /** + * Constructs a new SchedulerTask with a provided runnable. + * + * @param runnable The runnable task to be scheduled. + */ + public SchedulerTask(@Nullable Runnable runnable) { + this.runnable = runnable; + this.task = null; + } + + /** + * Constructs a new SchedulerTask with a provided task consumer. + * + * @param task The task consumer to be scheduled. + */ + public SchedulerTask(@Nullable Consumer task) { + this.task = task; + this.runnable = null; + } + + /** + * Wraps a provided runnable into a SchedulerTask. + * + * @param runnable The runnable to be wrapped. + * @return The wrapped SchedulerTask. + */ + public static @NotNull SchedulerTask wrap(@Nullable Runnable runnable) { + return new SchedulerTask(runnable); + } + + /** + * Wraps a provided task consumer into a SchedulerTask. + * + * @param task The task consumer to be wrapped. + * @return The wrapped SchedulerTask. + */ + public static @NotNull SchedulerTask wrap(@Nullable Consumer task) { + return new SchedulerTask(task); + } + + /** + * Gets the runnable task. + * + * @return The runnable task, or null if not set. + */ + public @Nullable Runnable runnable() { + return runnable; + } + + /** + * Gets the task consumer. + * + * @return The task consumer, or null if not set. + */ + public @Nullable Consumer task() { + return task; + } + + /** + * Gets the appropriate object based on the set values (runnable or task). + * + * @return The appropriate object, or null if neither is set. + */ + public @Nullable Object appropriate() { + if (task == null && runnable != null) { + return runnable; + } + + if (runnable == null && task != null) { + return task; + } + + return null; + } +} diff --git a/src/main/java/dev/manere/utils/scheduler/stacker/SchedulerStacker.java b/src/main/java/dev/manere/utils/scheduler/stacker/SchedulerStacker.java index efb2651..13e3cb1 100644 --- a/src/main/java/dev/manere/utils/scheduler/stacker/SchedulerStacker.java +++ b/src/main/java/dev/manere/utils/scheduler/stacker/SchedulerStacker.java @@ -1,166 +1,67 @@ package dev.manere.utils.scheduler.stacker; -import dev.manere.utils.scheduler.AsyncScheduler; -import dev.manere.utils.scheduler.Schedulers; -import dev.manere.utils.scheduler.SyncScheduler; -import dev.manere.utils.scheduler.TickTimes; import dev.manere.utils.scheduler.builder.SchedulerBuilder; -import dev.manere.utils.scheduler.builder.TaskType; -import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; -import java.util.function.Consumer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** - * A utility class for stacking synchronous and asynchronous Bukkit scheduler tasks. - * Allows chaining multiple tasks with different timing options. - * - * @see SchedulerBuilder - * @see AsyncScheduler - * @see SyncScheduler - * @see TickTimes - * @see Schedulers - * @see TaskType + * SchedulerStacker is a utility class that allows the stacking of multiple {@link SchedulerBuilder} instances + * for efficient execution of scheduled tasks. It provides methods to stack individual builders, a list of builders, + * or an array of builders. The stacked builders can then be executed in sequence using the {@code execute} method. */ public class SchedulerStacker { + private final @NotNull List builders; /** - * Creates a new instance of SchedulerStacker. - * @return A new @NotNull SchedulerStacker instance. + * Constructs a new SchedulerStacker with an empty list of builders. */ - public static @NotNull SchedulerStacker stacker() { - return new SchedulerStacker(); + public SchedulerStacker() { + this.builders = new ArrayList<>(); } /** - * Adds an asynchronous task to the scheduler. - * @param task The asynchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. + * Stacks a single {@link SchedulerBuilder} instance onto the list of builders. + * + * @param builder The SchedulerBuilder to be stacked. + * @return This SchedulerStacker instance for method chaining. */ - public @NotNull SchedulerStacker thenAsync(@NotNull Consumer task) { - Schedulers.async().now(task); + public @NotNull SchedulerStacker stack(@NotNull SchedulerBuilder builder) { + this.builders.add(builder); return this; } /** - * Adds an asynchronous task to the scheduler. - * @param task The asynchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. + * Stacks a list of {@link SchedulerBuilder} instances onto the list of builders. + * + * @param builders The list of SchedulerBuilders to be stacked. + * @return This SchedulerStacker instance for method chaining. */ - public @NotNull SchedulerStacker thenAsync(@NotNull Runnable task) { - Schedulers.async().now(task); + public @NotNull SchedulerStacker stack(@NotNull List builders) { + this.builders.addAll(builders); return this; } /** - * Adds a synchronous task to the scheduler. - * @param task The synchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. + * Stacks an array of {@link SchedulerBuilder} instances onto the list of builders. + * + * @param builders The array of SchedulerBuilders to be stacked. + * @return This SchedulerStacker instance for method chaining. */ - public @NotNull SchedulerStacker then(@NotNull Consumer task) { - Schedulers.sync().now(task); + public @NotNull SchedulerStacker stack(@NotNull SchedulerBuilder... builders) { + this.builders.addAll(Arrays.asList(builders)); return this; } /** - * Adds a synchronous task to the scheduler. - * @param task The synchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. + * Executes each stacked {@link SchedulerBuilder} in sequence, triggering the execution + * of their respective scheduled tasks. */ - public @NotNull SchedulerStacker then(@NotNull Runnable task) { - Schedulers.sync().now(task); - return this; - } - - /** - * Adds an asynchronous delayed task to the scheduler. - * @param after The delay before the task is executed, in server ticks. - * @param task The asynchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker thenAsync(long after, @NotNull Consumer task) { - Schedulers.async().later(task, after); - return this; - } - - /** - * Adds an asynchronous delayed task to the scheduler. - * @param after The delay before the task is executed, in server ticks. - * @param task The asynchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker thenAsync(long after, @NotNull Runnable task) { - Schedulers.async().later(task, after); - return this; - } - - /** - * Adds a synchronous delayed task to the scheduler. - * @param after The delay before the task is executed, in server ticks. - * @param task The synchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker then(long after, @NotNull Consumer task) { - Schedulers.sync().later(task, after); - return this; - } - - /** - * Adds a synchronous delayed task to the scheduler. - * @param after The delay before the task is executed, in server ticks. - * @param task The synchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker then(long after, @NotNull Runnable task) { - Schedulers.sync().later(task, after); - return this; - } - - /** - * Adds an asynchronous repeating task to the scheduler. - * @param after The delay before the first execution, in server ticks. - * @param every The time between successive executions, in server ticks. - * @param task The asynchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker thenAsync(long after, long every, @NotNull Consumer task) { - Schedulers.async().repeating(task, after, every); - return this; - } - - /** - * Adds an asynchronous repeating task to the scheduler. - * @param after The delay before the first execution, in server ticks. - * @param every The time between successive executions, in server ticks. - * @param task The asynchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker thenAsync(long after, long every, @NotNull Runnable task) { - Schedulers.async().repeating(task, after, every); - return this; - } - - /** - * Adds a synchronous repeating task to the scheduler. - * @param after The delay before the first execution, in server ticks. - * @param every The time between successive executions, in server ticks. - * @param task The synchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker then(long after, long every, @NotNull Consumer task) { - Schedulers.sync().repeating(task, after, every); - return this; - } - - /** - * Adds a synchronous repeating task to the scheduler. - * @param after The delay before the first execution, in server ticks. - * @param every The time between successive executions, in server ticks. - * @param task The synchronous task to be executed. - * @return The current @NotNull SchedulerStacker instance for method chaining. - */ - public @NotNull SchedulerStacker then(long after, long every, @NotNull Runnable task) { - Schedulers.sync().repeating(task, after, every); - return this; + public void execute() { + for (SchedulerBuilder builder : builders) { + builder.execute(); + } } } diff --git a/src/main/java/dev/manere/utils/scheduler/sync/SyncScheduler.java b/src/main/java/dev/manere/utils/scheduler/sync/SyncScheduler.java new file mode 100644 index 0000000..6c0b3fe --- /dev/null +++ b/src/main/java/dev/manere/utils/scheduler/sync/SyncScheduler.java @@ -0,0 +1,71 @@ +package dev.manere.utils.scheduler.sync; + +import dev.manere.utils.library.Utils; +import dev.manere.utils.scheduler.SchedulerBase; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * A synchronous scheduler wrapper for {@link SchedulerBase}. + */ +public class SyncScheduler extends SchedulerBase { + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Consumer task) { + scheduler().runTask(Utils.plugin(), task); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Runnable runnable) { + scheduler().runTask(Utils.plugin(), runnable); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Consumer task, int afterTicks) { + scheduler().runTaskLater(Utils.plugin(), task, afterTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Runnable runnable, int afterTicks) { + scheduler().runTaskLater(Utils.plugin(), runnable, afterTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Consumer task, int afterTicks, int everyTicks) { + scheduler().runTaskTimer(Utils.plugin(), task, afterTicks, everyTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public void execute(@NotNull Runnable runnable, int afterTicks, int everyTicks) { + scheduler().runTaskTimer(Utils.plugin(), runnable, afterTicks, everyTicks); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable Object execute(@NotNull Supplier supplier) { + return supplier.get(); + } +} diff --git a/src/main/java/dev/manere/utils/scoreboard/Sidebar.java b/src/main/java/dev/manere/utils/scoreboard/Sidebar.java index b6b211b..0367512 100644 --- a/src/main/java/dev/manere/utils/scoreboard/Sidebar.java +++ b/src/main/java/dev/manere/utils/scoreboard/Sidebar.java @@ -10,12 +10,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Method; -/** - * Lightweight packet-based scoreboard API for Bukkit plugins. - * Basically the same as FastBoard. It's literally using the code of it, it's just made a tiny bit prettier. - */ public class Sidebar extends SidebarHandler { - private static final MethodHandle COMPONENT_METHOD; private static final Object EMPTY_COMPONENT; private static final boolean ADVENTURE_SUPPORT; @@ -49,6 +44,10 @@ public Sidebar(Player player) { super(player); } + public static Sidebar sidebar(Player player) { + return new Sidebar(player); + } + /** * {@inheritDoc} */ @@ -85,4 +84,4 @@ protected String serializeLine(Component value) { protected Component emptyLine() { return Component.empty(); } -} \ No newline at end of file +} diff --git a/src/main/java/dev/manere/utils/scoreboard/SidebarHandler.java b/src/main/java/dev/manere/utils/scoreboard/SidebarHandler.java index 562baf3..05e7ce0 100644 --- a/src/main/java/dev/manere/utils/scoreboard/SidebarHandler.java +++ b/src/main/java/dev/manere/utils/scoreboard/SidebarHandler.java @@ -18,7 +18,7 @@ * Lightweight packet-based scoreboard API for Bukkit plugins. * Basically the same as FastBoard. It's literally using the code of it, it's just made a tiny bit prettier. */ -public abstract class SidebarHandler { +public abstract class SidebarHandler { private static final Map, Field[]> PACKETS = new HashMap<>(8); /** @@ -80,7 +80,7 @@ public abstract class SidebarHandler { .findFirst().orElseThrow(NoSuchFieldException::new); Method sendPacketMethod = Stream.concat( - Arrays.stream(playerConnectionClass.getSuperclass().getMethods()), Arrays.stream(playerConnectionClass.getMethods())) + Arrays.stream(playerConnectionClass.getSuperclass().getMethods()), Arrays.stream(playerConnectionClass.getMethods())) .filter(m -> m.getParameterCount() == 1 && m.getParameterTypes()[0] == packetClass) .findFirst().orElseThrow(NoSuchMethodException::new); @@ -140,8 +140,8 @@ public abstract class SidebarHandler { private final Player player; private final String uniqueId; - private final List lines = new ArrayList<>(); - private T title = emptyLine(); + private final List lines = new ArrayList<>(); + private S title = emptyLine(); private boolean deleted = false; @@ -167,7 +167,7 @@ protected SidebarHandler(Player player) { * * @return the title text */ - public T title() { + public S title() { return this.title; } @@ -176,7 +176,7 @@ public T title() { * * @param title the new title text */ - public void updateTitle(T title) { + public void updateTitle(S title) { if (this.title.equals(Objects.requireNonNull(title, "title"))) { return; } @@ -195,7 +195,7 @@ public void updateTitle(T title) { * * @return an unmodifiable list of lines */ - public List lines() { + public List lines() { return new ArrayList<>(this.lines); } @@ -206,7 +206,7 @@ public List lines() { * @return the text of the line * @throws IllegalArgumentException if line is out of bounds */ - public T line(int line) { + public S line(int line) { checkLineNumber(line, true, false); return this.lines.get(line); @@ -219,7 +219,7 @@ public T line(int line) { * @param text the new text for the line * @throws IllegalArgumentException if line is out of bounds */ - public synchronized void updateLine(int line, T text) { + public synchronized void updateLine(int line, S text) { checkLineNumber(line, false, true); try { @@ -230,7 +230,7 @@ public synchronized void updateLine(int line, T text) { return; } - List newLines = new ArrayList<>(this.lines); + List newLines = new ArrayList<>(this.lines); if (line > size()) { for (int i = size(); i < line; i++) { @@ -259,7 +259,7 @@ public synchronized void removeLine(int line) { return; } - List newLines = new ArrayList<>(this.lines); + List newLines = new ArrayList<>(this.lines); newLines.remove(line); updateLines(newLines); } @@ -270,7 +270,7 @@ public synchronized void removeLine(int line) { * @param lines the new contents of the scoreboard */ @SafeVarargs - public final void updateLines(T... lines) { + public final void updateLines(S... lines) { updateLines(Arrays.asList(lines)); } @@ -279,11 +279,11 @@ public final void updateLines(T... lines) { * * @param lines the new contents of the scoreboard */ - public synchronized void updateLines(Collection lines) { + public synchronized void updateLines(Collection lines) { Objects.requireNonNull(lines, "lines"); checkLineNumber(lines.size(), false, true); - List oldLines = new ArrayList<>(this.lines); + List oldLines = new ArrayList<>(this.lines); this.lines.clear(); this.lines.addAll(lines); @@ -291,7 +291,7 @@ public synchronized void updateLines(Collection lines) { try { if (oldLines.size() != linesSize) { - List oldLinesCopy = new ArrayList<>(oldLines); + List oldLinesCopy = new ArrayList<>(oldLines); if (oldLines.size() > linesSize) { for (int i = oldLinesCopy.size(); i > linesSize; i--) { @@ -379,12 +379,12 @@ public void delete() { protected abstract void sendLineChange(int score) throws Throwable; /** - * Converts {@code T} to a Minecraft component. + * Converts {@code S} to a Minecraft component. * * @param value the value to convert. * @return the Minecraft component. */ - protected abstract Object toMinecraftComponent(T value) throws Throwable; + protected abstract Object toMinecraftComponent(S value) throws Throwable; /** * Serializes a line. @@ -392,14 +392,14 @@ public void delete() { * @param value the value to serialize. * @return a String. */ - protected abstract String serializeLine(T value); + protected abstract String serializeLine(S value); /** * Returns an empty line. * * @return an empty line. */ - protected abstract T emptyLine(); + protected abstract S emptyLine(); private void checkLineNumber(int line, boolean checkInRange, boolean checkMax) { if (line < 0) { @@ -419,11 +419,11 @@ protected int scoreByLine(int line) { return this.lines.size() - line - 1; } - protected T lineByScore(int score) { + protected S lineByScore(int score) { return lineByScore(this.lines, score); } - protected T lineByScore(List lines, int score) { + protected S lineByScore(List lines, int score) { return score < lines.size() ? lines.get(lines.size() - score - 1) : null; } @@ -480,7 +480,7 @@ protected void sendTeamPacket(int score, TeamMode mode) throws Throwable { sendTeamPacket(score, mode, null, null); } - protected void sendTeamPacket(int score, TeamMode mode, T prefix, T suffix) throws Throwable { + protected void sendTeamPacket(int score, TeamMode mode, S prefix, S suffix) throws Throwable { if (mode == TeamMode.ADD_PLAYERS || mode == TeamMode.REMOVE_PLAYERS) { throw new UnsupportedOperationException(); } @@ -545,7 +545,7 @@ private void field(Object packet, Class fieldType, Object value, int count) t } } - private void componentField(Object packet, T value, int count) throws Throwable { + private void componentField(Object packet, S value, int count) throws Throwable { if (!VersionType.V1_13.isHigherOrEqual()) { String line = value != null ? serializeLine(value) : ""; field(packet, String.class, line, count); diff --git a/src/main/java/dev/manere/utils/serializers/Base64Serializer.java b/src/main/java/dev/manere/utils/serializers/Base64Serializer.java index 3e856bb..c24d6d2 100644 --- a/src/main/java/dev/manere/utils/serializers/Base64Serializer.java +++ b/src/main/java/dev/manere/utils/serializers/Base64Serializer.java @@ -14,7 +14,6 @@ * The Base64Serializer class provides methods for serializing and deserializing ItemStacks and ItemBuilders using Base64 encoding. */ public class Base64Serializer { - /** * Serialize a map of ItemStacks into a Base64 encoded string. * diff --git a/src/main/java/dev/manere/utils/serializers/ByteSerializer.java b/src/main/java/dev/manere/utils/serializers/ByteSerializer.java new file mode 100644 index 0000000..aa97e34 --- /dev/null +++ b/src/main/java/dev/manere/utils/serializers/ByteSerializer.java @@ -0,0 +1,105 @@ +package dev.manere.utils.serializers; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * The ByteSerializer class provides static methods for serializing and deserializing + * ItemStack objects to and from byte arrays. + */ +@SuppressWarnings("UnstableApiUsage") // Why Google. Why. +public class ByteSerializer { + /** + * Serializes a single ItemStack object into a byte array. + * + * @param item The ItemStack to be serialized. + * @return A byte array representing the serialized ItemStack. + */ + public byte[] serialize(ItemStack item) { + return item.serializeAsBytes(); + } + + /** + * Serializes a list of ItemStack objects into a byte array. + * + * @param items The list of ItemStack objects to be serialized. + * @return A byte array representing the serialized list of ItemStack objects. + */ + public byte[] serialize(List items) { + return serialize(items.toArray(new ItemStack[0])); + } + + /** + * Serializes an array of ItemStack objects into a byte array. + * + * @param items The array of ItemStack objects to be serialized. + * @return A byte array representing the serialized array of ItemStack objects. + */ + public byte[] serialize(ItemStack[] items) { + ByteArrayDataOutput stream = ByteStreams.newDataOutput(); + + for (ItemStack item : items) { + byte[] data = item == null || item.getType() == Material.AIR ? new byte[]{} : item.serializeAsBytes(); + + stream.writeInt(data.length); + stream.write(data); + } + + stream.writeInt(-1); + return stream.toByteArray(); + } + + /** + * Deserializes a byte array into an ItemStack object. + * + * @param bytes The byte array to be deserialized into an ItemStack. + * @return The deserialized ItemStack object. + */ + public ItemStack deserialize(byte[] bytes) { + return ItemStack.deserializeBytes(bytes); + } + + /** + * Deserializes a byte array into an array of ItemStack objects. + * + * @param bytes The byte array to be deserialized into an array of ItemStack objects. + * @return An array of deserialized ItemStack objects. + */ + public ItemStack[] deserializeArray(byte[] bytes) { + List items = new ArrayList<>(); + ByteArrayDataInput inputStream = ByteStreams.newDataInput(bytes); + int length = inputStream.readInt(); + + while (length != -1) { + if (length == 0) { + items.add(null); + } else { + byte[] data = new byte[length]; + + inputStream.readFully(data, 0, data.length); + items.add(ItemStack.deserializeBytes(data)); + } + + length = inputStream.readInt(); + } + + return items.toArray(new ItemStack[0]); + } + + /** + * Deserializes a byte array into a list of ItemStack objects. + * + * @param bytes The byte array to be deserialized into a list of ItemStack objects. + * @return A list of deserialized ItemStack objects. + */ + public List deserializeList(byte[] bytes) { + return Arrays.asList(deserializeArray(bytes)); + } +} diff --git a/src/main/java/dev/manere/utils/serializers/Serializers.java b/src/main/java/dev/manere/utils/serializers/Serializers.java index 6cdefca..7d2056d 100644 --- a/src/main/java/dev/manere/utils/serializers/Serializers.java +++ b/src/main/java/dev/manere/utils/serializers/Serializers.java @@ -6,13 +6,23 @@ * Provides easy access to all serializers/deserializers in one class. */ public class Serializers { - /** - * Provides an instance of Base64Serializer for serializing and deserializing ItemStacks and ItemBuilders using Base64 encoding. + * Provides an instance of Base64Serializer + * for serializing and deserializing ItemStacks and ItemBuilders using Base64 encoding. * * @return An instance of Base64Serializer. */ public static @NotNull Base64Serializer base64() { return new Base64Serializer(); } + + /** + * Provides an instance of ByteSerializer + * for serializing and deserializing ItemStacks and ItemBuilders using byte array encoding. + * + * @return An instance of ByteSerializer. + */ + public static @NotNull ByteSerializer bytes() { + return new ByteSerializer(); + } } diff --git a/src/main/java/dev/manere/utils/server/ServerUtils.java b/src/main/java/dev/manere/utils/server/ServerUtils.java index 64c1f90..8ac2a22 100644 --- a/src/main/java/dev/manere/utils/server/ServerUtils.java +++ b/src/main/java/dev/manere/utils/server/ServerUtils.java @@ -21,7 +21,6 @@ * The ServerUtils class provides utility methods for accessing server-related components. */ public class ServerUtils { - /** * Retrieves the PluginManager associated with the server. * diff --git a/src/main/java/dev/manere/utils/sql/connection/SQLConnector.java b/src/main/java/dev/manere/utils/sql/connection/SQLConnector.java index 525c93a..2fd0052 100644 --- a/src/main/java/dev/manere/utils/sql/connection/SQLConnector.java +++ b/src/main/java/dev/manere/utils/sql/connection/SQLConnector.java @@ -9,7 +9,6 @@ * A record representing an SQL connector with specified authentication details. */ public record SQLConnector(SQLAuthentication authentication) { - /** * Creates a new SQL connector with default authentication settings. * @return A new SQLConnector instance with default authentication settings. diff --git a/src/main/java/dev/manere/utils/tablist/Tablist.java b/src/main/java/dev/manere/utils/tablist/Tablist.java new file mode 100644 index 0000000..5757844 --- /dev/null +++ b/src/main/java/dev/manere/utils/tablist/Tablist.java @@ -0,0 +1,116 @@ +package dev.manere.utils.tablist; + +import dev.manere.utils.text.color.TextStyle; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * The Tablist class provides utility methods for managing and updating player tablists. + */ +public class Tablist { + private static final List header = new ArrayList<>(); + private static final List footer = new ArrayList<>(); + + /** + * Sets the header of the tablist for all players. + * + * @param header The list of components to set as the header. + */ + public static void header(List header) { + Tablist.header.clear(); + Tablist.header.addAll(header); + } + + /** + * Sets the header of the tablist for all players. + * + * @param header The components to set as the header. + */ + public static void header(Component... header) { + header(Arrays.asList(header)); + } + + /** + * Sets the header of the tablist for all players. + * + * @param header The strings to set as the header, with optional text styling. + */ + public static void header(String... header) { + header(TextStyle.style(header)); + } + + /** + * Sets the footer of the tablist for all players. + * + * @param footer The list of components to set as the footer. + */ + public static void footer(List footer) { + Tablist.footer.clear(); + Tablist.footer.addAll(footer); + } + + /** + * Sets the footer of the tablist for all players. + * + * @param footer The components to set as the footer. + */ + public static void footer(Component... footer) { + footer(Arrays.asList(footer)); + } + + /** + * Sets the footer of the tablist for all players. + * + * @param footer The strings to set as the footer, with optional text styling. + */ + public static void footer(String... footer) { + footer(TextStyle.style(footer)); + } + + /** + * Updates the tablist for a specific player. + * + * @param player The player whose tablist needs to be updated. + */ + public static void update(Player player) { + Component joinedHeader = Component.empty(); + Component joinedFooter = Component.empty(); + + if (!header.isEmpty()) { + joinedHeader = Component.join(JoinConfiguration.newlines(), header); + } + + if (!footer.isEmpty()) { + joinedFooter = Component.join(JoinConfiguration.newlines(), footer); + } + + player.sendPlayerListHeaderAndFooter(joinedHeader, joinedFooter); + } + + /** + * Updates the tablist for a list of players. + * + * @param players The list of players whose tablists need to be updated. + */ + public static void update(List players) { + for (Player player : players) { + Tablist.update(player); + } + } + + /** + * Updates the tablist for an array of players. + * + * @param players The array of players whose tablists need to be updated. + */ + public static void update(Player... players) { + for (Player player : players) { + Tablist.update(player); + } + } +} diff --git a/src/main/java/dev/manere/utils/text/Text.java b/src/main/java/dev/manere/utils/text/Text.java index 70e5c95..8467142 100644 --- a/src/main/java/dev/manere/utils/text/Text.java +++ b/src/main/java/dev/manere/utils/text/Text.java @@ -1,5 +1,6 @@ package dev.manere.utils.text; +import dev.manere.utils.misc.Storable; import dev.manere.utils.text.color.TextStyle; import net.kyori.adventure.text.Component; @@ -7,7 +8,7 @@ * Represents a simple text utility with formatting options. * @param string The text string to be encapsulated. */ -public record Text(String string) { +public record Text(String string) implements Storable { /** * Creates a new Text instance with the specified string. * @@ -54,4 +55,20 @@ public String string() { public String toString() { return string; } + + /** + * {@inheritDoc} + */ + @Override + public String serialize() { + return string; + } + + /** + * {@inheritDoc} + */ + @Override + public Text deserialize(String serialized) { + return Text.text(serialized); + } } diff --git a/src/main/java/dev/manere/utils/text/color/TextStyle.java b/src/main/java/dev/manere/utils/text/color/TextStyle.java index 26f335e..097c2ac 100644 --- a/src/main/java/dev/manere/utils/text/color/TextStyle.java +++ b/src/main/java/dev/manere/utils/text/color/TextStyle.java @@ -5,6 +5,9 @@ import net.kyori.adventure.text.minimessage.MiniMessage; import net.md_5.bungee.api.ChatColor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -12,7 +15,6 @@ * Utility class for handling formatting in text strings. */ public class TextStyle { - /** * Replaces hexadecimal legacy tags in the input string with ChatColor values. *

@@ -119,6 +121,20 @@ public static Component component(String text) { return miniMessage.deserialize(text).decoration(TextDecoration.ITALIC, false); } + public static List component(List texts) { + List list = new ArrayList<>(); + + for (String text : texts) { + list.add(component(text)); + } + + return list; + } + + public static List component(String... texts) { + return component(Arrays.asList(texts)); + } + /** * Converts a text string to a Component using MiniMessage. * @@ -129,6 +145,22 @@ public static Component color(String text) { return component(text); } + public static List color(List texts) { + return component(texts); + } + + public static List color(String... texts) { + return component(texts); + } + + public static List style(List texts) { + return component(texts); + } + + public static List style(String... texts) { + return component(texts); + } + /** * Converts a text string to a Component using MiniMessage. * diff --git a/src/main/java/dev/manere/utils/text/font/SmallFont.java b/src/main/java/dev/manere/utils/text/font/SmallFont.java index 716543c..80d771e 100644 --- a/src/main/java/dev/manere/utils/text/font/SmallFont.java +++ b/src/main/java/dev/manere/utils/text/font/SmallFont.java @@ -7,7 +7,6 @@ * A utility class for converting text to a small font representation using a character mapping. */ public class SmallFont { - /** * A map that holds the character mapping for converting normal characters to small font characters. */ diff --git a/src/main/java/dev/manere/utils/tierlist/data/PlayerInfo.java b/src/main/java/dev/manere/utils/tierlist/data/PlayerInfo.java index f1886b6..f833ab6 100644 --- a/src/main/java/dev/manere/utils/tierlist/data/PlayerInfo.java +++ b/src/main/java/dev/manere/utils/tierlist/data/PlayerInfo.java @@ -16,7 +16,6 @@ * Represents player information obtained from an external API for tier list data. */ public record PlayerInfo(String uuid, String name, Map rankings, String region, int points, int overall, List badges) { - /** * Represents a player's ranking details. */ diff --git a/src/main/java/dev/manere/utils/tierlist/data/TierList.java b/src/main/java/dev/manere/utils/tierlist/data/TierList.java index 52fe425..7ef421e 100644 --- a/src/main/java/dev/manere/utils/tierlist/data/TierList.java +++ b/src/main/java/dev/manere/utils/tierlist/data/TierList.java @@ -17,7 +17,6 @@ * Represents tier list data obtained from an external API. */ public record TierList(List>> rankings, Map players) { - /** * Represents a summary of player information for tier lists. */ diff --git a/src/main/java/dev/manere/utils/update/Updater.java b/src/main/java/dev/manere/utils/update/Updater.java index 2e8621b..f642c57 100644 --- a/src/main/java/dev/manere/utils/update/Updater.java +++ b/src/main/java/dev/manere/utils/update/Updater.java @@ -14,7 +14,6 @@ */ @SuppressWarnings("UnstableApiUsage") /* I sure do love the Paper API */ public class Updater { - /** * Fetches the latest version of the plugin from the SpigotMC API. * diff --git a/src/main/java/dev/manere/utils/world/Worlds.java b/src/main/java/dev/manere/utils/world/Worlds.java index 9101724..1f100b1 100644 --- a/src/main/java/dev/manere/utils/world/Worlds.java +++ b/src/main/java/dev/manere/utils/world/Worlds.java @@ -3,7 +3,10 @@ import dev.manere.utils.library.Utils; import org.bukkit.World; import org.bukkit.WorldCreator; +import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Objects; @@ -13,13 +16,12 @@ * A utility class for managing Bukkit worlds and related operations. */ public class Worlds { - /** * Retrieves all valid worlds on the server. * * @return All valid worlds on the server. */ - public static List worlds() { + public static @NotNull List worlds() { return Utils.plugin().getServer().getWorlds(); } @@ -29,7 +31,7 @@ public static List worlds() { * @param name The name of the world to retrieve. * @return The Bukkit World instance, or null if not found. */ - public static World world(String name) { + public static @Nullable World world(@NotNull String name) { return world(Utils.plugin(), name); } @@ -39,7 +41,7 @@ public static World world(String name) { * @param uuid The UUID of the world to retrieve. * @return The Bukkit World instance, or null if not found. */ - public static World world(UUID uuid) { + public static @Nullable World world(@NotNull UUID uuid) { return world(Utils.plugin(), uuid); } @@ -50,7 +52,7 @@ public static World world(UUID uuid) { * @param name The name of the world to retrieve. * @return The Bukkit World instance, or null if not found. */ - public static World world(JavaPlugin plugin, String name) { + public static @Nullable World world(@NotNull JavaPlugin plugin, @NotNull String name) { return plugin.getServer().getWorld(name); } @@ -61,7 +63,7 @@ public static World world(JavaPlugin plugin, String name) { * @param uuid The UUID of the world to retrieve. * @return The Bukkit World instance, or null if not found. */ - public static World world(JavaPlugin plugin, UUID uuid) { + public static @Nullable World world(@NotNull JavaPlugin plugin, @NotNull UUID uuid) { return plugin.getServer().getWorld(uuid); } @@ -71,7 +73,7 @@ public static World world(JavaPlugin plugin, UUID uuid) { * @param world The Bukkit World instance. * @return The name of the world. */ - public static String worldName(World world) { + public static @NotNull String name(@NotNull World world) { return world.getName(); } @@ -82,7 +84,7 @@ public static String worldName(World world) { * @param uuid The UUID of the world. * @return The name of the world. */ - public static String worldName(JavaPlugin plugin, UUID uuid) { + public static @NotNull String name(@NotNull JavaPlugin plugin, @NotNull UUID uuid) { return Objects.requireNonNull(plugin.getServer().getWorld(uuid)).getName(); } @@ -93,7 +95,7 @@ public static String worldName(JavaPlugin plugin, UUID uuid) { * @param name The name of the world to check. * @return True if the world exists, false otherwise. */ - public static boolean worldExists(JavaPlugin plugin, String name) { + public static boolean worldExists(@NotNull JavaPlugin plugin, @NotNull String name) { return plugin.getServer().getWorld(name) != null; } @@ -104,7 +106,7 @@ public static boolean worldExists(JavaPlugin plugin, String name) { * @param properties The WorldCreator instance with desired properties for the new world. * @return The newly created Bukkit World instance. */ - public static World create(JavaPlugin plugin, WorldCreator properties) { + public static @Nullable World create(@NotNull JavaPlugin plugin, @NotNull WorldCreator properties) { return plugin.getServer().createWorld(properties); } @@ -117,4 +119,37 @@ public static World create(JavaPlugin plugin, WorldCreator properties) { public static World create(WorldCreator properties) { return Utils.plugin().getServer().createWorld(properties); } + + /** + * Checks whether two players are in the same Bukkit world. + * + * @param playerOne The first Player instance. + * @param playerTwo The second Player instance. + * @return True if both players are in the same world, false otherwise. + */ + public static boolean isSameWorld(@NotNull Player playerOne, @NotNull Player playerTwo) { + return isSameWorld(playerOne.getWorld(), playerTwo.getWorld()); + } + + /** + * Checks whether two Bukkit worlds are the same. + * + * @param worldOne The first Bukkit World instance. + * @param worldTwo The second Bukkit World instance. + * @return True if both worlds have the same name, false otherwise. + */ + public static boolean isSameWorld(@NotNull World worldOne, @NotNull World worldTwo) { + return worldOne.getName().equalsIgnoreCase(worldTwo.getName()); + } + + /** + * Checks whether two world names are the same, ignoring case. + * + * @param worldOne The name of the first world. + * @param worldTwo The name of the second world. + * @return True if both world names are the same (case-insensitive), false otherwise. + */ + public static boolean isSameWorld(@NotNull String worldOne, @NotNull String worldTwo) { + return worldOne.equalsIgnoreCase(worldTwo); + } } diff --git a/src/main/java/dev/manere/utils/worldedit/AsyncWorldEditor.java b/src/main/java/dev/manere/utils/worldedit/AsyncWorldEditor.java index 5d4a830..12da677 100644 --- a/src/main/java/dev/manere/utils/worldedit/AsyncWorldEditor.java +++ b/src/main/java/dev/manere/utils/worldedit/AsyncWorldEditor.java @@ -9,7 +9,6 @@ * Utility class for interacting with WorldEdit in an asynchronous manner using {@link TaskManager#async(Runnable runnable)}. */ public class AsyncWorldEditor extends SyncWorldEditor { - /** * This method is run asynchronously using {@link TaskManager#async(Runnable runnable)} *

diff --git a/src/main/java/dev/manere/utils/worldedit/SyncWorldEditor.java b/src/main/java/dev/manere/utils/worldedit/SyncWorldEditor.java index d5a66a3..21f1c01 100644 --- a/src/main/java/dev/manere/utils/worldedit/SyncWorldEditor.java +++ b/src/main/java/dev/manere/utils/worldedit/SyncWorldEditor.java @@ -24,7 +24,6 @@ * Utility class for interacting with WorldEdit in a synchronous manner. */ public class SyncWorldEditor { - /** * Copies a region specified by two corner locations. * diff --git a/src/main/java/dev/manere/utils/worldedit/WorldEditor.java b/src/main/java/dev/manere/utils/worldedit/WorldEditor.java index 892eb69..4504fd3 100644 --- a/src/main/java/dev/manere/utils/worldedit/WorldEditor.java +++ b/src/main/java/dev/manere/utils/worldedit/WorldEditor.java @@ -10,7 +10,6 @@ * */ public class WorldEditor { - /** * Gets an instance of AsyncWorldEditor. * @return An instance of AsyncWorldEditor.