diff --git a/src/com/redstoner/modules/blockplacemods/BlockPlaceMods.java b/src/com/redstoner/modules/blockplacemods/BlockPlaceMods.java new file mode 100644 index 0000000..cfda593 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/BlockPlaceMods.java @@ -0,0 +1,169 @@ +package com.redstoner.modules.blockplacemods; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +import com.nemez.cmdmgr.Command; +import com.redstoner.annotations.Version; +import com.redstoner.misc.Main; +import com.redstoner.misc.Utils; +import com.redstoner.modules.Module; +import com.redstoner.modules.blockplacemods.mods.Mod; +import com.redstoner.modules.blockplacemods.mods.ModAbstract; +import com.redstoner.modules.blockplacemods.util.CommandException; +import com.redstoner.modules.blockplacemods.util.CommandMap; +import com.redstoner.modules.blockplacemods.util.ThrowingSupplier; + +@Version(major = 3, minor = 1, revision = 0, compatible = 3) +public final class BlockPlaceMods implements Module, Listener +{ + public static String PREFIX = ChatColor.GRAY + "[" + ChatColor.DARK_GREEN + "BPM" + ChatColor.GRAY + "]" + + ChatColor.GREEN; + + @Override + public boolean onEnable() + { + ModAbstract.constructAll(); + for (Mod mod : new ArrayList<>(ModAbstract.getMods().values())) + { + mod.register(); + } + // CommandManager.registerCommand(getCommandString(), this, Main.plugin); + // Sorry but this stuff isn't working for me. Not gonna spend more time on it. + try + { + Map commandMap = CommandMap.getCommandMap(); + String[] aliases = {"mod", Main.plugin.getName().toLowerCase() + ":mod"}; + org.bukkit.command.Command command = new org.bukkit.command.Command("mod") + { + @Override + public boolean execute(CommandSender sender, String label, String[] args) + { + onModCommand(sender, String.join(" ", args)); + return true; + } + }; + for (String alias : aliases) + { + commandMap.put(alias, command); + } + } + catch (ReflectiveOperationException ex) + { + throw new Error(ex); + } + return true; + } + + @Override + public void onDisable() + { + for (Mod mod : ModAbstract.getMods().values()) + { + mod.unregister(); + } + try + { + Map commandMap = CommandMap.getCommandMap(); + commandMap.remove("mod"); + commandMap.remove(Main.plugin.getName().toLowerCase() + ":mod"); + } + catch (Exception ignored) + {} + } + + /* @Override + * public String getCommandString() { + * return "command mod {\n" + + * "perm utils.blockplacemods.command;\n" + + * "type player;\n" + + * "[empty] {\n" + + * "run mod_empty;\n" + + * "}\n" + + * "[string:args...] {\n" + + * "run mod args;\n" + + * "}\n" + + * "}\n"; + * } */ + @Command(hook = "mod_empty") + public void onModEmptyCommand(CommandSender sender) + { + onModCommand(sender, ""); + } + + @Command(hook = "mod") + public void onModCommand(CommandSender sender, String input) + { + String[] args = new ArrayList<>(Arrays.asList(input.split(" "))).stream() + .filter(x -> x != null && !x.trim().isEmpty()).toArray(String[]::new); + String prefix = PREFIX; + ThrowingSupplier supplier; + if (args.length > 0) + { + Mod target = ModAbstract.getMod(args[0].toLowerCase()); + if (target != null) + { + prefix += "&7[&2" + target.getName() + "&7]&a"; + if (!(sender instanceof Player)) + { + supplier = () -> "&cYou must be a player to use any block place mod"; + } + else + { + supplier = () -> target.runCommand((Player) sender, Arrays.copyOfRange(args, 1, args.length)); + } + } + else if (args[0].equalsIgnoreCase("help")) + { + supplier = () -> commandHelp(sender, args); + } + else + { + supplier = () -> "&cThat argument could not be recognized"; + } + } + else + { + supplier = () -> commandHelp(sender, args); + } + handleCommand(sender, prefix, supplier); + } + + private String commandHelp(CommandSender sender, String[] args) + { + StringBuilder result = new StringBuilder("ยง7BlockPlaceMods adds some redstone-centric utilities"); + result.append("\n").append(ChatColor.GRAY.toString()).append("Available mods:"); + for (Mod mod : ModAbstract.getMods().values()) + { + result.append("\n").append(ChatColor.AQUA.toString()).append("/mod ").append(ChatColor.ITALIC.toString()) + .append(mod.getName().toLowerCase()).append(ChatColor.GRAY.toString()).append(" - ") + .append(mod.getDescription()); + } + return result.toString(); + } + + public static void handleCommand(CommandSender sender, String prefix, ThrowingSupplier supplier) + { + String message; + try + { + message = " &a" + supplier.get(); + } + catch (CommandException e) + { + message = " &c" + e.getMessage(); + } + catch (Throwable t) + { + message = " &cAn unexpected error occurred while executing this command."; + t.printStackTrace(); + } + Utils.sendMessage(sender, prefix, message, '&'); + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/Mod.java b/src/com/redstoner/modules/blockplacemods/mods/Mod.java new file mode 100644 index 0000000..c34a460 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/Mod.java @@ -0,0 +1,24 @@ +package com.redstoner.modules.blockplacemods.mods; + +import java.util.Set; + +import org.bukkit.entity.Player; + +import com.redstoner.modules.blockplacemods.util.CommandException; + +public interface Mod +{ + String getName(); + + String getDescription(); + + Set getAliases(); + + Object getDefault(); + + String runCommand(Player sender, String[] args) throws CommandException; + + void register(); + + void unregister(); +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModAbstract.java b/src/com/redstoner/modules/blockplacemods/mods/ModAbstract.java new file mode 100644 index 0000000..f2cde40 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModAbstract.java @@ -0,0 +1,83 @@ +package com.redstoner.modules.blockplacemods.mods; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; + +import com.redstoner.misc.Main; +import com.redstoner.misc.Utils; +import com.redstoner.modules.datamanager.DataManager; + +public abstract class ModAbstract implements Mod, Listener +{ + private static final Map mods = new HashMap<>(); + + public static Map getMods() + { + return Collections.unmodifiableMap(mods); + } + + public static Mod getMod(String name) + { + return mods.get(name); + } + + public static void constructAll() + { + new ModBooleanCauldron(); + new ModBooleanPiston(); + new ModBooleanStep(); + new ModBooleanTorch(); + new ModInventoryDropper(); + new ModInventoryFurnace(); + new ModInventoryHopper(); + } + + private final Set aliases; + + public ModAbstract() + { + preConstruction(); + Utils.info("Loaded mod " + getName()); + aliases = new HashSet<>(); + aliases.add(getName()); + mods.put(getName().toLowerCase(), this); + } + + protected void preConstruction() + {} + + @Override + public void register() + { + for (String alias : aliases) + { + mods.putIfAbsent(alias.toLowerCase(), this); + } + Bukkit.getPluginManager().registerEvents(this, Main.plugin); + } + + @Override + public void unregister() + { + HandlerList.unregisterAll(this); + } + + @Override + public Set getAliases() + { + return aliases; + } + + protected void reset(Player player) + { + DataManager.removeData(player.getUniqueId().toString(), "BlockPlaceMods", getName()); + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModBooleanAbstract.java b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanAbstract.java new file mode 100644 index 0000000..1faa8c5 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanAbstract.java @@ -0,0 +1,86 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.entity.Player; + +import com.redstoner.modules.blockplacemods.util.CommandException; +import com.redstoner.modules.datamanager.DataManager; + +public abstract class ModBooleanAbstract extends ModAbstract +{ + protected boolean enabledByDefault; + + protected abstract boolean enabledByDefault(); + + @Override + protected void preConstruction() + { + enabledByDefault = enabledByDefault(); + } + + protected boolean hasEnabled(Player player) + { + return (boolean) DataManager.getOrDefault(player.getUniqueId().toString(), "BlockPlaceMods", getName(), + enabledByDefault); + } + + protected boolean setEnabled(Player sender, boolean enabled) + { + if (enabled == hasEnabled(sender)) + return false; + if (enabled == (boolean) getDefault()) + reset(sender); + else + DataManager.setData(sender.getUniqueId().toString(), "BlockPlaceMods", getName(), enabled); + return true; + } + + @Override + public String runCommand(Player sender, String[] args) throws CommandException + { + if (args.length == 0 || args[0].equalsIgnoreCase("toggle")) + { + boolean enabled = hasEnabled(sender); + setEnabled(sender, !enabled); + return !enabled ? "Enabled" : "Disabled"; + } + if (args[0].equalsIgnoreCase("help")) + { + StringBuilder message = new StringBuilder(); + message.append("&a### &3").append(getName()).append("&a Help ###"); + message.append("\n&8If enabled, ").append(getDescription()); + message.append("\n&6/mod ").append(getName().toLowerCase()).append("&o toggle &btoggles state"); + message.append("\n&6/mod ").append(getName().toLowerCase()).append("&o on/off &bsets state"); + message.append("\n&6/mod ").append(getName().toLowerCase()).append("&o help &bshows this help page"); + return message.toString(); + } + final boolean enable; + if (args[0] == null) + { + throw new CommandException("Missing argument"); + } + else + { + switch (args[0].toLowerCase()) + { + case "on": + case "enable": + case "true": + enable = true; + break; + case "off": + case "disable": + case "false": + enable = false; + break; + default: + throw new CommandException("Input '" + args[0] + "' was not understood. " + + "Use one of: \non, enable, true, off, disable, false."); + } + } + if (!setEnabled(sender, enable)) + { + throw new CommandException("Was already " + (enable ? "enabled" : "disabled")); + } + return enable ? "Enabled" : "Disabled"; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModBooleanCauldron.java b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanCauldron.java new file mode 100644 index 0000000..d831b1e --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanCauldron.java @@ -0,0 +1,57 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; + +public class ModBooleanCauldron extends ModBooleanAbstract +{ + @Override + public String getName() + { + return "Cauldron"; + } + + @Override + public String getDescription() + { + return "fills cauldrons upon placement and cycles upon right click"; + } + + @Override + protected boolean enabledByDefault() + { + return false; + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) + { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && !event.getPlayer().isSneaking() + && event.getClickedBlock().getType() == Material.CAULDRON && hasEnabled(event.getPlayer())) + { + Block block = event.getClickedBlock(); + block.setData((byte) ((block.getData() - 1) & 0x3)); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) + { + if (event.getBlock().getType() == Material.CAULDRON && !event.getPlayer().isSneaking() + && hasEnabled(event.getPlayer())) + { + event.getBlock().setData((byte) 3); + } + } + + @Override + public Object getDefault() + { + return false; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModBooleanPiston.java b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanPiston.java new file mode 100644 index 0000000..e8542f7 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanPiston.java @@ -0,0 +1,75 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; + +public class ModBooleanPiston extends ModBooleanAbstract +{ + @Override + public String getName() + { + return "Piston"; + } + + @Override + public String getDescription() + { + return "makes pistons face the block you placed it against"; + } + + @Override + protected boolean enabledByDefault() + { + return false; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) + { + Player player = event.getPlayer(); + if (hasEnabled(player) && !player.isSneaking() && player.getGameMode() == GameMode.CREATIVE + && isPiston(event.getBlock().getType())) + { + Block block = event.getBlock(); + block.setData((byte) pistonDataForFace(block.getFace(event.getBlockAgainst()))); + } + } + + private boolean isPiston(Material block) + { + return block == Material.PISTON_BASE || block == Material.PISTON_STICKY_BASE; + } + + private int pistonDataForFace(BlockFace face) + { + switch (face) + { + case DOWN: + return 0; + case UP: + return 1; + case NORTH: + return 2; + case SOUTH: + return 3; + case WEST: + return 4; + case EAST: + return 5; + default: + return 0; + } + } + + @Override + public Object getDefault() + { + return false; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModBooleanStep.java b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanStep.java new file mode 100644 index 0000000..91f1126 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanStep.java @@ -0,0 +1,55 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; + +public class ModBooleanStep extends ModBooleanAbstract +{ + { + getAliases().add("Slab"); + } + + @Override + public String getName() + { + return "Step"; + } + + @Override + public String getDescription() + { + return "turns steps upside-down upon placement"; + } + + @Override + protected boolean enabledByDefault() + { + return true; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) + { + if (isStep(event.getBlock().getType()) && !event.getPlayer().isSneaking() && hasEnabled(event.getPlayer())) + { + byte data = event.getBlock().getData(); + if (data != (data |= 0x8)) + { + event.getBlock().setData(data); + } + } + } + + private boolean isStep(Material block) + { + return block == Material.STEP || block == Material.STONE_SLAB2; + } + + @Override + public Object getDefault() + { + return true; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModBooleanTorch.java b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanTorch.java new file mode 100644 index 0000000..b37cbeb --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModBooleanTorch.java @@ -0,0 +1,106 @@ +package com.redstoner.modules.blockplacemods.mods; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; + +import com.redstoner.misc.Main; + +public class ModBooleanTorch extends ModBooleanAbstract +{ + { + Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.plugin, this::updateTorches, 2, 2); + } + + private final Set torchesPlaced = new HashSet<>(); + + @Override + public String getName() + { + return "Torch"; + } + + @Override + public String getDescription() + { + return "removes redstone torches placed against a redstone block"; + } + + @Override + protected boolean enabledByDefault() + { + return true; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) + { + final Player player = event.getPlayer(); + if (!player.isSneaking() && player.getGameMode() == GameMode.CREATIVE && hasEnabled(player) + && event.getBlock().getType() == Material.REDSTONE_TORCH_ON) + { + if (isAttachedToRedstoneBlock(event.getBlock())) + { + torchesPlaced.add(event.getBlock()); + } + } + } + + private boolean isAttachedToRedstoneBlock(Block block) + { + BlockFace towardsAgainst = getFaceTowardsBlockAgainst(block.getData()); + return towardsAgainst != null && block.getRelative(towardsAgainst).getType() == Material.REDSTONE_BLOCK; + } + + private BlockFace getFaceTowardsBlockAgainst(byte data) + { + switch (data) + { + case 1: + return BlockFace.WEST; + case 2: + return BlockFace.EAST; + case 3: + return BlockFace.NORTH; + case 4: + return BlockFace.SOUTH; + case 5: + return BlockFace.DOWN; + default: + return null; + } + } + + private void updateTorches() + { + for (Iterator it = torchesPlaced.iterator(); it.hasNext();) + { + Block block = it.next(); + if (block.getType() == Material.REDSTONE_TORCH_OFF) + { + block.setType(Material.AIR); + it.remove(); + } + else if (block.getType() != Material.REDSTONE_TORCH_ON || !isAttachedToRedstoneBlock(block)) + { + it.remove(); + } + } + } + + @Override + public Object getDefault() + { + return true; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModInventoryAbstract.java b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryAbstract.java new file mode 100644 index 0000000..1ba7684 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryAbstract.java @@ -0,0 +1,174 @@ +package com.redstoner.modules.blockplacemods.mods; + +import java.util.ArrayList; + +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.redstoner.modules.blockplacemods.util.CommandException; +import com.redstoner.modules.blockplacemods.util.ItemProperties; +import com.redstoner.modules.datamanager.DataManager; + +public abstract class ModInventoryAbstract extends ModAbstract +{ + protected InventoryType inventoryType; + + @Override + protected void preConstruction() + { + inventoryType = getInventoryType(); + } + + protected abstract InventoryType getInventoryType(); + + private static int highestUsedIndex(ItemStack[] items) + { + for (int i = items.length - 1; i >= 0; i--) + { + if (items[i] != null) + { + return i; + } + } + return -1; + } + + @Override + public String getDescription() + { + return "Controls contents of " + inventoryType.name().toLowerCase() + "s upon placement"; + } + + @Override + public String runCommand(Player sender, String[] args) throws CommandException + { + if (args.length > 0) + { + if (args[0].equalsIgnoreCase("clear")) + { + reset(sender); + return "Reset data successfully"; + } + try + { + int slot = Integer.parseInt(args[0]); + if (slot >= inventoryType.getDefaultSize()) + { + throw new CommandException( + "Slot number " + slot + " is too high for " + inventoryType.toString().toLowerCase() + "s"); + } + if (slot < 0) + { + throw new CommandException("Slot number " + slot + " is negative"); + } + // Set the stored item to the item in the sender's hand + ItemStack item = sender.getItemInHand(); + if (item == null || item.getType() == Material.AIR || item.getAmount() == 0) + { + // Remove the item. + // Set item to null to ensure correct itemName below. + item = null; + if (present(sender)) + { + ItemStack[] data = get(sender); + data[slot] = null; + set(sender, data); + } + } + else + { + ItemStack[] data = get(sender); + data[slot] = item.clone(); + set(sender, data); + } + String itemName = item == null ? "nothing" + : item.getAmount() + " " + item.getType().toString().toLowerCase().replace("_", ""); + return "Set the item in slot " + slot + " to " + itemName; + } + catch (NumberFormatException ex) + { + if (!args[0].equalsIgnoreCase("help")) + { + throw new CommandException("Expected a number indicating the slot that you want to set"); + } + } + } + StringBuilder message = new StringBuilder(); + message.append("&a### &3").append(getName()).append("&a Help ###\n"); + message.append("&8").append(getDescription()).append('\n'); + message.append("&6/mod ").append(getName().toLowerCase()) + .append("&o &bsets the item in slot to your hand\n"); + message.append("&6/mod ").append(getName().toLowerCase()).append("&o clear &bclears the data\n"); + message.append("&6/mod ").append(getName().toLowerCase()).append("&o help &bshows this help page\n"); + return message.toString(); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) + { + if (present(event.getPlayer())) + { + BlockState state = event.getBlock().getState(); + if (state instanceof InventoryHolder) + { + Inventory inv = ((InventoryHolder) state).getInventory(); + if (inv.getType() == inventoryType) + { + ItemStack[] data = get(event.getPlayer()); + inv.setContents(data); + state.update(); + } + } + } + } + + @SuppressWarnings("unchecked") + protected ItemStack[] get(Player player) + { + Object obj = DataManager.getData(player.getUniqueId().toString(), "BlockPlaceMods", getName()); + if (obj == null) + return new ItemStack[inventoryType.getDefaultSize()]; + JSONArray array = (JSONArray) obj; + ArrayList items = new ArrayList(); + for (Object obj2 : array.toArray()) + { + items.add((new ItemProperties()).loadFrom((JSONObject) obj2).toItemStack()); + } + ItemStack[] itemArray = new ItemStack[array.size()]; + for (int i = 0; i < itemArray.length; i++) + { + itemArray[i] = items.get(i); + } + return itemArray; + } + + protected void set(Player player, ItemStack[] data) + { + if (highestUsedIndex(data) == -1) + reset(player); + else + { + JSONArray array = new JSONArray(); + for (ItemStack stack : data) + { + array.add((new ItemProperties(stack)).toJSONObject()); + } + DataManager.setData(player.getUniqueId().toString(), "BlockPlaceMods", getName(), array); + } + } + + protected boolean present(Player player) + { + return get(player) != null; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModInventoryDropper.java b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryDropper.java new file mode 100644 index 0000000..312dfe8 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryDropper.java @@ -0,0 +1,24 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.event.inventory.InventoryType; + +public class ModInventoryDropper extends ModInventoryAbstract +{ + @Override + public String getName() + { + return "Dropper"; + } + + @Override + protected InventoryType getInventoryType() + { + return InventoryType.DROPPER; + } + + @Override + public Object getDefault() + { + return null; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModInventoryFurnace.java b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryFurnace.java new file mode 100644 index 0000000..d0ecd46 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryFurnace.java @@ -0,0 +1,24 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.event.inventory.InventoryType; + +public class ModInventoryFurnace extends ModInventoryAbstract +{ + @Override + public String getName() + { + return "Furnace"; + } + + @Override + protected InventoryType getInventoryType() + { + return InventoryType.FURNACE; + } + + @Override + public Object getDefault() + { + return null; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/mods/ModInventoryHopper.java b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryHopper.java new file mode 100644 index 0000000..3154c98 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/mods/ModInventoryHopper.java @@ -0,0 +1,24 @@ +package com.redstoner.modules.blockplacemods.mods; + +import org.bukkit.event.inventory.InventoryType; + +public class ModInventoryHopper extends ModInventoryAbstract +{ + @Override + public String getName() + { + return "Hopper"; + } + + @Override + protected InventoryType getInventoryType() + { + return InventoryType.HOPPER; + } + + @Override + public Object getDefault() + { + return null; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/util/CommandException.java b/src/com/redstoner/modules/blockplacemods/util/CommandException.java new file mode 100644 index 0000000..e113026 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/util/CommandException.java @@ -0,0 +1,23 @@ +package com.redstoner.modules.blockplacemods.util; + +public class CommandException extends Exception { + + public CommandException(String message, Throwable cause) { + super(message, cause); + } + + public CommandException(Throwable cause) { + super(cause); + } + + public CommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public CommandException() { + } + + public CommandException(String message) { + super(message); + } +} diff --git a/src/com/redstoner/modules/blockplacemods/util/CommandMap.java b/src/com/redstoner/modules/blockplacemods/util/CommandMap.java new file mode 100644 index 0000000..d350a62 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/util/CommandMap.java @@ -0,0 +1,22 @@ +package com.redstoner.modules.blockplacemods.util; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.plugin.SimplePluginManager; + +import java.lang.reflect.Field; +import java.util.Map; + +public class CommandMap { + + public static Map getCommandMap() throws ReflectiveOperationException, ClassCastException { + Field field = SimplePluginManager.class.getDeclaredField("commandMap"); + field.setAccessible(true); + Object map = field.get(Bukkit.getPluginManager()); + field = SimpleCommandMap.class.getDeclaredField("knownCommands"); + field.setAccessible(true); + return (Map) field.get(map); + } + +} diff --git a/src/com/redstoner/modules/blockplacemods/util/ItemProperties.java b/src/com/redstoner/modules/blockplacemods/util/ItemProperties.java new file mode 100644 index 0000000..223987c --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/util/ItemProperties.java @@ -0,0 +1,270 @@ +package com.redstoner.modules.blockplacemods.util; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.BiConsumer; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +/** Save and load {@link ItemStack} in json format + * Any additional NBT data not included by {@link ItemMeta} is discarded. */ +public class ItemProperties +{ + private int id = 0; + private byte data = 0; + private int amount = 1; + private Map enchantments; + private List lore; + private String displayName; + private boolean unbreakable = false; + + public ItemProperties() + {} + + public ItemProperties(ItemStack item) + { + if (item == null) + return; + id = item.getTypeId(); + data = item.getData().getData(); + amount = item.getAmount(); + enchantments = new HashMap<>(); + ItemMeta meta = item.getItemMeta(); + if (meta == null) + return; + if (meta.hasEnchants()) + { + enchantments.putAll(meta.getEnchants()); + } + if (meta.hasLore()) + { + lore = meta.getLore(); + } + if (meta.hasDisplayName()) + { + displayName = meta.getDisplayName(); + } + unbreakable = meta.isUnbreakable(); + } + + public ItemStack toItemStack() + { + ItemStack result = new ItemStack(id, amount, data); + ItemMeta meta = result.getItemMeta(); + if (meta == null) + return result; + if (enchantments != null) + { + enchantments.forEach(new BiConsumer() + { + @Override + public void accept(Enchantment ench, Integer level) + { + meta.addEnchant(ench, level, true); + } + }); + } + if (lore != null) + { + meta.setLore(lore); + } + if (displayName != null) + { + meta.setDisplayName(displayName); + } + meta.setUnbreakable(unbreakable); + result.setItemMeta(meta); + return result; + } + + @SuppressWarnings("unchecked") + public JSONObject toJSONObject() + { + JSONObject object = new JSONObject(); + object.put("id", id + ""); + object.put("data", data + ""); + object.put("amount", amount + ""); + if (displayName != null) + { + object.put("displayName", displayName); + } + if (enchantments != null) + { + Map enchantments = this.enchantments; + JSONObject stringKeys = new JSONObject(); + for (Map.Entry entry : enchantments.entrySet()) + { + stringKeys.put(entry.getKey().getName(), entry.getValue()); + } + object.put("enchantments", stringKeys); + } + if (lore != null) + { + object.put("lore", JSONArray.toJSONString(lore)); + } + if (unbreakable) + { + object.put("unbreakable", true); + } + return object; + } + + @Override + public String toString() + { + return toJSONObject().toString(); + } + + @SuppressWarnings("unchecked") + public ItemProperties loadFrom(JSONObject object) + { + for (Object obj : object.entrySet()) + { + Entry entry = (Entry) obj; + final String key = entry.getKey(); + switch (key) + { + case "id": + id = Integer.parseInt((String) entry.getValue()); + break; + case "data": + data = Byte.parseByte((String) entry.getValue()); + break; + case "amount": + amount = Integer.parseInt((String) entry.getValue()); + break; + case "unbreakable": + unbreakable = (boolean) entry.getValue(); + break; + case "enchantments": + { + if (enchantments == null) + { + enchantments = new HashMap<>(); + } + else if (!enchantments.isEmpty()) + { + enchantments.clear(); + } + JSONObject read = (JSONObject) entry.getValue(); + if (read != null) + { + for (Object obj2 : read.entrySet()) + { + Entry entry2 = (Entry) obj2; + Enchantment ench = Enchantment.getByName(entry2.getKey()); + if (ench != null) + { + enchantments.put(ench, entry2.getValue()); + } + } + } + break; + } + case "lore": + JSONParser parser = new JSONParser(); + Object rawObject; + try + { + rawObject = parser.parse((String) entry.getValue()); + } + catch (ParseException e) + { + rawObject = new JSONArray(); + } + JSONArray jsonArray = (JSONArray) rawObject; + lore = jsonArray; + break; + case "displayName": + displayName = (String) entry.getValue(); + default: + } + } + return this; + } + + public int getId() + { + return id; + } + + public byte getData() + { + return data; + } + + public int getAmount() + { + return amount; + } + + public Map getEnchantments() + { + return enchantments; + } + + public List getLore() + { + return lore; + } + + public String getDisplayName() + { + return displayName; + } + + public boolean isUnbreakable() + { + return unbreakable; + } + + public ItemProperties setId(int id) + { + this.id = id; + return this; + } + + public ItemProperties setData(byte data) + { + this.data = data; + return this; + } + + public ItemProperties setAmount(int amount) + { + this.amount = amount; + return this; + } + + public ItemProperties setEnchantments(Map enchantments) + { + this.enchantments = enchantments; + return this; + } + + public ItemProperties setLore(List lore) + { + this.lore = lore; + return this; + } + + public ItemProperties setDisplayName(String displayName) + { + this.displayName = displayName; + return this; + } + + public ItemProperties setUnbreakable(boolean unbreakable) + { + this.unbreakable = unbreakable; + return this; + } +} diff --git a/src/com/redstoner/modules/blockplacemods/util/ThrowingSupplier.java b/src/com/redstoner/modules/blockplacemods/util/ThrowingSupplier.java new file mode 100644 index 0000000..9dc3cf3 --- /dev/null +++ b/src/com/redstoner/modules/blockplacemods/util/ThrowingSupplier.java @@ -0,0 +1,12 @@ +package com.redstoner.modules.blockplacemods.util; + +/** + * A supplier with a throws declaration. + * Once again, I have more solid alternatives, but if you want it in your utils... be my guest :D + * + * @param The type of object computed by this supplier. + */ +@FunctionalInterface +public interface ThrowingSupplier { + T get() throws Throwable; +}