add gui to core

This commit is contained in:
jascotty2 2019-08-27 07:21:59 -05:00
parent 1d41c3842d
commit 56d0b8f552
11 changed files with 1412 additions and 0 deletions

View File

@ -0,0 +1,556 @@
package com.songoda.core.gui;
import com.songoda.core.gui.methods.Clickable;
import com.songoda.core.gui.methods.Closable;
import com.songoda.core.gui.methods.Droppable;
import com.songoda.core.gui.methods.Pagable;
import com.songoda.core.gui.methods.SimpleClickable;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
/**
* DO NOT USE YET!
* TODO: does not restore inventory if server is shut down while player inventory is open (1.8)
* Method to fix: save inv + ender slot to file, store paper in ender inv with name of cache file, check for paper item in slot when loading
*
* @since 2019-08-25
* @author jascotty2
*/
public class DoubleGUI extends GUI {
protected int playerRows = 4;
protected Map<Player, ItemStack[]> stash = new HashMap();
public DoubleGUI(GUIType type) {
super(type);
allowDropItems = false;
}
public DoubleGUI(int rows) {
super(rows);
allowDropItems = false;
}
public DoubleGUI(int rows, GUI parent) {
super(rows, parent);
allowDropItems = false;
}
public int getPlayerRows() {
return playerRows;
}
// 9 -> 0 -> 54
// 18 -> 9 -> 63
// 27 -> 18 -> 72
// 0 -> 27 -> 81
// offset required to make click translations
int clickOffset(int cell) {
return 54 + (cell < 9 ? cell + 27 : cell - 9);
}
// offset required to make inventory translations
int invOffset(int cell) {
return 54 + cell;
}
public DoubleGUI setPlayerUnlocked(int cell) {
unlockedCells.put(invOffset(cell), true);
return this;
}
public DoubleGUI setPlayerUnlocked(int row, int col) {
unlockedCells.put(invOffset(col + row * 9), true);
return this;
}
public DoubleGUI setPlayerUnlocked(int cell, boolean open) {
unlockedCells.put(invOffset(cell), open);
return this;
}
public DoubleGUI setPlayerUnlocked(int row, int col, boolean open) {
unlockedCells.put(invOffset(col + row * 9), open);
return this;
}
public DoubleGUI setPlayerItem(int cell, ItemStack item) {
cellItems.put(invOffset(cell), item);
if (open && cell >= 0 && cell < 36) {
cell = cell >= 27 ? cell - 27 : cell + 9;
for (HumanEntity e : inventory.getViewers()) {
e.getInventory().setItem(cell, item);
}
}
return this;
}
public DoubleGUI setPlayerItem(int row, int col, ItemStack item) {
int cell = col + row * 9;
cellItems.put(invOffset(cell), item);
if (open && cell >= 0 && cell < 36) {
cell = cell >= 27 ? cell - 27 : cell + 9;
for (HumanEntity e : inventory.getViewers()) {
e.getInventory().setItem(cell, item);
}
}
return this;
}
public DoubleGUI setPlayerAction(int cell, Clickable action) {
setConditional(invOffset(cell), null, action, null);
return this;
}
public DoubleGUI setPlayerAction(int cell, SimpleClickable action) {
setConditional(invOffset(cell), null, null, action);
return this;
}
public DoubleGUI setPlayerAction(int row, int col, Clickable action) {
setConditional(invOffset(col + row * 9), null, action, null);
return this;
}
public DoubleGUI setPlayerAction(int row, int col, SimpleClickable action) {
setConditional(invOffset(col + row * 9), null, null, action);
return this;
}
public DoubleGUI setPlayerAction(int cell, ClickType type, Clickable action) {
setConditional(invOffset(cell), type, action, null);
return this;
}
public DoubleGUI setPlayerAction(int cell, ClickType type, SimpleClickable action) {
setConditional(invOffset(cell), type, null, action);
return this;
}
public DoubleGUI setPlayerAction(int row, int col, ClickType type, Clickable action) {
setConditional(invOffset(col + row * 9), type, action, null);
return this;
}
public DoubleGUI setPlayerAction(int row, int col, ClickType type, SimpleClickable action) {
setConditional(invOffset(col + row * 9), type, null, action);
return this;
}
public DoubleGUI setPlayerActionForRange(int cellFirst, int cellLast, Clickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(invOffset(cell), null, action, null);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellFirst, int cellLast, SimpleClickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(invOffset(cell), null, null, action);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, Clickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(invOffset(cell), null, action, null);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, SimpleClickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(invOffset(cell), null, null, action);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellFirst, int cellLast, ClickType type, Clickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(invOffset(cell), type, action, null);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellFirst, int cellLast, ClickType type, SimpleClickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(invOffset(cell), type, null, action);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, ClickType type, Clickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(invOffset(cell), type, action, null);
}
return this;
}
public DoubleGUI setPlayerActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, ClickType type, SimpleClickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(invOffset(cell), type, null, action);
}
return this;
}
public DoubleGUI clearPlayerActions(int cell) {
conditionalButtons.remove(cell = invOffset(cell));
conditionalSimpleButtons.remove(cell);
return this;
}
public DoubleGUI clearPlayerActions(int row, int col) {
final int cell = invOffset(col + row * 9);
conditionalButtons.remove(cell);
conditionalSimpleButtons.remove(cell);
return this;
}
public DoubleGUI setPlayerButton(int cell, ItemStack item, Clickable action) {
setPlayerItem(cell, item);
setConditional(invOffset(cell), null, action, null);
return this;
}
public DoubleGUI setPlayerButton(int cell, ItemStack item, SimpleClickable action) {
setPlayerItem(cell, item);
setConditional(invOffset(cell), null, null, action);
return this;
}
public DoubleGUI setPlayerButton(int row, int col, ItemStack item, Clickable action) {
final int cell = col + row * 9;
setPlayerItem(cell, item);
setConditional(invOffset(cell), null, action, null);
return this;
}
public DoubleGUI setPlayerButton(int row, int col, ItemStack item, SimpleClickable action) {
final int cell = col + row * 9;
setPlayerItem(cell, item);
setConditional(invOffset(cell), null, null, action);
return this;
}
public DoubleGUI setPlayerButton(int cell, ItemStack item, ClickType type, Clickable action) {
setItem(cell, item);
setConditional(invOffset(cell), type, action, null);
return this;
}
public DoubleGUI setPlayerButton(int cell, ItemStack item, ClickType type, SimpleClickable action) {
setPlayerItem(cell, item);
setConditional(invOffset(cell), type, null, action);
return this;
}
public DoubleGUI setPlayerButton(int row, int col, ItemStack item, ClickType type, Clickable action) {
final int cell = col + row * 9;
setPlayerItem(cell, item);
setConditional(invOffset(cell), type, action, null);
return this;
}
public DoubleGUI setPlayerButton(int row, int col, ItemStack item, ClickType type, SimpleClickable action) {
final int cell = col + row * 9;
setPlayerItem(cell, item);
setConditional(invOffset(cell), type, null, action);
return this;
}
@Override
protected boolean onClickPlayerInventory(Player player, Inventory openInv, InventoryClickEvent event) {
final int cell = event.getSlot(), offsetCell = clickOffset(cell);
Map<ClickType, Clickable> conditionals = conditionalButtons.get(offsetCell);
Map<ClickType, SimpleClickable> simpleConditionals;
Clickable button;
SimpleClickable simpleButton;
if (conditionals != null
&& ((button = conditionals.get(event.getClick())) != null || (button = conditionals.get(null)) != null)) {
button.onClick(player, inventory, this, event.getCursor(), cell, event.getClick());
} else if ((simpleConditionals = conditionalSimpleButtons.get(offsetCell)) != null
&& ((simpleButton = simpleConditionals.get(event.getClick())) != null || (simpleButton = simpleConditionals.get(null)) != null)) {
simpleButton.onClick(cell);
} else {
// no event for this button
return false;
}
event.setCancelled(!unlockedCells.entrySet().stream().anyMatch(e -> offsetCell == e.getKey() && e.getValue()));
return true;
}
@Override
protected boolean onClickOutside(Player player, Inventory inventory, ItemStack cursor, ClickType click) {
if (dropper != null) {
return dropper.onDrop(player, inventory, this, cursor);
}
// do not allow by default
return false;
}
@Override
public void onOpen(Player player) {
// replace the player's inventory
ItemStack[] oldInv = player.getInventory().getContents();
ItemStack[] newInv = new ItemStack[oldInv.length];
for (int i = 0; i < newInv.length; ++i) {
final ItemStack item = cellItems.get(invOffset(i < 9 ? i + 27 : i - 9));
newInv[i] = item != null ? item : blankItem;
}
stash.put(player, oldInv);
player.getInventory().setContents(newInv);
}
@Override
public void onClose(GUIManager manager, Player player) {
// restore the player's inventory
if (stash.containsKey(player)) {
player.getInventory().setContents(stash.remove(player));
player.updateInventory();
}
// other closing functions
super.onClose(manager, player);
}
/*
*********************************************************
* Other functions from GUI that we don't actually override
*********************************************************
*/
@Override
public DoubleGUI setAcceptsItems(boolean acceptsItems) {
return (DoubleGUI) super.setAcceptsItems(acceptsItems);
}
@Override
public DoubleGUI setUnlocked(int cell) {
return (DoubleGUI) super.setUnlocked(cell);
}
@Override
public DoubleGUI setUnlocked(int cell, boolean open) {
return (DoubleGUI) super.setUnlocked(cell, open);
}
@Override
public DoubleGUI setUnlocked(int row, int col) {
return (DoubleGUI) super.setUnlocked(row, col);
}
@Override
public DoubleGUI setUnlocked(int row, int col, boolean open) {
return (DoubleGUI) super.setUnlocked(row, col, open);
}
@Override
public DoubleGUI setUnlockedRange(int cellFirst, int cellLast) {
return (DoubleGUI) super.setUnlockedRange(cellFirst, cellLast);
}
@Override
public DoubleGUI setUnlockedRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast) {
return (DoubleGUI) super.setUnlockedRange(cellRowFirst, cellColFirst, cellRowLast, cellColLast);
}
@Override
public DoubleGUI setAllowDrops(boolean allow) {
return (DoubleGUI) super.setAllowDrops(allow);
}
@Override
public DoubleGUI setAllowClose(boolean allow) {
return (DoubleGUI) super.setAllowClose(allow);
}
@Override
public DoubleGUI setTitle(String title) {
return (DoubleGUI) super.setTitle(title);
}
@Override
public DoubleGUI setRows(int rows) {
return (DoubleGUI) super.setRows(rows);
}
@Override
public DoubleGUI setDefaultItem(ItemStack item) {
return (DoubleGUI) super.setDefaultItem(item);
}
@Override
public DoubleGUI setItem(int cell, ItemStack item) {
return (DoubleGUI) super.setItem(cell, item);
}
@Override
public DoubleGUI setItem(int row, int col, ItemStack item) {
return (DoubleGUI) super.setItem(row, col, item);
}
@Override
public DoubleGUI setAction(int cell, Clickable action) {
return (DoubleGUI) super.setAction(cell, action);
}
@Override
public DoubleGUI setAction(int cell, SimpleClickable action) {
return (DoubleGUI) super.setAction(cell, action);
}
@Override
public DoubleGUI setAction(int row, int col, Clickable action) {
return (DoubleGUI) super.setAction(row, col, action);
}
@Override
public DoubleGUI setAction(int row, int col, SimpleClickable action) {
return (DoubleGUI) super.setAction(row, col, action);
}
@Override
public DoubleGUI setAction(int cell, ClickType type, Clickable action) {
return (DoubleGUI) super.setAction(cell, type, action);
}
@Override
public DoubleGUI setAction(int cell, ClickType type, SimpleClickable action) {
return (DoubleGUI) super.setAction(cell, type, action);
}
@Override
public DoubleGUI setAction(int row, int col, ClickType type, Clickable action) {
return (DoubleGUI) super.setAction(row, col, type, action);
}
@Override
public DoubleGUI setAction(int row, int col, ClickType type, SimpleClickable action) {
return (DoubleGUI) super.setAction(row, col, type, action);
}
@Override
public DoubleGUI setActionForRange(int cellFirst, int cellLast, Clickable action) {
return (DoubleGUI) super.setActionForRange(cellFirst, cellLast, action);
}
@Override
public DoubleGUI setActionForRange(int cellFirst, int cellLast, SimpleClickable action) {
return (DoubleGUI) super.setActionForRange(cellFirst, cellLast, action);
}
@Override
public DoubleGUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, Clickable action) {
return (DoubleGUI) super.setActionForRange(cellRowFirst, cellColFirst, cellRowLast, cellColLast, action);
}
@Override
public DoubleGUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, SimpleClickable action) {
return (DoubleGUI) super.setActionForRange(cellRowFirst, cellColFirst, cellRowLast, cellColLast, action);
}
@Override
public DoubleGUI setActionForRange(int cellFirst, int cellLast, ClickType type, Clickable action) {
return (DoubleGUI) super.setActionForRange(cellFirst, cellLast, type, action);
}
@Override
public DoubleGUI setActionForRange(int cellFirst, int cellLast, ClickType type, SimpleClickable action) {
return (DoubleGUI) super.setActionForRange(cellFirst, cellLast, type, action);
}
@Override
public DoubleGUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, ClickType type, Clickable action) {
return (DoubleGUI) super.setActionForRange(cellRowFirst, cellColFirst, cellRowLast, cellColLast, type, action);
}
@Override
public DoubleGUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, ClickType type, SimpleClickable action) {
return (DoubleGUI) super.setActionForRange(cellRowFirst, cellColFirst, cellRowLast, cellColLast, type, action);
}
@Override
public DoubleGUI clearActions(int cell) {
return (DoubleGUI) super.clearActions(cell);
}
@Override
public DoubleGUI clearActions(int row, int col) {
return (DoubleGUI) super.clearActions(row, col);
}
@Override
public DoubleGUI setButton(int cell, ItemStack item, Clickable action) {
return (DoubleGUI) super.setButton(cell, item, action);
}
@Override
public DoubleGUI setButton(int cell, ItemStack item, SimpleClickable action) {
return (DoubleGUI) super.setButton(cell, item, action);
}
@Override
public DoubleGUI setButton(int row, int col, ItemStack item, Clickable action) {
return (DoubleGUI) super.setButton(row, col, item, action);
}
@Override
public DoubleGUI setButton(int row, int col, ItemStack item, SimpleClickable action) {
return (DoubleGUI) super.setButton(row, col, item, action);
}
@Override
public DoubleGUI setButton(int cell, ItemStack item, ClickType type, Clickable action) {
return (DoubleGUI) super.setButton(cell, item, type, action);
}
@Override
public DoubleGUI setButton(int cell, ItemStack item, ClickType type, SimpleClickable action) {
return (DoubleGUI) super.setButton(cell, item, type, action);
}
@Override
public DoubleGUI setButton(int row, int col, ItemStack item, ClickType type, Clickable action) {
return (DoubleGUI) super.setButton(row, col, item, type, action);
}
@Override
public DoubleGUI setButton(int row, int col, ItemStack item, ClickType type, SimpleClickable action) {
return (DoubleGUI) super.setButton(row, col, item, type, action);
}
@Override
public DoubleGUI setOnClose(Closable action) {
return (DoubleGUI) super.setOnClose(action);
}
@Override
public DoubleGUI setOnDrop(Droppable action) {
return (DoubleGUI) super.setOnDrop(action);
}
@Override
public DoubleGUI setOnPage(Pagable action) {
return (DoubleGUI) super.setOnPage(action);
}
@Override
public DoubleGUI setNextPage(int row, int col, ItemStack item) {
return (DoubleGUI) super.setNextPage(row, col, item);
}
@Override
public DoubleGUI setPrevPage(int row, int col, ItemStack item) {
return (DoubleGUI) super.setPrevPage(row, col, item);
}
}

View File

@ -0,0 +1,578 @@
package com.songoda.core.gui;
import com.songoda.core.gui.methods.Pagable;
import com.songoda.core.gui.methods.Clickable;
import com.songoda.core.gui.methods.Droppable;
import com.songoda.core.gui.methods.Closable;
import com.songoda.core.gui.methods.SimpleClickable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
/**
* TODO: animated buttons
*
* @since 2019-08-25
* @author jascotty2
*/
public class GUI {
protected Inventory inventory;
protected String title;
protected GUIType type = GUIType.STANDARD;
protected int rows, page, pages;
protected boolean acceptsItems = false;
protected boolean allowDropItems = true;
protected boolean allowClose = true;
protected final Map<Integer, Boolean> unlockedCells = new HashMap<>();
protected final Map<Integer, ItemStack> cellItems = new HashMap<>();
protected final Map<Integer, Map<ClickType, Clickable>> conditionalButtons = new HashMap<>();
protected final Map<Integer, Map<ClickType, SimpleClickable>> conditionalSimpleButtons = new HashMap<>();
protected ItemStack blankItem = GuiUtils.getBorderGlassItem();
protected int nextPageIndex, prevPageIndex;
protected ItemStack nextPage, prevPage;
protected GUI parent = null;
protected static ItemStack AIR = new ItemStack(Material.AIR);
protected boolean open = false;
protected Closable closer = null;
protected Droppable dropper = null;
protected Pagable pager = null;
public GUI(GUIType type) {
this.type = type;
switch (type) {
case HOPPER:
case DISPENSER:
this.rows = 1;
break;
default:
this.rows = 3;
}
}
public GUI(int rows) {
this.rows = Math.max(1, Math.min(6, rows));
}
public GUI(int rows, GUI parent) {
this.parent = parent;
this.rows = Math.max(1, Math.min(6, rows));
}
public List<Player> getPlayers() {
return inventory == null ? Collections.EMPTY_LIST
: inventory.getViewers().stream()
.filter(e -> e instanceof Player)
.map(e -> (Player) e)
.collect(Collectors.toList());
}
public boolean isOpen() {
// double check
if (inventory != null && inventory.getViewers().isEmpty()) {
open = false;
}
return open;
}
public boolean getAcceptsItems() {
return acceptsItems;
}
public GUI setAcceptsItems(boolean acceptsItems) {
this.acceptsItems = acceptsItems;
return this;
}
/**
* If this is true, then items in the player's cursor when the GUI is closed
* will be cleared
*/
public boolean getAllowDrops() {
return allowDropItems;
}
/**
* Set if items in the player's cursor will be cleared when the GUI is
* closed
*/
public GUI setAllowDrops(boolean allow) {
this.allowDropItems = allow;
return this;
}
public boolean getAllowClose() {
return allowClose;
}
public GUI setAllowClose(boolean allow) {
this.allowClose = allow;
return this;
}
public void exit() {
allowClose = true;
parent = null;
inventory.getViewers().stream()
.filter(e -> e instanceof Player)
.map(e -> (Player) e)
.collect(Collectors.toList())
.forEach(Player::closeInventory);
}
public GUIType getType() {
return type;
}
public GUI setUnlocked(int cell) {
unlockedCells.put(cell, true);
return this;
}
public GUI setUnlocked(int row, int col) {
final int cell = col + row * 9;
unlockedCells.put(cell, true);
return this;
}
public GUI setUnlockedRange(int cellFirst, int cellLast) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
unlockedCells.put(cell, true);
}
return this;
}
public GUI setUnlockedRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
unlockedCells.put(cell, true);
}
return this;
}
public GUI setUnlocked(int cell, boolean open) {
unlockedCells.put(cell, open);
return this;
}
public GUI setUnlocked(int row, int col, boolean open) {
final int cell = col + row * 9;
unlockedCells.put(cell, open);
return this;
}
public GUI setTitle(String title) {
this.title = title;
return this;
}
public int getRows() {
return rows;
}
public GUI setRows(int rows) {
switch (type) {
case HOPPER:
case DISPENSER:
break;
default:
this.rows = Math.max(1, Math.min(6, rows));
}
return this;
}
public GUI setDefaultItem(ItemStack item) {
blankItem = item;
return this;
}
public GUI setItem(int cell, ItemStack item) {
cellItems.put(cell, item);
if (open && cell >= 0 && cell < inventory.getSize()) {
inventory.setItem(cell, item);
}
return this;
}
public GUI setItem(int row, int col, ItemStack item) {
final int cell = col + row * 9;
cellItems.put(cell, item);
if (open && cell >= 0 && cell < inventory.getSize()) {
inventory.setItem(cell, item);
}
return this;
}
public GUI setAction(int cell, Clickable action) {
setConditional(cell, null, action, null);
return this;
}
public GUI setAction(int cell, SimpleClickable action) {
setConditional(cell, null, null, action);
return this;
}
public GUI setAction(int row, int col, Clickable action) {
setConditional(col + row * 9, null, action, null);
return this;
}
public GUI setAction(int row, int col, SimpleClickable action) {
setConditional(col + row * 9, null, null, action);
return this;
}
public GUI setAction(int cell, ClickType type, Clickable action) {
setConditional(cell, type, action, null);
return this;
}
public GUI setAction(int cell, ClickType type, SimpleClickable action) {
setConditional(cell, type, null, action);
return this;
}
public GUI setAction(int row, int col, ClickType type, Clickable action) {
setConditional(col + row * 9, type, action, null);
return this;
}
public GUI setAction(int row, int col, ClickType type, SimpleClickable action) {
setConditional(col + row * 9, type, null, action);
return this;
}
public GUI setActionForRange(int cellFirst, int cellLast, Clickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(cell, null, action, null);
}
return this;
}
public GUI setActionForRange(int cellFirst, int cellLast, SimpleClickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(cell, null, null, action);
}
return this;
}
public GUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, Clickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(cell, null, action, null);
}
return this;
}
public GUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, SimpleClickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(cell, null, null, action);
}
return this;
}
public GUI setActionForRange(int cellFirst, int cellLast, ClickType type, Clickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(cell, type, action, null);
}
return this;
}
public GUI setActionForRange(int cellFirst, int cellLast, ClickType type, SimpleClickable action) {
for (int cell = cellFirst; cell <= cellLast; ++cell) {
setConditional(cell, type, null, action);
}
return this;
}
public GUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, ClickType type, Clickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(cell, type, action, null);
}
return this;
}
public GUI setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, ClickType type, SimpleClickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
setConditional(cell, type, null, action);
}
return this;
}
public GUI clearActions(int cell) {
conditionalButtons.remove(cell);
conditionalSimpleButtons.remove(cell);
return this;
}
public GUI clearActions(int row, int col) {
final int cell = col + row * 9;
conditionalButtons.remove(cell);
conditionalSimpleButtons.remove(cell);
return this;
}
public GUI setButton(int cell, ItemStack item, Clickable action) {
setItem(cell, item);
setConditional(cell, null, action, null);
return this;
}
public GUI setButton(int cell, ItemStack item, SimpleClickable action) {
setItem(cell, item);
setConditional(cell, null, null, action);
return this;
}
public GUI setButton(int row, int col, ItemStack item, Clickable action) {
final int cell = col + row * 9;
setItem(cell, item);
setConditional(cell, null, action, null);
return this;
}
public GUI setButton(int row, int col, ItemStack item, SimpleClickable action) {
final int cell = col + row * 9;
setItem(cell, item);
setConditional(cell, null, null, action);
return this;
}
public GUI setButton(int cell, ItemStack item, ClickType type, Clickable action) {
setItem(cell, item);
setConditional(cell, type, action, null);
return this;
}
public GUI setButton(int cell, ItemStack item, ClickType type, SimpleClickable action) {
setItem(cell, item);
setConditional(cell, type, null, action);
return this;
}
public GUI setButton(int row, int col, ItemStack item, ClickType type, Clickable action) {
final int cell = col + row * 9;
setItem(cell, item);
setConditional(cell, type, action, null);
return this;
}
public GUI setButton(int row, int col, ItemStack item, ClickType type, SimpleClickable action) {
final int cell = col + row * 9;
setItem(cell, item);
setConditional(cell, type, null, action);
return this;
}
protected void setConditional(int cell, ClickType type, Clickable action, SimpleClickable simpleAction) {
Map<ClickType, Clickable> conditionals = conditionalButtons.get(cell);
Map<ClickType, SimpleClickable> simpleConditionals = conditionalSimpleButtons.get(cell);
if (action != null) {
if (conditionals == null) {
conditionalButtons.put(cell, conditionals = new HashMap());
}
conditionals.put(type, action);
if (simpleConditionals != null) {
simpleConditionals.remove(type);
}
} else {
if (simpleConditionals == null) {
conditionalSimpleButtons.put(cell, simpleConditionals = new HashMap());
}
simpleConditionals.put(type, simpleAction);
if (conditionals != null) {
conditionals.remove(type);
}
}
}
public GUI setOnClose(Closable action) {
closer = action;
return this;
}
public GUI setOnDrop(Droppable action) {
dropper = action;
return this;
}
public GUI setOnPage(Pagable action) {
pager = action;
return this;
}
public GUI setNextPage(int row, int col, ItemStack item) {
nextPageIndex = col + row * 9;
if (page < pages) {
setButton(nextPageIndex, item, ClickType.LEFT, (slot) -> this.nextPage());
}
return this;
}
public GUI setPrevPage(int row, int col, ItemStack item) {
prevPageIndex = col + row * 9;
if (page > 1) {
setButton(prevPageIndex, item, ClickType.LEFT, (slot) -> this.prevPage());
}
return this;
}
public void nextPage() {
if (page < pages) {
int lastPage = page;
++page;
// page switch events
if (pager != null) {
pager.onPageChange(this, lastPage, page);
// page markers
updatePageNavigation();
// push new inventory to the view inventory
update();
}
}
}
public void prevPage() {
if (page > 1) {
int lastPage = page;
--page;
if (pager != null) {
pager.onPageChange(this, lastPage, page);
// page markers
updatePageNavigation();
// push new inventory to the view inventory
update();
}
}
}
protected void updatePageNavigation() {
if (page > 1) {
this.setButton(prevPageIndex, prevPage, ClickType.LEFT, (slot) -> this.prevPage());
} else {
this.setItem(prevPageIndex, null);
this.clearActions(prevPageIndex);
}
if (pages > 1 && page != pages) {
this.setButton(nextPageIndex, nextPage, ClickType.LEFT, (slot) -> this.nextPage());
} else {
this.setItem(nextPageIndex, null);
this.clearActions(nextPageIndex);
}
}
protected Inventory getOrCreateInventory() {
return inventory != null ? inventory : generateInventory();
}
protected Inventory generateInventory() {
final int cells = rows * 9;
InventoryType t = type == null ? InventoryType.CHEST : type.type;
switch (t) {
case DISPENSER:
case HOPPER:
inventory = Bukkit.getServer().createInventory(new GUIHolder(this), t,
title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title)));
break;
default:
inventory = Bukkit.getServer().createInventory(new GUIHolder(this), cells,
title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title)));
}
for (int i = 0; i < cells; ++i) {
final ItemStack item = cellItems.get(i);
inventory.setItem(i, item != null ? item : blankItem);
}
return inventory;
}
public GUI getParent() {
return parent;
}
public void update() {
if (inventory == null) {
return;
}
final int cells = rows * 9;
for (int i = 0; i < cells; ++i) {
final ItemStack item = cellItems.get(i);
inventory.setItem(i, item != null ? item : blankItem);
}
}
protected static String trimTitle(String title) {
if (title != null && title.length() > 32) {
return title.substring(0, 31);
}
return title;
}
protected boolean onClickOutside(Player player, Inventory inventory, ItemStack cursor, ClickType click) {
return dropper != null ? dropper.onDrop(player, inventory, this, cursor) : true;
}
protected boolean onClick(Player player, Inventory inventory, InventoryClickEvent event) {
final int cell = event.getSlot();
Map<ClickType, Clickable> conditionals = conditionalButtons.get(cell);
Map<ClickType, SimpleClickable> simpleConditionals;
Clickable button;
SimpleClickable simpleButton;
if (conditionals != null
&& ((button = conditionals.get(event.getClick())) != null || (button = conditionals.get(null)) != null)) {
button.onClick(player, inventory, this, event.getCursor(), cell, event.getClick());
} else if ((simpleConditionals = conditionalSimpleButtons.get(cell)) != null
&& ((simpleButton = simpleConditionals.get(event.getClick())) != null || (simpleButton = simpleConditionals.get(null)) != null)) {
simpleButton.onClick(cell);
} else {
// no event for this button
return false;
}
return true;
}
protected boolean onClickPlayerInventory(Player player, Inventory openInv, InventoryClickEvent event) {
// no events for this yet
return false;
}
public void onOpen(Player player) {
open = true;
}
public void onClose(GUIManager manager, Player player) {
if (!allowClose) {
manager.showGUI(player, this);
return;
}
if (open && closer != null) {
open = inventory.getViewers().isEmpty();
closer.onClose(player, this);
}
if (parent != null) {
manager.showGUI(player, parent);
}
}
}

View File

@ -0,0 +1,22 @@
package com.songoda.core.gui;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
class GUIHolder implements InventoryHolder {
final GUI gui;
GUIHolder(GUI gui) {
this.gui = gui;
}
@Override
public Inventory getInventory() {
return gui.inventory;
}
public GUI getGUI() {
return gui;
}
}

View File

@ -0,0 +1,135 @@
package com.songoda.core.gui;
import com.songoda.core.compatibility.CompatibleSounds;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.plugin.Plugin;
/**
* @since 2019-08-25
* @author jascotty2
*/
public class GUIManager {
final Plugin plugin;
final GuiListener listener = new GuiListener(this);
final Map<Player, Inventory> openInventories = new HashMap();
private boolean initialized = false;
public GUIManager(Plugin plugin) {
this.plugin = plugin;
}
/**
* Initialize the GUI handlers
*/
public void init() {
Bukkit.getPluginManager().registerEvents(listener, plugin);
initialized = true;
}
/**
* Create and display a GUI interface for a player
*
* @param player player to open the interface for
* @param gui GUI to use
*/
public void showGUI(Player player, GUI gui) {
if (!initialized) {
init();
}
Inventory inv = gui.generateInventory();
player.openInventory(inv);
gui.onOpen(player);
openInventories.put(player, inv);
}
/**
* Close all active GUIs
*/
public void closeAll() {
openInventories.entrySet().stream()
.filter(e -> e.getKey().getOpenInventory().getTopInventory().getHolder() instanceof GUIHolder)
.collect(Collectors.toList()) // to prevent concurrency exceptions
.forEach(e -> e.getKey().closeInventory());
openInventories.clear();
}
protected static class GuiListener implements Listener {
final GUIManager manager;
public GuiListener(GUIManager manager) {
this.manager = manager;
}
@EventHandler(priority = EventPriority.LOW)
void onClickGUI(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player)) {
return;
}
Inventory openInv = event.getInventory();
final Player player = (Player) event.getWhoClicked();
GUI gui;
if (openInv.getHolder() != null && openInv.getHolder() instanceof GUIHolder) {
gui = ((GUIHolder) openInv.getHolder()).getGUI();
if (event.getSlotType() == SlotType.OUTSIDE) {
if (!gui.onClickOutside(player, openInv, event.getCursor(), event.getClick())) {
event.setCancelled(true);
}
} // did we click the gui or in the user's inventory?
else if (event.getRawSlot() < gui.inventory.getSize()) {// or could use event.getClickedInventory() == gui.inventory
// allow event if this is not a GUI element
event.setCancelled(!gui.unlockedCells.entrySet().stream().anyMatch(e -> event.getSlot() == e.getKey() && e.getValue()));
// process button press
if (gui.onClick(player, openInv, event)) {
player.playSound(player.getLocation(), CompatibleSounds.UI_BUTTON_CLICK.getSound(), 1F, 1F);
}
} else {
// Player clicked in the bottom inventory while GUI is open
if (gui.onClickPlayerInventory(player, openInv, event)) {
player.playSound(player.getLocation(), CompatibleSounds.UI_BUTTON_CLICK.getSound(), 1F, 1F);
} else if (!gui.acceptsItems || event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY) {
event.setCancelled(true);
}
}
}
}
@EventHandler(priority = EventPriority.LOW)
void onCloseGUI(InventoryCloseEvent event) {
Inventory openInv = event.getInventory();
if (openInv.getHolder() != null && openInv.getHolder() instanceof GUIHolder) {
final Player player = (Player) event.getPlayer();
GUI gui = ((GUIHolder) openInv.getHolder()).getGUI();
if (!gui.allowDropItems) {
player.setItemOnCursor(null);
}
Bukkit.getScheduler().runTaskLater(manager.plugin, () -> gui.onClose(manager, player), 1);
manager.openInventories.remove(player);
}
}
@EventHandler
void onDisable(PluginDisableEvent event) {
if (event.getPlugin() == manager.plugin) {
// uh-oh! Abandon ship!!
manager.closeAll();
manager.initialized = false;
}
}
}
}

View File

@ -0,0 +1,17 @@
package com.songoda.core.gui;
import org.bukkit.event.inventory.InventoryType;
public enum GUIType {
STANDARD(InventoryType.CHEST),
DISPENSER(InventoryType.DISPENSER),
HOPPER(InventoryType.HOPPER);
protected final InventoryType type;
private GUIType(InventoryType type) {
this.type = type;
}
}

View File

@ -0,0 +1,59 @@
package com.songoda.core.gui;
import com.songoda.core.compatibility.LegacyMaterials;
import java.util.Arrays;
import java.util.Collections;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
/**
* @since 2019-08-25
* @author jascotty2
*/
public class GuiUtils {
public static ItemStack getBorderGlassItem() {
ItemStack glass = LegacyMaterials.LIGHT_BLUE_STAINED_GLASS_PANE.getItem();
ItemMeta glassmeta = glass.getItemMeta();
glassmeta.setDisplayName(ChatColor.BLACK.toString());
glass.setItemMeta(glassmeta);
return glass;
}
public static ItemStack createButtonItem(Material mat, String title, String... lore) {
ItemStack item = new ItemStack(mat);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(title);
if (lore != null) {
meta.setLore(Arrays.asList(lore.length == 1 ? lore[0].split("\n") : lore));
}
item.setItemMeta(meta);
return item;
}
public static ItemStack createButtonItem(LegacyMaterials mat, String title, String... lore) {
ItemStack item = mat.getItem();
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(title);
if (lore != null) {
meta.setLore(Arrays.asList(lore.length == 1 ? lore[0].split("\n") : lore));
}
item.setItemMeta(meta);
return item;
}
public static ItemStack createButtonItem(ItemStack from, String title, String... lore) {
ItemStack item = from.clone();
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(title);
if (lore != null) {
meta.setLore(Arrays.asList(lore.length == 1 ? lore[0].split("\n") : lore));
} else {
meta.setLore(Collections.EMPTY_LIST);
}
item.setItemMeta(meta);
return item;
}
}

View File

@ -0,0 +1,12 @@
package com.songoda.core.gui.methods;
import com.songoda.core.gui.GUI;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public interface Clickable {
void onClick(Player player, Inventory inventory, GUI gui, ItemStack cursor, int slot, ClickType type);
}

View File

@ -0,0 +1,9 @@
package com.songoda.core.gui.methods;
import com.songoda.core.gui.GUI;
import org.bukkit.entity.Player;
public interface Closable {
void onClose(Player player, GUI gui);
}

View File

@ -0,0 +1,11 @@
package com.songoda.core.gui.methods;
import com.songoda.core.gui.GUI;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public interface Droppable {
boolean onDrop(Player player, Inventory inventory, GUI gui, ItemStack cursor);
}

View File

@ -0,0 +1,8 @@
package com.songoda.core.gui.methods;
import com.songoda.core.gui.GUI;
public interface Pagable {
void onPageChange(GUI gui, int lastPage, int newPage);
}

View File

@ -0,0 +1,5 @@
package com.songoda.core.gui.methods;
public interface SimpleClickable {
void onClick(int slot);
}