diff --git a/api/src/main/java/me/filoghost/chestcommands/api/ChestCommandsAPI.java b/api/src/main/java/me/filoghost/chestcommands/api/ChestCommandsAPI.java
index a501312..46aa149 100644
--- a/api/src/main/java/me/filoghost/chestcommands/api/ChestCommandsAPI.java
+++ b/api/src/main/java/me/filoghost/chestcommands/api/ChestCommandsAPI.java
@@ -53,18 +53,24 @@ public class ChestCommandsAPI {
* Menus loaded by Chest Commands from the menus folder always display placeholders, including those registered
* through this method.
*
- * The identifier is automatically converted to the appropriate placeholder format. For example, given the
- * identifier "test", the callback would be invoked to replace the the following placeholders:
+ * The identifier is used to compute which placeholder formats will invoke the replacer callback. For example, given
+ * the identifier "test", the callback would be invoked to replace the following placeholders (case insensitive):
*
* - {test}
- *
- {test: 123}
- *
- {test: hello world}
+ *
- {test: argument}
+ *
- {pluginName/test}
+ *
- {pluginName/test: argument}
*
+ * The plugin name is used as optional namespace, to distinguish two placeholders with the same identifier but
+ * registered by distinct plugins.
+ *
+ * This replaces any currently registered placeholder with the same plugin and identifier.
*
* @param plugin the plugin registering the placeholder
* @param identifier the identifier of the placeholder, which can only contain letters, digits and
* underscores
* @param placeholderReplacer the callback that returns the displayed value
+ * @throws IllegalArgumentException if the identifier contains invalid characters
* @see PlaceholderReplacer#getReplacement(Player, String)
* @since 1
*/
@@ -74,12 +80,11 @@ public class ChestCommandsAPI {
BackendAPI.getImplementation().registerPlaceholder(plugin, identifier, placeholderReplacer);
}
-
/**
* Returns if a menu with a given file name exists and was loaded successfully by Chest Commands from the menus
* folder.
*
- * @param menuFileName the file name of the menu to check
+ * @param menuFileName the file name of the menu to check, including the {@code .yml} file extension
* @return true if the menu exists, false otherwise
* @since 1
*/
@@ -94,7 +99,7 @@ public class ChestCommandsAPI {
* WARNING: this method opens the menu without checking the permissions of the player.
*
* @param player the player that will see the menu
- * @param menuFileName the file name of the menu to open
+ * @param menuFileName the file name of the menu to open, including the {@code .yml} file extension
* @return true if the menu was found and opened successfully, false otherwise
* @since 1
*/
diff --git a/api/src/main/java/me/filoghost/chestcommands/api/Menu.java b/api/src/main/java/me/filoghost/chestcommands/api/Menu.java
index 5fb4b09..9b5e141 100644
--- a/api/src/main/java/me/filoghost/chestcommands/api/Menu.java
+++ b/api/src/main/java/me/filoghost/chestcommands/api/Menu.java
@@ -8,30 +8,34 @@ package me.filoghost.chestcommands.api;
import me.filoghost.chestcommands.api.internal.BackendAPI;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
- * Menus are containers of {@link Icon}s that can be displayed to players as unmodifiable inventories.
+ * Menus are containers of {@link Icon}s that can be displayed to players as unmodifiable inventories, organized as a
+ * grid with a number of rows and columns.
*
- * It is not recommended to implement this interface, use the provided constructor {@link Menu#create(Plugin, String,
- * int)}.
+ * This interface should not be implemented, use the provided constructor {@link Menu#create(Plugin, String, int)}. Any
+ * custom implementation will not be handled by Chest Commands' event listener, which relies on internal details. New
+ * methods may also be added, making existing custom implementations incompatible.
*
* @since 1
*/
+@ApiStatus.NonExtendable
public interface Menu {
/**
* Creates a new menu.
*
- * @param owner the plugin creating the menu
- * @param title title of the menu that will be displayed in the inventory
- * @param rowCount number of rows in the menu (the number of columns is always 9, currently)
+ * @param plugin the plugin creating the menu
+ * @param title title of the menu that appears in the displayed inventory
+ * @param rows number of rows in the menu (the number of columns is always 9, currently)
* @return the created menu
* @since 1
*/
- static @NotNull Menu create(@NotNull Plugin owner, @NotNull String title, int rowCount) {
- return BackendAPI.getImplementation().createMenu(owner, title, rowCount);
+ static @NotNull Menu create(@NotNull Plugin plugin, @NotNull String title, int rows) {
+ return BackendAPI.getImplementation().createMenu(plugin, title, rows);
}
/**
@@ -40,6 +44,8 @@ public interface Menu {
* @param row the row position
* @param column the column position
* @param icon the new icon, null to remove the current one
+ * @throws IndexOutOfBoundsException if the row or the column is outside the limits ({@code row < 0 || row >=
+ * getRows() || column < 0 || column >= getColumns()})
* @since 1
*/
void setIcon(int row, int column, @Nullable Icon icon);
@@ -50,39 +56,17 @@ public interface Menu {
* @param row the row position
* @param column the column position
* @return the icon at the give position, null if absent
+ * @throws IndexOutOfBoundsException if the row or the column is outside the limits ({@code row < 0 || row >=
+ * getRows() || column < 0 || column >= getColumns()})
* @since 1
*/
@Nullable Icon getIcon(int row, int column);
- /**
- * Returns the title of the displayed inventory.
- *
- * @return the title
- * @since 1
- */
- @NotNull String getTitle();
-
- /**
- * Returns the amount of rows of the displayed inventory.
- *
- * @return the amount of rows
- * @since 1
- */
- int getRowCount();
-
- /**
- * Returns the amount of columns of the displayed inventory.
- *
- * @return the amount of columns
- * @since 1
- */
- int getColumnCount();
-
/**
* Displays the menu to a player, creating a rendering of this menu and its icons.
*
* If icons are added, removed or changed after the menu is displayed to a player, the view is not updated
- * automatically and you may want to invoke {@link Menu#refreshOpenMenuViews()}.
+ * automatically and you may want to invoke {@link Menu#refreshOpenViews()}.
*
* @param player the player to which the menu will be displayed
* @return the newly created view for the player
@@ -97,10 +81,42 @@ public interface Menu {
* This method should be called after adding, removing or changing one or more icons to update the open menu views
* of players.
*
- * This method invokes {@link MenuView#refresh()} on each open view created by this menu.
+ * This method invokes {@link MenuView#refresh()} on each currently open view created by this menu.
*
* @since 1
*/
- void refreshOpenMenuViews();
+ void refreshOpenViews();
+
+ /**
+ * Returns the amount of rows of the displayed inventory.
+ *
+ * @return the amount of rows
+ * @since 1
+ */
+ int getRows();
+
+ /**
+ * Returns the amount of columns of the displayed inventory.
+ *
+ * @return the amount of columns
+ * @since 1
+ */
+ int getColumns();
+
+ /**
+ * Returns the title of the displayed inventory.
+ *
+ * @return the title
+ * @since 1
+ */
+ @NotNull String getTitle();
+
+ /**
+ * Returns the plugin that created the menu.
+ *
+ * @return the plugin that created the menu
+ * @since 1
+ */
+ Plugin getPlugin();
}
\ No newline at end of file
diff --git a/api/src/main/java/me/filoghost/chestcommands/api/MenuView.java b/api/src/main/java/me/filoghost/chestcommands/api/MenuView.java
index f1fb4c5..5583a15 100644
--- a/api/src/main/java/me/filoghost/chestcommands/api/MenuView.java
+++ b/api/src/main/java/me/filoghost/chestcommands/api/MenuView.java
@@ -29,7 +29,7 @@ public interface MenuView {
* player and you want to refresh the money placeholder instantly.
*
* Note that {@link ClickHandler} exposes the menu view being interacted with, so you don't need to refresh all the
- * views of a menu through {@link Menu#refreshOpenMenuViews()}.
+ * views of a menu through {@link Menu#refreshOpenViews()}.
*
* @since 1
*/
diff --git a/api/src/main/java/me/filoghost/chestcommands/api/PlaceholderReplacer.java b/api/src/main/java/me/filoghost/chestcommands/api/PlaceholderReplacer.java
index d05c2f5..347d22b 100644
--- a/api/src/main/java/me/filoghost/chestcommands/api/PlaceholderReplacer.java
+++ b/api/src/main/java/me/filoghost/chestcommands/api/PlaceholderReplacer.java
@@ -27,6 +27,8 @@ public interface PlaceholderReplacer {
*
* If this method returns null, the placeholder is not replaced. It is preferred to return a descriptive error
* message rather than returning null.
+ *
+ * Warning: this method should be performance efficient, as it may be invoked quite often.
*
* @param player the player viewing the placeholder
* @param argument the argument inside the placeholder, if present
diff --git a/api/src/main/java/me/filoghost/chestcommands/api/internal/BackendAPI.java b/api/src/main/java/me/filoghost/chestcommands/api/internal/BackendAPI.java
index c7ddb35..6902352 100644
--- a/api/src/main/java/me/filoghost/chestcommands/api/internal/BackendAPI.java
+++ b/api/src/main/java/me/filoghost/chestcommands/api/internal/BackendAPI.java
@@ -42,7 +42,7 @@ public abstract class BackendAPI {
public abstract boolean openPluginMenu(@NotNull Player player, @NotNull String menuFileName);
- public abstract @NotNull Menu createMenu(@NotNull Plugin owner, @NotNull String title, int rows);
+ public abstract @NotNull Menu createMenu(@NotNull Plugin plugin, @NotNull String title, int rows);
public abstract @NotNull ConfigurableIcon createConfigurableIcon(@NotNull Material material);
diff --git a/checkstyle/checkstyle.xml b/checkstyle/checkstyle.xml
index bd8bc17..7375114 100644
--- a/checkstyle/checkstyle.xml
+++ b/checkstyle/checkstyle.xml
@@ -75,7 +75,6 @@
-
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java b/plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java
index 6ff40f4..5d34b60 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java
@@ -184,7 +184,7 @@ public class ChestCommands extends BaseJavaPlugin {
}
- public static Plugin getPluginInstance() {
+ public static Plugin getInstance() {
return pluginInstance;
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/DefaultBackendAPI.java b/plugin/src/main/java/me/filoghost/chestcommands/DefaultBackendAPI.java
index c77bc0a..7e64a2d 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/DefaultBackendAPI.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/DefaultBackendAPI.java
@@ -53,8 +53,8 @@ public class DefaultBackendAPI extends BackendAPI {
}
@Override
- public @NotNull Menu createMenu(@NotNull Plugin owner, @NotNull String title, int rows) {
- return new APIMenu(owner, title, rows);
+ public @NotNull Menu createMenu(@NotNull Plugin plugin, @NotNull String title, int rows) {
+ return new APIMenu(plugin, title, rows);
}
@Override
@@ -63,7 +63,9 @@ public class DefaultBackendAPI extends BackendAPI {
}
@Override
- public void registerPlaceholder(@NotNull Plugin plugin, @NotNull String identifier, @NotNull PlaceholderReplacer placeholderReplacer) {
+ public void registerPlaceholder(@NotNull Plugin plugin,
+ @NotNull String identifier,
+ @NotNull PlaceholderReplacer placeholderReplacer) {
PlaceholderManager.registerPluginPlaceholder(plugin, identifier, placeholderReplacer);
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/action/OpenMenuAction.java b/plugin/src/main/java/me/filoghost/chestcommands/action/OpenMenuAction.java
index 86f7c99..05fb200 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/action/OpenMenuAction.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/action/OpenMenuAction.java
@@ -31,7 +31,7 @@ public class OpenMenuAction implements Action {
* Delay the task, since this action is executed in ClickInventoryEvent
* and opening another inventory in the same moment is not a good idea.
*/
- Bukkit.getScheduler().runTask(ChestCommands.getPluginInstance(), () -> {
+ Bukkit.getScheduler().runTask(ChestCommands.getInstance(), () -> {
menu.openCheckingPermission(player);
});
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/command/CommandHandler.java b/plugin/src/main/java/me/filoghost/chestcommands/command/CommandHandler.java
index 4ac1283..e3d22c4 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/command/CommandHandler.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/command/CommandHandler.java
@@ -42,7 +42,7 @@ public class CommandHandler extends MultiCommandManager {
@Override
protected void sendNoArgsMessage(CommandSender sender, String rootCommandLabel) {
sender.sendMessage(ChestCommands.CHAT_PREFIX);
- sender.sendMessage(ChatColor.GREEN + "Version: " + ChatColor.GRAY + ChestCommands.getPluginInstance().getDescription().getVersion());
+ sender.sendMessage(ChatColor.GREEN + "Version: " + ChatColor.GRAY + ChestCommands.getInstance().getDescription().getVersion());
sender.sendMessage(ChatColor.GREEN + "Developer: " + ChatColor.GRAY + "filoghost");
sender.sendMessage(ChatColor.GREEN + "Commands: " + ChatColor.GRAY + "/" + rootCommandLabel + " help");
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/hook/BungeeCordHook.java b/plugin/src/main/java/me/filoghost/chestcommands/hook/BungeeCordHook.java
index 32d4b93..3ac3f7a 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/hook/BungeeCordHook.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/hook/BungeeCordHook.java
@@ -22,8 +22,8 @@ public enum BungeeCordHook implements PluginHook {
@Override
public void setup() {
- if (!Bukkit.getMessenger().isOutgoingChannelRegistered(ChestCommands.getPluginInstance(), BUNGEE_CORD_CHANNEL)) {
- Bukkit.getMessenger().registerOutgoingPluginChannel(ChestCommands.getPluginInstance(), BUNGEE_CORD_CHANNEL);
+ if (!Bukkit.getMessenger().isOutgoingChannelRegistered(ChestCommands.getInstance(), BUNGEE_CORD_CHANNEL)) {
+ Bukkit.getMessenger().registerOutgoingPluginChannel(ChestCommands.getInstance(), BUNGEE_CORD_CHANNEL);
}
}
@@ -50,7 +50,7 @@ public enum BungeeCordHook implements PluginHook {
throw new AssertionError();
}
- player.sendPluginMessage(ChestCommands.getPluginInstance(), BUNGEE_CORD_CHANNEL, byteArrayOutputStream.toByteArray());
+ player.sendPluginMessage(ChestCommands.getInstance(), BUNGEE_CORD_CHANNEL, byteArrayOutputStream.toByteArray());
}
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/inventory/DefaultMenuView.java b/plugin/src/main/java/me/filoghost/chestcommands/inventory/DefaultMenuView.java
index 6b4cade..d5f210d 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/inventory/DefaultMenuView.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/inventory/DefaultMenuView.java
@@ -14,9 +14,6 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-/**
- * Represents a particular view of a menu.
- */
public class DefaultMenuView implements MenuView {
private final BaseMenu menu;
@@ -26,7 +23,7 @@ public class DefaultMenuView implements MenuView {
public DefaultMenuView(@NotNull BaseMenu menu, @NotNull Player viewer) {
this.menu = menu;
this.viewer = viewer;
- this.bukkitInventory = new InventoryGrid(new MenuInventoryHolder(this), menu.getRowCount(), menu.getTitle());
+ this.bukkitInventory = new InventoryGrid(new MenuInventoryHolder(this), menu.getRows(), menu.getTitle());
refresh();
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/listener/InventoryListener.java b/plugin/src/main/java/me/filoghost/chestcommands/listener/InventoryListener.java
index 09e6ff5..c6235fa 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/listener/InventoryListener.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/listener/InventoryListener.java
@@ -8,9 +8,13 @@ package me.filoghost.chestcommands.listener;
import me.filoghost.chestcommands.ChestCommands;
import me.filoghost.chestcommands.api.ClickResult;
import me.filoghost.chestcommands.api.Icon;
+import me.filoghost.chestcommands.api.Menu;
import me.filoghost.chestcommands.config.Settings;
import me.filoghost.chestcommands.inventory.DefaultMenuView;
+import me.filoghost.chestcommands.logging.Errors;
+import me.filoghost.chestcommands.menu.InternalMenu;
import me.filoghost.chestcommands.menu.MenuManager;
+import me.filoghost.fcommons.logging.Log;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -75,13 +79,28 @@ public class InventoryListener implements Listener {
}
// Only handle the click AFTER the event has finished
- Bukkit.getScheduler().runTask(ChestCommands.getPluginInstance(), () -> {
- ClickResult result = icon.onClick(menuView, clicker);
+ Bukkit.getScheduler().runTask(ChestCommands.getInstance(), () -> {
+ try {
+ ClickResult result = icon.onClick(menuView, clicker);
- if (result == ClickResult.CLOSE) {
- clicker.closeInventory();
+ if (result == ClickResult.CLOSE) {
+ clicker.closeInventory();
+ }
+ } catch (Throwable t) {
+ handleIconClickException(menuView.getMenu(), t);
}
});
}
+ private void handleIconClickException(Menu menu, Throwable throwable) {
+ String menuDescription;
+ if (menu.getPlugin() == ChestCommands.getInstance()) {
+ menuDescription = "the menu \"" + Errors.formatPath(((InternalMenu) menu).getSourceFile()) + "\"";
+ } else {
+ menuDescription = "a menu created by the plugin \"" + menu.getPlugin().getName() + "\"";
+ }
+
+ Log.severe("Encountered exception while handling a click inside " + menuDescription, throwable);
+ }
+
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/logging/Errors.java b/plugin/src/main/java/me/filoghost/chestcommands/logging/Errors.java
index 246a528..5cf2c4d 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/logging/Errors.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/logging/Errors.java
@@ -215,7 +215,7 @@ public class Errors {
}
- private static String formatPath(Path path) {
+ public static String formatPath(Path path) {
return ConfigErrors.formatPath(ChestCommands.getDataFolderPath(), path);
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/menu/APIMenu.java b/plugin/src/main/java/me/filoghost/chestcommands/menu/APIMenu.java
index d726acb..fa7ea05 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/menu/APIMenu.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/menu/APIMenu.java
@@ -11,16 +11,17 @@ import org.jetbrains.annotations.NotNull;
public class APIMenu extends BaseMenu {
- private final Plugin owner;
-
- public APIMenu(@NotNull Plugin owner, @NotNull String title, int rows) {
+ private final Plugin plugin;
+
+ public APIMenu(@NotNull Plugin plugin, @NotNull String title, int rows) {
super(title, rows);
- Preconditions.notNull(owner, "owner");
- this.owner = owner;
+ Preconditions.notNull(plugin, "plugin");
+ this.plugin = plugin;
}
- public @NotNull Plugin getOwner() {
- return owner;
+ @Override
+ public Plugin getPlugin() {
+ return plugin;
}
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/menu/BaseMenu.java b/plugin/src/main/java/me/filoghost/chestcommands/menu/BaseMenu.java
index 315b005..c751071 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/menu/BaseMenu.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/menu/BaseMenu.java
@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable;
public abstract class BaseMenu implements Menu {
-
+
private final String title;
private final Grid icons;
@@ -42,12 +42,31 @@ public abstract class BaseMenu implements Menu {
}
@Override
- public int getRowCount() {
+ public @NotNull MenuView open(@NotNull Player player) {
+ Preconditions.notNull(player, "player");
+
+ DefaultMenuView menuView = new DefaultMenuView(this, player);
+ menuView.open();
+ return menuView;
+ }
+
+ @Override
+ public void refreshOpenViews() {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ DefaultMenuView menuView = MenuManager.getOpenMenuView(player);
+ if (menuView != null && menuView.getMenu() == this) {
+ menuView.refresh();
+ }
+ }
+ }
+
+ @Override
+ public int getRows() {
return icons.getRows();
}
-
+
@Override
- public int getColumnCount() {
+ public int getColumns() {
return icons.getColumns();
}
@@ -60,22 +79,4 @@ public abstract class BaseMenu implements Menu {
return icons;
}
- @Override
- public @NotNull MenuView open(@NotNull Player player) {
- Preconditions.notNull(player, "player");
-
- DefaultMenuView menuView = new DefaultMenuView(this, player);
- menuView.open();
- return menuView;
- }
-
- @Override
- public void refreshOpenMenuViews() {
- for (Player player : Bukkit.getOnlinePlayers()) {
- DefaultMenuView menuView = MenuManager.getOpenMenuView(player);
- if (menuView != null && menuView.getMenu() == this) {
- menuView.refresh();
- }
- }
- }
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/menu/InternalMenu.java b/plugin/src/main/java/me/filoghost/chestcommands/menu/InternalMenu.java
index 202c71a..014df87 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/menu/InternalMenu.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/menu/InternalMenu.java
@@ -6,6 +6,7 @@
package me.filoghost.chestcommands.menu;
import com.google.common.collect.ImmutableList;
+import me.filoghost.chestcommands.ChestCommands;
import me.filoghost.chestcommands.Permissions;
import me.filoghost.chestcommands.action.Action;
import me.filoghost.chestcommands.api.MenuView;
@@ -13,6 +14,7 @@ import me.filoghost.chestcommands.config.Lang;
import me.filoghost.fcommons.collection.CollectionUtils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
@@ -63,6 +65,11 @@ public class InternalMenu extends BaseMenu {
return super.open(player);
}
+ @Override
+ public Plugin getPlugin() {
+ return ChestCommands.getInstance();
+ }
+
public void openCheckingPermission(Player player) {
if (player.hasPermission(openPermission)) {
open(player);
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java b/plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java
index fa6a8f1..1a2f7da 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java
@@ -63,16 +63,16 @@ public class MenuParser {
int row = positionY.getPosition() - 1;
int column = positionX.getPosition() - 1;
- if (row < 0 || row >= menu.getRowCount()) {
+ if (row < 0 || row >= menu.getRows()) {
errorCollector.add(
Errors.Menu.invalidAttribute(iconSettings, AttributeType.POSITION_Y),
- "it must be between 1 and " + menu.getRowCount());
+ "it must be between 1 and " + menu.getRows());
return;
}
- if (column < 0 || column >= menu.getColumnCount()) {
+ if (column < 0 || column >= menu.getColumns()) {
errorCollector.add(
Errors.Menu.invalidAttribute(iconSettings, AttributeType.POSITION_X),
- "it must be between 1 and " + menu.getColumnCount());
+ "it must be between 1 and " + menu.getColumns());
return;
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/Placeholder.java b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/Placeholder.java
new file mode 100644
index 0000000..077b4cf
--- /dev/null
+++ b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/Placeholder.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) filoghost and contributors
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+package me.filoghost.chestcommands.placeholder;
+
+import me.filoghost.chestcommands.api.PlaceholderReplacer;
+import org.bukkit.plugin.Plugin;
+
+public class Placeholder {
+
+ private final Plugin plugin;
+ private final PlaceholderReplacer placeholderReplacer;
+
+ public Placeholder(Plugin plugin, PlaceholderReplacer placeholderReplacer) {
+ this.plugin = plugin;
+ this.placeholderReplacer = placeholderReplacer;
+ }
+
+ public Plugin getPlugin() {
+ return plugin;
+ }
+
+ public PlaceholderReplacer getReplacer() {
+ return placeholderReplacer;
+ }
+
+}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderManager.java b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderManager.java
index c2cfcd2..bf09d4c 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderManager.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderManager.java
@@ -10,6 +10,7 @@ import me.filoghost.chestcommands.hook.PlaceholderAPIHook;
import me.filoghost.chestcommands.placeholder.scanner.PlaceholderMatch;
import me.filoghost.chestcommands.placeholder.scanner.PlaceholderScanner;
import me.filoghost.fcommons.Preconditions;
+import me.filoghost.fcommons.logging.Log;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
@@ -21,14 +22,13 @@ public class PlaceholderManager {
private static final List staticPlaceholders = new ArrayList<>();
private static final PlaceholderRegistry relativePlaceholderRegistry = new PlaceholderRegistry();
+ private static final PlaceholderCache placeholderCache = new PlaceholderCache();
static {
for (DefaultPlaceholder placeholder : DefaultPlaceholder.values()) {
relativePlaceholderRegistry.registerInternalPlaceholder(placeholder.getIdentifier(), placeholder.getReplacer());
}
}
- private static final PlaceholderCache placeholderCache = new PlaceholderCache();
-
public static boolean hasRelativePlaceholders(List list) {
for (String element : list) {
if (hasRelativePlaceholders(element)) {
@@ -61,18 +61,24 @@ public class PlaceholderManager {
}
private static boolean isValidPlaceholder(PlaceholderMatch placeholderMatch) {
- return relativePlaceholderRegistry.getPlaceholderReplacer(placeholderMatch) != null;
+ return relativePlaceholderRegistry.getPlaceholder(placeholderMatch) != null;
}
private static @Nullable String getReplacement(PlaceholderMatch placeholderMatch, Player player) {
- PlaceholderReplacer placeholderReplacer = relativePlaceholderRegistry.getPlaceholderReplacer(placeholderMatch);
+ Placeholder placeholder = relativePlaceholderRegistry.getPlaceholder(placeholderMatch);
- if (placeholderReplacer == null) {
+ if (placeholder == null) {
return null; // Placeholder not found
}
return placeholderCache.computeIfAbsent(placeholderMatch, player, () -> {
- return placeholderReplacer.getReplacement(player, placeholderMatch.getArgument());
+ try {
+ return placeholder.getReplacer().getReplacement(player, placeholderMatch.getArgument());
+ } catch (Throwable t) {
+ Log.severe("Encountered exception while replacing the placeholder \"" + placeholderMatch
+ + "\" registered by the plugin \"" + placeholder.getPlugin().getName() + "\"", t);
+ return "[ERROR]";
+ }
});
}
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderRegistry.java b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderRegistry.java
index 3d20c61..ae3e3d7 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderRegistry.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/PlaceholderRegistry.java
@@ -5,47 +5,54 @@
*/
package me.filoghost.chestcommands.placeholder;
+import me.filoghost.chestcommands.ChestCommands;
import me.filoghost.chestcommands.api.PlaceholderReplacer;
import me.filoghost.chestcommands.placeholder.scanner.PlaceholderMatch;
+import me.filoghost.fcommons.collection.CaseInsensitiveMap;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
-import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class PlaceholderRegistry {
- private final Map internalPlaceholders = new HashMap<>();
- private final Map> externalPlaceholders = new HashMap<>();
+ //
+ private final Map internalPlaceholders = new CaseInsensitiveMap<>();
+
+ // >
+ private final Map> externalPlaceholders = new CaseInsensitiveMap<>();
public void registerInternalPlaceholder(String identifier, PlaceholderReplacer replacer) {
- internalPlaceholders.put(identifier, replacer);
+ internalPlaceholders.put(identifier, new Placeholder(ChestCommands.getInstance(), replacer));
}
public void registerExternalPlaceholder(Plugin plugin, String identifier, PlaceholderReplacer placeholderReplacer) {
externalPlaceholders
- .computeIfAbsent(identifier, key -> new LinkedHashMap<>())
- .put(plugin.getName(), placeholderReplacer);
+ .computeIfAbsent(identifier, key -> new CaseInsensitiveMap<>(new LinkedHashMap<>()))
+ .put(plugin.getName(), new Placeholder(plugin, placeholderReplacer));
}
- public @Nullable PlaceholderReplacer getPlaceholderReplacer(PlaceholderMatch placeholderMatch) {
+ public @Nullable Placeholder getPlaceholder(PlaceholderMatch placeholderMatch) {
+ String identifier = placeholderMatch.getIdentifier();
+
if (placeholderMatch.getPluginNamespace() == null) {
- PlaceholderReplacer internalReplacer = internalPlaceholders.get(placeholderMatch.getIdentifier());
- if (internalReplacer != null) {
- return internalReplacer;
+ Placeholder internalPlaceholder = internalPlaceholders.get(identifier);
+ if (internalPlaceholder != null) {
+ return internalPlaceholder;
}
}
- Map externalReplacers = externalPlaceholders.get(placeholderMatch.getIdentifier());
+ Map externalPlaceholdersByPlugin = externalPlaceholders.get(identifier);
// Find exact replacer if plugin name is specified
if (placeholderMatch.getPluginNamespace() != null) {
- return externalReplacers.get(placeholderMatch.getPluginNamespace());
+ return externalPlaceholdersByPlugin.get(placeholderMatch.getPluginNamespace());
}
- if (externalReplacers != null && !externalReplacers.isEmpty()) {
- return externalReplacers.values().iterator().next();
+ // Otherwise try find the first one registered
+ if (externalPlaceholdersByPlugin != null && !externalPlaceholdersByPlugin.isEmpty()) {
+ return externalPlaceholdersByPlugin.values().iterator().next();
}
return null;
diff --git a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/scanner/PlaceholderMatch.java b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/scanner/PlaceholderMatch.java
index 29d73c0..6db89ef 100644
--- a/plugin/src/main/java/me/filoghost/chestcommands/placeholder/scanner/PlaceholderMatch.java
+++ b/plugin/src/main/java/me/filoghost/chestcommands/placeholder/scanner/PlaceholderMatch.java
@@ -35,9 +35,10 @@ public class PlaceholderMatch {
/*
* Valid formats:
- * {pluginName/placeholder: argument}
- * {placeholder: argument}
* {placeholder}
+ * {placeholder: argument}
+ * {pluginName/identifier}
+ * {pluginName/identifier: argument}
*/
public static PlaceholderMatch parse(String placeholderContent) {
String explicitPluginName = null;