Skip to content

Instantly share code, notes, and snippets.

@Oskang09
Last active February 23, 2021 08:03
Show Gist options
  • Save Oskang09/b0e34fb081a9de7906c24b432b7bc08a to your computer and use it in GitHub Desktop.
Save Oskang09/b0e34fb081a9de7906c24b432b7bc08a to your computer and use it in GitHub Desktop.
Minecraft Inventory UI API inspired by React
package me.ms.plugin.inventory;
public class ExampleInventory extends InventoryUI<ExampleInventory.Props, ExampleInventory.State> {
protected ExampleInventory(Props props) {
super("ExampleInventory", 54, props, null);
}
public class Props {
}
public class State {
}
@Override
protected InventoryOptions options() {
return InventoryOptions.DEFAULT;
}
@Override
protected State initialState() {
return new State();
}
@Override
protected void disposeState() {
}
@Override
protected void render() {
}
}
package me.ms.plugin.inventory;
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.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
public class InventoryListener implements Listener {
private static Map<String, LinkedList<InventoryUI>> inventories;
private static boolean registered;
protected static void register(JavaPlugin plugin) {
registered = true;
inventories = new HashMap<>();
plugin.getServer().getPluginManager().registerEvents(new InventoryListener(), plugin);
}
protected static boolean isRegistered() {
return registered;
}
protected static void replace(Player player, InventoryUI inventoryUI) {
String uuid = player.getUniqueId().toString();
LinkedList<InventoryUI> lists = new LinkedList<>();
InventoryUI instance = inventoryUI;
if (!instance.options().isGlobalSharedInventory) {
instance = inventoryUI.clone();
}
lists.addFirst(instance);
player.closeInventory();
inventories.replace(uuid, lists);
player.openInventory(instance.getInventory());
instance.render();
}
protected static void push(Player player, InventoryUI inventoryUI) {
String uuid = player.getUniqueId().toString();
inventories.compute(uuid, (__, lists) -> {
if (lists == null) {
lists = new LinkedList<>();
}
InventoryUI instance = inventoryUI;
if (!instance.options().isGlobalSharedInventory) {
instance = inventoryUI.clone();
}
lists.addFirst(instance);
player.closeInventory();
player.openInventory(instance.getInventory());
instance.render();
return lists;
});
}
protected static void pop(Player player) {
String uuid = player.getUniqueId().toString();
inventories.compute(uuid, (__, lists) -> {
InventoryUI last = lists.removeFirst();
player.closeInventory();
last.disposeState();
if (lists.size() == 0) {
return null;
}
InventoryUI instance = lists.getFirst();
if (instance.options().refreshStateWhenGoBack) {
instance.state = instance.initialState();
}
player.openInventory(instance.getInventory());
if (instance.options().renderWhenGoBack) {
instance.render();
}
return lists;
});
}
private InventoryListener() {}
@EventHandler(priority = EventPriority.MONITOR)
public void onClick(InventoryClickEvent event) {
String uuid = event.getWhoClicked().getUniqueId().toString();
LinkedList<InventoryUI> inventoryList = inventories.getOrDefault(uuid, null);
if (inventoryList == null || inventoryList.size() == 0) {
return;
}
InventoryUI inventory = inventoryList.getFirst();
if (event.getClickedInventory() == inventory.getInventory()) {
event.setCancelled(!inventory.options().clickableByDefault);
inventory.click(event);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onClose(InventoryCloseEvent event) {
Player player = (Player) event.getPlayer();
String uuid = event.getPlayer().getUniqueId().toString();
LinkedList<InventoryUI> inventoryList = inventories.getOrDefault(uuid, null);
if (inventoryList == null || inventoryList.size() == 0) {
return;
}
InventoryUI inventory = inventoryList.getFirst();
if (inventory.options().closableByEvent) {
pop(player);
return;
}
player.openInventory(inventory.getInventory());
}
}
package me.ms.plugin.inventory;
public class InventoryOptions {
public static InventoryOptions DEFAULT = new InventoryOptions();
public boolean clickableByDefault;
public boolean closableByEvent;
public boolean refreshStateWhenGoBack;
public boolean renderWhenGoBack;
public boolean isGlobalSharedInventory;
public InventoryOptions() {
clickableByDefault = false;
closableByEvent = true;
refreshStateWhenGoBack = false;
renderWhenGoBack = false;
isGlobalSharedInventory = false;
}
}
package me.ms.plugin.inventory;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class InventoryUI<P, S> implements Cloneable {
public static void register(JavaPlugin plugin) {
InventoryListener.register(plugin);
}
@Getter
protected Inventory inventory;
private final Map<Integer, Consumer<InventoryClickEvent>> actions;
@Getter
protected S state;
@Getter
protected P props;
protected abstract InventoryOptions options();
protected abstract S initialState();
protected abstract void render();
protected abstract void disposeState();
protected void setState(Function<S,S> update) {
setState(update.apply(this.state));
}
protected void setState(S state) {
this.state = state;
this.render();
}
protected void set(int index, ItemStack item) {
this.set(index, item, null);
}
protected void set(int index, ItemStack item, Consumer<InventoryClickEvent> action) {
this.inventory.setItem(index, item);
if (action != null) {
this.actions.put(index, action);
}
}
protected void set(int[] index, ItemStack item) {
this.set(index, item, null);
}
protected void set(int[] index, ItemStack item, Consumer<InventoryClickEvent> action) {
for ( int i = 0; i < index.length; i++) {
this.inventory.setItem(i, item);
if (action != null) {
this.actions.put(i, action);
}
}
}
protected void push(Player player, InventoryUI inventoryUI) {
InventoryListener.push(player, inventoryUI);
}
protected void pop(Player player) {
InventoryListener.pop(player);
}
void click(InventoryClickEvent event) {
Consumer<InventoryClickEvent> action = this.actions.getOrDefault(event.getSlot(), null);
if (action != null) {
action.accept(event);
}
}
protected InventoryUI(P props, S state) {
if (!InventoryListener.isRegistered()) {
throw new IllegalStateException("Disabling InventoryUI because InventoryListener hasn't registered.");
}
this.actions = new HashMap<>();
this.props = props;
this.state = state;
if (state == null) {
this.state = initialState();
}
}
public InventoryUI(InventoryType type, String title, P props, S state) {
this(props, state);
this.inventory = Bukkit.createInventory(null, type, title);
}
public InventoryUI(InventoryType type, P props, S state) {
this(props, state);
this.inventory = Bukkit.createInventory(null, type);
}
public InventoryUI(String title, int size, P props, S state) {
this(props, state);
this.inventory = Bukkit.createInventory(null, size, title);
}
@Override
protected InventoryUI clone() {
try {
return (InventoryUI) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment