From f89ecdd13cf3652c4168d1d3ce6915d4efee1722 Mon Sep 17 00:00:00 2001 From: jameslfc19 Date: Mon, 16 Sep 2019 19:22:50 +0100 Subject: [PATCH] Init Commit! --- .gitignore | 4 + .idea/.gitignore | 2 + .idea/compiler.xml | 13 ++ .idea/misc.xml | 14 ++ .idea/uiDesigner.xml | 124 ++++++++++ .idea/vcs.xml | 6 + ChestsPlusPlus.iml | 2 + pom.xml | 94 ++++++++ .../minecraft/chests/ChestsPlusPlus.java | 39 ++++ .../jamesdpeters/minecraft/chests/Config.java | 139 ++++++++++++ .../minecraft/chests/Messages.java | 27 +++ .../jamesdpeters/minecraft/chests/Utils.java | 213 ++++++++++++++++++ .../jamesdpeters/minecraft/chests/Values.java | 12 + .../chests/commands/CommandListener.java | 7 + .../chests/commands/RemoteChestCommand.java | 126 +++++++++++ .../chests/commands/ServerCommand.java | 19 ++ .../chests/containers/ChestLinkInfo.java | 43 ++++ .../interfaces/VirtualInventoryHolder.java | 23 ++ .../chests/listeners/ChestLinkListener.java | 105 +++++++++ .../chests/listeners/HopperListener.java | 85 +++++++ .../chests/listeners/InventoryListener.java | 61 +++++ .../chests/listeners/TempListener.java | 23 ++ .../chests/protocollib/AbstractPacket.java | 115 ++++++++++ .../WrapperPlayServerBlockAction.java | 120 ++++++++++ .../chests/runnables/ChestLinkVerifier.java | 66 ++++++ .../runnables/VirtualChestToHopper.java | 43 ++++ .../chests/serialize/InventoryStorage.java | 113 ++++++++++ .../chests/serialize/LinkedChest.java | 33 +++ src/main/resources/plugin.yml | 11 + 29 files changed, 1682 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 ChestsPlusPlus.iml create mode 100644 pom.xml create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/Config.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/Messages.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/Utils.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/Values.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/commands/CommandListener.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/commands/RemoteChestCommand.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/commands/ServerCommand.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/containers/ChestLinkInfo.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualInventoryHolder.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/listeners/ChestLinkListener.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/listeners/TempListener.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/protocollib/AbstractPacket.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/protocollib/WrapperPlayServerBlockAction.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/runnables/ChestLinkVerifier.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/serialize/InventoryStorage.java create mode 100644 src/main/java/com/jamesdpeters/minecraft/chests/serialize/LinkedChest.java create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8225f90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +Server/ +target/ +*.log \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..0fa236a --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4b661a5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ChestsPlusPlus.iml b/ChestsPlusPlus.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/ChestsPlusPlus.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..43e28e8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + com.jamesdpeters.chests + ChestsPlusPlus + 1.0-SNAPSHOT + + + 8 + 8 + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + ossrh + https://oss.sonatype.org/content/groups/public/ + + + + dmulloy2-repo + http://repo.dmulloy2.net/nexus/repository/public/ + + + + + + org.spigotmc + spigot-api + 1.14.4-R0.1-SNAPSHOT + provided + + + + + org.apache.commons + commons-lang3 + 3.4 + + + + com.comphenix.protocol + ProtocolLib + 4.4.0 + + + + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + + + package + + + shade + + + + + ${project.basedir}/Server/plugins/${project.artifactId}.jar + true + + + + + + + + + + src/main/resources + true + + + + + \ No newline at end of file diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java b/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java new file mode 100644 index 0000000..f991245 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java @@ -0,0 +1,39 @@ +package com.jamesdpeters.minecraft.chests; + +import com.jamesdpeters.minecraft.chests.commands.RemoteChestCommand; +import com.jamesdpeters.minecraft.chests.listeners.ChestLinkListener; +import com.jamesdpeters.minecraft.chests.listeners.HopperListener; +import com.jamesdpeters.minecraft.chests.listeners.InventoryListener; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import com.jamesdpeters.minecraft.chests.serialize.LinkedChest; +import org.bukkit.configuration.serialization.ConfigurationSerialization; +import org.bukkit.plugin.java.JavaPlugin; + +public class ChestsPlusPlus extends JavaPlugin { + + public static JavaPlugin PLUGIN; + + static { + ConfigurationSerialization.registerClass(LinkedChest.class, "LinkedChest"); + ConfigurationSerialization.registerClass(InventoryStorage.class, "InventoryStorage"); + } + + @Override + public void onEnable() { + PLUGIN = this; + new RemoteChestCommand().register(this); + getServer().getPluginManager().registerEvents(new ChestLinkListener(),this); + getServer().getPluginManager().registerEvents(new InventoryListener(),this); + getServer().getPluginManager().registerEvents(new HopperListener(),this); + + new Config(); + getLogger().info("Chests++ enabled!"); + } + + @Override + public void onDisable() { + super.onDisable(); + Config.save(); + } + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/Config.java b/src/main/java/com/jamesdpeters/minecraft/chests/Config.java new file mode 100644 index 0000000..fe03991 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/Config.java @@ -0,0 +1,139 @@ +package com.jamesdpeters.minecraft.chests; + +import com.jamesdpeters.minecraft.chests.containers.ChestLinkInfo; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import com.jamesdpeters.minecraft.chests.serialize.LinkedChest; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.block.*; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class Config { + + static LinkedChest store; + + public Config(){ + try { + FileConfiguration configuration = YamlConfiguration.loadConfiguration(new File("chests.yml")); + store = (LinkedChest) configuration.get("chests++", new HashMap>>()); + } catch (Exception e){ + store = new LinkedChest(); + save(); + } + } + + public static void save(){ + FileConfiguration config = new YamlConfiguration(); + + config.set("chests++", store); + try { + config.save("chests.yml"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static HashMap getPlayer(Player player){ + String id = player.getUniqueId().toString(); + if(store.chests.containsKey(id)){ + return store.chests.get(id); + } else { + HashMap hashMap = new HashMap<>(); + store.chests.put(id, hashMap); + return hashMap; + } + } + + public static InventoryStorage getInventoryStorage(Player player, String identifier){ + HashMap map = getPlayer(player); + return map.getOrDefault(identifier, null); + } + + public static InventoryStorage getInventoryStorage(Location location){ + if(location != null) { + Block block = location.getBlock(); + if (block.getState() instanceof Chest) { + Chest chest = (Chest) block.getState(); + ChestLinkInfo info = Utils.getChestLinkInfo(chest.getLocation()); + if(info != null){ + return info.getStorage(); + } + } + } + return null; + } + + public static void addChest(Player player, String identifier, Location chestLocation){ + //List of groups this player has. + HashMap map = getPlayer(player); + + //Get Inventory Storage for the given group or create it if it doesnt exist. + if(!map.containsKey(identifier)){ + InventoryStorage storage = new InventoryStorage(player,identifier,chestLocation); + map.put(identifier, storage); + } + InventoryStorage inventoryStorage = map.get(identifier); + + //Migrates that chest into InventoryStorage and if full drops it at the chest location. + Chest chest = (Chest) chestLocation.getBlock().getState(); + boolean hasOverflow = false; + for(ItemStack chestItem : chest.getInventory().getContents()) { + if(chestItem != null) { + HashMap overflow = inventoryStorage.getInventory().addItem(chestItem); + for (ItemStack item : overflow.values()) + if (item != null){ + player.getWorld().dropItemNaturally(chestLocation, item); + hasOverflow = true; + } + } + } + if(hasOverflow) Messages.CHEST_HAD_OVERFLOW(player); + chest.getInventory().clear(); + + //If the location isn't already part of the system add it. + if(!inventoryStorage.getLocations().contains(chestLocation)){ + inventoryStorage.getLocations().add(chestLocation); + } + save(); + } + + public static InventoryStorage removeChest(InventoryStorage storage, Location location){ + if(storage != null) { + storage.getLocations().remove(location); + if (storage.getLocations().size() == 0) { + storage.dropInventory(location); + getPlayer(storage.getOwner()).remove(storage.getIdentifier()); + } + save(); + return storage; + } + return null; + } + + public static InventoryStorage removeChest(Player player, String identifier, Location chestLocation){ + return removeChest(getPlayer(player).get(identifier),chestLocation); + } + + public static InventoryStorage removeChest(Location chestLocation){ + InventoryStorage storage = getInventoryStorage(chestLocation); + return removeChest(storage,chestLocation); + } + + public static boolean setChests(Player player, String group, InventoryStorage storage){ + HashMap groups = getPlayer(player); + groups.put(group,storage); + save(); + return true; + } + + + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/Messages.java b/src/main/java/com/jamesdpeters/minecraft/chests/Messages.java new file mode 100644 index 0000000..cde2d2a --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/Messages.java @@ -0,0 +1,27 @@ +package com.jamesdpeters.minecraft.chests; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +public class Messages { + + public static void CHEST_REMOVED(Player target, String group, String player){ + target.sendMessage(ChatColor.RED+"Succesfully removed a chest from group: "+group+" for "+player); + } + + public static void CHEST_ADDED(Player target, String group, String player){ + target.sendMessage(ChatColor.GREEN+"Succesfully added a chest to group: "+group+" for "+player); + } + + public static void CHEST_HAD_OVERFLOW(Player target){ + target.sendMessage(ChatColor.GOLD+"Chest item's wouldn't all fit into ChestLink!"); + } + + public static void MUST_LOOK_AT_CHEST(Player target){ + target.sendMessage(ChatColor.RED+"You must be looking at the chest you want to ChestLink!"); + } + + public static void MUST_HOLD_SIGN(Player target){ + target.sendMessage(ChatColor.RED+"You must be hold a sign to do that!"); + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/Utils.java b/src/main/java/com/jamesdpeters/minecraft/chests/Utils.java new file mode 100644 index 0000000..8c17c75 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/Utils.java @@ -0,0 +1,213 @@ +package com.jamesdpeters.minecraft.chests; + +import com.jamesdpeters.minecraft.chests.containers.ChestLinkInfo; +import com.jamesdpeters.minecraft.chests.runnables.ChestLinkVerifier; +import org.apache.commons.lang.StringUtils; +import org.bukkit.*; +import org.bukkit.block.*; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +import java.util.*; + +public class Utils { + +// public static String[] getChestLinkInfo(String[] lines){ +// if(lines.length < 2){ +// return null; +// } +// if(lines[0].contains(Values.signTag)) { +// String id = StringUtils.substringBetween(lines[1], "[", "]"); +// String username = ChatColor.stripColor(lines[2]); +// return new String[]{id,username}; +// } +// return null; +// } + + public static ChestLinkInfo getChestLinkInfo(Location location){ + return getChestLinkInfo(location,null); + } + public static ChestLinkInfo getChestLinkInfo(Sign sign, Player player){ return getChestLinkInfo(sign,sign.getLines(),player);} + + public static ChestLinkInfo getChestLinkInfo(Sign sign, String[] lines, Player player){ + if(lines.length >= 2 && lines[0].contains(Values.signTag)) { + String playerUUID = sign.getPersistentDataContainer().get(Values.playerUUID, PersistentDataType.STRING); + String group = ChatColor.stripColor(StringUtils.substringBetween(lines[1], "[", "]")); + if(playerUUID != null){ + return new ChestLinkInfo(playerUUID, group); + } + else if(player != null) return new ChestLinkInfo(player, group); + } + return null; + } + + /** + * Returns ChestLinkInfo for a sign. + * @param location - Location of ChestLink to find. + * @param player - Player that ChestLink belongs to if it doesn't already exist. + * @return @{@link ChestLinkInfo} + */ + public static ChestLinkInfo getChestLinkInfo(Location location, Player player){ + Block block = location.getBlock(); + if(block.getBlockData() instanceof Directional) { + Directional chest = (Directional) block.getBlockData(); + BlockFace facing = chest.getFacing(); + Block sign = block.getRelative(facing); + + if (sign.getState() instanceof Sign) { + Sign s = (Sign) sign.getState(); + return getChestLinkInfo(s,player); + } + } + return null; + } + + public static String locationPrettyPrint(Location location){ + return "["+location.getX()+","+location.getY()+","+location.getZ()+"] in "+location.getWorld().getName(); + } + + public static void openInventory(Player player, Inventory inventory){ + if(inventory.getLocation() != null) player.getWorld().playSound(inventory.getLocation(), Sound.BLOCK_CHEST_OPEN,0.5f,1f); + else player.getWorld().playSound(player.getLocation(), Sound.BLOCK_CHEST_OPEN,0.5f,1f); + player.openInventory(inventory); + } + + public static void closeInventorySound(Player player, Inventory inventory){ + if(inventory.getLocation() != null) player.getWorld().playSound(inventory.getLocation(), Sound.BLOCK_CHEST_CLOSE,0.5f,1f); + else player.getWorld().playSound(player.getLocation(), Sound.BLOCK_CHEST_CLOSE,0.5f,1f); + //player.closeInventory(); + } + + public static ItemStack removeStackFromInventory(Inventory inventory, int amount, List filters){ + ItemStack toRemove; + for(int i=0; i filters){ + ItemStack removed = removeStackFromInventory(from,amount,filters); + if(removed != null) { + HashMap leftOvers = to.addItem(removed); + for (ItemStack leftOver : leftOvers.values()) { + from.addItem(leftOver); + } + return true; + } + return false; + } + + public static boolean moveToOtherInventory(Inventory from, int amount, Inventory to) { + return moveToOtherInventory(from,amount,to,null); + } + + public static void createChestLink(Player player, Block block, String identifier){ + if(block.getState() instanceof Chest){ + new ChestLinkVerifier(block).withDelay(0).check(); + if(block.getBlockData() instanceof Directional) { + Directional chest = (Directional) block.getBlockData(); + BlockFace facing = chest.getFacing(); + Block toReplace = block.getRelative(facing); + + if(toReplace.getType() == Material.AIR){ + BlockState replacedBlockState = toReplace.getState(); + + if(player.getGameMode() == GameMode.SURVIVAL) { + if (player.getEquipment() != null) { + if (!Tag.SIGNS.isTagged(player.getEquipment().getItemInMainHand().getType())) { + Messages.MUST_HOLD_SIGN(player); + return; + } + player.getEquipment().getItemInMainHand().setAmount(player.getEquipment().getItemInMainHand().getAmount() - 1); + } else { + Messages.MUST_HOLD_SIGN(player); + return; + } + } + + toReplace.setType(Material.OAK_WALL_SIGN); + Sign sign = (Sign) toReplace.getState(); + WallSign signBlockData = (WallSign) sign.getBlockData(); + signBlockData.setFacing(facing); + sign.setBlockData(signBlockData); + sign.update(); + + String[] lines = new String[4]; + lines[0] = Values.signTag; + lines[1] = Values.identifier(identifier); + + BlockPlaceEvent event = new BlockPlaceEvent(sign.getBlock(),replacedBlockState,block,new ItemStack(Material.AIR),player,true, EquipmentSlot.HAND); + ChestsPlusPlus.PLUGIN.getServer().getPluginManager().callEvent(event); + if(event.isCancelled()){ + sign.setType(Material.AIR); + return; + } + + SignChangeEvent signChangeEvent = new SignChangeEvent(sign.getBlock(),player,lines); + ChestsPlusPlus.PLUGIN.getServer().getPluginManager().callEvent(signChangeEvent); + } + } + } + } + + public static List hasFilter(Block block){ + List filters = new ArrayList<>(); + addIfNotNull(filters,getFilter(block,1,0)); + addIfNotNull(filters,getFilter(block,-1,0)); + addIfNotNull(filters,getFilter(block,0,1)); + addIfNotNull(filters,getFilter(block,0,-1)); + return filters; + } + + private static ItemStack getFilter(Block block, int xOffset, int zOffset){ + Block frame = block.getRelative(xOffset, 0,zOffset); + if(frame.getState() instanceof ItemFrame){ + return ((ItemFrame) frame.getState()).getItem(); + } + return null; + } + + private static void addIfNotNull(List list, T element){ + if(element != null) list.add(element); + } + + public static boolean isInFilter(List filters, ItemStack item){ + if(filters == null) return true; + if(filters.size() == 0) return true; + for(ItemStack filter : filters){ + if(filter.isSimilar(item)) return true; + } + return false; + } + + public static List getHopperFilters(Block block){ + Collection ent = block.getLocation().getWorld().getNearbyEntities(block.getLocation(),1.01,1.01,1.01); + List filters = new ArrayList<>(); + for(Entity frame : ent){ + if(frame instanceof ItemFrame){ + Block attachedBlock = frame.getLocation().getBlock().getRelative(((ItemFrame) frame).getAttachedFace()); + if(block.equals(attachedBlock)){ + filters.add(((ItemFrame) frame).getItem()); + } + } + } + return filters; + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/Values.java b/src/main/java/com/jamesdpeters/minecraft/chests/Values.java new file mode 100644 index 0000000..c9e460f --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/Values.java @@ -0,0 +1,12 @@ +package com.jamesdpeters.minecraft.chests; + +import org.bukkit.NamespacedKey; + +public class Values { + public final static String signTag = "[ChestLink]"; + public static String identifier(String identifier){ + return "["+identifier+"]"; + } + + public final static NamespacedKey playerUUID = new NamespacedKey(ChestsPlusPlus.PLUGIN,"playerUUID"); +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/commands/CommandListener.java b/src/main/java/com/jamesdpeters/minecraft/chests/commands/CommandListener.java new file mode 100644 index 0000000..92e81d0 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/commands/CommandListener.java @@ -0,0 +1,7 @@ +package com.jamesdpeters.minecraft.chests.commands; + +public class CommandListener { + + + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/commands/RemoteChestCommand.java b/src/main/java/com/jamesdpeters/minecraft/chests/commands/RemoteChestCommand.java new file mode 100644 index 0000000..aa6efae --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/commands/RemoteChestCommand.java @@ -0,0 +1,126 @@ +package com.jamesdpeters.minecraft.chests.commands; + +import com.jamesdpeters.minecraft.chests.ChestsPlusPlus; +import com.jamesdpeters.minecraft.chests.Config; +import com.jamesdpeters.minecraft.chests.Messages; +import com.jamesdpeters.minecraft.chests.Utils; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChatTabCompleteEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class RemoteChestCommand extends ServerCommand { + + private enum OPTIONS { + ADD("/chestlink add ", "Create/add a chest to a ChestLink group"), + OPEN("/chestlink open ","Open the inventory of a ChestLink group"); + + String description, commandHelp; + static List valuesList; + + static { + valuesList = Stream.of(OPTIONS.values()).map(OPTIONS::toString).collect(Collectors.toList()); + } + + OPTIONS( String commandHelp, String description){ + this.commandHelp = commandHelp; + this.description = description; + } + + @Override + public String toString() { + return super.toString().toLowerCase(); + } + + String getCommandHelp(){ + return commandHelp; + } + + String getDescription(){ + return description; + } + } + + @Override + public String getCommandName() { + return "chestlink"; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if(!(sender instanceof Player)){ + sender.sendMessage("Only a player can use this command"); + return false; + } + Player player = (Player) sender; + if(args != null) { + + switch (OPTIONS.valueOf(args[0].toUpperCase())){ + case ADD: + if(args.length > 1){ + Block targetBlock = player.getTargetBlockExact(5); + if(targetBlock != null) Utils.createChestLink(player,targetBlock,args[1]); + else Messages.MUST_LOOK_AT_CHEST(player); + return true; + } else { + player.sendMessage(ChatColor.RED+OPTIONS.ADD.commandHelp); + player.sendMessage(ChatColor.RED+OPTIONS.ADD.description); + return true; + } + case OPEN: + if(args.length > 1){ + InventoryStorage invs = Config.getInventoryStorage(player,args[1]); + Utils.openInventory(player,invs.getInventory()); + return true; + } else { + player.sendMessage(ChatColor.RED+OPTIONS.OPEN.commandHelp); + player.sendMessage(ChatColor.RED+OPTIONS.OPEN.description); + return true; + } + } + } + + return false; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if((sender instanceof Player)) { + Player player = (Player) sender; + + if (args.length == 1) { + return OPTIONS.valuesList; + } + try { + switch (OPTIONS.valueOf(args[0].toUpperCase())) { + case ADD: + return null; + case OPEN: + return new ArrayList<>(Config.getPlayer(player).keySet()); + } + } catch (IllegalArgumentException e){ + + } + } + return null; + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/commands/ServerCommand.java b/src/main/java/com/jamesdpeters/minecraft/chests/commands/ServerCommand.java new file mode 100644 index 0000000..21289e8 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/commands/ServerCommand.java @@ -0,0 +1,19 @@ +package com.jamesdpeters.minecraft.chests.commands; + +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.TabCompleter; +import org.bukkit.plugin.java.JavaPlugin; + +public abstract class ServerCommand implements CommandExecutor, TabCompleter { + + /** + * @param plugin Registers command to given plugin. + */ + public void register(JavaPlugin plugin){ + plugin.getCommand(getCommandName()).setExecutor(this); + plugin.getCommand(getCommandName()).setTabCompleter(this); + } + + public abstract String getCommandName(); + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/containers/ChestLinkInfo.java b/src/main/java/com/jamesdpeters/minecraft/chests/containers/ChestLinkInfo.java new file mode 100644 index 0000000..355d1c7 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/containers/ChestLinkInfo.java @@ -0,0 +1,43 @@ +package com.jamesdpeters.minecraft.chests.containers; + +import com.jamesdpeters.minecraft.chests.Config; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; + +public class ChestLinkInfo { + + private String group; + private UUID playerUUID; + private Player player; + private InventoryStorage storage; + + public ChestLinkInfo(String playerUUID, String group){ + this(Bukkit.getOfflinePlayer(UUID.fromString(playerUUID)).getPlayer(),group); + } + + public ChestLinkInfo(Player player, String group){ + this.group = group; + this.storage = Config.getInventoryStorage(player,group); + this.player = player; + this.playerUUID = player.getUniqueId(); + } + + public String getGroup() { + return group; + } + + public UUID getPlayerUUID() { + return playerUUID; + } + + public Player getPlayer() { + return player; + } + + public InventoryStorage getStorage() { + return storage; + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualInventoryHolder.java b/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualInventoryHolder.java new file mode 100644 index 0000000..1a58a09 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualInventoryHolder.java @@ -0,0 +1,23 @@ +package com.jamesdpeters.minecraft.chests.interfaces; + +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; + +public class VirtualInventoryHolder implements InventoryHolder { + + InventoryStorage storage; + + public VirtualInventoryHolder(InventoryStorage storage){ + this.storage = storage; + } + + @Override + public Inventory getInventory() { + return storage.getInventory(); + } + + public InventoryStorage getStorage(){ + return storage; + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/listeners/ChestLinkListener.java b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/ChestLinkListener.java new file mode 100644 index 0000000..f55fddd --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/ChestLinkListener.java @@ -0,0 +1,105 @@ +package com.jamesdpeters.minecraft.chests.listeners; + +import com.jamesdpeters.minecraft.chests.*; +import com.jamesdpeters.minecraft.chests.containers.ChestLinkInfo; +import com.jamesdpeters.minecraft.chests.runnables.ChestLinkVerifier; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Chest; +import org.bukkit.block.Sign; +import org.bukkit.block.data.Directional; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.persistence.PersistentDataType; + +import java.util.Arrays; + +public class ChestLinkListener implements Listener { + + @EventHandler + public void playerInteract(BlockPlaceEvent event){ + if(event.getBlockPlaced().getState() instanceof Sign){ + if(event.getBlockAgainst().getState() instanceof Chest) { + new TempListener(){ + @EventHandler + public void onSignChange(SignChangeEvent signChangeEvent){ + if(event.getBlockPlaced().getLocation().equals(signChangeEvent.getBlock().getLocation())) { + Sign sign = (Sign) signChangeEvent.getBlock().getState(); + ChestLinkInfo info = Utils.getChestLinkInfo(sign, signChangeEvent.getLines(), signChangeEvent.getPlayer()); + if (info != null) { + Config.addChest(info.getPlayer(), info.getGroup(), event.getBlockAgainst().getLocation()); + Messages.CHEST_ADDED(event.getPlayer(), info.getGroup(), event.getPlayer().getDisplayName()); + setLine(sign,signChangeEvent,0, ChatColor.RED + signChangeEvent.getLine(0)); + setLine(sign,signChangeEvent,1, ChatColor.GREEN + signChangeEvent.getLine(1)); + setLine(sign,signChangeEvent,2, ChatColor.BOLD + event.getPlayer().getDisplayName()); + sign.getPersistentDataContainer().set(Values.playerUUID, PersistentDataType.STRING, event.getPlayer().getUniqueId().toString()); + sign.update(); + } + done(); + } + } + }; + + } + } + } + + @EventHandler + public void onSignBreak(BlockBreakEvent event){ + if(event.getBlock().getState() instanceof Sign) { + Sign sign = (Sign) event.getBlock().getState(); + //Get blockface of sign. + if(sign.getBlockData() instanceof Directional) { + + BlockFace chestFace = ((Directional) sign.getBlockData()).getFacing().getOppositeFace(); + Block chest = sign.getBlock().getRelative(chestFace); + + //If block sign is placed on is a chest we can remove it. + if(chest.getState() instanceof Chest) { + + ChestLinkInfo info = Utils.getChestLinkInfo(sign,null); + + if (info != null) { ; + Config.removeChest(info.getPlayer(), info.getGroup(), chest.getLocation()); + ((Chest) chest.getState()).getInventory().clear(); + Messages.CHEST_REMOVED(event.getPlayer(),info.getGroup(),info.getPlayer().getDisplayName()); + } + } + } + } + } + + @EventHandler + public void onChestPlace(BlockPlaceEvent event){ + if(event.getBlockPlaced().getState() instanceof Chest){ + new ChestLinkVerifier(event.getBlock()).check(); + } + } + + + @EventHandler(priority = EventPriority.HIGHEST) + public void onChestBreak(BlockBreakEvent event){ + if(event.getBlock().getState() instanceof Chest){ + InventoryStorage storage = Config.removeChest(event.getBlock().getLocation()); + if(storage != null){ + Messages.CHEST_REMOVED(event.getPlayer(),storage.getIdentifier(),storage.getOwner().getDisplayName()); + } + } + } + + private void setLine(Sign sign, SignChangeEvent signChangeEvent, int i, String s){ + sign.setLine(i,s); + signChangeEvent.setLine(i,s); + } + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java new file mode 100644 index 0000000..ac5fd1e --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java @@ -0,0 +1,85 @@ +package com.jamesdpeters.minecraft.chests.listeners; + +import com.jamesdpeters.minecraft.chests.ChestsPlusPlus; +import com.jamesdpeters.minecraft.chests.Config; +import com.jamesdpeters.minecraft.chests.Utils; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Hopper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemFrame; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.inventory.InventoryPickupItemEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static com.jamesdpeters.minecraft.chests.Utils.hasFilter; + +public class HopperListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST) + public void onHopperMoveEvent(InventoryMoveItemEvent event) { + //TO HOPPER + if(event.getDestination().getHolder() instanceof Hopper){ + event.setCancelled(!isItemInFilter(event.getDestination().getLocation().getBlock(),event.getItem())); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void fromHopper(InventoryMoveItemEvent event){ + //FROM HOPPER + if (event.getInitiator().getHolder() instanceof Hopper) { + InventoryStorage storage = Config.getInventoryStorage(event.getDestination().getLocation()); + if (storage != null) { + if(!event.isCancelled()) { + event.setCancelled(true); + new BukkitRunnable() { + @Override + public void run() { + Utils.moveToOtherInventory(event.getSource(), 1, storage.getInventory()); + event.getDestination().getHolder().getInventory().clear(); + } + }.runTaskLater(ChestsPlusPlus.PLUGIN, 1); + } + } + } + } + + @EventHandler + public void onHopperPickup(InventoryPickupItemEvent event){ + if(event.getInventory().getHolder() instanceof Hopper){ + event.setCancelled(!isItemInFilter(event.getInventory().getLocation().getBlock(),event.getItem().getItemStack())); + } + } + + public static boolean isItemInFilter(Block block, ItemStack item){ + Collection ent = block.getLocation().getWorld().getNearbyEntities(block.getLocation(),1.01,1.01,1.01); + boolean hasFilter = false; + for(Entity frame : ent){ + if(frame instanceof ItemFrame){ + Block attachedBlock = frame.getLocation().getBlock().getRelative(((ItemFrame) frame).getAttachedFace()); + if(block.equals(attachedBlock)){ + if(((ItemFrame) frame).getItem().getType() != Material.AIR) hasFilter = true; + if(item.isSimilar(((ItemFrame) frame).getItem())){ + return true; + } + } + } + } + if(!hasFilter) return true; + return false; + } + + + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java new file mode 100644 index 0000000..db564e3 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java @@ -0,0 +1,61 @@ +package com.jamesdpeters.minecraft.chests.listeners; + +import com.comphenix.protocol.wrappers.BlockPosition; +import com.jamesdpeters.minecraft.chests.Config; +import com.jamesdpeters.minecraft.chests.Utils; +import com.jamesdpeters.minecraft.chests.interfaces.VirtualInventoryHolder; +import com.jamesdpeters.minecraft.chests.protocollib.WrapperPlayServerBlockAction; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.Location; +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.event.inventory.InventoryOpenEvent; + +public class InventoryListener implements Listener { + + @EventHandler(priority = EventPriority.LOWEST) + public void onInventoryPlayerUpdate(InventoryClickEvent event){ + if(event.getInventory().getHolder() instanceof VirtualInventoryHolder){ + Config.save(); + } + } + + @EventHandler + public void onInventoryOpen(InventoryOpenEvent event){ + if(event.getInventory().getLocation() != null){ + InventoryStorage storage = Config.getInventoryStorage(event.getInventory().getLocation()); + if(storage != null){ + event.setCancelled(true); + + Location chestLocation = event.getInventory().getLocation(); + BlockPosition blockPosition = new BlockPosition((int) chestLocation.getX(),(int)chestLocation.getY(),(int)chestLocation.getZ()); + + WrapperPlayServerBlockAction packet = new WrapperPlayServerBlockAction(); + packet.setLocation(blockPosition); + packet.setBlockType(event.getInventory().getLocation().getBlock().getType()); + packet.setByte1(1); + packet.setByte2(1); + + packet.broadcastPacket(); + packet.sendPacket((Player) event.getPlayer()); + + Utils.openInventory((Player) event.getPlayer(),storage.getInventory()); + } + } + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent event){ + if(event.getInventory().getLocation() == null){ + Utils.closeInventorySound((Player) event.getPlayer(),event.getInventory()); + } + if(event.getInventory().getHolder() instanceof VirtualInventoryHolder){ + Config.save(); + } + } + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/listeners/TempListener.java b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/TempListener.java new file mode 100644 index 0000000..ea63b10 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/listeners/TempListener.java @@ -0,0 +1,23 @@ +package com.jamesdpeters.minecraft.chests.listeners; + +import com.jamesdpeters.minecraft.chests.ChestsPlusPlus; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; + +public class TempListener implements Listener { + + public TempListener(){ + this(ChestsPlusPlus.PLUGIN); + } + + public TempListener(Plugin plugin){ + plugin.getServer().getPluginManager().registerEvents(this,plugin); + } + + public void done(){ + HandlerList.unregisterAll(this); + } + + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/protocollib/AbstractPacket.java b/src/main/java/com/jamesdpeters/minecraft/chests/protocollib/AbstractPacket.java new file mode 100644 index 0000000..15f1e1b --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/protocollib/AbstractPacket.java @@ -0,0 +1,115 @@ +package com.jamesdpeters.minecraft.chests.protocollib; + +/** + * PacketWrapper - ProtocolLib wrappers for Minecraft packets + * Copyright (C) dmulloy2 + * Copyright (C) Kristian S. Strangeland + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import java.lang.reflect.InvocationTargetException; + +import org.bukkit.entity.Player; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketContainer; +import com.google.common.base.Objects; + +public abstract class AbstractPacket { + // The packet we will be modifying + protected PacketContainer handle; + + /** + * Constructs a new strongly typed wrapper for the given packet. + * + * @param handle - handle to the raw packet data. + * @param type - the packet type. + */ + protected AbstractPacket(PacketContainer handle, PacketType type) { + // Make sure we're given a valid packet + if (handle == null) + throw new IllegalArgumentException("Packet handle cannot be NULL."); + if (!Objects.equal(handle.getType(), type)) + throw new IllegalArgumentException(handle.getHandle() + + " is not a packet of type " + type); + + this.handle = handle; + } + + /** + * Retrieve a handle to the raw packet data. + * + * @return Raw packet data. + */ + public PacketContainer getHandle() { + return handle; + } + + /** + * Send the current packet to the given receiver. + * + * @param receiver - the receiver. + * @throws RuntimeException If the packet cannot be sent. + */ + public void sendPacket(Player receiver) { + try { + ProtocolLibrary.getProtocolManager().sendServerPacket(receiver, + getHandle()); + } catch (InvocationTargetException e) { + throw new RuntimeException("Cannot send packet.", e); + } + } + + /** + * Send the current packet to all online players. + */ + public void broadcastPacket() { + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle()); + } + + /** + * Simulate receiving the current packet from the given sender. + * + * @param sender - the sender. + * @throws RuntimeException If the packet cannot be received. + * @deprecated Misspelled. recieve to receive + * @see #receivePacket(Player) + */ + @Deprecated + public void recievePacket(Player sender) { + try { + ProtocolLibrary.getProtocolManager().recieveClientPacket(sender, + getHandle()); + } catch (Exception e) { + throw new RuntimeException("Cannot recieve packet.", e); + } + } + + /** + * Simulate receiving the current packet from the given sender. + * + * @param sender - the sender. + * @throws RuntimeException if the packet cannot be received. + */ + public void receivePacket(Player sender) { + try { + ProtocolLibrary.getProtocolManager().recieveClientPacket(sender, + getHandle()); + } catch (Exception e) { + throw new RuntimeException("Cannot receive packet.", e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/protocollib/WrapperPlayServerBlockAction.java b/src/main/java/com/jamesdpeters/minecraft/chests/protocollib/WrapperPlayServerBlockAction.java new file mode 100644 index 0000000..5e6446a --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/protocollib/WrapperPlayServerBlockAction.java @@ -0,0 +1,120 @@ +package com.jamesdpeters.minecraft.chests.protocollib; + +/** + * PacketWrapper - ProtocolLib wrappers for Minecraft packets + * Copyright (C) dmulloy2 + * Copyright (C) Kristian S. Strangeland + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import org.bukkit.Material; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.BlockPosition; + +public class WrapperPlayServerBlockAction extends AbstractPacket { + public static final PacketType TYPE = PacketType.Play.Server.BLOCK_ACTION; + + public WrapperPlayServerBlockAction() { + super(new PacketContainer(TYPE), TYPE); + handle.getModifier().writeDefaults(); + } + + public WrapperPlayServerBlockAction(PacketContainer packet) { + super(packet, TYPE); + } + + /** + * Retrieve Location. + *

+ * Notes: block Coordinates + * + * @return The current Location + */ + public BlockPosition getLocation() { + return handle.getBlockPositionModifier().read(0); + } + + /** + * Set Location. + * + * @param value - new value. + */ + public void setLocation(BlockPosition value) { + handle.getBlockPositionModifier().write(0, value); + } + + /** + * Retrieve Byte 1. + *

+ * Notes: varies depending on block - see Block_Actions + * + * @return The current Byte 1 + */ + public int getByte1() { + return handle.getIntegers().read(0); + } + + /** + * Set Byte 1. + * + * @param value - new value. + */ + public void setByte1(int value) { + handle.getIntegers().write(0, value); + } + + /** + * Retrieve Byte 2. + *

+ * Notes: varies depending on block - see Block_Actions + * + * @return The current Byte 2 + */ + public int getByte2() { + return handle.getIntegers().read(1); + } + + /** + * Set Byte 2. + * + * @param value - new value. + */ + public void setByte2(int value) { + handle.getIntegers().write(1, value); + } + + /** + * Retrieve Block Type. + *

+ * Notes: the block type for the block + * + * @return The current Block Type + */ + public Material getBlockType() { + return handle.getBlocks().read(0); + } + + /** + * Set Block Type. + * + * @param value - new value. + */ + public void setBlockType(Material value) { + handle.getBlocks().write(0, value); + } + +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/runnables/ChestLinkVerifier.java b/src/main/java/com/jamesdpeters/minecraft/chests/runnables/ChestLinkVerifier.java new file mode 100644 index 0000000..040d539 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/runnables/ChestLinkVerifier.java @@ -0,0 +1,66 @@ +package com.jamesdpeters.minecraft.chests.runnables; + +import com.jamesdpeters.minecraft.chests.ChestsPlusPlus; +import com.jamesdpeters.minecraft.chests.Config; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.block.DoubleChest; +import org.bukkit.inventory.Inventory; +import org.bukkit.scheduler.BukkitRunnable; + +public class ChestLinkVerifier extends BukkitRunnable { + + private Block block; + private int delay = 1; + + public ChestLinkVerifier(Block block){ + this.block = block; + } + + public void check(){ + runTaskLater(ChestsPlusPlus.PLUGIN,delay); + } + + public ChestLinkVerifier withDelay(int delay){ + this.delay = delay; + return this; + } + + @Override + public void run() { + Chest chest = (Chest) block.getState(); + + if(chest.getInventory().getHolder() instanceof DoubleChest) { + DoubleChest doubleChest = (DoubleChest) chest.getInventory().getHolder(); + if(isChestLinked(doubleChest)) { + convertToSingleChest(doubleChest.getRightSide().getInventory()); + convertToSingleChest(doubleChest.getLeftSide().getInventory()); + convertToSingleChest(doubleChest.getRightSide().getInventory()); + } + } + } + + public void convertToSingleChest(Inventory inventory){ + if(inventory != null) { + org.bukkit.block.data.type.Chest blockData = (org.bukkit.block.data.type.Chest) inventory.getLocation().getBlock().getBlockData(); + blockData.setType(org.bukkit.block.data.type.Chest.Type.SINGLE); + inventory.getLocation().getBlock().setBlockData(blockData); + } + } + + public boolean isChestLinked(DoubleChest chest){ + Location chestSide1 = block.getLocation(); + Location diff = chest.getLocation().clone().subtract(chestSide1).multiply(2); + Location chestSide2 = chestSide1.clone().add(diff); + + InventoryStorage leftStorage = Config.getInventoryStorage(chestSide1); + InventoryStorage rightStorage = Config.getInventoryStorage(chestSide2); + + if((leftStorage != null) || (rightStorage != null)){ + return true; + } + return false; + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java b/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java new file mode 100644 index 0000000..a845f19 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java @@ -0,0 +1,43 @@ +package com.jamesdpeters.minecraft.chests.runnables; + +import com.jamesdpeters.minecraft.chests.ChestsPlusPlus; +import com.jamesdpeters.minecraft.chests.Utils; +import com.jamesdpeters.minecraft.chests.interfaces.VirtualInventoryHolder; +import com.jamesdpeters.minecraft.chests.serialize.InventoryStorage; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Hopper; +import org.bukkit.inventory.Inventory; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.List; + +public class VirtualChestToHopper extends BukkitRunnable { + + InventoryStorage storage; + BukkitTask task; + + public VirtualChestToHopper(InventoryStorage storage){ + this.storage = storage; + } + + public void start(){ + task = runTaskTimer(ChestsPlusPlus.PLUGIN,1,8); + } + + public void stop(){ + task.cancel(); + } + + @Override + public void run() { + for(Location location : storage.getLocations()) { + Location below = location.clone().subtract(0, 1, 0); + if (below.getBlock().getState() instanceof Hopper) { + Hopper hopper = (Hopper) below.getBlock().getState(); + Utils.moveToOtherInventory(storage.getInventory(),1,hopper.getInventory(),Utils.getHopperFilters(below.getBlock())); + } + } + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/serialize/InventoryStorage.java b/src/main/java/com/jamesdpeters/minecraft/chests/serialize/InventoryStorage.java new file mode 100644 index 0000000..992ccc4 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/serialize/InventoryStorage.java @@ -0,0 +1,113 @@ +package com.jamesdpeters.minecraft.chests.serialize; + + +import com.jamesdpeters.minecraft.chests.Messages; +import com.jamesdpeters.minecraft.chests.interfaces.VirtualInventoryHolder; +import com.jamesdpeters.minecraft.chests.runnables.VirtualChestToHopper; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Array; +import java.util.*; + +public class InventoryStorage implements ConfigurationSerializable { + + Inventory inventory; + ArrayList locationsList; + String inventoryName = "Chest"; + VirtualChestToHopper chestToHopper; + Player player; + UUID playerUUID; + + @Override + public Map serialize() { + LinkedHashMap hashMap = new LinkedHashMap<>(); + hashMap.put("inventory",inventory.getContents()); + hashMap.put("locations",locationsList); + hashMap.put("inventoryName",inventoryName); + hashMap.put("playerUUID",playerUUID.toString()); + return hashMap; + } + + @SuppressWarnings("unchecked") + public InventoryStorage(Map map){ + String tempName = (String) map.get("inventoryName"); + if(tempName != null) inventoryName = tempName; + + inventory = initInventory(); + ItemStack[] itemStacks = ((ArrayList) map.get("inventory")).toArray(new ItemStack[0]); + + inventory.setContents(itemStacks); + locationsList = (ArrayList) map.get("locations"); + + playerUUID = UUID.fromString((String) map.get("playerUUID")); + player = Bukkit.getOfflinePlayer(playerUUID).getPlayer(); + + init(); + } + + public InventoryStorage(Player player, String group, Location location){ + this.inventoryName = group; + this.player = player; + this.playerUUID = player.getUniqueId(); + locationsList = new ArrayList<>(Collections.singleton(location)); + + Block block = location.getBlock(); + if(block.getState() instanceof Chest){ + Chest chest = (Chest) block.getState(); + inventory = initInventory(); + inventory.setContents(chest.getInventory().getContents()); + chest.getInventory().clear(); + } + + init(); + } + + private void init(){ + chestToHopper = new VirtualChestToHopper(this); + chestToHopper.start(); + } + + private Inventory initInventory(){ + return Bukkit.createInventory(new VirtualInventoryHolder(this), 54,inventoryName); + } + + public Inventory getInventory() { + return inventory; + } + + public List getLocations() { + return locationsList; + } + + public void dropInventory(Location location){ + for(ItemStack item : inventory.getContents()) { + if(location.getWorld() != null){ + if(item != null) { + location.getWorld().dropItemNaturally(location, item); + inventory.remove(item); + } + } + } + } + + public String getIdentifier() { + return inventoryName; + } + + public Player getOwner() { + return player; + } + + @Override + public String toString() { + return inventoryName+": "+locationsList.toString(); + } +} diff --git a/src/main/java/com/jamesdpeters/minecraft/chests/serialize/LinkedChest.java b/src/main/java/com/jamesdpeters/minecraft/chests/serialize/LinkedChest.java new file mode 100644 index 0000000..ad276f8 --- /dev/null +++ b/src/main/java/com/jamesdpeters/minecraft/chests/serialize/LinkedChest.java @@ -0,0 +1,33 @@ +package com.jamesdpeters.minecraft.chests.serialize; + +import org.bukkit.Location; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.SerializableAs; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@SerializableAs("LinkedChest") +public class LinkedChest implements ConfigurationSerializable { + + public HashMap> chests; + + @Override + public Map serialize() { + LinkedHashMap hashMap = new LinkedHashMap<>(); + hashMap.put("chests",chests); + return hashMap; + } + + @SuppressWarnings("unchecked") + public LinkedChest(Map map){ + chests = (HashMap>) map.get("chests"); + } + + public LinkedChest(){ + chests = new HashMap<>(); + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..3b473af --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,11 @@ +name: ChestsPlusPlus +version: 1.14.4-v1 +main: com.jamesdpeters.minecraft.chests.ChestsPlusPlus +api-version: "1.14" + +depend: [ProtocolLib] + +commands: + chestlink: + description: Chest++ Commands. + usage: Use /chestlink help for more info. \ No newline at end of file