diff --git a/src/main/java/de/studiocode/invgui/animation/impl/BaseAnimation.java b/src/main/java/de/studiocode/invgui/animation/impl/BaseAnimation.java index 1969e1d..c0f8243 100644 --- a/src/main/java/de/studiocode/invgui/animation/impl/BaseAnimation.java +++ b/src/main/java/de/studiocode/invgui/animation/impl/BaseAnimation.java @@ -6,7 +6,6 @@ import de.studiocode.invgui.gui.GUI; import de.studiocode.invgui.util.SlotUtils; import de.studiocode.invgui.window.Window; import org.bukkit.Bukkit; -import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; @@ -14,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.stream.Collectors; @@ -71,7 +71,7 @@ public abstract class BaseAnimation implements Animation { public void start() { task = Bukkit.getScheduler().runTaskTimer(InvGui.getInstance().getPlugin(), () -> { // if there are no viewers for more than 3 ticks, the animation can be cancelled - if (getViewers().isEmpty()) { + if (getCurrentViewers().isEmpty()) { noViewerTicks++; if (noViewerTicks > 3) { gui.cancelAnimation(); @@ -120,14 +120,11 @@ public abstract class BaseAnimation implements Animation { return height; } - public List getViewers() { + public Set getCurrentViewers() { return windows.stream() - .map(window -> { - List viewers = window.getInventory().getViewers(); - return (Player) (viewers.isEmpty() ? null : viewers.get(0)); - }) + .map(Window::getCurrentViewer) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .collect(Collectors.toSet()); } } diff --git a/src/main/java/de/studiocode/invgui/animation/impl/ColumnAnimation.java b/src/main/java/de/studiocode/invgui/animation/impl/ColumnAnimation.java index f05b499..c13eb10 100644 --- a/src/main/java/de/studiocode/invgui/animation/impl/ColumnAnimation.java +++ b/src/main/java/de/studiocode/invgui/animation/impl/ColumnAnimation.java @@ -13,7 +13,7 @@ public class ColumnAnimation extends SoundAnimation { boolean showedSomething = false; while (!showedSomething || column == getWidth() - 1) { - for (int y = 0; y != getHeight(); y++) { + for (int y = 0; y < getHeight(); y++) { int index = convToIndex(column, y); if (getSlots().contains(index)) { show(index); diff --git a/src/main/java/de/studiocode/invgui/animation/impl/RowAnimation.java b/src/main/java/de/studiocode/invgui/animation/impl/RowAnimation.java index 6c6bd17..e898060 100644 --- a/src/main/java/de/studiocode/invgui/animation/impl/RowAnimation.java +++ b/src/main/java/de/studiocode/invgui/animation/impl/RowAnimation.java @@ -13,7 +13,7 @@ public class RowAnimation extends SoundAnimation { boolean showedSomething = false; while (!showedSomething || row == getHeight() - 1) { - for (int x = 0; x != getWidth(); x++) { + for (int x = 0; x < getWidth(); x++) { int index = convToIndex(x, row); if (getSlots().contains(index)) { show(index); diff --git a/src/main/java/de/studiocode/invgui/animation/impl/SoundAnimation.java b/src/main/java/de/studiocode/invgui/animation/impl/SoundAnimation.java index ffd1e33..9833dff 100644 --- a/src/main/java/de/studiocode/invgui/animation/impl/SoundAnimation.java +++ b/src/main/java/de/studiocode/invgui/animation/impl/SoundAnimation.java @@ -7,7 +7,7 @@ public abstract class SoundAnimation extends BaseAnimation { public SoundAnimation(int tickDelay, boolean sound) { super(tickDelay); - if (sound) addShowHandler((frame, index) -> getViewers().forEach(player -> + if (sound) addShowHandler((frame, index) -> getCurrentViewers().forEach(player -> player.playSound(player.getLocation(), Sound.ENTITY_ITEM_PICKUP, 1, 1))); } diff --git a/src/main/java/de/studiocode/invgui/gui/GUI.java b/src/main/java/de/studiocode/invgui/gui/GUI.java index 74fd53e..642ebe4 100644 --- a/src/main/java/de/studiocode/invgui/gui/GUI.java +++ b/src/main/java/de/studiocode/invgui/gui/GUI.java @@ -34,7 +34,7 @@ import java.util.function.Predicate; * @see SimplePagedItemsGUI * @see SimplePagedGUIs */ -public interface GUI { +public interface GUI extends GUIParent { /** * Gets the size of the {@link GUI}. @@ -212,38 +212,38 @@ public interface GUI { /** * Adds a {@link GUIParent} to the set of {@link GUIParent}s. - * + * * @param parent The {@link GUIParent} to add */ void addParent(@NotNull GUIParent parent); /** * Removes a {@link GUIParent} from the set of {@link GUIParent}s - * + * * @param parent The {@link GUIParent} to remove */ void removeParent(@NotNull GUIParent parent); /** * Gets all {@link GUIParent}s. - * + * * @return The {@link GUIParent}s of this {@link GUI} */ Set getParents(); /** * Finds all {@link Window}s that show this {@link GUI}. - * + * * @return The list of {@link Window} that show this {@link GUI} */ List findAllWindows(); /** * Finds all {@link Player}s that are currently seeing this {@link Window}. - * + * * @return The list of {@link Player}s that are currently seeing this {@link Window} */ - List findAllViewers(); + Set findAllCurrentViewers(); /** * Plays an {@link Animation}. diff --git a/src/main/java/de/studiocode/invgui/gui/impl/IndexedGUI.java b/src/main/java/de/studiocode/invgui/gui/impl/IndexedGUI.java index 3c3dd7a..d3da316 100644 --- a/src/main/java/de/studiocode/invgui/gui/impl/IndexedGUI.java +++ b/src/main/java/de/studiocode/invgui/gui/impl/IndexedGUI.java @@ -23,8 +23,9 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Predicate; +import java.util.stream.Collectors; -abstract class IndexedGUI implements GUI, GUIParent { +abstract class IndexedGUI implements GUI { private final int size; private final SlotElement[] slotElements; @@ -219,13 +220,11 @@ abstract class IndexedGUI implements GUI, GUIParent { } @Override - public List findAllViewers() { - List players = new ArrayList<>(); - findAllWindows().stream() - .flatMap(window -> window.getInventory().getViewers().stream()) - .forEach(humanEntity -> players.add((Player) humanEntity)); - - return players; + public Set findAllCurrentViewers() { + return findAllWindows().stream() + .map(Window::getCurrentViewer) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); } @Override @@ -243,7 +242,7 @@ abstract class IndexedGUI implements GUI, GUIParent { setSlotElement(i, null); } } - + animation.setSlots(slots); animation.setGUI(this); animation.setWindows(findAllWindows()); @@ -262,7 +261,7 @@ abstract class IndexedGUI implements GUI, GUIParent { // cancel the scheduler task and set animation to null animation.cancel(); animation = null; - + // show all SlotElements again for (int i = 0; i < size; i++) setSlotElement(i, animationElements[i]); animationElements = null; diff --git a/src/main/java/de/studiocode/invgui/util/SlotUtils.java b/src/main/java/de/studiocode/invgui/util/SlotUtils.java index 0b229b0..a318fb2 100644 --- a/src/main/java/de/studiocode/invgui/util/SlotUtils.java +++ b/src/main/java/de/studiocode/invgui/util/SlotUtils.java @@ -41,4 +41,14 @@ public class SlotUtils { return y * width + x; } + public static int translatePlayerInvToGui(int slot) { + if (slot > 8) return slot - 9; + else return slot + 27; + } + + public static int translateGuiToPlayerInv(int slot) { + if (slot > 26) return slot - 27; + else return slot + 9; + } + } diff --git a/src/main/java/de/studiocode/invgui/window/Window.java b/src/main/java/de/studiocode/invgui/window/Window.java index ffad200..84f6a05 100644 --- a/src/main/java/de/studiocode/invgui/window/Window.java +++ b/src/main/java/de/studiocode/invgui/window/Window.java @@ -1,14 +1,15 @@ package de.studiocode.invgui.window; import de.studiocode.invgui.gui.GUI; +import de.studiocode.invgui.gui.GUIParent; import de.studiocode.invgui.item.Item; import de.studiocode.invgui.item.itembuilder.ItemBuilder; import de.studiocode.invgui.virtualinventory.VirtualInventory; -import de.studiocode.invgui.window.impl.BaseWindow; -import de.studiocode.invgui.window.impl.DropperWindow; -import de.studiocode.invgui.window.impl.HopperWindow; -import de.studiocode.invgui.window.impl.NormalInventoryWindow; +import de.studiocode.invgui.window.impl.combined.combinedgui.SimpleCombinedGUIWindow; +import de.studiocode.invgui.window.impl.combined.splitgui.SimpleSplitGUIWindow; +import de.studiocode.invgui.window.impl.single.SimpleWindow; import org.bukkit.entity.Player; +import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.inventory.Inventory; @@ -20,26 +21,25 @@ import java.util.UUID; * A window is the way to show a player a GUI. * Windows can only have one viewer. * - * @see BaseWindow - * @see NormalInventoryWindow - * @see HopperWindow - * @see DropperWindow + * @see SimpleWindow + * @see SimpleCombinedGUIWindow + * @see SimpleSplitGUIWindow */ -public interface Window { +public interface Window extends GUIParent { /** - * Gets the underlying {@link Inventory}. + * Gets the underlying {@link Inventory}s. * - * @return The underlying {@link Inventory}. + * @return The underlying {@link Inventory}s. */ - Inventory getInventory(); + Inventory[] getInventories(); /** - * Gets the underlying {@link GUI}. + * Gets the underlying {@link GUI}s. * - * @return The underlying {@link GUI}. + * @return The underlying {@link GUI}s. */ - GUI getGui(); + GUI[] getGuis(); /** * A method called by the {@link WindowManager} to notify the Window @@ -72,6 +72,14 @@ public interface Window { */ void handleClose(Player player); + /** + * A method called by the {@link WindowManager} to notify the Window + * that it's viewer has died. + * + * @param event The {@link PlayerDeathEvent} associated with this action. + */ + void handleViewerDeath(PlayerDeathEvent event); + /** * A method called by the {@link Item} itself to notify the Window * that its {@link ItemBuilder} has been updated and the {@link ItemStack} @@ -132,10 +140,18 @@ public interface Window { /** * Gets the viewer of this {@link Window} * - * @return The viewer of this window, can be null. + * @return The viewer of this window. */ Player getViewer(); + /** + * Gets a the current {@link Player} that is viewing this + * {@link Window} or null of there isn't one. + * + * @return The current viewer of this {@link Window} (can be null) + */ + Player getCurrentViewer(); + /** * Gets the viewer's UUID or null if there is no viewer. * diff --git a/src/main/java/de/studiocode/invgui/window/WindowManager.java b/src/main/java/de/studiocode/invgui/window/WindowManager.java index 2bf7c01..79d337c 100644 --- a/src/main/java/de/studiocode/invgui/window/WindowManager.java +++ b/src/main/java/de/studiocode/invgui/window/WindowManager.java @@ -6,11 +6,13 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.inventory.*; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.Inventory; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; @@ -27,7 +29,7 @@ public class WindowManager implements Listener { private WindowManager() { Bukkit.getPluginManager().registerEvents(this, InvGui.getInstance().getPlugin()); - InvGui.getInstance().addDisableHandler(() -> windows.forEach(w -> w.close(true))); + InvGui.getInstance().addDisableHandler(() -> windows.forEach(window -> window.close(true))); } /** @@ -67,7 +69,7 @@ public class WindowManager implements Listener { */ public Optional findWindow(Inventory inventory) { return windows.stream() - .filter(w -> w.getInventory() == inventory) + .filter(w -> Arrays.stream(w.getInventories()).anyMatch(inv -> inv == inventory)) .findFirst(); } @@ -85,15 +87,14 @@ public class WindowManager implements Listener { /** * Finds the {@link Window} the {@link Player} has currently open. - * + * * @param player The {@link Player} - * @return The {@link Window} the {@link Player} has currently open or null - * if there isn't one. + * @return The {@link Window} the {@link Player} has currently open */ - public Window findWindow(Player player) { + public Optional findOpenWindow(Player player) { return windows.stream() - .filter(w -> w.getInventory().getViewers().contains(player)) - .findFirst().orElse(null); + .filter(w -> w.getCurrentViewer().equals(player)) + .findFirst(); } /** @@ -139,4 +140,9 @@ public class WindowManager implements Listener { findWindow(event.getPlayer().getOpenInventory().getTopInventory()).ifPresent(window -> window.handleClose(event.getPlayer())); } + @EventHandler + public void handlePlayerDeath(PlayerDeathEvent event) { + findWindows(event.getEntity()).forEach(window -> window.handleViewerDeath(event)); + } + } diff --git a/src/main/java/de/studiocode/invgui/window/impl/BaseWindow.java b/src/main/java/de/studiocode/invgui/window/impl/BaseWindow.java index d5348b4..2ae31cd 100644 --- a/src/main/java/de/studiocode/invgui/window/impl/BaseWindow.java +++ b/src/main/java/de/studiocode/invgui/window/impl/BaseWindow.java @@ -1,8 +1,6 @@ package de.studiocode.invgui.window.impl; import de.studiocode.invgui.InvGui; -import de.studiocode.invgui.gui.GUI; -import de.studiocode.invgui.gui.GUIParent; import de.studiocode.invgui.gui.SlotElement.ItemSlotElement; import de.studiocode.invgui.gui.SlotElement.ItemStackHolder; import de.studiocode.invgui.gui.SlotElement.VISlotElement; @@ -14,50 +12,33 @@ import de.studiocode.invgui.window.WindowManager; import org.bukkit.Bukkit; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import java.util.*; -public abstract class BaseWindow implements Window, GUIParent { +public abstract class BaseWindow implements Window { - private final GUI gui; - private final int size; private final UUID viewerUUID; - private final Inventory inventory; private final boolean closeOnEvent; private final ItemStackHolder[] itemsDisplayed; private boolean closeable; private boolean closed; - public BaseWindow(UUID viewerUUID, GUI gui, Inventory inventory, boolean closeable, boolean closeOnEvent) { - this.gui = gui; - this.size = gui.getSize(); + public BaseWindow(UUID viewerUUID, int size, boolean closeable, boolean closeOnEvent) { this.viewerUUID = viewerUUID; - this.inventory = inventory; this.closeable = closeable; this.closeOnEvent = closeOnEvent; this.itemsDisplayed = new ItemStackHolder[size]; - gui.addParent(this); - initItems(); WindowManager.getInstance().addWindow(this); } - private void initItems() { - for (int i = 0; i < size; i++) { - ItemStackHolder holder = gui.getItemStackHolder(i); - if (holder != null) redrawItem(i, holder, true); - } - } - - private void redrawItem(int index, ItemStackHolder holder, boolean setItem) { + protected void redrawItem(int index, ItemStackHolder holder, boolean setItem) { // put ItemStack in inventory ItemStack itemStack = holder == null ? null : holder.getItemStack(viewerUUID); - inventory.setItem(index, itemStack); + setInvItem(index, itemStack); if (setItem) { // tell the previous item (if there is one) that this is no longer its window @@ -91,35 +72,22 @@ public abstract class BaseWindow implements Window, GUIParent { } } - @Override - public void handleSlotElementUpdate(GUI child, int slotIndex) { - redrawItem(slotIndex, gui.getItemStackHolder(slotIndex), true); - } - - @Override - public void handleClick(InventoryClickEvent event) { - gui.handleClick(event.getSlot(), (Player) event.getWhoClicked(), event.getClick(), event); - } - - @Override - public void handleItemShift(InventoryClickEvent event) { - gui.handleItemShift(event); - } - @Override public void handleOpen(InventoryOpenEvent event) { if (!event.getPlayer().equals(getViewer())) event.setCancelled(true); + else handleOpened(); } @Override public void handleClose(Player player) { if (closeable) { if (closeOnEvent) close(false); + handleClosed(); } else { if (player.equals(getViewer())) Bukkit.getScheduler().runTaskLater(InvGui.getInstance().getPlugin(), - () -> player.openInventory(inventory), 0); + () -> player.openInventory(getInventories()[0]), 0); } } @@ -135,12 +103,12 @@ public abstract class BaseWindow implements Window, GUIParent { redrawItem(index, slotElement, false)); } - private Map getItemSlotElements(Item item) { + protected Map getItemSlotElements(Item item) { return ArrayUtils.findAllOccurrences(itemsDisplayed, holder -> holder instanceof ItemSlotElement && ((ItemSlotElement) holder).getItem() == item); } - private Map getVISlotElements(VirtualInventory virtualInventory) { + protected Map getVISlotElements(VirtualInventory virtualInventory) { return ArrayUtils.findAllOccurrences(itemsDisplayed, holder -> holder instanceof VISlotElement && ((VISlotElement) holder).getVirtualInventory() == virtualInventory); } @@ -157,7 +125,8 @@ public abstract class BaseWindow implements Window, GUIParent { .map(holder -> ((ItemSlotElement) holder).getItem()) .forEach(item -> item.removeWindow(this)); - gui.removeParent(this); + Arrays.stream(getGuis()) + .forEach(gui -> gui.removeParent(this)); if (closeForViewer) closeForViewer(); } @@ -166,7 +135,9 @@ public abstract class BaseWindow implements Window, GUIParent { public void closeForViewer() { closeable = true; // clone list to prevent ConcurrentModificationException - new ArrayList<>(inventory.getViewers()).forEach(HumanEntity::closeInventory); + new ArrayList<>(getInventories()[0].getViewers()).forEach(HumanEntity::closeInventory); + + handleClosed(); } @Override @@ -175,7 +146,13 @@ public abstract class BaseWindow implements Window, GUIParent { Player viewer = getViewer(); if (viewer == null) throw new IllegalStateException("The player is not online."); - viewer.openInventory(inventory); + viewer.openInventory(getInventories()[0]); + } + + @Override + public Player getCurrentViewer() { + List viewers = getInventories()[0].getViewers(); + return viewers.isEmpty() ? null : (Player) viewers.get(0); } @Override @@ -188,16 +165,6 @@ public abstract class BaseWindow implements Window, GUIParent { return viewerUUID; } - @Override - public Inventory getInventory() { - return inventory; - } - - @Override - public GUI getGui() { - return gui; - } - @Override public boolean isCloseable() { return closeable; @@ -213,4 +180,10 @@ public abstract class BaseWindow implements Window, GUIParent { return closed; } + protected abstract void setInvItem(int slot, ItemStack itemStack); + + protected abstract void handleOpened(); + + protected abstract void handleClosed(); + } \ No newline at end of file diff --git a/src/main/java/de/studiocode/invgui/window/impl/DropperWindow.java b/src/main/java/de/studiocode/invgui/window/impl/DropperWindow.java deleted file mode 100644 index b2dbcd2..0000000 --- a/src/main/java/de/studiocode/invgui/window/impl/DropperWindow.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.studiocode.invgui.window.impl; - -import de.studiocode.invgui.gui.GUI; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.Inventory; - -import java.util.UUID; - -public class DropperWindow extends BaseWindow { - - public DropperWindow(UUID viewerUUID, GUI gui, String title, boolean closeable, boolean closeOnEvent) { - super(viewerUUID, gui, createInventory(gui, title), closeable, closeOnEvent); - } - - public DropperWindow(Player player, GUI gui, String title, boolean closeable, boolean closeOnEvent) { - this(player.getUniqueId(), gui, title, closeable, closeOnEvent); - } - - private static Inventory createInventory(GUI gui, String title) { - if (gui.getWidth() != 3 || gui.getHeight() != 3) - throw new IllegalArgumentException("GUI width and height have to be 3."); - return Bukkit.createInventory(null, InventoryType.DROPPER, title); - } - -} diff --git a/src/main/java/de/studiocode/invgui/window/impl/HopperWindow.java b/src/main/java/de/studiocode/invgui/window/impl/HopperWindow.java deleted file mode 100644 index a3a693e..0000000 --- a/src/main/java/de/studiocode/invgui/window/impl/HopperWindow.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.studiocode.invgui.window.impl; - -import de.studiocode.invgui.gui.GUI; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.Inventory; - -import java.util.UUID; - -public class HopperWindow extends BaseWindow { - - public HopperWindow(UUID viewerUUID, GUI gui, String title, boolean closeable, boolean closeOnEvent) { - super(viewerUUID, gui, createInventory(gui, title), closeable, closeOnEvent); - } - - public HopperWindow(Player player, GUI gui, String title, boolean closeable, boolean closeOnEvent) { - this(player.getUniqueId(), gui, title, closeable, closeOnEvent); - } - - private static Inventory createInventory(GUI gui, String title) { - if (gui.getWidth() != 5 || gui.getHeight() != 1) - throw new IllegalArgumentException("GUI width has to be 5, height 1."); - return Bukkit.createInventory(null, InventoryType.HOPPER, title); - } - -} diff --git a/src/main/java/de/studiocode/invgui/window/impl/combined/BaseCombinedWindow.java b/src/main/java/de/studiocode/invgui/window/impl/combined/BaseCombinedWindow.java new file mode 100644 index 0000000..e3e1db2 --- /dev/null +++ b/src/main/java/de/studiocode/invgui/window/impl/combined/BaseCombinedWindow.java @@ -0,0 +1,125 @@ +package de.studiocode.invgui.window.impl.combined; + +import de.studiocode.invgui.gui.SlotElement.ItemStackHolder; +import de.studiocode.invgui.gui.SlotElement.VISlotElement; +import de.studiocode.invgui.util.SlotUtils; +import de.studiocode.invgui.window.impl.BaseWindow; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + + +public abstract class BaseCombinedWindow extends BaseWindow { + + private final Inventory upperInventory; + private final Inventory playerInventory; + + private final ItemStack[] playerItems = new ItemStack[36]; + private boolean isCurrentlyOpened; + + public BaseCombinedWindow(Player player, int size, Inventory upperInventory, boolean closeable, boolean closeOnEvent) { + super(player.getUniqueId(), size, closeable, closeOnEvent); + this.upperInventory = upperInventory; + this.playerInventory = player.getInventory(); + } + + protected void initUpperItems() { + for (int i = 0; i < upperInventory.getSize(); i++) { + ItemStackHolder holder = getItemStackHolder(i); + if (holder != null) redrawItem(i, holder, true); + } + } + + private void initPlayerItems() { + for (int i = upperInventory.getSize(); i < upperInventory.getSize() + 36; i++) { + ItemStackHolder holder = getItemStackHolder(i); + if (holder != null) redrawItem(i, holder, true); + } + } + + private void clearPlayerInventory() { + Inventory inventory = getViewer().getInventory(); + for (int i = 0; i < 36; i++) { + playerItems[i] = inventory.getItem(i); + inventory.setItem(i, null); + } + } + + private void restorePlayerInventory() { + Inventory inventory = getViewer().getInventory(); + for (int i = 0; i < 36; i++) { + inventory.setItem(i, playerItems[i]); + } + } + + @Override + protected void redrawItem(int index, ItemStackHolder holder, boolean setItem) { + if (holder instanceof VISlotElement) + throw new IllegalArgumentException("VirtualInventories are not allowed in CombinedWindows"); + + super.redrawItem(index, holder, setItem); + } + + @Override + protected void setInvItem(int slot, ItemStack itemStack) { + if (slot >= upperInventory.getSize()) { + if (isCurrentlyOpened) { + int invSlot = SlotUtils.translateGuiToPlayerInv(slot - upperInventory.getSize()); + playerInventory.setItem(invSlot, itemStack); + } + } else upperInventory.setItem(slot, itemStack); + } + + @Override + public void handleViewerDeath(PlayerDeathEvent event) { + if (isCurrentlyOpened) { + List drops = event.getDrops(); + if (!event.getKeepInventory()) { + drops.clear(); + Arrays.stream(playerItems) + .filter(Objects::nonNull) + .forEach(drops::add); + } + } + } + + @Override + protected void handleOpened() { + isCurrentlyOpened = true; + clearPlayerInventory(); + initPlayerItems(); + } + + @Override + protected void handleClosed() { + isCurrentlyOpened = false; + restorePlayerInventory(); + } + + @Override + public void handleItemShift(InventoryClickEvent event) { + event.setCancelled(true); + } + + @Override + public Inventory[] getInventories() { + return isCurrentlyOpened ? new Inventory[] {upperInventory, playerInventory} : new Inventory[] {upperInventory}; + } + + public Inventory getUpperInventory() { + return upperInventory; + } + + public Inventory getPlayerInventory() { + return playerInventory; + } + + protected abstract ItemStackHolder getItemStackHolder(int index); + +} diff --git a/src/main/java/de/studiocode/invgui/window/impl/combined/combinedgui/CombinedGUIWindow.java b/src/main/java/de/studiocode/invgui/window/impl/combined/combinedgui/CombinedGUIWindow.java new file mode 100644 index 0000000..f184e5c --- /dev/null +++ b/src/main/java/de/studiocode/invgui/window/impl/combined/combinedgui/CombinedGUIWindow.java @@ -0,0 +1,47 @@ +package de.studiocode.invgui.window.impl.combined.combinedgui; + +import de.studiocode.invgui.gui.GUI; +import de.studiocode.invgui.gui.SlotElement.ItemStackHolder; +import de.studiocode.invgui.util.SlotUtils; +import de.studiocode.invgui.window.impl.combined.BaseCombinedWindow; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; + +public abstract class CombinedGUIWindow extends BaseCombinedWindow { + + private final GUI gui; + + public CombinedGUIWindow(Player player, GUI gui, Inventory upperInventory, boolean closeable, boolean closeOnEvent) { + super(player, gui.getSize(), upperInventory, closeable, closeOnEvent); + this.gui = gui; + + gui.addParent(this); + initUpperItems(); + } + + @Override + public void handleSlotElementUpdate(GUI child, int slotIndex) { + redrawItem(slotIndex, gui.getItemStackHolder(slotIndex), true); + } + + @Override + public void handleClick(InventoryClickEvent event) { + Inventory clicked = event.getClickedInventory(); + int guiSlot = clicked == getUpperInventory() ? event.getSlot() + : getUpperInventory().getSize() + SlotUtils.translatePlayerInvToGui(event.getSlot()); + + gui.handleClick(guiSlot, (Player) event.getWhoClicked(), event.getClick(), event); + } + + @Override + protected ItemStackHolder getItemStackHolder(int index) { + return gui.getItemStackHolder(index); + } + + @Override + public GUI[] getGuis() { + return new GUI[] {gui}; + } + +} diff --git a/src/main/java/de/studiocode/invgui/window/impl/combined/combinedgui/SimpleCombinedGUIWindow.java b/src/main/java/de/studiocode/invgui/window/impl/combined/combinedgui/SimpleCombinedGUIWindow.java new file mode 100644 index 0000000..f0da1c5 --- /dev/null +++ b/src/main/java/de/studiocode/invgui/window/impl/combined/combinedgui/SimpleCombinedGUIWindow.java @@ -0,0 +1,23 @@ +package de.studiocode.invgui.window.impl.combined.combinedgui; + +import de.studiocode.invgui.gui.GUI; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +public class SimpleCombinedGUIWindow extends CombinedGUIWindow { + + public SimpleCombinedGUIWindow(Player player, String title, GUI gui, boolean closeable, boolean closeOnEvent) { + super(player, gui, createInventory(gui, title), closeable, closeOnEvent); + } + + private static Inventory createInventory(GUI gui, String title) { + if (gui.getWidth() != 9) + throw new IllegalArgumentException("GUI width has to be 9"); + if (gui.getHeight() <= 4) + throw new IllegalArgumentException("GUI height has to be bigger than 4"); + + return Bukkit.createInventory(null, gui.getSize() - 36, title); + } + +} diff --git a/src/main/java/de/studiocode/invgui/window/impl/combined/splitgui/SimpleSplitGUIWindow.java b/src/main/java/de/studiocode/invgui/window/impl/combined/splitgui/SimpleSplitGUIWindow.java new file mode 100644 index 0000000..0532a31 --- /dev/null +++ b/src/main/java/de/studiocode/invgui/window/impl/combined/splitgui/SimpleSplitGUIWindow.java @@ -0,0 +1,21 @@ +package de.studiocode.invgui.window.impl.combined.splitgui; + +import de.studiocode.invgui.gui.GUI; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +public class SimpleSplitGUIWindow extends SplitGUIWindow { + + public SimpleSplitGUIWindow(Player player, String title, GUI upperGui, GUI lowerGui, boolean closeable, boolean closeOnEvent) { + super(player, upperGui, lowerGui, createInventory(upperGui, title), closeable, closeOnEvent); + } + + private static Inventory createInventory(GUI gui, String title) { + if (gui.getWidth() != 9) + throw new IllegalArgumentException("GUI width has to be 9"); + + return Bukkit.createInventory(null, gui.getSize(), title); + } + +} diff --git a/src/main/java/de/studiocode/invgui/window/impl/combined/splitgui/SplitGUIWindow.java b/src/main/java/de/studiocode/invgui/window/impl/combined/splitgui/SplitGUIWindow.java new file mode 100644 index 0000000..2072831 --- /dev/null +++ b/src/main/java/de/studiocode/invgui/window/impl/combined/splitgui/SplitGUIWindow.java @@ -0,0 +1,54 @@ +package de.studiocode.invgui.window.impl.combined.splitgui; + +import de.studiocode.invgui.gui.GUI; +import de.studiocode.invgui.gui.SlotElement.ItemStackHolder; +import de.studiocode.invgui.util.SlotUtils; +import de.studiocode.invgui.window.impl.combined.BaseCombinedWindow; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; + +public abstract class SplitGUIWindow extends BaseCombinedWindow { + + private final GUI upperGui; + private final GUI lowerGui; + + public SplitGUIWindow(Player player, GUI upperGui, GUI lowerGui, Inventory upperInventory, boolean closeable, boolean closeOnEvent) { + super(player, upperGui.getSize() + lowerGui.getSize(), upperInventory, closeable, closeOnEvent); + this.upperGui = upperGui; + this.lowerGui = lowerGui; + + upperGui.addParent(this); + lowerGui.addParent(this); + initUpperItems(); + } + + @Override + public void handleSlotElementUpdate(GUI child, int slotIndex) { + redrawItem(child == upperGui ? slotIndex : upperGui.getSize() + slotIndex, + child.getItemStackHolder(slotIndex), true); + } + + @Override + public void handleClick(InventoryClickEvent event) { + Inventory clicked = event.getClickedInventory(); + if (clicked == getUpperInventory()) { + upperGui.handleClick(event.getSlot(), (Player) event.getWhoClicked(), event.getClick(), event); + } else { + int index = SlotUtils.translatePlayerInvToGui(event.getSlot()); + lowerGui.handleClick(index, (Player) event.getWhoClicked(), event.getClick(), event); + } + } + + @Override + public ItemStackHolder getItemStackHolder(int index) { + if (index >= upperGui.getSize()) return lowerGui.getItemStackHolder(index - upperGui.getSize()); + else return upperGui.getItemStackHolder(index); + } + + @Override + public GUI[] getGuis() { + return new GUI[] {upperGui, lowerGui}; + } + +} diff --git a/src/main/java/de/studiocode/invgui/window/impl/NormalInventoryWindow.java b/src/main/java/de/studiocode/invgui/window/impl/single/SimpleWindow.java similarity index 57% rename from src/main/java/de/studiocode/invgui/window/impl/NormalInventoryWindow.java rename to src/main/java/de/studiocode/invgui/window/impl/single/SimpleWindow.java index e3cf697..cf628fd 100644 --- a/src/main/java/de/studiocode/invgui/window/impl/NormalInventoryWindow.java +++ b/src/main/java/de/studiocode/invgui/window/impl/single/SimpleWindow.java @@ -1,4 +1,4 @@ -package de.studiocode.invgui.window.impl; +package de.studiocode.invgui.window.impl.single; import de.studiocode.invgui.gui.GUI; import org.bukkit.Bukkit; @@ -7,14 +7,14 @@ import org.bukkit.inventory.Inventory; import java.util.UUID; -public final class NormalInventoryWindow extends BaseWindow { +public final class SimpleWindow extends SingleWindow { - public NormalInventoryWindow(UUID viewerUUID, GUI gui, String title, boolean closeable, boolean closeOnEvent) { + public SimpleWindow(UUID viewerUUID, String title, GUI gui, boolean closeable, boolean closeOnEvent) { super(viewerUUID, gui, createInventory(gui, title), closeable, closeOnEvent); } - public NormalInventoryWindow(Player player, GUI gui, String title, boolean closeable, boolean closeOnEvent) { - this(player.getUniqueId(), gui, title, closeable, closeOnEvent); + public SimpleWindow(Player player, String title, GUI gui, boolean closeable, boolean closeOnEvent) { + this(player.getUniqueId(), title, gui, closeable, closeOnEvent); } private static Inventory createInventory(GUI gui, String title) { diff --git a/src/main/java/de/studiocode/invgui/window/impl/single/SingleWindow.java b/src/main/java/de/studiocode/invgui/window/impl/single/SingleWindow.java new file mode 100644 index 0000000..2b13cf0 --- /dev/null +++ b/src/main/java/de/studiocode/invgui/window/impl/single/SingleWindow.java @@ -0,0 +1,82 @@ +package de.studiocode.invgui.window.impl.single; + +import de.studiocode.invgui.gui.GUI; +import de.studiocode.invgui.gui.SlotElement.ItemStackHolder; +import de.studiocode.invgui.window.impl.BaseWindow; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.UUID; + +public abstract class SingleWindow extends BaseWindow { + + private final GUI gui; + private final int size; + private final Inventory inventory; + + public SingleWindow(UUID viewerUUID, GUI gui, Inventory inventory, boolean closeable, boolean closeOnEvent) { + super(viewerUUID, gui.getSize(), closeable, closeOnEvent); + this.gui = gui; + this.size = gui.getSize(); + this.inventory = inventory; + + gui.addParent(this); + initItems(); + } + + private void initItems() { + for (int i = 0; i < size; i++) { + ItemStackHolder holder = gui.getItemStackHolder(i); + if (holder != null) redrawItem(i, holder, true); + } + } + + @Override + protected void setInvItem(int slot, ItemStack itemStack) { + inventory.setItem(slot, itemStack); + } + + @Override + protected void handleOpened() { + // empty + } + + @Override + protected void handleClosed() { + // empty + } + + @Override + public void handleSlotElementUpdate(GUI child, int slotIndex) { + redrawItem(slotIndex, gui.getItemStackHolder(slotIndex), true); + } + + @Override + public void handleClick(InventoryClickEvent event) { + gui.handleClick(event.getSlot(), (Player) event.getWhoClicked(), event.getClick(), event); + } + + @Override + public void handleItemShift(InventoryClickEvent event) { + gui.handleItemShift(event); + } + + @Override + public void handleViewerDeath(PlayerDeathEvent event) { + // empty + } + + @Override + public Inventory[] getInventories() { + return new Inventory[] {inventory}; + } + + @Override + public GUI[] getGuis() { + return new GUI[] {gui}; + } + +}