Window outside click handlers

This commit is contained in:
NichtStudioCode 2023-03-20 14:03:32 +01:00
parent 3ca3a0a76e
commit 13bef06660
4 changed files with 125 additions and 44 deletions

@ -11,6 +11,7 @@ import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
@ -45,6 +46,7 @@ public abstract class AbstractWindow implements Window, GuiParent {
private final SlotElement[] elementsDisplayed; private final SlotElement[] elementsDisplayed;
private List<Runnable> openHandlers; private List<Runnable> openHandlers;
private List<Runnable> closeHandlers; private List<Runnable> closeHandlers;
private List<Consumer<InventoryClickEvent>> outsideClickHandlers;
private ComponentWrapper title; private ComponentWrapper title;
private boolean closeable; private boolean closeable;
private boolean currentlyOpen; private boolean currentlyOpen;
@ -133,7 +135,7 @@ public abstract class AbstractWindow implements Window, GuiParent {
} }
} }
public void handleDrag(InventoryDragEvent event) { public void handleDragEvent(InventoryDragEvent event) {
Player player = ((Player) event.getWhoClicked()).getPlayer(); Player player = ((Player) event.getWhoClicked()).getPlayer();
UpdateReason updateReason = new PlayerUpdateReason(player, event); UpdateReason updateReason = new PlayerUpdateReason(player, event);
Map<Integer, ItemStack> newItems = event.getNewItems(); Map<Integer, ItemStack> newItems = event.getNewItems();
@ -197,6 +199,32 @@ public abstract class AbstractWindow implements Window, GuiParent {
} }
} }
public void handleClickEvent(InventoryClickEvent event) {
if (Arrays.asList(getInventories()).contains(event.getClickedInventory())) {
// The inventory that was clicked is part of the open window
handleClick(event);
} else if (event.getSlotType() == InventoryType.SlotType.OUTSIDE) {
// The player clicked outside the inventory
if (outsideClickHandlers != null) {
for (var handler : outsideClickHandlers) {
handler.accept(event);
}
}
} else {
switch (event.getAction()) {
// The inventory that was clicked is not part of the open window, so it is the player inventory
case MOVE_TO_OTHER_INVENTORY:
handleItemShift(event);
break;
// items have been collected by clicking a slot in the player inv
case COLLECT_TO_CURSOR:
handleCursorCollect(event);
break;
}
}
}
public void handleItemProviderUpdate(Item item) { public void handleItemProviderUpdate(Item item) {
getItemSlotElements(item).forEach((index, slotElement) -> getItemSlotElements(item).forEach((index, slotElement) ->
redrawItem(index, slotElement, false)); redrawItem(index, slotElement, false));
@ -324,6 +352,25 @@ public abstract class AbstractWindow implements Window, GuiParent {
closeHandlers.remove(closeHandler); closeHandlers.remove(closeHandler);
} }
@Override
public void setOutsideClickHandlers(@NotNull List<@NotNull Consumer<@NotNull InventoryClickEvent>> outsideClickHandlers) {
this.outsideClickHandlers = outsideClickHandlers;
}
@Override
public void addOutsideClickHandler(@NotNull Consumer<@NotNull InventoryClickEvent> outsideClickHandlers) {
if (this.outsideClickHandlers == null)
this.outsideClickHandlers = new ArrayList<>();
this.outsideClickHandlers.add(outsideClickHandlers);
}
@Override
public void removeOutsideClickHandler(@NotNull Consumer<@NotNull InventoryClickEvent> outsideClickHandlers) {
if (this.outsideClickHandlers != null)
this.outsideClickHandlers.remove(outsideClickHandlers);
}
@Override @Override
public @Nullable Player getCurrentViewer() { public @Nullable Player getCurrentViewer() {
List<HumanEntity> viewers = getInventories()[0].getViewers(); List<HumanEntity> viewers = getInventories()[0].getViewers();
@ -380,11 +427,11 @@ public abstract class AbstractWindow implements Window, GuiParent {
protected abstract void handleClosed(); protected abstract void handleClosed();
public abstract void handleClick(InventoryClickEvent event); protected abstract void handleClick(InventoryClickEvent event);
public abstract void handleItemShift(InventoryClickEvent event); protected abstract void handleItemShift(InventoryClickEvent event);
public abstract void handleCursorCollect(InventoryClickEvent event); protected abstract void handleCursorCollect(InventoryClickEvent event);
public abstract void handleViewerDeath(PlayerDeathEvent event); public abstract void handleViewerDeath(PlayerDeathEvent event);
@ -396,6 +443,7 @@ public abstract class AbstractWindow implements Window, GuiParent {
protected boolean closeable = true; protected boolean closeable = true;
protected List<Runnable> openHandlers; protected List<Runnable> openHandlers;
protected List<Runnable> closeHandlers; protected List<Runnable> closeHandlers;
protected List<Consumer<InventoryClickEvent>> outsideClickHandlers;
protected List<Consumer<Window>> modifiers; protected List<Consumer<Window>> modifiers;
@Override @Override
@ -458,6 +506,21 @@ public abstract class AbstractWindow implements Window, GuiParent {
return (S) this; return (S) this;
} }
@Override
public @NotNull S setOutsideClickHandlers(@NotNull List<@NotNull Consumer<@NotNull InventoryClickEvent>> outsideClickHandlers) {
this.outsideClickHandlers = outsideClickHandlers;
return (S) this;
}
@Override
public @NotNull S addOutsideClickHandler(@NotNull Consumer<@NotNull InventoryClickEvent> outsideClickHandler) {
if (outsideClickHandlers == null)
outsideClickHandlers = new ArrayList<>();
outsideClickHandlers.add(outsideClickHandler);
return (S) this;
}
@Override @Override
public @NotNull S setModifiers(List<Consumer<Window>> modifiers) { public @NotNull S setModifiers(List<Consumer<Window>> modifiers) {
this.modifiers = modifiers; this.modifiers = modifiers;
@ -477,6 +540,9 @@ public abstract class AbstractWindow implements Window, GuiParent {
if (closeHandlers != null) if (closeHandlers != null)
window.setCloseHandlers(closeHandlers); window.setCloseHandlers(closeHandlers);
if (outsideClickHandlers != null)
window.setOutsideClickHandlers(outsideClickHandlers);
if (modifiers != null) if (modifiers != null)
modifiers.forEach(modifier -> modifier.accept(window)); modifiers.forEach(modifier -> modifier.accept(window));
} }

@ -2,7 +2,6 @@ package xyz.xenondevs.invui.window;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta; import org.bukkit.inventory.meta.MapMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -13,6 +12,7 @@ import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.inventoryaccess.map.MapIcon; import xyz.xenondevs.inventoryaccess.map.MapIcon;
import xyz.xenondevs.inventoryaccess.map.MapPatch; import xyz.xenondevs.inventoryaccess.map.MapPatch;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.util.MathUtils; import xyz.xenondevs.invui.util.MathUtils;
import java.util.List; import java.util.List;
@ -28,7 +28,7 @@ final class CartographySingleWindowImpl extends AbstractSingleWindow implements
@NotNull AbstractGui gui, @NotNull AbstractGui gui,
boolean closeable boolean closeable
) { ) {
super(player.getUniqueId(), title, gui, null, closeable); super(player.getUniqueId(), title, createWrappingGui(gui), null, closeable);
if (gui.getWidth() != 2 || gui.getHeight() != 1) throw new IllegalArgumentException("Gui has to be 2x1"); if (gui.getWidth() != 2 || gui.getHeight() != 1) throw new IllegalArgumentException("Gui has to be 2x1");
cartographyInventory = InventoryAccess.createCartographyInventory(player, title.localized(player)); cartographyInventory = InventoryAccess.createCartographyInventory(player, title.localized(player));
@ -37,6 +37,15 @@ final class CartographySingleWindowImpl extends AbstractSingleWindow implements
resetMap(); resetMap();
} }
private static AbstractGui createWrappingGui(Gui upperGui) {
if (upperGui.getWidth() != 2 || upperGui.getHeight() != 1)
throw new IllegalArgumentException("Gui has to be 2x1");
Gui wrapperGui = Gui.empty(3, 1);
wrapperGui.fillRectangle(1, 0, upperGui, true);
return (AbstractGui) wrapperGui;
}
@Override @Override
public void updateMap(@Nullable MapPatch patch, @Nullable List<MapIcon> icons) { public void updateMap(@Nullable MapPatch patch, @Nullable List<MapIcon> icons) {
InventoryAccess.getPlayerUtils().sendMapUpdate(getViewer(), mapId, (byte) 0, false, patch, icons); InventoryAccess.getPlayerUtils().sendMapUpdate(getViewer(), mapId, (byte) 0, false, patch, icons);
@ -53,20 +62,6 @@ final class CartographySingleWindowImpl extends AbstractSingleWindow implements
cartographyInventory.setItem(0, map); cartographyInventory.setItem(0, map);
} }
@Override
protected void setInvItem(int slot, ItemStack itemStack) {
cartographyInventory.setItem(slot + 1, itemStack);
}
@Override
public void handleClick(InventoryClickEvent event) {
if (event.getSlot() != 0) {
getGui().handleClick(event.getSlot() - 1, (Player) event.getWhoClicked(), event.getClick(), event);
} else {
event.setCancelled(true);
}
}
@Override @Override
protected void openInventory(@NotNull Player viewer) { protected void openInventory(@NotNull Player viewer) {
cartographyInventory.open(); cartographyInventory.open();

@ -2,6 +2,7 @@ package xyz.xenondevs.invui.window;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -196,6 +197,26 @@ public interface Window {
*/ */
void removeCloseHandler(@NotNull Runnable closeHandler); void removeCloseHandler(@NotNull Runnable closeHandler);
/**
* Replaces the currently registered outside click handlers with the given list.
* @param outsideClickHandlers The new outside click handlers
*/
void setOutsideClickHandlers(@NotNull List<@NotNull Consumer<@NotNull InventoryClickEvent>> outsideClickHandlers);
/**
* Adds an outside click handler that will be called when a player clicks outside the inventory.
*
* @param outsideClickHandlers The outside click handler to add
*/
void addOutsideClickHandler(@NotNull Consumer<@NotNull InventoryClickEvent> outsideClickHandlers);
/**
* Removes an outside click handler that has been added previously.
*
* @param outsideClickHandlers The outside click handler to remove
*/
void removeOutsideClickHandler(@NotNull Consumer<@NotNull InventoryClickEvent> outsideClickHandlers);
/** /**
* A {@link Window} builder. * A {@link Window} builder.
* *
@ -285,6 +306,24 @@ public interface Window {
@Contract("_ -> this") @Contract("_ -> this")
@NotNull S addCloseHandler(Runnable closeHandler); @NotNull S addCloseHandler(Runnable closeHandler);
/**
* Sets the outside click handlers of the {@link Window}.
*
* @param outsideClickHandlers The outside click handlers of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
@NotNull S setOutsideClickHandlers(@NotNull List<@NotNull Consumer<@NotNull InventoryClickEvent>> outsideClickHandlers);
/**
* Adds an outside click handler to the {@link Window}.
*
* @param outsideClickHandler The outside click handler to add
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
@NotNull S addOutsideClickHandler(@NotNull Consumer<@NotNull InventoryClickEvent> outsideClickHandler);
/** /**
* Sets the modifiers of the {@link Window}. * Sets the modifiers of the {@link Window}.
* *

@ -105,28 +105,9 @@ public class WindowManager implements Listener {
@EventHandler @EventHandler
private void handleInventoryClick(InventoryClickEvent event) { private void handleInventoryClick(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked(); AbstractWindow window = (AbstractWindow) getOpenWindow((Player) event.getWhoClicked());
AbstractWindow window = (AbstractWindow) getOpenWindow(player);
if (window != null) { if (window != null) {
Inventory clicked = event.getClickedInventory(); window.handleClickEvent(event);
if (Arrays.asList(window.getInventories()).contains(clicked)) {
// The inventory that was clicked is part of the open window
window.handleClick(event);
} else {
// The inventory that was clicked is not part of the open window, so it is the player inventory
switch (event.getAction()) {
case MOVE_TO_OTHER_INVENTORY:
window.handleItemShift(event);
break;
// items have been collected by clicking a slot in the player inv
case COLLECT_TO_CURSOR:
window.handleCursorCollect(event);
break;
}
}
} }
} }
@ -134,17 +115,17 @@ public class WindowManager implements Listener {
private void handleInventoryDrag(InventoryDragEvent event) { private void handleInventoryDrag(InventoryDragEvent event) {
AbstractWindow window = (AbstractWindow) getOpenWindow((Player) event.getWhoClicked()); AbstractWindow window = (AbstractWindow) getOpenWindow((Player) event.getWhoClicked());
if (window != null) { if (window != null) {
window.handleDrag(event); window.handleDragEvent(event);
} }
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
private void handleInventoryClose(InventoryCloseEvent event) { private void handleInventoryClose(InventoryCloseEvent event) {
Player player = (Player) event.getPlayer(); Player player = (Player) event.getPlayer();
AbstractWindow window = (AbstractWindow) getWindow(event.getInventory()); AbstractWindow window = (AbstractWindow) getWindow(event.getInventory());
if (window != null) if (window != null) {
window.handleCloseEvent(player); window.handleCloseEvent(player);
}
openWindows.remove(player); openWindows.remove(player);
} }