Javadoc and some API changes

This commit is contained in:
Marc Baloup 2022-08-11 01:32:37 +02:00
parent b6fc3c2b61
commit 99a07a2ba6
Signed by: marcbal
GPG Key ID: BBC0FE3ABC30B893
13 changed files with 298 additions and 188 deletions

View File

@ -31,7 +31,7 @@ public abstract class BungeeBrigadierCommand extends BrigadierCommand<CommandSen
protected BungeeBrigadierDispatcher dispatcher;
/**
* Instanciate this command isntance.
* Instanciate this command instance.
* @param d the dispatcher in which to register this command.
*/
public BungeeBrigadierCommand(BungeeBrigadierDispatcher d) {

View File

@ -10,40 +10,20 @@ import org.fusesource.jansi.AnsiConsole;
import fr.pandacube.lib.util.Log;
/**
* Class to hangle general standard IO operation for a CLI application. It uses Jlines {@link ConsoleReader} for the
* console rendering, a JUL {@link Logger} for logging, and Brigadier for the command management.
*/
public class CLI {
public static final String ANSI_RESET = "\u001B[0m";
public static final String ANSI_BLACK = "\u001B[30m";
public static final String ANSI_DARK_RED = "\u001B[31m";
public static final String ANSI_DARK_GREEN = "\u001B[32m";
public static final String ANSI_GOLD = "\u001B[33m";
public static final String ANSI_DARK_BLUE = "\u001B[34m";
public static final String ANSI_DARK_PURPLE = "\u001B[35m";
public static final String ANSI_DARK_AQUA = "\u001B[36m";
public static final String ANSI_GRAY = "\u001B[37m";
public static final String ANSI_DARK_GRAY = "\u001B[30;1m";
public static final String ANSI_RED = "\u001B[31;1m";
public static final String ANSI_GREEN = "\u001B[32;1m";
public static final String ANSI_YELLOW = "\u001B[33;1m";
public static final String ANSI_BLUE = "\u001B[34;1m";
public static final String ANSI_LIGHT_PURPLE = "\u001B[35;1m";
public static final String ANSI_AQUA = "\u001B[36;1m";
public static final String ANSI_WHITE = "\u001B[37;1m";
public static final String ANSI_BOLD = "\u001B[1m";
public static final String ANSI_CLEAR_SCREEN = "\u001B[2J\u001B[1;1H";
private final ConsoleReader reader;
private final Logger logger;
/**
* Create a new instance of {@link CLI}.
* @throws IOException if an IO error occurs.
*/
public CLI() throws IOException {
AnsiConsole.systemInstall();
reader = new ConsoleReader();
@ -55,22 +35,29 @@ public class CLI {
System.setProperty("net.md_5.bungee.log-date-format", "yyyy-MM-dd HH:mm:ss");
logger = CLILogger.getLogger(this);
}
/**
* Gets the Jline {@link ConsoleReader} of this CLI instance.
* @return the Jline {@link ConsoleReader} of this CLI instance.
*/
public ConsoleReader getConsoleReader() {
return reader;
}
/**
* Gets the {@link Logger} of this CLI instance.
* @return the {@link Logger} of this CLI instance.
*/
public Logger getLogger() {
return logger;
}
/**
* Runs the main loop of the console interface. This method will not return until the input stream is closed.
* Every command will be send to the command handler asynchronously.
*/
public void loop() {
int i = 0;
@ -81,7 +68,6 @@ public class CLI {
continue;
String cmdLine = line;
new Thread(() -> CLIBrigadierDispatcher.instance.execute(cmdLine), "CLICmdThread #"+(i++)).start();
}
} catch (IOException e) {
Log.severe(e);

View File

@ -1,25 +1,22 @@
package fr.pandacube.lib.cli.commands;
import java.util.Arrays;
import java.util.List;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.LiteralCommandNode;
import fr.pandacube.lib.commands.BrigadierCommand;
import fr.pandacube.lib.commands.SuggestionsSupplier;
import java.util.function.Function;
import java.util.function.Predicate;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.ParsedCommandNode;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.LiteralCommandNode;
import fr.pandacube.lib.commands.BrigadierCommand;
import fr.pandacube.lib.commands.BrigadierSuggestionsUtil;
import fr.pandacube.lib.commands.SuggestionsSupplier;
import fr.pandacube.lib.util.Log;
/**
* Abstract class that holds the logic of a specific command to be registered in {@link CLIBrigadierDispatcher}.
*/
public abstract class CLIBrigadierCommand extends BrigadierCommand<Object> {
/**
* Instanciate this command instance.
*/
public CLIBrigadierCommand() {
LiteralCommandNode<Object> commandNode = buildCommand().build();
postBuildCommand(commandNode);
@ -28,7 +25,7 @@ public abstract class CLIBrigadierCommand extends BrigadierCommand<Object> {
aliases = new String[0];
CLIBrigadierDispatcher.instance.register(commandNode);
for (String alias : aliases) {
CLIBrigadierDispatcher.instance.register(literal(alias)
@ -66,6 +63,11 @@ public abstract class CLIBrigadierCommand extends BrigadierCommand<Object> {
/**
* Wraps the provided {@link SuggestionsSupplier} into a Brigadiers {@link SuggestionProvider}.
* @param suggestions the suggestions to wrap.
* @return a {@link SuggestionProvider} generating the suggestions from the provided {@link SuggestionsSupplier}.
*/
protected SuggestionProvider<Object> wrapSuggestions(SuggestionsSupplier<Object> suggestions) {
return wrapSuggestions(suggestions, Function.identity());
}

View File

@ -11,14 +11,25 @@ import fr.pandacube.lib.util.Log;
import jline.console.completer.Completer;
import net.kyori.adventure.text.ComponentLike;
/**
* Implementation of {@link BrigadierDispatcher} that integrates the commands into the JLine CLI interface.
*/
public class CLIBrigadierDispatcher extends BrigadierDispatcher<Object> implements Completer {
/**
* The instance of {@link CLIBrigadierDispatcher}.
*/
public static final CLIBrigadierDispatcher instance = new CLIBrigadierDispatcher();
private static final Object sender = new Object();
/**
* Executes the provided command.
* @param commandWithoutSlash the command, without the eventual slash at the begining.
* @return the value returned by the executed command.
*/
public int execute(String commandWithoutSlash) {
return execute(sender, commandWithoutSlash);
}
@ -37,7 +48,12 @@ public class CLIBrigadierDispatcher extends BrigadierDispatcher<Object> implemen
return completeResult.getRange().getStart();
}
/**
* Gets the suggestions for the currently being typed command.
* @param buffer the command that is being typed.
* @return the suggestions for the currently being typed command.
*/
public Suggestions getSuggestions(String buffer) {
return getSuggestions(sender, buffer);
}

View File

@ -11,10 +11,18 @@ import net.md_5.bungee.log.ColouredWriter;
import net.md_5.bungee.log.ConciseFormatter;
import net.md_5.bungee.log.LoggingOutputStream;
/**
* Initializer for the logging system of a CLI application.
*/
public class CLILogger {
private static Logger logger = null;
/**
* Initialize and return the logger for this application.
* @param cli the CLI instance to use
* @return the logger of this application.
*/
public static synchronized Logger getLogger(CLI cli) {
if (logger == null) {
logger = Logger.getGlobal();

View File

@ -63,10 +63,10 @@ public abstract class BrigadierDispatcher<S> {
/**
* Gets the suggestions for the currenlty being typed command.
* Gets the suggestions for the currently being typed command.
* @param sender the command sender.
* @param buffer the command that is being typed.
* @return the suggestions for the currenlty being typed command.
* @return the suggestions for the currently being typed command.
*/
public Suggestions getSuggestions(S sender, String buffer) {
ParseResults<S> parsed = dispatcher.parse(buffer, sender);

View File

@ -129,7 +129,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
private Set<String> registeredAliases;
/**
* Instanciate this command isntance.
* Instanciate this command instance.
*
* @param pl the plugin instance.
* @param regPolicy the registration policy for this command.

View File

@ -58,13 +58,11 @@
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>${paper.version}-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-mojangapi</artifactId>
<version>${paper.version}-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@ -7,6 +7,7 @@ import java.util.Map.Entry;
import java.util.function.Consumer;
import com.google.common.collect.ImmutableMap;
import fr.pandacube.lib.paper.PandaLibPaper;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@ -18,13 +19,19 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import fr.pandacube.lib.chat.Chat;
import fr.pandacube.lib.paper.util.ItemStackBuilder;
/**
* An inventory based GUI.
*/
public class GUIInventory implements Listener {
/**
* Used as parameter of {@link #buildButton(ItemStack, Integer, Chat, List, Map)} to indicate that a button should
* shine like an enchanted object, without showing enchant informations in the hover text.
*/
public static final Map<Enchantment, Integer> FAKE_ENCHANT = ImmutableMap.of(Enchantment.DURABILITY, 1);
private final Player player;
@ -33,8 +40,14 @@ public class GUIInventory implements Listener {
private boolean isOpened = false;
private final Map<Integer, Consumer<InventoryClickEvent>> onClickEvents;
public GUIInventory(Player p, int nbLines, Chat title, Consumer<InventoryCloseEvent> closeEventAction,
Plugin pl) {
/**
* Create a new inventory based GUI.
* @param p the player for which to create the GUI.
* @param nbLines the number of invotory lines for the interface.
* @param title the title of the GUI (title of the inventory)
* @param closeEventAction the action to perform when the player closes the GUI inventory
*/
public GUIInventory(Player p, int nbLines, Chat title, Consumer<InventoryCloseEvent> closeEventAction) {
if (title == null)
inv = Bukkit.createInventory(null, nbLines * 9);
else
@ -46,7 +59,7 @@ public class GUIInventory implements Listener {
player = p;
Bukkit.getPluginManager().registerEvents(this, pl);
Bukkit.getPluginManager().registerEvents(this, PandaLibPaper.getPlugin());
}
@ -55,9 +68,11 @@ public class GUIInventory implements Listener {
}
/**
* @param clickEventActions (l'event passé en paramètre de la méthode done a
* été pré-annulée. Pour la rétablir, faites un
* event.setCancelled(false)).
* Set a button on the provided slot, if this slot is still empty.
* @param p the slot index.
* @param iStack the item to put in the slot.
* @param clickEventActions the action to perform when the user clicks that button. The event passed as a parameter
* is already cancelled. It is possible to uncancel it if needed.
*/
public void setButtonIfEmpty(int p, ItemStack iStack, Consumer<InventoryClickEvent> clickEventActions) {
if (inv.getItem(p) == null)
@ -65,9 +80,11 @@ public class GUIInventory implements Listener {
}
/**
* @param clickEventActions (l'event passé en paramètre de la méthode done a
* été pré-annulée. Pour la rétablir, faites un
* event.setCancelled(false)).
* Set a button on the provided slot.
* @param p the slot index.
* @param iStack the item to put in the slot.
* @param clickEventActions the action to perform when the user clicks that button. The event passed as a parameter
* is already cancelled. It is possible to uncancel it if needed.
*/
public void setButton(int p, ItemStack iStack, Consumer<InventoryClickEvent> clickEventActions) {
inv.setItem(p, iStack);
@ -75,38 +92,63 @@ public class GUIInventory implements Listener {
}
/**
* @param clickEventActions (l'event passé en paramètre de la méthode done a
* été pré-annulée. Pour la rétablir, faites un
* event.setCancelled(false)).
* Update/replace the action to perform for a specific slot.
* @param p the slot index.
* @param clickEventActions the action to perform when the user clicks that button. The event passed as a parameter
* is already cancelled. It is possible to uncancel it if needed.
*/
public void changeClickEventAction(int p, Consumer<InventoryClickEvent> clickEventActions) {
onClickEvents.put(p, clickEventActions);
}
/**
* Returns the item that is in the provided slot.
* @param p the slot index.
* @return the item that is in the provided slot.
*/
public ItemStack getItemStack(int p) {
return inv.getItem(p);
}
/**
* Makes the GUI inventory appears for the player.
*/
public void open() {
if (isOpened) return;
player.openInventory(inv);
isOpened = true;
}
/**
* Force this GUI to be closes, without the intervention of the player.
* The bukkit API will call the {@link InventoryCloseEvent}, trigerring eventual actions associated with this event.
*/
public void forceClose() {
if (!isOpened) return;
player.closeInventory(); // internally calls the InventoryCloseEvent
}
/**
* Tells if this inventory is open for the player.
* @return true if this inventory is open for the player, false otherwise.
*/
public boolean isOpen() {
return isOpened;
}
/**
* Clears the content of the GUI and the click event actions.
*/
public void clear() {
onClickEvents.clear();
inv.clear();
}
/**
* Clears a part of the GUI and the click event actions.
* @param firstElement the first element to remove.
* @param nbElement the number of element to remove.
*/
public void clear(int firstElement, int nbElement) {
for (int i = firstElement; i < firstElement + nbElement; i++) {
inv.setItem(i, null);
@ -114,10 +156,18 @@ public class GUIInventory implements Listener {
}
}
/**
* Gets the underlying inventory of this GUI.
* @return the underlying inventory of this GUI.
*/
public Inventory getInventory() {
return inv;
}
/**
* Inventory click event handler.
* @param event the event.
*/
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!event.getWhoClicked().equals(player)) return;
@ -135,6 +185,10 @@ public class GUIInventory implements Listener {
}
/**
* Inventory close event handler.
* @param event the event.
*/
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
if (!event.getPlayer().equals(player)) return;
@ -183,9 +237,6 @@ public class GUIInventory implements Listener {
public static ItemStack buildButton(ItemStack base, Chat displayName, List<Chat> lores, Map<Enchantment, Integer> enchantments) {
return buildButton(base, null, displayName, lores, enchantments);
}
public static ItemStack buildButton(ItemStack base, Integer amount, Chat displayName, Map<Enchantment, Integer> enchantments) {
return buildButton(base, amount, displayName, null, enchantments);
}
public static ItemStack buildButton(ItemStack base, Chat displayName, Map<Enchantment, Integer> enchantments) {
return buildButton(base, null, displayName, null, enchantments);
}
@ -195,45 +246,22 @@ public class GUIInventory implements Listener {
public static ItemStack buildButton(ItemStack base, Chat displayName, List<Chat> lores) {
return buildButton(base, null, displayName, lores, null);
}
public static ItemStack buildButton(ItemStack base, Integer amount, Chat displayName) {
return buildButton(base, amount, displayName, null, null);
}
public static ItemStack buildButton(ItemStack base, Chat displayName) {
return buildButton(base, null, displayName, null, null);
}
public static ItemStack buildButton(ItemStack base, Integer amount) {
return buildButton(base, amount, null, null, null);
}
public static ItemStack buildButton(Material m, int amount, Chat displayName, List<Chat> lores, Map<Enchantment, Integer> enchantments) {
return buildButton(new ItemStack(m, amount), displayName, lores, enchantments);
}
public static ItemStack buildButton(Material m, Chat displayName, List<Chat> lores, Map<Enchantment, Integer> enchantments) {
return buildButton(m, 1, displayName, lores, enchantments);
}
public static ItemStack buildButton(Material m, int amount, Chat displayName, Map<Enchantment, Integer> enchantments) {
return buildButton(m, amount, displayName, null, enchantments);
return buildButton(new ItemStack(m), null, displayName, lores, enchantments);
}
public static ItemStack buildButton(Material m, Chat displayName, Map<Enchantment, Integer> enchantments) {
return buildButton(m, 1, displayName, null, enchantments);
}
public static ItemStack buildButton(Material m, int amount, Chat displayName, List<Chat> lores) {
return buildButton(m, amount, displayName, lores, null);
return buildButton(new ItemStack(m), null, displayName, null, enchantments);
}
public static ItemStack buildButton(Material m, Chat displayName, List<Chat> lores) {
return buildButton(m, 1, displayName, lores, null);
}
public static ItemStack buildButton(Material m, int amount, Chat displayName) {
return buildButton(m, amount, displayName, null, null);
return buildButton(new ItemStack(m), null, displayName, lores, null);
}
public static ItemStack buildButton(Material m, Chat displayName) {
return buildButton(m, 1, displayName, null, null);
}
public static ItemStack buildButton(Material m, int amount) {
return buildButton(m, amount, null, null, null);
return buildButton(new ItemStack(m), null, displayName, null, null);
}

View File

@ -1,64 +0,0 @@
package fr.pandacube.lib.paper.scheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
import fr.pandacube.lib.paper.PandaLibPaper;
public class AutoUpdatedObject {
private static final Plugin plugin = PandaLibPaper.getPlugin();
private Runnable updater;
private final List<BukkitTask> tasks = new ArrayList<>();
protected AutoUpdatedObject() { }
public AutoUpdatedObject(Runnable updater) {
this.updater = Objects.requireNonNull(updater);
}
public synchronized void updateSync() {
tasks.add(Bukkit.getScheduler().runTask(plugin, this::update));
}
public synchronized void updateAsync() {
tasks.add(Bukkit.getScheduler().runTaskAsynchronously(plugin, this::update));
}
public synchronized void updateLater(long delay)
throws IllegalArgumentException, IllegalStateException {
tasks.add(Bukkit.getScheduler().runTaskLater(plugin, this::update, delay));
}
public synchronized void updateLaterAsync(long delay)
throws IllegalArgumentException, IllegalStateException {
tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, this::update, delay));
}
public synchronized void updateTimer(long delay, long period)
throws IllegalArgumentException, IllegalStateException {
tasks.add(Bukkit.getScheduler().runTaskTimer(plugin, this::update, delay, period));
}
public synchronized void updateTimerAsync(long delay, long period)
throws IllegalArgumentException, IllegalStateException {
tasks.add(Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, this::update, delay, period));
}
public synchronized void cancel() {
tasks.forEach(BukkitTask::cancel);
tasks.clear();
}
public void update() {
Objects.requireNonNull(updater, "Please use new AutoUpdatedObject(Runnable) or override the run method.");
updater.run();
}
}

View File

@ -0,0 +1,104 @@
package fr.pandacube.lib.paper.scheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import fr.pandacube.lib.paper.PandaLibPaper;
/**
* An extension of {@link BukkitRunnable} that already integrates a reference to the Bukkit plugin.
*/
public class PandalibRunnable extends BukkitRunnable {
private static final Plugin plugin = PandaLibPaper.getPlugin();
private Runnable updater;
/**
* Instanciate a {@link PandalibRunnable}, whose {@link #run()} method will be called by the server scheduler.
* When using this default constructor, the {@link #run()} method must be override to provides code to run.
*/
protected PandalibRunnable() { }
/**
* Instanciate a {@link PandalibRunnable}, with an {@code updater} that will be called by the server scheduler.
* @param updater the updater to run when this task is executed.
*/
public PandalibRunnable(Runnable updater) {
this.updater = Objects.requireNonNull(updater);
}
/**
* Same as {@link #runTask(Plugin)}, but the plugin instance is already provided by
* {@link PandaLibPaper#getPlugin()}.
* @return a {@link BukkitTask} that contains the id number.
*/
public synchronized BukkitTask runTask() {
return runTask(plugin);
}
/**
* Same as {@link #runTaskAsynchronously(Plugin)}, but the plugin instance is already provided by
* {@link PandaLibPaper#getPlugin()}.
* @return a {@link BukkitTask} that contains the id number.
*/
public synchronized BukkitTask runTaskAsynchronously() {
return runTaskAsynchronously(plugin);
}
/**
* Same as {@link #runTaskLater(Plugin, long)}, but the plugin instance is already provided by
* {@link PandaLibPaper#getPlugin()}.
* @param delay the ticks to wait before running the task.
* @return a {@link BukkitTask} that contains the id number.
*/
public synchronized BukkitTask runTaskLater(long delay) {
return runTaskLater(plugin, delay);
}
/**
* Same as {@link #runTaskLaterAsynchronously(Plugin, long)}, but the plugin instance is already provided by
* {@link PandaLibPaper#getPlugin()}.
* @param delay the ticks to wait before running the task.
* @return a {@link BukkitTask} that contains the id number.
*/
public synchronized BukkitTask runTaskLaterAsynchronously(long delay) {
return runTaskLaterAsynchronously(plugin, delay);
}
/**
* Same as {@link #runTaskTimer(Plugin, long, long)}, but the plugin instance is already provided by
* {@link PandaLibPaper#getPlugin()}.
* @param delay the ticks to wait before running the task.
* @param period the ticks to wait between runs.
* @return a {@link BukkitTask} that contains the id number.
*/
public synchronized BukkitTask runTaskTimer(long delay, long period) {
return runTaskTimer(plugin, delay, period);
}
/**
* Same as {@link #runTaskTimerAsynchronously(Plugin, long, long)}, but the plugin instance is already provided by
* {@link PandaLibPaper#getPlugin()}.
* @param delay the ticks to wait before running the task.
* @param period the ticks to wait between runs.
* @return a {@link BukkitTask} that contains the id number.
*/
public synchronized BukkitTask runTaskTimerAsynchronously(long delay, long period) {
return runTaskTimerAsynchronously(plugin, delay, period);
}
@Override
public void run() {
Objects.requireNonNull(updater, "Please use new PandalibRunnable(Runnable) or override the run method.")
.run();
}
}

View File

@ -1,21 +1,45 @@
package fr.pandacube.lib.paper.scheduler;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import org.bukkit.Bukkit;
import fr.pandacube.lib.util.Log;
import fr.pandacube.lib.paper.PandaLibPaper;
/**
* Provides methods to easily manage synchronous and asynchronous operations with the server thread.
*/
public class SchedulerUtil {
/**
* Ensure that the provided runnable is run on the server thread.
* If the current thread is the server thread, then the task is run right now, then this method returns.
* If the current thread is another thread, it passes over the runnable to the Bukkit scheduler, then returns
* imediately.
* @param task the task to run on the main thread.
*/
public static void runOnServerThread(Runnable task) {
if (Bukkit.isPrimaryThread())
task.run();
Bukkit.getScheduler().runTask(PandaLibPaper.getPlugin(), task);
}
/**
* Runs the provided task on the main thread, and wait for this task to end to return its value.
* If the current thread is the server thread, then the task is run right now, then this method returns with the
* return value of the provided task. Otherwise, it will wait for the task to run on the main thread, to be able to
* return the value from the task.
* @param task the task to run on the main thread and to get the value from.
* @return the value returned by the task.
* @param <T> the type fo the return value of the task
* @throws CancellationException if the task was cancelled
* @throws ExecutionException if the task threw an exception
* @throws InterruptedException if the current thread was interrupted while waiting
*/
public static <T> T runOnServerThreadAndWait(Callable<T> task) throws Exception {
if (Bukkit.isPrimaryThread())
return task.call();
@ -29,7 +53,16 @@ public class SchedulerUtil {
}
}).get();
}
/**
* Runs the provided task on the main thread, and wait for this task to end to return.
* If the current thread is the server thread, then the task is run right now, then this method returns.
* Otherwise, it will wait for the task to finish on the main thread.
* @param task the task to run on the main thread.
* @throws CancellationException if the task was cancelled
* @throws ExecutionException if the task threw an exception
* @throws InterruptedException if the current thread was interrupted while waiting
*/
public static void runOnServerThreadAndWait(Runnable task) throws Exception {
runOnServerThreadAndWait((Callable<Void>)() -> {
task.run();

View File

@ -24,10 +24,9 @@ public class ItemStackBuilder {
/**
* Create a builder with a clone of the provided ItemStack.
*
* <p>
* The returned builder will not alter the provided ItemStack.
* IF you want to modify the ItemStack with the builder, please use {@link #wrap(ItemStack)}.
*
* If you want to modify the ItemStack with the builder, please use {@link #wrap(ItemStack)}.
* @param base the original ItemStack.
* @return the builder
*/
@ -37,7 +36,6 @@ public class ItemStackBuilder {
/**
* Create a builder of a new ItemStack with the specified Material.
*
* @param mat the material of the new builded ItemStack
* @return the builder
*/
@ -47,11 +45,12 @@ public class ItemStackBuilder {
/**
* Create a builder that will alter the data of the provided ItemStack.
*
* The {@link #build()} method of thez returned builder will return the same instance
* <p>
* The {@link #build()} method of the returned builder will return the same instance
* of ItemStack as the parameter of this method.
*
* <p>
* To create a builder that doesnt modify the provided ItemStack, use {@link #of(ItemStack)}.
* @param stack the wrapped itemstack.
* @return the builder
*/
public static ItemStackBuilder wrap(ItemStack stack) {