Skip to content

Commit

Permalink
Refactored inventory interaction event blocking system (#37)
Browse files Browse the repository at this point in the history
* Add click and action filtering in SGMenu

Introduced permittedMenuClickTypes, blockedMenuActions, and blockedAdjacentActions arrays in SGMenu to handle specific click and action types. Refactored SGMenu constructors to support these new features and updated event handling to utilize the new arrays for more flexible and secure menu interactions.

* Correct conditional check for permitted menu click types

Previously, the constructor incorrectly defaulted to permitted click types if an empty array was passed. The updated check now ensures that `DEFAULT_PERMITTED_MENU_CLICK_TYPES` is used only if no specific click types are provided.

* Fix SGMenu constructor to handle permitted click types correctly

The constructor now properly checks if permittedMenuClickTypes is non-empty. Previously, an empty array was incorrectly accepted, potentially leading to unintended behavior. This ensures that the default permitted click types are used only when no custom types are provided.

* Refactor SGMenuListener to streamline event handling

Simplified the SGMenuListener by removing an unnecessary return statement. This change improves code readability without altering the logical flow of blocking specific menu actions.

* Refactor SGMenu and SGMenuListener to simplify click and action handling

Refactor the `SGMenu` class to change `public` ArrayLists to `private` arrays for `permittedMenuClickTypes`, `blockedMenuActions`, and `blockedAdjacentActions`. Introduce getter and setter methods for these fields to maintain encapsulation. Update references in `SGMenuListener` to use the new getter methods, improving code readability and ensuring better data encapsulation.

* Refactor to use HashSet for menu action and click type lists

Refactored SGMenu and SGMenuListener to use HashSet instead of arrays for permitted menu click types and blocked actions. This change includes adding methods to add and remove elements from these HashSets, providing better performance and flexibility. Updated related methods and listeners accordingly.
  • Loading branch information
Stanley-Dam authored Aug 10, 2024
1 parent cbd1050 commit 4ac7764
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 53 deletions.
3 changes: 0 additions & 3 deletions src/main/java/com/samjakob/spigui/SpiGUI.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.samjakob.spigui;

import com.samjakob.spigui.buttons.SGButton;
import com.samjakob.spigui.menu.SGMenu;
import com.samjakob.spigui.menu.SGMenuListener;
import com.samjakob.spigui.menu.SGOpenMenu;
import com.samjakob.spigui.item.ItemBuilder;
import com.samjakob.spigui.toolbar.SGDefaultToolbarBuilder;
import com.samjakob.spigui.toolbar.SGToolbarBuilder;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.plugin.java.JavaPlugin;
Expand Down
162 changes: 153 additions & 9 deletions src/main/java/com/samjakob/spigui/menu/SGMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.plugin.java.JavaPlugin;
Expand All @@ -23,7 +25,7 @@
* <br><br>
* You do not instantiate this class when you need it - as you would
* have done with the older version of the library - rather you make a
* call to {@link SpiGUI#create(String, int)} (or {@link SpiGUI#create(String, int, String)})
* call to {@link SpiGUI#create(String, int)} or {@link SpiGUI#create(String, int, String)}
* from your plugin's {@link SpiGUI} instance.
* <br><br>
* This creates an inventory that is already associated with your plugin.
Expand Down Expand Up @@ -70,20 +72,53 @@ public class SGMenu implements InventoryHolder {
/** The action to be performed on page change. */
private Consumer<SGMenu> onPageChange;

/**
* Any click types not in this array will be immediately prevented in
* this menu without further processing (i.e., the button's
* listener will not be called).
*/
private HashSet<ClickType> permittedMenuClickTypes;

/**
* Any actions in this list will be blocked immediately without further
* processing if they occur in a SpiGUI menu.
*/
private HashSet<InventoryAction> blockedMenuActions;

/**
* Any actions in this list will be blocked if they occur in the adjacent
* inventory to an SGMenu.
*/
private HashSet<InventoryAction> blockedAdjacentActions;

/// DEFAULT PERMITTED / BLOCKED ACTIONS ///

private static final ClickType[] DEFAULT_PERMITTED_MENU_CLICK_TYPES = new ClickType[]{
ClickType.LEFT,
ClickType.RIGHT
};

private static final InventoryAction[] DEFAULT_BLOCKED_MENU_ACTIONS = new InventoryAction[] {
InventoryAction.MOVE_TO_OTHER_INVENTORY,
InventoryAction.COLLECT_TO_CURSOR
};

private static final InventoryAction[] DEFAULT_BLOCKED_ADJACENT_ACTIONS = new InventoryAction[] {
InventoryAction.MOVE_TO_OTHER_INVENTORY,
InventoryAction.COLLECT_TO_CURSOR
};

/**
* <b>Intended for internal use only. Use {@link SpiGUI#create(String, int)} or {@link SpiGUI#create(String, int, String)}!</b><br>
* Used by the library internally to construct an SGMenu.
* <br>
* The name parameter is color code translated.
*
* @param owner The plugin the inventory should be associated with.
* @param spiGUI The SpiGUI that created this inventory.
* @param name The display name of the inventory.
* @param rowsPerPage The number of rows per page.
* @param tag The inventory's tag.
*
* @see SpiGUI#create(String, int)
* @see SpiGUI#create(String, int, String)
* @param owner The JavaPlugin that owns this menu.
* @param spiGUI The SpiGUI instance associated with this menu.
* @param name The name of the menu.
* @param rowsPerPage The number of rows per page in the menu.
* @param tag The tag associated with this menu.
*/
public SGMenu(JavaPlugin owner, SpiGUI spiGUI, String name, int rowsPerPage, String tag) {
this.owner = owner;
Expand Down Expand Up @@ -599,6 +634,115 @@ public void setOnPageChange(Consumer<SGMenu> onPageChange) {
this.onPageChange = onPageChange;
}

/**
* Returns the permitted menu click types.
*
* @return A hashSet of permitted menu click types
*/
public HashSet<ClickType> getPermittedMenuClickTypes() {
return this.permittedMenuClickTypes;
}

/**
* Returns an array of blocked menu actions for the current Inventory.
*
* @return A hashSet of blocked menu actions
*/
public HashSet<InventoryAction> getBlockedMenuActions() {
return this.blockedMenuActions;
}

/**
* Returns the blocked adjacent actions for this object.
*
* @return A hashSet of InventoryAction objects representing the blocked adjacent actions.
*/
public HashSet<InventoryAction> getBlockedAdjacentActions() {
return this.blockedAdjacentActions;
}

/**
* Sets the permitted menu click types.
*
* @param clickTypes One or more click types you want to allow for this menu.
*/
public void setPermittedMenuClickTypes(ClickType... clickTypes) {
this.permittedMenuClickTypes = new HashSet<>(Arrays.asList(clickTypes));
}

/**
* Sets the blocked menu actions for the inventory.
*
* @param actions the menu actions to be blocked
*/
public void setBlockedMenuActions(InventoryAction... actions) {
this.blockedMenuActions = new HashSet<>(Arrays.asList(actions));
}

/**
* Sets the blocked adjacent actions for this object.
*
* @param actions The actions to be blocked.
*/
public void setBlockedAdjacentActions(InventoryAction... actions) {
this.blockedAdjacentActions = new HashSet<>(Arrays.asList(actions));
}

/**
* Adds a permitted click type to the menu.
*
* @param clickType the click type to be added
*/
public void addPermittedClickType(ClickType clickType) {
this.permittedMenuClickTypes.add(clickType);
}

/**
* Adds the given InventoryAction to the list of blocked menu actions.
* Blocked menu actions are actions that are not allowed to be performed on the inventory menu.
*
* @param action The InventoryAction to be added to the blocked menu actions list.
*/
public void addBlockedMenuAction(InventoryAction action) {
this.blockedMenuActions.add(action);
}

/**
* Adds a blocked adjacent action to the list of blocked adjacent actions.
*
* @param action The inventory action to be added as blocked adjacent action.
*/
public void addBlockedAdjacentAction(InventoryAction action) {
this.getBlockedAdjacentActions().add(action);
}

/**
* Removes a permitted click type from the list of permitted menu click types.
*
* @param clickType the click type to be removed
*/
public void removePermittedClickType(ClickType clickType) {
this.permittedMenuClickTypes.remove(clickType);
}

/**
* Removes the specified InventoryAction from the list of blocked menu actions.
*
* @param action the InventoryAction to be removed
*/
public void removeBlockedMenuAction(InventoryAction action) {
this.blockedMenuActions.remove(action);
}

/**
* Removes the given action from the list of blocked adjacent actions.
*
* @param action The action to be removed
*/
public void removeBlockedAdjacentAction(InventoryAction action) {
this.getBlockedAdjacentActions().remove(action);
}

/// INVENTORY API ///

/**
Expand Down
51 changes: 10 additions & 41 deletions src/main/java/com/samjakob/spigui/menu/SGMenuListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.bukkit.inventory.InventoryView;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.Arrays;
import java.util.Objects;
import java.util.Set;

Expand All @@ -27,34 +26,6 @@
*/
public class SGMenuListener implements Listener {

/**
* Any click types not in this array will be immediately prevented in
* SpiGUI inventories without further processing (i.e., the button's
* listener will not be called).
*/
private static final ClickType[] PERMITTED_MENU_CLICK_TYPES = new ClickType[]{
ClickType.LEFT,
ClickType.RIGHT,
};

/**
* Any actions in this list will be blocked immediately without further
* processing if they occur in a SpiGUI menu.
*/
private static final InventoryAction[] BLOCKED_MENU_ACTIONS = new InventoryAction[] {
InventoryAction.MOVE_TO_OTHER_INVENTORY,
InventoryAction.COLLECT_TO_CURSOR,
};

/**
* Any actions in this list will be blocked if they occur in the adjacent
* inventory to an SGMenu.
*/
private static final InventoryAction[] BLOCKED_ADJACENT_ACTIONS = new InventoryAction[] {
InventoryAction.MOVE_TO_OTHER_INVENTORY,
InventoryAction.COLLECT_TO_CURSOR,
};

/** The plugin that this listener is registered for. */
private final JavaPlugin owner;
/** The instance of {@link SpiGUI} this listener is operating for. */
Expand Down Expand Up @@ -134,29 +105,26 @@ public static boolean willHandleInventoryEvent(JavaPlugin plugin, Inventory inve
*/
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {

// This should only run for SpiGUI menus, so if the clicked
// inventory was not a SpiGUI menu (i.e., an SGMenu), don't
// continue.
if (shouldIgnoreInventoryEvent(event.getClickedInventory())) return;

// Get the instance of the SpiGUI that was clicked.
SGMenu clickedGui = (SGMenu) event.getClickedInventory().getHolder();

// If the click type is not permitted, instantly deny the event and
// do nothing else.
if (Arrays.stream(PERMITTED_MENU_CLICK_TYPES).noneMatch(type -> type == event.getClick())) {
if (clickedGui.getPermittedMenuClickTypes().stream().noneMatch(type -> type == event.getClick())) {
event.setResult(Event.Result.DENY);
return;
}

// If the action is blocked, instantly deny the event and do nothing
// else.
if (Arrays.stream(BLOCKED_MENU_ACTIONS).anyMatch(action -> action == event.getAction())) {
// If the action is blocked, instantly deny the event
if (clickedGui.getBlockedMenuActions().stream().anyMatch(action -> action == event.getAction())) {
event.setResult(Event.Result.DENY);
return;
}

// Get the instance of the SpiGUI that was clicked.
SGMenu clickedGui = (SGMenu) event.getClickedInventory().getHolder();

// Check if the GUI is owner by the current plugin
// (if not, it'll be deferred to the SGMenuListener registered
// by that plugin that does own the GUI.)
Expand Down Expand Up @@ -215,7 +183,6 @@ public void onInventoryClick(InventoryClickEvent event) {
*/
@EventHandler(priority = EventPriority.LOWEST)
public void onAdjacentInventoryClick(InventoryClickEvent event) {

// If the clicked inventory is not adjacent to a SpiGUI menu, ignore
// the click event.
if (event.getView().getTopInventory() == null ||
Expand All @@ -225,12 +192,14 @@ public void onAdjacentInventoryClick(InventoryClickEvent event) {
// ignore the click event.
if (event.getClickedInventory() == event.getView().getTopInventory()) return;

// Get the instance of the SpiGUI that was clicked.
SGMenu clickedGui = (SGMenu) event.getClickedInventory().getHolder();

// If the clicked inventory is not a SpiGUI menu, block the event if
// it is one of the blocked actions.
if (Arrays.stream(BLOCKED_ADJACENT_ACTIONS).anyMatch(action -> action == event.getAction())) {
if (clickedGui.getBlockedAdjacentActions().stream().anyMatch(action -> action == event.getAction())) {
event.setResult(Event.Result.DENY);
}

}

/**
Expand Down

0 comments on commit 4ac7764

Please sign in to comment.