diff --git a/Commands/CommandAPI-11.1.0/pom.xml b/Commands/CommandAPI-11.1.0/pom.xml index 7c852d93..e1134d94 100644 --- a/Commands/CommandAPI-11.1.0/pom.xml +++ b/Commands/CommandAPI-11.1.0/pom.xml @@ -27,7 +27,7 @@ dev.jorel - commandapi-spigot-core + commandapi-spigot-shade 11.1.0 provided diff --git a/Common/pom.xml b/Common/pom.xml index aa614730..46cf4dc0 100644 --- a/Common/pom.xml +++ b/Common/pom.xml @@ -52,6 +52,13 @@ 3.36.0.3 provided + + + com.github.Anon8281 + UniversalScheduler + 0.1.6 + compile + diff --git a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementMain.java b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementMain.java index 85d91fb6..04aa0840 100644 --- a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementMain.java +++ b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementMain.java @@ -13,6 +13,7 @@ import com.fren_gor.ultimateAdvancementAPI.nms.util.ReflectionUtil; import com.fren_gor.ultimateAdvancementAPI.util.AdvancementKey; import com.fren_gor.ultimateAdvancementAPI.util.Versions; +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; import com.google.common.base.Preconditions; import net.byteflux.libby.BukkitLibraryManager; import org.bukkit.Bukkit; @@ -57,6 +58,7 @@ public final class AdvancementMain { private final static AtomicBoolean LOADED = new AtomicBoolean(false), ENABLED = new AtomicBoolean(false), INVALID_VERSION = new AtomicBoolean(false); + private final TaskScheduler scheduler; private final Plugin owningPlugin; private EventManager eventManager; private DatabaseManager databaseManager; @@ -68,13 +70,14 @@ public final class AdvancementMain { /** * Creates a new {@code AdvancementMain}. *

The library folder is {@code "plugins/pluginDirectory/.libs"}. - * Use {@link #AdvancementMain(Plugin, String)} to customize. + * Use {@link #AdvancementMain(Plugin, TaskScheduler, String)} to customize. * * @param owningPlugin The plugin instantiating the API. */ - public AdvancementMain(@NotNull Plugin owningPlugin) { + public AdvancementMain(@NotNull Plugin owningPlugin, @NotNull TaskScheduler scheduler) { // Don't use AdvancementUtils here until having checked that the current mc version is supported Preconditions.checkNotNull(owningPlugin, "Plugin is null."); + this.scheduler = scheduler; this.owningPlugin = owningPlugin; this.libFolder = ".libs"; } @@ -83,13 +86,15 @@ public AdvancementMain(@NotNull Plugin owningPlugin) { * Creates a new {@code AdvancementMain}. * * @param owningPlugin The plugin instantiating the API. + * @param scheduler The scheduler from the plugin. * @param libFolder The name of the folder when additional libraries will be stored into. * The folder is created into the plugin directory. */ - public AdvancementMain(@NotNull Plugin owningPlugin, String libFolder) { + public AdvancementMain(@NotNull Plugin owningPlugin, @NotNull TaskScheduler scheduler, String libFolder) { // Don't use AdvancementUtils here until having checked that the current mc version is supported Preconditions.checkNotNull(owningPlugin, "Plugin is null."); Preconditions.checkNotNull(libFolder, "Lib folder is null."); + this.scheduler = scheduler; this.owningPlugin = owningPlugin; this.libFolder = libFolder; } @@ -307,7 +312,7 @@ public AdvancementTab createAdvancementTab(@NotNull Plugin plugin, @NotNull Stri throw new DuplicatedException("An AdvancementTab with '" + namespace + "' namespace already exists."); } - AdvancementTab tab = new AdvancementTab(plugin, databaseManager, namespace); + AdvancementTab tab = new AdvancementTab(plugin, scheduler, databaseManager, namespace); tabs.put(namespace, tab); pluginMap.computeIfAbsent(plugin, p -> new LinkedList<>()).add(tab); return tab; @@ -553,6 +558,16 @@ public Plugin getOwningPlugin() { return owningPlugin; } + /** + * Gets the scheduler from the plugin that instantiated the API. + * + * @return The scheduler from plugin that instantiated the API. + */ + @NotNull + public TaskScheduler getScheduler() { + return scheduler; + } + /** * Gets the {@link EventManager} API global instance. * diff --git a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementTab.java b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementTab.java index 4b3cba71..c4b99a9c 100644 --- a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementTab.java +++ b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementTab.java @@ -22,6 +22,8 @@ import com.fren_gor.ultimateAdvancementAPI.util.AdvancementKey; import com.fren_gor.ultimateAdvancementAPI.util.AdvancementUtils; import com.fren_gor.ultimateAdvancementAPI.util.LazyValue; +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; +import com.github.Anon8281.universalScheduler.scheduling.tasks.MyScheduledTask; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -32,7 +34,6 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; -import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -70,6 +71,7 @@ public final class AdvancementTab { private final Map advancements = new HashMap<>(); private final Map> players = new HashMap<>(); private final AdvsUpdateRunnable updateManager; + private static TaskScheduler scheduler; private RootAdvancement rootAdvancement; private boolean initialised = false, disposed = false, automaticallyShown = false, automaticallyGrant = false; @@ -78,10 +80,11 @@ public final class AdvancementTab { @LazyValue private Collection advsWithoutRoot; - AdvancementTab(@NotNull Plugin owningPlugin, @NotNull DatabaseManager databaseManager, @NotNull String namespace) { + AdvancementTab(@NotNull Plugin owningPlugin, @NotNull TaskScheduler scheduler, @NotNull DatabaseManager databaseManager, @NotNull String namespace) { checkNamespace(namespace); this.namespace = Objects.requireNonNull(namespace); this.owningPlugin = Objects.requireNonNull(owningPlugin); + this.scheduler = Objects.requireNonNull(scheduler); this.eventManager = new EventManager(owningPlugin); this.databaseManager = Objects.requireNonNull(databaseManager); this.updateManager = new AdvsUpdateRunnable(); @@ -769,6 +772,16 @@ public Plugin getOwningPlugin() { return owningPlugin; } + /** + * Gets the scheduler from the plugin that created this advancement tab. + * + * @return The scheduler from the plugin that created this advancement tab. + */ + @NotNull + public TaskScheduler getScheduler() { + return scheduler; + } + /** * Gets the {@link EventManager} of this tab. * @@ -821,12 +834,12 @@ private class AdvsUpdateRunnable implements Runnable { private final Set advsToUpdate = new HashSet<>(); private boolean scheduled = false; - private BukkitTask task; + private MyScheduledTask task; public void schedule(@NotNull TeamProgression progression) { if (!scheduled) { scheduled = true; - task = Bukkit.getScheduler().runTaskLater(owningPlugin, this, 1L); + task = scheduler.runTaskLater(this, 1L); } advsToUpdate.add(progression); } diff --git a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/UltimateAdvancementAPI.java b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/UltimateAdvancementAPI.java index de1e698f..b53e7c74 100644 --- a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/UltimateAdvancementAPI.java +++ b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/UltimateAdvancementAPI.java @@ -867,7 +867,7 @@ public void getStoredPlayerName(@NotNull OfflinePlayer player, @NotNull Consumer */ public void getStoredPlayerName(@NotNull UUID uuid, @NotNull Consumer> action) { Preconditions.checkNotNull(action, "Consumer is null."); - getMain().getDatabaseManager().getStoredPlayerName(uuid).thenAccept(s -> runSync(plugin, () -> action.accept(s))); + getMain().getDatabaseManager().getStoredPlayerName(uuid).thenAccept(s -> runSync(plugin, main.getScheduler(), () -> action.accept(s))); } private void callAfterLoad(@NotNull Player player, @NotNull Function> internalAction, @Nullable Consumer action) { @@ -892,7 +892,7 @@ private void callAfterLoad(@NotNull UUID uuid, @NotNull Funct } c.thenAccept(b -> { if (action != null) { - runSync(plugin, () -> { + runSync(plugin, main.getScheduler(), () -> { try { if (plugin.isEnabled()) action.accept(b); @@ -936,7 +936,7 @@ private void callAfterLoad(@NotNull UUID uuid1, @NotNull UUID } c.thenAccept(b -> { if (action != null) { - runSync(plugin, () -> { + runSync(plugin, main.getScheduler(), () -> { try { if (plugin.isEnabled()) action.accept(b); @@ -959,7 +959,7 @@ private void callAfterLoad(@NotNull UUID uuid1, @NotNull UUID private void callSyncIfNotNull(@NotNull CompletableFuture completableFuture, @Nullable Consumer action) { if (action != null) { - completableFuture.thenAccept(t -> runSync(plugin, () -> action.accept(t))); + completableFuture.thenAccept(t -> runSync(plugin, main.getScheduler(), () -> action.accept(t))); } } diff --git a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/advancement/Advancement.java b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/advancement/Advancement.java index 84fa0918..67864a33 100644 --- a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/advancement/Advancement.java +++ b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/advancement/Advancement.java @@ -541,7 +541,7 @@ public boolean isVisible(@NotNull UUID uuid) { * When overridden, this method (called via {@code super}) enables the AVS features for that method. */ public boolean isVisible(@NotNull TeamProgression progression) { - validateTeamProgression(progression); + // validateTeamProgression(progression); // Advancement visibility system if (iVisibilityMethod != null) { try { @@ -576,7 +576,7 @@ public void onGrant(@NotNull Player player, boolean giveRewards) { // Show Toast if (display.doesShowToast()) { // TODO Find a better solution - runSync(advancementTab.getOwningPlugin(), 2, () -> AdvancementUtils.displayToastDuringUpdate(player, this)); + runSync(advancementTab.getOwningPlugin(), advancementTab.getScheduler(), 2, () -> AdvancementUtils.displayToastDuringUpdate(player, this)); } if (giveRewards) @@ -623,7 +623,7 @@ public void revoke(@NotNull Player player) { * The values are the current progressions of the team. */ public void onUpdate(@NotNull TeamProgression teamProgression, @NotNull Map addedAdvancements) { - if (isVisible(teamProgression)) { + if (teamProgression.isValid() && isVisible(teamProgression)) { addedAdvancements.put(getNMSWrapper(), getProgression(teamProgression)); } } diff --git a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/database/DatabaseManager.java b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/database/DatabaseManager.java index 069c2866..e86a77f5 100644 --- a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/database/DatabaseManager.java +++ b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/database/DatabaseManager.java @@ -161,7 +161,7 @@ private void unloadPlayerOnQuit(@NotNull UUID uuid) { if (Bukkit.isPrimaryThread()) { callEventCatchingExceptions(new TeamUnloadEvent(t)); } else { - runSync(main.getOwningPlugin(), () -> callEventCatchingExceptions(new TeamUnloadEvent(t))); + runSync(main.getOwningPlugin(), main.getScheduler(), () -> callEventCatchingExceptions(new TeamUnloadEvent(t))); } } } diff --git a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/util/AdvancementUtils.java b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/util/AdvancementUtils.java index 510de548..a7791fac 100644 --- a/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/util/AdvancementUtils.java +++ b/Common/src/main/java/com/fren_gor/ultimateAdvancementAPI/util/AdvancementUtils.java @@ -15,6 +15,7 @@ import com.fren_gor.ultimateAdvancementAPI.nms.wrappers.advancement.AdvancementFrameTypeWrapper; import com.fren_gor.ultimateAdvancementAPI.nms.wrappers.advancement.AdvancementWrapper; import com.fren_gor.ultimateAdvancementAPI.nms.wrappers.packets.PacketPlayOutAdvancementsWrapper; +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; import com.google.common.base.Preconditions; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ComponentBuilder; @@ -247,21 +248,21 @@ public static void checkSync() { } public static void runSync(@NotNull AdvancementMain main, @NotNull Runnable runnable) { - runSync(main.getOwningPlugin(), runnable); + runSync(main.getOwningPlugin(), main.getScheduler(), runnable); } - public static void runSync(@NotNull Plugin plugin, @NotNull Runnable runnable) { - runSync(plugin, 1, runnable); + public static void runSync(@NotNull Plugin plugin, @NotNull TaskScheduler scheduler, @NotNull Runnable runnable) { + runSync(plugin, scheduler, 1, runnable); } public static void runSync(@NotNull AdvancementMain main, long delay, @NotNull Runnable runnable) { - runSync(main.getOwningPlugin(), delay, runnable); + runSync(main.getOwningPlugin(), main.getScheduler(), delay, runnable); } - public static void runSync(@NotNull Plugin plugin, long delay, @NotNull Runnable runnable) { + public static void runSync(@NotNull Plugin plugin, @NotNull TaskScheduler scheduler, long delay, @NotNull Runnable runnable) { Preconditions.checkNotNull(plugin, "Plugin is null."); Preconditions.checkNotNull(runnable, "Runnable is null."); - Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, runnable, delay); + scheduler.runTaskLater(runnable, delay); } @NotNull diff --git a/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/CoordAdapterTest.java b/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/CoordAdapterTest.java index e37b7261..806b724b 100644 --- a/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/CoordAdapterTest.java +++ b/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/CoordAdapterTest.java @@ -8,6 +8,7 @@ import com.fren_gor.ultimateAdvancementAPI.util.AdvancementKey; import com.fren_gor.ultimateAdvancementAPI.util.CoordAdapter; import com.fren_gor.ultimateAdvancementAPI.util.CoordAdapter.Coord; +import com.github.Anon8281.universalScheduler.UniversalScheduler; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.bukkit.Bukkit; @@ -139,7 +140,7 @@ private void testCoordAdapterHelper(@NotNull Collection coordinates) { @Test public void docCodeTest() { Plugin myPlugin = InterfaceImplementer.newFakePlugin("myPlugin"); - AdvancementMain main = Utils.newAdvancementMain(myPlugin); + AdvancementMain main = Utils.newAdvancementMain(myPlugin, UniversalScheduler.getScheduler(myPlugin)); AdvancementTab myTab = main.createAdvancementTab(myPlugin, "mytab"); // Keys of the advancements to create diff --git a/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/Utils.java b/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/Utils.java index 741b8474..19351629 100644 --- a/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/Utils.java +++ b/Common/src/test/java/com/fren_gor/ultimateAdvancementAPI/tests/Utils.java @@ -4,6 +4,7 @@ import com.fren_gor.ultimateAdvancementAPI.AdvancementMain; import com.fren_gor.ultimateAdvancementAPI.database.DatabaseManager; import com.fren_gor.ultimateAdvancementAPI.util.Versions; +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; import net.byteflux.libby.BukkitLibraryManager; import org.bukkit.Bukkit; import org.bukkit.Server; @@ -115,8 +116,8 @@ public static MockedStatic mockServer() { * * @param plugin The plugin */ - public static AdvancementMain newAdvancementMain(@NotNull Plugin plugin) { - return newAdvancementMain(plugin, new EventManager(plugin)); + public static AdvancementMain newAdvancementMain(@NotNull Plugin plugin, @NotNull TaskScheduler scheduler) { + return newAdvancementMain(plugin, scheduler, new EventManager(plugin)); } /** @@ -129,11 +130,11 @@ public static AdvancementMain newAdvancementMain(@NotNull Plugin plugin) { * @param plugin The plugin * @param manager The event manager */ - public static AdvancementMain newAdvancementMain(@NotNull Plugin plugin, @NotNull EventManager manager) { + public static AdvancementMain newAdvancementMain(@NotNull Plugin plugin, @NotNull TaskScheduler scheduler, @NotNull EventManager manager) { assertNotNull("newAdvancementMain(...) must be called inside Utils.mockServer(...)", Bukkit.getServer()); assertNotNull(plugin); assertNotNull(manager); - AdvancementMain main = new AdvancementMain(plugin); + AdvancementMain main = new AdvancementMain(plugin, scheduler); try { ((AtomicBoolean) mainLOADED.get(main)).set(true); ((AtomicBoolean) mainENABLED.get(main)).set(true); diff --git a/Plugin/pom.xml b/Plugin/pom.xml index 3fc209f1..7ce23496 100644 --- a/Plugin/pom.xml +++ b/Plugin/pom.xml @@ -102,6 +102,13 @@ + + + com.github.Anon8281 + UniversalScheduler + 0.1.6 + compile + @@ -198,6 +205,10 @@ org.bstats com.fren_gor.ultimateAdvancementAPI.libs.org.bstats + + com.github.Anon8281.universalScheduler + com.frengor.ultimateadvancementapi-parent.universalScheduler + false false diff --git a/Plugin/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementPlugin.java b/Plugin/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementPlugin.java index 2dc664b1..e39368de 100644 --- a/Plugin/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementPlugin.java +++ b/Plugin/src/main/java/com/fren_gor/ultimateAdvancementAPI/AdvancementPlugin.java @@ -6,11 +6,12 @@ import com.fren_gor.ultimateAdvancementAPI.metrics.BStats; import com.fren_gor.ultimateAdvancementAPI.nms.wrappers.VanillaAdvancementDisablerWrapper; import com.fren_gor.ultimateAdvancementAPI.util.AdvancementUtils; +import com.github.Anon8281.universalScheduler.UniversalScheduler; +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.Nullable; import java.io.InputStream; @@ -25,7 +26,7 @@ public class AdvancementPlugin extends JavaPlugin { private static final int RESOURCE_ID = 95585; private static AdvancementPlugin instance; - + private static TaskScheduler scheduler; private AdvancementMain main; private ConfigManager configManager; private boolean correctVersion = true, commandsEnabled = false; @@ -34,8 +35,12 @@ public class AdvancementPlugin extends JavaPlugin { @Override public void onLoad() { - instance = this; - main = new AdvancementMain(this); + if (instance == null) + instance = this; + if (scheduler == null) + scheduler = UniversalScheduler.getScheduler(this); + if (main == null) + main = new AdvancementMain(this, scheduler); try { main.load(); } catch (InvalidVersionException e) { @@ -68,6 +73,12 @@ public void onLoad() { @Override public void onEnable() { + if (instance == null) + instance = this; + if (scheduler == null) + scheduler = UniversalScheduler.getScheduler(this); + if (main == null) + main = new AdvancementMain(this, scheduler); if (!correctVersion) { Bukkit.getPluginManager().disablePlugin(this); return; @@ -100,17 +111,14 @@ public void onEnable() { } if (configManager.getDisableVanillaAdvancements() || configManager.getDisableVanillaRecipeAdvancements()) { - new BukkitRunnable() { - @Override - public void run() { - try { - VanillaAdvancementDisablerWrapper.disableVanillaAdvancements(configManager.getDisableVanillaAdvancements(), configManager.getDisableVanillaRecipeAdvancements()); - } catch (Exception e) { - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[UltimateAdvancementAPI] Couldn't disable vanilla advancements:"); - e.printStackTrace(); - } + scheduler.runTaskLater(() -> { + try { + AdvancementUtils.disableVanillaAdvancements(); + } catch (Exception e) { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[UltimateAdvancementAPI] Couldn't disable vanilla advancements:"); + e.printStackTrace(); } - }.runTaskLater(this, 20); + }, 20L); } BStats.init(this); @@ -135,24 +143,26 @@ public void onDisable() { } private void checkForUpdates() { - Bukkit.getScheduler().runTaskAsynchronously(this, () -> { + getScheduler().runTaskAsynchronously(() -> { try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openStream(); Scanner scanner = new Scanner(inputStream)) { if (scanner.hasNextLine()) { if (!this.getDescription().getVersion().equalsIgnoreCase(scanner.next())) { - AdvancementUtils.runSync(this, () -> { + AdvancementUtils.runSync(this, scheduler, () -> { getLogger().info("A new version of " + this.getDescription().getName() + " is out! Download it at https://modrinth.com/plugin/ultimateadvancementapi"); }); } } } catch (Exception e) { - AdvancementUtils.runSync(this, () -> { + AdvancementUtils.runSync(this, scheduler, () -> { getLogger().info("Cannot look for updates: " + e.getMessage()); }); } }); } + public static TaskScheduler getScheduler() { return scheduler; } + public static AdvancementPlugin getInstance() { return instance; } diff --git a/Plugin/src/main/resources/plugin.yml b/Plugin/src/main/resources/plugin.yml index e24cb699..135509b7 100644 --- a/Plugin/src/main/resources/plugin.yml +++ b/Plugin/src/main/resources/plugin.yml @@ -4,5 +4,6 @@ version: ${project.version} description: ${project.description} authors: [fren_gor, EscanorTargaryen] website: ${project.url} +folia-supported: true load: STARTUP api-version: 1.15 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 24c4efc7..295208be 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,11 @@ AlessioDP https://repo.alessiodp.com/releases/ + + + jitpack.io + https://jitpack.io + @@ -206,7 +211,7 @@ all,-missing true - https://frengor.com/javadocs/EventManagerAPI/build-server/ + https://javadoc.io/doc/org.jetbrains/annotations/22.0.0/ https://javadoc.io/static/net.md-5/bungeecord-chat/1.16-R0.4/ https://hub.spigotmc.org/javadocs/spigot/