Bukkit utilities for creating GUI

This commit is contained in:
Roman Zhuravlev 2023-08-11 19:38:17 +05:00
parent b03e0a9dd6
commit 2d1d2287f7
9 changed files with 514 additions and 0 deletions

View file

@ -0,0 +1,51 @@
package org.zhdev.varioutil.bukkit;
import org.bukkit.Material;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public enum LegacyMaterial {
SKULL("PLAYER_HEAD");
private static final Map<String, Material> BY_NAME = new HashMap<>();
private final Material material;
private final String[] aliases;
LegacyMaterial(String... aliases) {
Material material = Material.getMaterial(name());
if (material == null) {
for (String name : aliases) {
material = Material.getMaterial(name);
if (material != null) break;
}
if (material == null) {
throw new IllegalStateException("Unknown material names: " + Arrays.toString(aliases));
}
}
this.material = material;
this.aliases = aliases;
}
public Material getMaterial() {
return material;
}
public static Material of(String name) {
Material material = BY_NAME.get(name);
if (material == null) {
material = Material.getMaterial(name);
}
return material;
}
static {
for (LegacyMaterial material : values()) {
for (String alias : material.aliases) {
BY_NAME.put(alias, material.material);
}
}
}
}

View file

@ -0,0 +1,8 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
@FunctionalInterface
public interface ClickHandler extends Function<InventoryClickEvent, Boolean> { }

View file

@ -0,0 +1,95 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
public class Gui {
final GuiHolder holder = new GuiHolder(this);
private final Map<Integer, GuiIcon> iconMap = new HashMap<>();
private String title;
private GuiType type = GuiType.SIZE_27;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public GuiType getType() {
return type;
}
public void setType(GuiType type) {
this.type = type;
}
public GuiIcon getIcon(int slot) {
return iconMap.get(slot);
}
public GuiIcon removeIcon(int slot) {
GuiIcon existsIcon = iconMap.remove(slot);
holder.inventory.setItem(slot, null);
return existsIcon;
}
public void updateIconIfChanged(int slot, GuiIcon icon) {
ItemStack exists = holder.inventory.getItem(slot);
if (exists != null && exists.getType() != Material.AIR && exists.equals(icon.stack)) {
return;
}
iconMap.put(slot, icon);
holder.inventory.setItem(slot, icon.stack);
}
public void updateIcon(int slot, GuiIcon icon) {
iconMap.put(slot, icon);
holder.inventory.setItem(slot, icon.stack);
}
public void createInventory() {
holder.inventory = type.createInventory(holder, title);
}
public void updateChangedIcons() {
for (int i = 0; i < holder.inventory.getSize(); i++) {
GuiIcon icon = iconMap.get(i);
ItemStack exists = holder.inventory.getItem(i);
if (icon == null) {
if (exists != null) holder.inventory.setItem(i, null);
continue;
}
if (exists != null && exists.getType() != Material.AIR && exists.equals(icon.stack)) {
continue;
}
holder.inventory.setItem(i, icon.stack);
}
}
public void update() {
for (int i = 0; i < holder.inventory.getSize(); i++) {
GuiIcon icon = iconMap.get(i);
if (icon == null) {
holder.inventory.setItem(i, null);
} else {
holder.inventory.setItem(i, icon.stack);
}
}
}
public void open(Player viewer) {
Inventory inventory = viewer.getOpenInventory().getTopInventory();
if (inventory.getHolder() != holder) {
viewer.openInventory(holder.inventory);
}
}
}

View file

@ -0,0 +1,63 @@
package org.zhdev.varioutil.bukkit.gui;
import org.zhdev.varioutil.config.ConfigSection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GuiConfig {
private final GuiType type;
private final Map<Integer, GuiIconConfig> iconMap = new HashMap<>();
private final Map<Character, Integer> charToSlotMap = new HashMap<>();
public GuiConfig(ConfigSection config) {
ConfigSection itemsSection = config.getOrCreateSection("items");
List<?> list = config.getList("shape", Collections.emptyList());
int x = 0, maxSlot = 0;
for (; x < list.size(); x++) {
String l = String.valueOf(list.get(x));
int y;
for (y = 0; y < l.length(); y++) {
char c = l.charAt(y);
if (c == ' ') continue;
ConfigSection iconSection = itemsSection.getOrCreateSection(String.valueOf(c));
GuiIconConfig iconConfig = new GuiIconConfig(iconSection);
int slot = x * 9 + y;
iconMap.put(slot, iconConfig);
charToSlotMap.put(c, slot);
}
if (y > maxSlot) maxSlot = y;
}
GuiType type;
try {
if (x == 1 && maxSlot < 6) {
type = GuiType.SIZE_5;
} else if (x == 3 && maxSlot < 4) {
type = GuiType.SIZE_3X3;
} else if (x > 0) {
type = GuiType.valueOf("SIZE_" + (x * 9));
} else {
type = GuiType.SIZE_9;
}
} catch (IllegalArgumentException e) {
type = GuiType.SIZE_9;
}
this.type = type;
}
public GuiType getType() {
return type;
}
public GuiIconConfig getIconConfig(int slot) {
return iconMap.get(slot);
}
public int getSlot(char c) {
return charToSlotMap.get(c);
}
}

View file

@ -0,0 +1,23 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.Bukkit;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
public class GuiHolder implements InventoryHolder {
private static final Inventory FALLBACK_INVENTORY = Bukkit.createInventory(null, 9, "");
final Gui gui;
Inventory inventory = FALLBACK_INVENTORY;
GuiHolder(Gui gui) {
this.gui = gui;
}
@NotNull
@Override
public Inventory getInventory() {
return inventory;
}
}

View file

@ -0,0 +1,120 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.Material;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.zhdev.varioutil.util.BukkitUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class GuiIcon {
ItemStack stack;
ClickHandler clickHandler;
public ItemStack stack() {
return stack;
}
public GuiIcon stack(ItemStack stack) {
this.stack = stack;
return this;
}
public StackBuilder stackBuilder(Material type) {
return new StackBuilder(type);
}
public StackBuilder stackBuilder(Material type, Byte data) {
return new StackBuilder(type, data);
}
public ClickHandler clickHandler() {
return clickHandler;
}
public GuiIcon clickHandler(ClickHandler clickHandler) {
this.clickHandler = clickHandler;
return this;
}
public class StackBuilder {
private final Material type;
private final Byte data;
private int amount = 1;
private String displayName;
private List<String> lore;
private ItemFlag[] flags;
private String texture;
private StackBuilder(Material type) {
this.type = type;
this.data = null;
}
private StackBuilder(Material type, Byte data) {
this.type = type;
this.data = data;
}
public StackBuilder amount(int amount) {
this.amount = amount;
return this;
}
public StackBuilder displayName(String displayName) {
this.displayName = displayName;
return this;
}
public StackBuilder lore(List<String> lore) {
this.lore = lore;
return this;
}
public StackBuilder lore(String lore) {
return lore(Collections.singletonList(lore));
}
public StackBuilder lore(String... lore) {
return lore(Arrays.asList(lore));
}
public StackBuilder flags(ItemFlag... flags) {
this.flags = flags;
return this;
}
public StackBuilder flagsAll() {
this.flags = ItemFlag.values();
return this;
}
public StackBuilder texture(String texture) {
this.texture = texture;
return this;
}
public GuiIcon build() {
ItemStack stack;
if (data == null) stack = new ItemStack(type, amount);
else stack = new ItemStack(type, amount, (short) 0, data);
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
meta.setDisplayName(displayName);
meta.setLore(lore);
meta.addItemFlags(flags);
if (texture != null && meta instanceof SkullMeta) {
BukkitUtils.setSkullTexture(((SkullMeta) meta), texture);
}
stack.setItemMeta(meta);
}
GuiIcon.this.stack = stack;
return GuiIcon.this;
}
}
}

View file

@ -0,0 +1,54 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.Material;
import org.zhdev.varioutil.bukkit.LegacyMaterial;
import org.zhdev.varioutil.config.ConfigSection;
import org.zhdev.varioutil.util.StringUtils;
public class GuiIconConfig {
protected final Material type;
protected final Byte data;
protected final int amount;
protected final String texture;
public GuiIconConfig(ConfigSection config) {
String[] rawType = config.getString("type", "AIR").toUpperCase().split(":", 2);
Material type = LegacyMaterial.of(rawType[0]);
Byte data = rawType.length > 1 ? StringUtils.parseByte(rawType[1]) : null;
if (type == null) type = Material.STONE;
int amount = config.getInteger("amount", 1);
String texture = config.getString("texture");
this.type = type;
this.data = data;
this.amount = amount;
this.texture = texture;
}
public Material getType() {
return type;
}
public Byte getData() {
return data;
}
public int getAmount() {
return amount;
}
public String getTexture() {
return texture;
}
public GuiIcon.StackBuilder stackBuilder() {
return new GuiIcon()
.stackBuilder(type, data)
.amount(amount)
.texture(texture)
.flagsAll();
}
public GuiIcon create() {
return stackBuilder().build();
}
}

View file

@ -0,0 +1,59 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.plugin.Plugin;
public class GuiListener implements Listener {
private final Plugin plugin;
public GuiListener(Plugin plugin) {
this.plugin = plugin;
}
@EventHandler
public void onClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player)) {
return;
}
if (!(event.getInventory().getHolder() instanceof GuiHolder)) {
return;
}
switch (event.getAction()) {
case CLONE_STACK: case COLLECT_TO_CURSOR: case MOVE_TO_OTHER_INVENTORY: event.setCancelled(true);
break;
}
int slot = event.getRawSlot();
if (slot > event.getInventory().getSize() - 1) {
return;
}
GuiHolder holder = (GuiHolder) event.getInventory().getHolder();
GuiIcon icon = holder.gui.getIcon(slot);
if (icon == null || icon.clickHandler == null) {
event.setCancelled(true);
return;
}
Boolean result = icon.clickHandler.apply(event);
event.setCancelled(result == null || result);
}
@EventHandler
public void onPluginDisable(PluginDisableEvent event) {
if (event.getPlugin() == plugin) {
for (Player player : Bukkit.getOnlinePlayers()) {
Inventory inventory = player.getOpenInventory().getTopInventory();
if (inventory.getHolder() instanceof GuiHolder) player.closeInventory();
}
}
}
}

View file

@ -0,0 +1,41 @@
package org.zhdev.varioutil.bukkit.gui;
import org.bukkit.Bukkit;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
public enum GuiType {
SIZE_3X3(9) {
@Override
public Inventory createInventory(InventoryHolder holder, String title) {
return Bukkit.createInventory(holder, InventoryType.WORKBENCH, title);
}
},
SIZE_5(5) {
@Override
public Inventory createInventory(InventoryHolder holder, String title) {
return Bukkit.createInventory(holder, InventoryType.HOPPER, title);
}
},
SIZE_9(9),
SIZE_18(18),
SIZE_27(27),
SIZE_36(36),
SIZE_45(45),
SIZE_54(54);
private final int size;
GuiType(int size) {
this.size = size;
}
public int getSize() {
return size;
}
public Inventory createInventory(InventoryHolder holder, String title) {
return Bukkit.createInventory(holder, size, title);
}
}