Skip to content

Instantly share code, notes, and snippets.

@Sxtanna
Created February 3, 2020 13:12
Show Gist options
  • Save Sxtanna/5ec752663c4fa8ee1d27b9a312b849bc to your computer and use it in GitHub Desktop.
Save Sxtanna/5ec752663c4fa8ee1d27b9a312b849bc to your computer and use it in GitHub Desktop.
Spigot Menu
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
public abstract class Menu implements InventoryHolder, Listener
{
private boolean loaded;
protected final Plugin plugin;
protected final Inventory inventory;
protected final Map<Integer, Consumer<InventoryClickEvent>> consumers = new HashMap<>();
protected Menu(@NotNull final Plugin plugin, @NotNull final String title, @NotNull final Size size)
{
this.plugin = plugin;
this.inventory = plugin.getServer().createInventory(this, (size.ordinal() + 1) * 9, color(title));
}
@NotNull
@Override
public final Inventory getInventory()
{
return inventory;
}
@NotNull
public final Map<Integer, Consumer<InventoryClickEvent>> getConsumers()
{
return consumers;
}
private void load()
{
if (loaded)
{
return;
}
loaded = true;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
private void kill()
{
if (!loaded)
{
return;
}
loaded = false;
HandlerList.unregisterAll(this);
getConsumers().clear();
getInventory().clear();
}
public final void open(@NotNull final Player player)
{
if (!loaded)
{
load();
make();
}
player.openInventory(getInventory());
opened(player);
}
protected void make()
{
}
protected void redo()
{
consumers.clear();
getInventory().clear();
make();
}
protected void opened(@NotNull final Player player)
{
}
protected void closed(@NotNull final Player player)
{
}
protected final void slot(final int slot, @NotNull final ItemStack item)
{
getInventory().setItem(slot, item);
}
protected final void slot(final int slot, @NotNull final Consumer<InventoryClickEvent> consumer)
{
consumers.put(slot, consumer);
}
protected final void slot(final int slot, @NotNull final ItemStack item, @NotNull final Consumer<InventoryClickEvent> consumer)
{
slot(slot, item);
slot(slot, consumer);
}
protected final void grid(@NotNull final Rows row, @NotNull final Cols col, @NotNull final ItemStack item)
{
slot(Grid.from(row, col), item);
}
protected final void grid(@NotNull final Rows row, @NotNull final Cols col, @NotNull final Consumer<InventoryClickEvent> consumer)
{
slot(Grid.from(row, col), consumer);
}
protected final void grid(@NotNull final Rows row, @NotNull final Cols col, @NotNull final ItemStack item, @NotNull final Consumer<InventoryClickEvent> consumer)
{
grid(row, col, item);
grid(row, col, consumer);
}
protected final void grid(@NotNull final Rows row, @NotNull final ItemStack item)
{
for (final Cols col : Cols.COLS)
{
final int slot = Grid.from(row, col);
if (slot > getInventory().getSize())
{
break;
}
if (getInventory().getItem(slot) != null)
{
continue;
}
slot(slot, item);
}
}
protected final void grid(@NotNull final Rows row, @NotNull final Consumer<InventoryClickEvent> consumer)
{
for (final Cols col : Cols.COLS)
{
final int slot = Grid.from(row, col);
if (slot > getInventory().getSize())
{
break;
}
if (consumers.containsKey(slot))
{
continue;
}
slot(slot, consumer);
}
}
protected final void grid(@NotNull final Rows row, @NotNull final ItemStack item, @NotNull final Consumer<InventoryClickEvent> consumer)
{
for (final Cols col : Cols.COLS)
{
final int slot = Grid.from(row, col);
if (slot > getInventory().getSize())
{
break;
}
if (consumers.containsKey(slot) || getInventory().getItem(slot) != null)
{
continue;
}
slot(slot, item);
slot(slot, consumer);
}
}
protected final void grid(@NotNull final Cols col, @NotNull final ItemStack item)
{
for (final Rows row : Rows.ROWS)
{
final int slot = Grid.from(row, col);
if (slot > getInventory().getSize())
{
break;
}
if (getInventory().getItem(slot) != null)
{
continue;
}
slot(slot, item);
}
}
protected final void grid(@NotNull final Cols col, @NotNull final Consumer<InventoryClickEvent> consumer)
{
for (final Rows row : Rows.ROWS)
{
final int slot = Grid.from(row, col);
if (slot > getInventory().getSize())
{
break;
}
if (consumers.containsKey(slot))
{
continue;
}
slot(slot, consumer);
}
}
protected final void grid(@NotNull final Cols col, @NotNull final ItemStack item, @NotNull final Consumer<InventoryClickEvent> consumer)
{
for (final Rows row : Rows.ROWS)
{
final int slot = Grid.from(row, col);
if (slot > getInventory().getSize())
{
break;
}
if (consumers.containsKey(slot) || getInventory().getItem(slot) != null)
{
continue;
}
slot(slot, item);
slot(slot, consumer);
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public final void onClick(@NotNull final InventoryClickEvent event)
{
if (event.getView().getTopInventory().getHolder() != this)
{
// if we aren't the holder, do nothing
return;
}
if (event.getSlotType() == InventoryType.SlotType.OUTSIDE || event.getRawSlot() > getInventory().getSize())
{
// if they click outside of the inventory, or the slot the click isn't in this inventory, do nothing
return;
}
final Consumer<InventoryClickEvent> consumer = consumers.get(event.getRawSlot());
if (consumer == null)
{
// if there is no consumer for this slot, do nothing
return;
}
consumer.accept(event);
}
@EventHandler
public final void onClose(@NotNull final InventoryCloseEvent event)
{
if (event.getView().getTopInventory().getHolder() != this)
{
// if we aren't the holder, do nothing
return;
}
if (event.getPlayer() instanceof Player)
{
closed(((Player) event.getPlayer()));
}
if (getInventory().getViewers().size() > 1)
{
// if there is more than one player viewing this inventory, do nothing
return;
}
kill();
}
@NotNull
public static String color(@NotNull final String text)
{
return ChatColor.translateAlternateColorCodes('&', text);
}
@NotNull
public static ItemStack item(@NotNull final Material type)
{
return item(type, 1);
}
@NotNull
public static ItemStack item(@NotNull final Material type, final int amount)
{
return new ItemStack(type, amount);
}
@NotNull
public static ItemStack item(@NotNull final Material type, final int amount, @NotNull final Consumer<ItemMeta> consumer)
{
return meta(item(type, amount), consumer);
}
@NotNull
@Contract("_, _ -> param1")
public static ItemStack meta(@NotNull final ItemStack item, @NotNull final Consumer<ItemMeta> consumer)
{
final ItemMeta meta = item.getItemMeta();
consumer.accept(meta);
item.setItemMeta(meta);
return item;
}
public enum Size
{
ROWS_1,
ROWS_2,
ROWS_3,
ROWS_4,
ROWS_5,
ROWS_6,
}
/**
* C_1 C_2 C_3 C_4 C_5 C_6 C_7 C_8 C_9
* ╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
* R_1║ 0║ 1║ 2║ 3║ 4║ 5║ 6║ 7║ 8║
* ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
* R_2║ 9║ 10║ 11║ 12║ 13║ 14║ 15║ 16║ 17║
* ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
* R_3║ 18║ 19║ 20║ 21║ 22║ 23║ 24║ 25║ 26║
* ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
* R_4║ 27║ 28║ 29║ 30║ 31║ 32║ 33║ 34║ 35║
* ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
* R_5║ 36║ 37║ 38║ 39║ 40║ 41║ 42║ 43║ 44║
* ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
* R_6║ 45║ 46║ 47║ 48║ 49║ 50║ 51║ 52║ 53║
* ╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝
*/
public enum Grid
{
;
public static int from(@NotNull final Rows row, @NotNull final Cols col)
{
return (row.ordinal() * 9) + col.ordinal();
}
@NotNull
@Contract(value = "_ -> new", pure = true)
public static RaC into(final int slot)
{
final int row = slot / 9;
final int col = slot - row * 9;
return new RaC(Rows.ROWS[row], Cols.COLS[col]);
}
public static final class RaC
{
public final Rows row;
public final Cols col;
private RaC(final Rows row, final Cols col)
{
this.row = row;
this.col = col;
}
}
}
public enum Rows
{
R_1,
R_2,
R_3,
R_4,
R_5,
R_6;
public static final Rows[] ROWS = values();
}
public enum Cols
{
C_1,
C_2,
C_3,
C_4,
C_5,
C_6,
C_7,
C_8,
C_9;
public static final Cols[] COLS = values();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment