CombinedWindow

This commit is contained in:
NichtStudioCode 2021-01-31 16:24:38 +01:00
parent e6c4af7765
commit 5eb859e6c9
19 changed files with 464 additions and 165 deletions

@ -6,7 +6,6 @@ import de.studiocode.invgui.gui.GUI;
import de.studiocode.invgui.util.SlotUtils; import de.studiocode.invgui.util.SlotUtils;
import de.studiocode.invgui.window.Window; import de.studiocode.invgui.window.Window;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -14,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -71,7 +71,7 @@ public abstract class BaseAnimation implements Animation {
public void start() { public void start() {
task = Bukkit.getScheduler().runTaskTimer(InvGui.getInstance().getPlugin(), () -> { task = Bukkit.getScheduler().runTaskTimer(InvGui.getInstance().getPlugin(), () -> {
// if there are no viewers for more than 3 ticks, the animation can be cancelled // if there are no viewers for more than 3 ticks, the animation can be cancelled
if (getViewers().isEmpty()) { if (getCurrentViewers().isEmpty()) {
noViewerTicks++; noViewerTicks++;
if (noViewerTicks > 3) { if (noViewerTicks > 3) {
gui.cancelAnimation(); gui.cancelAnimation();
@ -120,14 +120,11 @@ public abstract class BaseAnimation implements Animation {
return height; return height;
} }
public List<Player> getViewers() { public Set<Player> getCurrentViewers() {
return windows.stream() return windows.stream()
.map(window -> { .map(Window::getCurrentViewer)
List<HumanEntity> viewers = window.getInventory().getViewers();
return (Player) (viewers.isEmpty() ? null : viewers.get(0));
})
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toSet());
} }
} }

@ -13,7 +13,7 @@ public class ColumnAnimation extends SoundAnimation {
boolean showedSomething = false; boolean showedSomething = false;
while (!showedSomething || column == getWidth() - 1) { while (!showedSomething || column == getWidth() - 1) {
for (int y = 0; y != getHeight(); y++) { for (int y = 0; y < getHeight(); y++) {
int index = convToIndex(column, y); int index = convToIndex(column, y);
if (getSlots().contains(index)) { if (getSlots().contains(index)) {
show(index); show(index);

@ -13,7 +13,7 @@ public class RowAnimation extends SoundAnimation {
boolean showedSomething = false; boolean showedSomething = false;
while (!showedSomething || row == getHeight() - 1) { while (!showedSomething || row == getHeight() - 1) {
for (int x = 0; x != getWidth(); x++) { for (int x = 0; x < getWidth(); x++) {
int index = convToIndex(x, row); int index = convToIndex(x, row);
if (getSlots().contains(index)) { if (getSlots().contains(index)) {
show(index); show(index);

@ -7,7 +7,7 @@ public abstract class SoundAnimation extends BaseAnimation {
public SoundAnimation(int tickDelay, boolean sound) { public SoundAnimation(int tickDelay, boolean sound) {
super(tickDelay); 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))); player.playSound(player.getLocation(), Sound.ENTITY_ITEM_PICKUP, 1, 1)));
} }

@ -34,7 +34,7 @@ import java.util.function.Predicate;
* @see SimplePagedItemsGUI * @see SimplePagedItemsGUI
* @see SimplePagedGUIs * @see SimplePagedGUIs
*/ */
public interface GUI { public interface GUI extends GUIParent {
/** /**
* Gets the size of the {@link GUI}. * Gets the size of the {@link GUI}.
@ -243,7 +243,7 @@ public interface GUI {
* *
* @return The list of {@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<Player> findAllViewers(); Set<Player> findAllCurrentViewers();
/** /**
* Plays an {@link Animation}. * Plays an {@link Animation}.

@ -23,8 +23,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.function.Predicate; 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 int size;
private final SlotElement[] slotElements; private final SlotElement[] slotElements;
@ -219,13 +220,11 @@ abstract class IndexedGUI implements GUI, GUIParent {
} }
@Override @Override
public List<Player> findAllViewers() { public Set<Player> findAllCurrentViewers() {
List<Player> players = new ArrayList<>(); return findAllWindows().stream()
findAllWindows().stream() .map(Window::getCurrentViewer)
.flatMap(window -> window.getInventory().getViewers().stream()) .filter(Objects::nonNull)
.forEach(humanEntity -> players.add((Player) humanEntity)); .collect(Collectors.toSet());
return players;
} }
@Override @Override

@ -41,4 +41,14 @@ public class SlotUtils {
return y * width + x; 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;
}
} }

@ -1,14 +1,15 @@
package de.studiocode.invgui.window; package de.studiocode.invgui.window;
import de.studiocode.invgui.gui.GUI; import de.studiocode.invgui.gui.GUI;
import de.studiocode.invgui.gui.GUIParent;
import de.studiocode.invgui.item.Item; import de.studiocode.invgui.item.Item;
import de.studiocode.invgui.item.itembuilder.ItemBuilder; import de.studiocode.invgui.item.itembuilder.ItemBuilder;
import de.studiocode.invgui.virtualinventory.VirtualInventory; import de.studiocode.invgui.virtualinventory.VirtualInventory;
import de.studiocode.invgui.window.impl.BaseWindow; import de.studiocode.invgui.window.impl.combined.combinedgui.SimpleCombinedGUIWindow;
import de.studiocode.invgui.window.impl.DropperWindow; import de.studiocode.invgui.window.impl.combined.splitgui.SimpleSplitGUIWindow;
import de.studiocode.invgui.window.impl.HopperWindow; import de.studiocode.invgui.window.impl.single.SimpleWindow;
import de.studiocode.invgui.window.impl.NormalInventoryWindow;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
@ -20,26 +21,25 @@ import java.util.UUID;
* A window is the way to show a player a GUI. * A window is the way to show a player a GUI.
* Windows can only have one viewer. * Windows can only have one viewer.
* *
* @see BaseWindow * @see SimpleWindow
* @see NormalInventoryWindow * @see SimpleCombinedGUIWindow
* @see HopperWindow * @see SimpleSplitGUIWindow
* @see DropperWindow
*/ */
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 * A method called by the {@link WindowManager} to notify the Window
@ -72,6 +72,14 @@ public interface Window {
*/ */
void handleClose(Player player); 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 * A method called by the {@link Item} itself to notify the Window
* that its {@link ItemBuilder} has been updated and the {@link ItemStack} * 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} * Gets the viewer of this {@link Window}
* *
* @return The viewer of this window, can be null. * @return The viewer of this window.
*/ */
Player getViewer(); 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. * Gets the viewer's UUID or null if there is no viewer.
* *

@ -6,11 +6,13 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.*; import org.bukkit.event.inventory.*;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@ -27,7 +29,7 @@ public class WindowManager implements Listener {
private WindowManager() { private WindowManager() {
Bukkit.getPluginManager().registerEvents(this, InvGui.getInstance().getPlugin()); 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<Window> findWindow(Inventory inventory) { public Optional<Window> findWindow(Inventory inventory) {
return windows.stream() return windows.stream()
.filter(w -> w.getInventory() == inventory) .filter(w -> Arrays.stream(w.getInventories()).anyMatch(inv -> inv == inventory))
.findFirst(); .findFirst();
} }
@ -87,13 +89,12 @@ public class WindowManager implements Listener {
* Finds the {@link Window} the {@link Player} has currently open. * Finds the {@link Window} the {@link Player} has currently open.
* *
* @param player The {@link Player} * @param player The {@link Player}
* @return The {@link Window} the {@link Player} has currently open or <code>null</code> * @return The {@link Window} the {@link Player} has currently open
* if there isn't one.
*/ */
public Window findWindow(Player player) { public Optional<Window> findOpenWindow(Player player) {
return windows.stream() return windows.stream()
.filter(w -> w.getInventory().getViewers().contains(player)) .filter(w -> w.getCurrentViewer().equals(player))
.findFirst().orElse(null); .findFirst();
} }
/** /**
@ -139,4 +140,9 @@ public class WindowManager implements Listener {
findWindow(event.getPlayer().getOpenInventory().getTopInventory()).ifPresent(window -> window.handleClose(event.getPlayer())); 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));
}
} }

@ -1,8 +1,6 @@
package de.studiocode.invgui.window.impl; package de.studiocode.invgui.window.impl;
import de.studiocode.invgui.InvGui; 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.ItemSlotElement;
import de.studiocode.invgui.gui.SlotElement.ItemStackHolder; import de.studiocode.invgui.gui.SlotElement.ItemStackHolder;
import de.studiocode.invgui.gui.SlotElement.VISlotElement; import de.studiocode.invgui.gui.SlotElement.VISlotElement;
@ -14,50 +12,33 @@ import de.studiocode.invgui.window.WindowManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.*; 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 UUID viewerUUID;
private final Inventory inventory;
private final boolean closeOnEvent; private final boolean closeOnEvent;
private final ItemStackHolder[] itemsDisplayed; private final ItemStackHolder[] itemsDisplayed;
private boolean closeable; private boolean closeable;
private boolean closed; private boolean closed;
public BaseWindow(UUID viewerUUID, GUI gui, Inventory inventory, boolean closeable, boolean closeOnEvent) { public BaseWindow(UUID viewerUUID, int size, boolean closeable, boolean closeOnEvent) {
this.gui = gui;
this.size = gui.getSize();
this.viewerUUID = viewerUUID; this.viewerUUID = viewerUUID;
this.inventory = inventory;
this.closeable = closeable; this.closeable = closeable;
this.closeOnEvent = closeOnEvent; this.closeOnEvent = closeOnEvent;
this.itemsDisplayed = new ItemStackHolder[size]; this.itemsDisplayed = new ItemStackHolder[size];
gui.addParent(this);
initItems();
WindowManager.getInstance().addWindow(this); WindowManager.getInstance().addWindow(this);
} }
private void initItems() { protected void redrawItem(int index, ItemStackHolder holder, boolean setItem) {
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) {
// put ItemStack in inventory // put ItemStack in inventory
ItemStack itemStack = holder == null ? null : holder.getItemStack(viewerUUID); ItemStack itemStack = holder == null ? null : holder.getItemStack(viewerUUID);
inventory.setItem(index, itemStack); setInvItem(index, itemStack);
if (setItem) { if (setItem) {
// tell the previous item (if there is one) that this is no longer its window // 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 @Override
public void handleOpen(InventoryOpenEvent event) { public void handleOpen(InventoryOpenEvent event) {
if (!event.getPlayer().equals(getViewer())) if (!event.getPlayer().equals(getViewer()))
event.setCancelled(true); event.setCancelled(true);
else handleOpened();
} }
@Override @Override
public void handleClose(Player player) { public void handleClose(Player player) {
if (closeable) { if (closeable) {
if (closeOnEvent) close(false); if (closeOnEvent) close(false);
handleClosed();
} else { } else {
if (player.equals(getViewer())) if (player.equals(getViewer()))
Bukkit.getScheduler().runTaskLater(InvGui.getInstance().getPlugin(), 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)); redrawItem(index, slotElement, false));
} }
private Map<Integer, ItemStackHolder> getItemSlotElements(Item item) { protected Map<Integer, ItemStackHolder> getItemSlotElements(Item item) {
return ArrayUtils.findAllOccurrences(itemsDisplayed, holder -> holder instanceof ItemSlotElement return ArrayUtils.findAllOccurrences(itemsDisplayed, holder -> holder instanceof ItemSlotElement
&& ((ItemSlotElement) holder).getItem() == item); && ((ItemSlotElement) holder).getItem() == item);
} }
private Map<Integer, ItemStackHolder> getVISlotElements(VirtualInventory virtualInventory) { protected Map<Integer, ItemStackHolder> getVISlotElements(VirtualInventory virtualInventory) {
return ArrayUtils.findAllOccurrences(itemsDisplayed, holder -> holder instanceof VISlotElement return ArrayUtils.findAllOccurrences(itemsDisplayed, holder -> holder instanceof VISlotElement
&& ((VISlotElement) holder).getVirtualInventory() == virtualInventory); && ((VISlotElement) holder).getVirtualInventory() == virtualInventory);
} }
@ -157,7 +125,8 @@ public abstract class BaseWindow implements Window, GUIParent {
.map(holder -> ((ItemSlotElement) holder).getItem()) .map(holder -> ((ItemSlotElement) holder).getItem())
.forEach(item -> item.removeWindow(this)); .forEach(item -> item.removeWindow(this));
gui.removeParent(this); Arrays.stream(getGuis())
.forEach(gui -> gui.removeParent(this));
if (closeForViewer) closeForViewer(); if (closeForViewer) closeForViewer();
} }
@ -166,7 +135,9 @@ public abstract class BaseWindow implements Window, GUIParent {
public void closeForViewer() { public void closeForViewer() {
closeable = true; closeable = true;
// clone list to prevent ConcurrentModificationException // clone list to prevent ConcurrentModificationException
new ArrayList<>(inventory.getViewers()).forEach(HumanEntity::closeInventory); new ArrayList<>(getInventories()[0].getViewers()).forEach(HumanEntity::closeInventory);
handleClosed();
} }
@Override @Override
@ -175,7 +146,13 @@ public abstract class BaseWindow implements Window, GUIParent {
Player viewer = getViewer(); Player viewer = getViewer();
if (viewer == null) throw new IllegalStateException("The player is not online."); if (viewer == null) throw new IllegalStateException("The player is not online.");
viewer.openInventory(inventory); viewer.openInventory(getInventories()[0]);
}
@Override
public Player getCurrentViewer() {
List<HumanEntity> viewers = getInventories()[0].getViewers();
return viewers.isEmpty() ? null : (Player) viewers.get(0);
} }
@Override @Override
@ -188,16 +165,6 @@ public abstract class BaseWindow implements Window, GUIParent {
return viewerUUID; return viewerUUID;
} }
@Override
public Inventory getInventory() {
return inventory;
}
@Override
public GUI getGui() {
return gui;
}
@Override @Override
public boolean isCloseable() { public boolean isCloseable() {
return closeable; return closeable;
@ -213,4 +180,10 @@ public abstract class BaseWindow implements Window, GUIParent {
return closed; return closed;
} }
protected abstract void setInvItem(int slot, ItemStack itemStack);
protected abstract void handleOpened();
protected abstract void handleClosed();
} }

@ -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);
}
}

@ -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);
}
}

@ -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<ItemStack> 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);
}

@ -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};
}
}

@ -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);
}
}

@ -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);
}
}

@ -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};
}
}

@ -1,4 +1,4 @@
package de.studiocode.invgui.window.impl; package de.studiocode.invgui.window.impl.single;
import de.studiocode.invgui.gui.GUI; import de.studiocode.invgui.gui.GUI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -7,14 +7,14 @@ import org.bukkit.inventory.Inventory;
import java.util.UUID; 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); super(viewerUUID, gui, createInventory(gui, title), closeable, closeOnEvent);
} }
public NormalInventoryWindow(Player player, GUI gui, String title, boolean closeable, boolean closeOnEvent) { public SimpleWindow(Player player, String title, GUI gui, boolean closeable, boolean closeOnEvent) {
this(player.getUniqueId(), gui, title, closeable, closeOnEvent); this(player.getUniqueId(), title, gui, closeable, closeOnEvent);
} }
private static Inventory createInventory(GUI gui, String title) { private static Inventory createInventory(GUI gui, String title) {

@ -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};
}
}