diff --git a/src/lishid/openinv/OpenInv.java b/src/com/lishid/openinv/OpenInv.java similarity index 70% rename from src/lishid/openinv/OpenInv.java rename to src/com/lishid/openinv/OpenInv.java index acd77af..03813c1 100644 --- a/src/lishid/openinv/OpenInv.java +++ b/src/com/lishid/openinv/OpenInv.java @@ -14,21 +14,27 @@ * along with this program. If not, see . */ -package lishid.openinv; +package com.lishid.openinv; import java.util.HashMap; +import java.util.logging.Logger; -import lishid.openinv.commands.*; -import lishid.openinv.utils.Metrics; -import lishid.openinv.utils.OpenInvEnderChest; -import lishid.openinv.utils.OpenInvPlayerInventory; import org.bukkit.ChatColor; import org.bukkit.entity.Player; -import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import com.lishid.openinv.commands.*; +import com.lishid.openinv.internal.IAnySilentChest; +import com.lishid.openinv.internal.IInventoryAccess; +import com.lishid.openinv.internal.IPlayerDataManager; +import com.lishid.openinv.internal.ISpecialEnderChest; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import com.lishid.openinv.internal.InternalAccessor; +import com.lishid.openinv.utils.Metrics; +import com.lishid.openinv.utils.UpdateManager; + /** * Open other player's inventory * @@ -36,25 +42,46 @@ import org.bukkit.plugin.java.JavaPlugin; */ public class OpenInv extends JavaPlugin { - public static HashMap inventories = new HashMap(); - public static HashMap enderChests = new HashMap(); - public static OpenInv mainPlugin; + public static final Logger logger = Logger.getLogger("Minecraft.OpenInv"); + + public static HashMap inventories = new HashMap(); + public static HashMap enderChests = new HashMap(); private static Metrics metrics; - public void onDisable() - { - PluginDescriptionFile pdfFile = this.getDescription(); - System.out.println("[" + pdfFile.getName() + "] version " + pdfFile.getVersion() + " disabled!"); - } + private UpdateManager updater = new UpdateManager(); + + public static OpenInv mainPlugin; + + public static IPlayerDataManager playerLoader; + public static IInventoryAccess inventoryAccess; + public static IAnySilentChest anySilentChest; public void onEnable() { + // Get plugin manager + PluginManager pm = getServer().getPluginManager(); + + // Version check + boolean success = InternalAccessor.Initialize(this.getServer()); + + if(!success) + { + OpenInv.log("Your version of CraftBukkit is not supported."); + OpenInv.log("Please look for an updated version of Orebfuscator."); + pm.disablePlugin(this); + return; + } + + playerLoader = InternalAccessor.Instance.newPlayerDataManager(); + inventoryAccess = InternalAccessor.Instance.newInventoryAccess(); + anySilentChest = InternalAccessor.Instance.newAnySilentChest(); + mainPlugin = this; mainPlugin.getConfig().addDefault("ItemOpenInvItemID", 280); + mainPlugin.getConfig().addDefault("CheckForUpdates", true); mainPlugin.getConfig().options().copyDefaults(true); mainPlugin.saveConfig(); - PluginManager pm = getServer().getPluginManager(); pm.registerEvents(new OpenInvPlayerListener(), this); pm.registerEvents(new OpenInvEntityListener(), this); pm.registerEvents(new OpenInvInventoryListener(), this); @@ -66,6 +93,8 @@ public class OpenInv extends JavaPlugin getCommand("anychest").setExecutor(new AnyChestPluginCommand(this)); getCommand("openender").setExecutor(new OpenEnderPluginCommand(this)); + updater.Initialize(this, getFile()); + // Metrics try { @@ -74,11 +103,13 @@ public class OpenInv extends JavaPlugin } catch (Exception e) { - e.printStackTrace(); + OpenInv.log(e); } - - PluginDescriptionFile pdfFile = this.getDescription(); - System.out.println("[" + pdfFile.getName() + "] version " + pdfFile.getVersion() + " enabled!"); + } + + public static boolean GetCheckForUpdates() + { + return mainPlugin.getConfig().getBoolean("CheckForUpdates", true); } public static boolean GetPlayerItemOpenInvStatus(String name) @@ -143,6 +174,23 @@ public class OpenInv extends JavaPlugin mainPlugin.saveConfig(); } + /** + * Log an information + */ + public static void log(String text) + { + logger.info("[OpenInv] " + text); + } + + /** + * Log an error + */ + public static void log(Throwable e) + { + logger.severe("[OpenInv] " + e.toString()); + e.printStackTrace(); + } + public static void ShowHelp(Player player) { player.sendMessage(ChatColor.GREEN + "/openinv - Open a player's inventory"); diff --git a/src/lishid/openinv/OpenInvEntityListener.java b/src/com/lishid/openinv/OpenInvEntityListener.java similarity index 95% rename from src/lishid/openinv/OpenInvEntityListener.java rename to src/com/lishid/openinv/OpenInvEntityListener.java index 4fb3e7b..b77d1fc 100644 --- a/src/lishid/openinv/OpenInvEntityListener.java +++ b/src/com/lishid/openinv/OpenInvEntityListener.java @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -package lishid.openinv; +package com.lishid.openinv; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; diff --git a/src/lishid/openinv/OpenInvInventoryListener.java b/src/com/lishid/openinv/OpenInvInventoryListener.java similarity index 54% rename from src/lishid/openinv/OpenInvInventoryListener.java rename to src/com/lishid/openinv/OpenInvInventoryListener.java index a7d974d..2046bdc 100644 --- a/src/lishid/openinv/OpenInvInventoryListener.java +++ b/src/com/lishid/openinv/OpenInvInventoryListener.java @@ -14,14 +14,8 @@ * along with this program. If not, see . */ -package lishid.openinv; +package com.lishid.openinv; -import lishid.openinv.utils.OpenInvEnderChest; -import lishid.openinv.utils.OpenInvPlayerInventory; -import net.minecraft.server.IInventory; - -import org.bukkit.craftbukkit.inventory.CraftInventory; -import org.bukkit.entity.HumanEntity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -32,18 +26,10 @@ public class OpenInvInventoryListener implements Listener @EventHandler(priority = EventPriority.NORMAL) public void onInventoryClick(InventoryClickEvent event) { - IInventory inv = ((CraftInventory) event.getInventory()).getInventory(); - HumanEntity player = event.getWhoClicked(); - if (inv instanceof OpenInvPlayerInventory && event.getView().convertSlot(event.getRawSlot()) == event.getRawSlot()) + // If this is the top inventory + if (event.getView().convertSlot(event.getRawSlot()) == event.getRawSlot()) { - if (!player.hasPermission(Permissions.PERM_EDITINV)) - { - event.setCancelled(true); - } - } - else if (inv instanceof OpenInvEnderChest && event.getView().convertSlot(event.getRawSlot()) == event.getRawSlot()) - { - if (!player.hasPermission(Permissions.PERM_EDITENDER)) + if (!OpenInv.inventoryAccess.check(event.getInventory(), event.getWhoClicked())) { event.setCancelled(true); } diff --git a/src/com/lishid/openinv/OpenInvPlayerListener.java b/src/com/lishid/openinv/OpenInvPlayerListener.java new file mode 100644 index 0000000..a197d7d --- /dev/null +++ b/src/com/lishid/openinv/OpenInvPlayerListener.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv; + +import org.bukkit.ChatColor; +import org.bukkit.block.Chest; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Event.Result; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import com.lishid.openinv.internal.ISpecialEnderChest; +import com.lishid.openinv.internal.ISpecialPlayerInventory; + +public class OpenInvPlayerListener implements Listener +{ + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerJoin(PlayerJoinEvent event) + { + ISpecialPlayerInventory inventory = OpenInv.inventories.get(event.getPlayer().getName().toLowerCase()); + + if (inventory != null) + { + inventory.PlayerGoOnline(event.getPlayer()); + } + + ISpecialEnderChest chest = OpenInv.enderChests.get(event.getPlayer().getName().toLowerCase()); + + if (chest != null) + { + chest.PlayerGoOnline(event.getPlayer()); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(PlayerQuitEvent event) + { + ISpecialPlayerInventory inventory = OpenInv.inventories.get(event.getPlayer().getName().toLowerCase()); + if (inventory != null) + { + inventory.PlayerGoOffline(); + inventory.InventoryRemovalCheck(); + } + ISpecialEnderChest chest = OpenInv.enderChests.get(event.getPlayer().getName().toLowerCase()); + if (chest != null) + { + chest.PlayerGoOffline(); + chest.InventoryRemovalCheck(); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerInteract(PlayerInteractEvent event) + { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.useInteractedBlock() == Result.DENY) + return; + + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == org.bukkit.Material.ENDER_CHEST) + { + if (event.getPlayer().hasPermission(Permissions.PERM_SILENT) && OpenInv.GetPlayerSilentChestStatus(event.getPlayer().getName())) + { + event.setCancelled(true); + event.getPlayer().openInventory(event.getPlayer().getEnderChest()); + } + } + + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getState() instanceof Chest) + { + boolean silentchest = false; + boolean anychest = false; + int x = event.getClickedBlock().getX(); + int y = event.getClickedBlock().getY(); + int z = event.getClickedBlock().getZ(); + + if (event.getPlayer().hasPermission(Permissions.PERM_SILENT) && OpenInv.GetPlayerSilentChestStatus(event.getPlayer().getName())) + { + silentchest = true; + } + + if (event.getPlayer().hasPermission(Permissions.PERM_ANYCHEST) && OpenInv.GetPlayerAnyChestStatus(event.getPlayer().getName())) + { + try + { + anychest = OpenInv.anySilentChest.IsAnyChestNeeded(event.getPlayer(), x, y, z); + } + catch (Exception e) + { + event.getPlayer().sendMessage(ChatColor.RED + "Error while executing openinv. Unsupported CraftBukkit."); + e.printStackTrace(); + } + } + + // If the anychest or silentchest is active + if (anychest || silentchest) + { + if (!OpenInv.anySilentChest.ActivateChest(event.getPlayer(), anychest, silentchest, x, y, z)) + { + event.setCancelled(true); + } + } + } + + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getState() instanceof Sign) + { + Player player = event.getPlayer(); + try + { + Sign sign = ((Sign) event.getClickedBlock().getState()); + if (player.hasPermission(Permissions.PERM_OPENINV) && sign.getLine(0).equalsIgnoreCase("[openinv]")) + { + String text = sign.getLine(1).trim() + sign.getLine(2).trim() + sign.getLine(3).trim(); + player.performCommand("openinv " + text); + } + } + catch (Exception ex) + { + player.sendMessage("Internal Error."); + ex.printStackTrace(); + } + } + + if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) + { + Player player = event.getPlayer(); + + if (!(player.getItemInHand().getType().getId() == OpenInv.GetItemOpenInvItem()) || (!OpenInv.GetPlayerItemOpenInvStatus(player.getName())) + || !player.hasPermission(Permissions.PERM_OPENINV)) + { + return; + } + + player.performCommand("openinv"); + } + } +} \ No newline at end of file diff --git a/src/lishid/openinv/Permissions.java b/src/com/lishid/openinv/Permissions.java similarity index 94% rename from src/lishid/openinv/Permissions.java rename to src/com/lishid/openinv/Permissions.java index 73d7173..e354c69 100644 --- a/src/lishid/openinv/Permissions.java +++ b/src/com/lishid/openinv/Permissions.java @@ -1,4 +1,4 @@ -package lishid.openinv; +package com.lishid.openinv; public class Permissions { diff --git a/src/lishid/openinv/commands/AnyChestPluginCommand.java b/src/com/lishid/openinv/commands/AnyChestPluginCommand.java similarity index 94% rename from src/lishid/openinv/commands/AnyChestPluginCommand.java rename to src/com/lishid/openinv/commands/AnyChestPluginCommand.java index 9f7f819..37c86b7 100644 --- a/src/lishid/openinv/commands/AnyChestPluginCommand.java +++ b/src/com/lishid/openinv/commands/AnyChestPluginCommand.java @@ -14,10 +14,7 @@ * along with this program. If not, see . */ -package lishid.openinv.commands; - -import lishid.openinv.OpenInv; -import lishid.openinv.Permissions; +package com.lishid.openinv.commands; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -25,6 +22,9 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.Permissions; + public class AnyChestPluginCommand implements CommandExecutor { public AnyChestPluginCommand(OpenInv plugin) diff --git a/src/lishid/openinv/commands/OpenEnderPluginCommand.java b/src/com/lishid/openinv/commands/OpenEnderPluginCommand.java similarity index 56% rename from src/lishid/openinv/commands/OpenEnderPluginCommand.java rename to src/com/lishid/openinv/commands/OpenEnderPluginCommand.java index 69405e6..f494284 100644 --- a/src/lishid/openinv/commands/OpenEnderPluginCommand.java +++ b/src/com/lishid/openinv/commands/OpenEnderPluginCommand.java @@ -14,34 +14,24 @@ * along with this program. If not, see . */ -package lishid.openinv.commands; +package com.lishid.openinv.commands; -import java.io.File; -import java.util.Arrays; import java.util.HashMap; -import lishid.openinv.OpenInv; -import lishid.openinv.Permissions; -import lishid.openinv.utils.OpenInvEnderChest; -import lishid.openinv.utils.OpenInvPlayerInventory; - -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.ItemInWorldManager; -import net.minecraft.server.MinecraftServer; - -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.Permissions; +import com.lishid.openinv.internal.ISpecialEnderChest; +import com.lishid.openinv.internal.InternalAccessor; + public class OpenEnderPluginCommand implements CommandExecutor { private final OpenInv plugin; - public static HashMap offlineEnder = new HashMap(); public static HashMap openEnderHistory = new HashMap(); public OpenEnderPluginCommand(OpenInv plugin) @@ -108,43 +98,12 @@ public class OpenEnderPluginCommand implements CommandExecutor if (target == null) { - // Offline ender here... - try + // Try loading the player's data + target = OpenInv.playerLoader.loadPlayer(name); + + if (target == null) { - // Default player folder - File playerfolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "players"); - if (!playerfolder.exists()) - { - sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); - return true; - } - - String playername = OpenInvPluginCommand.matchUser(Arrays.asList(playerfolder.listFiles()), name); - if (playername == null) - { - sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); - return true; - } - - // Create an entity to load the player data - final MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - final EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), playername, new ItemInWorldManager(server.getWorldServer(0))); - target = (entity == null) ? null : (Player) entity.getBukkitEntity(); - if (target != null) - { - target.loadData(); - offline = true; - } - else - { - sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); - return true; - } - } - catch (Exception e) - { - sender.sendMessage("Error while retrieving offline player data!"); - e.printStackTrace(); + sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); return true; } } @@ -154,16 +113,16 @@ public class OpenEnderPluginCommand implements CommandExecutor openEnderHistory.put(player, history); // Create the inventory - OpenInvEnderChest chest = OpenInv.enderChests.get(target.getName().toLowerCase()); + ISpecialEnderChest chest = OpenInv.enderChests.get(target.getName().toLowerCase()); if (chest == null) { - chest = new OpenInvEnderChest((CraftPlayer) target, !offline); + chest = InternalAccessor.Instance.newSpecialEnderChest(target, !offline); OpenInv.enderChests.put(target.getName().toLowerCase(), chest); } // Open the inventory - (((CraftPlayer) player).getHandle()).openContainer(chest); + player.openInventory(chest.getBukkitInventory()); return true; } diff --git a/src/lishid/openinv/commands/OpenInvPluginCommand.java b/src/com/lishid/openinv/commands/OpenInvPluginCommand.java similarity index 51% rename from src/lishid/openinv/commands/OpenInvPluginCommand.java rename to src/com/lishid/openinv/commands/OpenInvPluginCommand.java index b756226..9ef100e 100644 --- a/src/lishid/openinv/commands/OpenInvPluginCommand.java +++ b/src/com/lishid/openinv/commands/OpenInvPluginCommand.java @@ -14,34 +14,24 @@ * along with this program. If not, see . */ -package lishid.openinv.commands; +package com.lishid.openinv.commands; -import java.io.File; -import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; -import lishid.openinv.OpenInv; -import lishid.openinv.Permissions; -import lishid.openinv.utils.OpenInvPlayerInventory; - -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.ItemInWorldManager; -import net.minecraft.server.MinecraftServer; - -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.Permissions; +import com.lishid.openinv.internal.ISpecialPlayerInventory; +import com.lishid.openinv.internal.InternalAccessor; + public class OpenInvPluginCommand implements CommandExecutor { private final OpenInv plugin; - public static HashMap offlineInv = new HashMap(); public static HashMap openInvHistory = new HashMap(); public OpenInvPluginCommand(OpenInv plugin) @@ -96,58 +86,19 @@ public class OpenInvPluginCommand implements CommandExecutor } target = this.plugin.getServer().getPlayer(name); - + if (target == null) { - // Offline inv here... - try + if (target == null) { - // See if the player has data files + // Try loading the player's data + target = OpenInv.playerLoader.loadPlayer(name); - // Go through current world first, if not found then go through default world. - /* - * World worldFound = matchWorld(Bukkit.getWorlds(), player.getWorld().getName()); - * if (worldFound != null) - * { - * - * } - */ - - // Default player folder - File playerfolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "players"); - if (!playerfolder.exists()) + if (target == null) { sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); return true; } - - String playername = matchUser(Arrays.asList(playerfolder.listFiles()), name); - if (playername == null) - { - sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); - return true; - } - - // Create an entity to load the player data - final MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - final EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), playername, new ItemInWorldManager(server.getWorldServer(0))); - target = (entity == null) ? null : (Player) entity.getBukkitEntity(); - if (target != null) - { - target.loadData(); - offline = true; - } - else - { - sender.sendMessage(ChatColor.RED + "Player " + name + " not found!"); - return true; - } - } - catch (Exception e) - { - sender.sendMessage("Error while retrieving offline player data!"); - e.printStackTrace(); - return true; } } @@ -175,54 +126,19 @@ public class OpenInvPluginCommand implements CommandExecutor // Record the target history = target.getName(); openInvHistory.put(player, history); - + // Create the inventory - OpenInvPlayerInventory inv = OpenInv.inventories.get(target.getName().toLowerCase()); + ISpecialPlayerInventory inv = OpenInv.inventories.get(target.getName().toLowerCase()); if (inv == null) { - inv = new OpenInvPlayerInventory((CraftPlayer) target, !offline); + inv = InternalAccessor.Instance.newSpecialPlayerInventory(target, !offline); OpenInv.inventories.put(target.getName().toLowerCase(), inv); } - + // Open the inventory - (((CraftPlayer) player).getHandle()).openContainer(inv); + player.openInventory(inv.getBukkitInventory()); return true; } - - /** - * @author Balor (aka Antoine Aflalo) - */ - public static String matchUser(final Collection container, final String search) - { - String found = null; - if (search == null) - { - return found; - } - final String lowerSearch = search.toLowerCase(); - int delta = Integer.MAX_VALUE; - for (final File file : container) - { - final String filename = file.getName(); - final String str = filename.substring(0, filename.length() - 4); - if (!str.toLowerCase().startsWith(lowerSearch)) - { - continue; - } - final int curDelta = str.length() - lowerSearch.length(); - if (curDelta < delta) - { - found = str; - delta = curDelta; - } - if (curDelta == 0) - { - break; - } - - } - return found; - } } diff --git a/src/lishid/openinv/commands/SearchInvPluginCommand.java b/src/com/lishid/openinv/commands/SearchInvPluginCommand.java similarity index 97% rename from src/lishid/openinv/commands/SearchInvPluginCommand.java rename to src/com/lishid/openinv/commands/SearchInvPluginCommand.java index fa0731d..dc5c8a3 100644 --- a/src/lishid/openinv/commands/SearchInvPluginCommand.java +++ b/src/com/lishid/openinv/commands/SearchInvPluginCommand.java @@ -14,9 +14,7 @@ * along with this program. If not, see . */ -package lishid.openinv.commands; - -import lishid.openinv.Permissions; +package com.lishid.openinv.commands; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -26,6 +24,8 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import com.lishid.openinv.Permissions; + public class SearchInvPluginCommand implements CommandExecutor { public SearchInvPluginCommand() diff --git a/src/lishid/openinv/commands/SilentChestPluginCommand.java b/src/com/lishid/openinv/commands/SilentChestPluginCommand.java similarity index 95% rename from src/lishid/openinv/commands/SilentChestPluginCommand.java rename to src/com/lishid/openinv/commands/SilentChestPluginCommand.java index 1223181..cd2abb6 100644 --- a/src/lishid/openinv/commands/SilentChestPluginCommand.java +++ b/src/com/lishid/openinv/commands/SilentChestPluginCommand.java @@ -14,10 +14,7 @@ * along with this program. If not, see . */ -package lishid.openinv.commands; - -import lishid.openinv.OpenInv; -import lishid.openinv.Permissions; +package com.lishid.openinv.commands; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -25,6 +22,9 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.Permissions; + public class SilentChestPluginCommand implements CommandExecutor { public SilentChestPluginCommand(OpenInv plugin) diff --git a/src/lishid/openinv/commands/ToggleOpenInvPluginCommand.java b/src/com/lishid/openinv/commands/ToggleOpenInvPluginCommand.java similarity index 95% rename from src/lishid/openinv/commands/ToggleOpenInvPluginCommand.java rename to src/com/lishid/openinv/commands/ToggleOpenInvPluginCommand.java index 6663cf6..4693a44 100644 --- a/src/lishid/openinv/commands/ToggleOpenInvPluginCommand.java +++ b/src/com/lishid/openinv/commands/ToggleOpenInvPluginCommand.java @@ -14,10 +14,7 @@ * along with this program. If not, see . */ -package lishid.openinv.commands; - -import lishid.openinv.OpenInv; -import lishid.openinv.Permissions; +package com.lishid.openinv.commands; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -26,6 +23,9 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.Permissions; + public class ToggleOpenInvPluginCommand implements CommandExecutor { diff --git a/src/com/lishid/openinv/internal/IAnySilentChest.java b/src/com/lishid/openinv/internal/IAnySilentChest.java new file mode 100644 index 0000000..230408c --- /dev/null +++ b/src/com/lishid/openinv/internal/IAnySilentChest.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal; + +import org.bukkit.entity.Player; + +public interface IAnySilentChest +{ + public boolean IsAnyChestNeeded(Player p, int x, int y, int z); + + public boolean ActivateChest(Player p, boolean anychest, boolean silentchest, int x, int y, int z); +} diff --git a/src/com/lishid/openinv/internal/IInventoryAccess.java b/src/com/lishid/openinv/internal/IInventoryAccess.java new file mode 100644 index 0000000..124bed0 --- /dev/null +++ b/src/com/lishid/openinv/internal/IInventoryAccess.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; + +public interface IInventoryAccess +{ + public boolean check(Inventory inventory, HumanEntity player); +} diff --git a/src/com/lishid/openinv/internal/IPlayerDataManager.java b/src/com/lishid/openinv/internal/IPlayerDataManager.java new file mode 100644 index 0000000..e6824bd --- /dev/null +++ b/src/com/lishid/openinv/internal/IPlayerDataManager.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal; + +import org.bukkit.entity.Player; + +public interface IPlayerDataManager +{ + public Player loadPlayer(String name); +} diff --git a/src/com/lishid/openinv/internal/ISpecialEnderChest.java b/src/com/lishid/openinv/internal/ISpecialEnderChest.java new file mode 100644 index 0000000..8b7fa5c --- /dev/null +++ b/src/com/lishid/openinv/internal/ISpecialEnderChest.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +public interface ISpecialEnderChest +{ + public Inventory getBukkitInventory(); + + public void InventoryRemovalCheck(); + + public void PlayerGoOnline(Player p); + + public void PlayerGoOffline(); + +} diff --git a/src/com/lishid/openinv/internal/ISpecialPlayerInventory.java b/src/com/lishid/openinv/internal/ISpecialPlayerInventory.java new file mode 100644 index 0000000..604e62d --- /dev/null +++ b/src/com/lishid/openinv/internal/ISpecialPlayerInventory.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +public interface ISpecialPlayerInventory +{ + public Inventory getBukkitInventory(); + + public void InventoryRemovalCheck(); + + public void PlayerGoOnline(Player p); + + public void PlayerGoOffline(); +} diff --git a/src/com/lishid/openinv/internal/InternalAccessor.java b/src/com/lishid/openinv/internal/InternalAccessor.java new file mode 100644 index 0000000..54c9705 --- /dev/null +++ b/src/com/lishid/openinv/internal/InternalAccessor.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal; + +import org.bukkit.Server; +import org.bukkit.entity.Player; + +import com.lishid.openinv.OpenInv; + +public class InternalAccessor +{ + public static InternalAccessor Instance; + private String version; + + /* + * Returns false if version not supported + */ + public static boolean Initialize(Server server) + { + Instance = new InternalAccessor(); + String packageName = server.getClass().getPackage().getName(); + Instance.version = packageName.substring(packageName.lastIndexOf('.') + 1); + + try + { + Class.forName("com.lishid.orebfuscator.internal." + Instance.version + ".PlayerHook"); + return true; + } + catch (Exception e) + { + return false; + } + } + + public void PrintError() + { + OpenInv.log("OpenInv encountered an error with the CraftBukkit version \"" + Instance.version + "\". Please look for an updated version of OpenInv."); + } + + public IPlayerDataManager newPlayerDataManager() + { + return (IPlayerDataManager) createObject(IPlayerDataManager.class, "PlayerDataManager"); + } + + public IInventoryAccess newInventoryAccess() + { + return (IInventoryAccess) createObject(IInventoryAccess.class, "InventoryAccess"); + } + + public IAnySilentChest newAnySilentChest() + { + return (IAnySilentChest) createObject(IAnySilentChest.class, "AnySilentChest"); + } + + public ISpecialPlayerInventory newSpecialPlayerInventory(Player player, boolean offline) + { + try + { + Class internalClass = Class.forName("com.lishid.openinv.internal." + version + ".SpecialPlayerInventory"); + if (ISpecialPlayerInventory.class.isAssignableFrom(internalClass)) + { + return (ISpecialPlayerInventory) internalClass.getConstructor(Player.class, Boolean.class).newInstance(player, offline); + } + } + catch (Exception e) + { + PrintError(); + OpenInv.log(e); + } + + return null; + } + + public ISpecialEnderChest newSpecialEnderChest(Player player, boolean offline) + { + try + { + Class internalClass = Class.forName("com.lishid.openinv.internal." + version + ".SpecialEnderChest"); + if (ISpecialEnderChest.class.isAssignableFrom(internalClass)) + { + return (ISpecialEnderChest) internalClass.getConstructor(Player.class, Boolean.class).newInstance(player, offline); + } + } + catch (Exception e) + { + PrintError(); + OpenInv.log(e); + } + + return null; + } + + private Object createObject(Class assignableClass, String className) + { + try + { + Class internalClass = Class.forName("com.lishid.openinv.internal." + version + "." + className); + if (assignableClass.isAssignableFrom(internalClass)) + { + return internalClass.getConstructor().newInstance(); + } + } + catch (Exception e) + { + PrintError(); + OpenInv.log(e); + } + + return null; + } +} diff --git a/src/com/lishid/openinv/internal/craftbukkit/AnySilentChest.java b/src/com/lishid/openinv/internal/craftbukkit/AnySilentChest.java new file mode 100644 index 0000000..674f312 --- /dev/null +++ b/src/com/lishid/openinv/internal/craftbukkit/AnySilentChest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.craftbukkit; + +import java.lang.reflect.Field; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import com.lishid.openinv.internal.IAnySilentChest; + +//Volatile +import net.minecraft.server.*; +import org.bukkit.craftbukkit.entity.*; + +public class AnySilentChest implements IAnySilentChest +{ + public boolean IsAnyChestNeeded(Player p, int x, int y, int z) + { + // FOR REFERENCE, LOOK AT net.minecraft.server.BlockChest + EntityPlayer player = ((CraftPlayer) p).getHandle(); + World world = player.world; + // If block on top + if (world.s(x, y + 1, z)) + return true; + + // If block next to chest is chest and has a block on top + if ((world.getTypeId(x - 1, y, z) == Block.CHEST.id) && (world.s(x - 1, y + 1, z))) + return true; + if ((world.getTypeId(x + 1, y, z) == Block.CHEST.id) && (world.s(x + 1, y + 1, z))) + return true; + if ((world.getTypeId(x, y, z - 1) == Block.CHEST.id) && (world.s(x, y + 1, z - 1))) + return true; + if ((world.getTypeId(x, y, z + 1) == Block.CHEST.id) && (world.s(x, y + 1, z + 1))) + return true; + + return false; + } + + public boolean ActivateChest(Player p, boolean anychest, boolean silentchest, int x, int y, int z) + { + EntityPlayer player = ((CraftPlayer) p).getHandle(); + World world = player.world; + Object chest = (TileEntityChest) world.getTileEntity(x, y, z); + if (chest == null) + return true; + + if (!anychest) + { + if (world.s(x, y + 1, z)) + return true; + if ((world.getTypeId(x - 1, y, z) == Block.CHEST.id) && (world.s(x - 1, y + 1, z))) + return true; + if ((world.getTypeId(x + 1, y, z) == Block.CHEST.id) && (world.s(x + 1, y + 1, z))) + return true; + if ((world.getTypeId(x, y, z - 1) == Block.CHEST.id) && (world.s(x, y + 1, z - 1))) + return true; + if ((world.getTypeId(x, y, z + 1) == Block.CHEST.id) && (world.s(x, y + 1, z + 1))) + return true; + } + + if (world.getTypeId(x - 1, y, z) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x - 1, y, z), (IInventory) chest); + if (world.getTypeId(x + 1, y, z) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x + 1, y, z)); + if (world.getTypeId(x, y, z - 1) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x, y, z - 1), (IInventory) chest); + if (world.getTypeId(x, y, z + 1) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x, y, z + 1)); + + if (!silentchest) + { + player.openContainer((IInventory) chest); + } + else + { + try + { + int id = 0; + try + { + Field windowID = player.getClass().getDeclaredField("containerCounter"); + windowID.setAccessible(true); + id = windowID.getInt(player); + id = id % 100 + 1; + windowID.setInt(player, id); + } + catch (NoSuchFieldException e) + { + } + + player.netServerHandler.sendPacket(new Packet100OpenWindow(id, 0, ((IInventory) chest).getName(), ((IInventory) chest).getSize())); + player.activeContainer = new SilentContainerChest(player.inventory, ((IInventory) chest)); + player.activeContainer.windowId = id; + player.activeContainer.addSlotListener(player); + // event.getPlayer().sendMessage("You are opening a chest silently."); + return false; + } + catch (Exception e) + { + e.printStackTrace(); + p.sendMessage(ChatColor.RED + "Error while sending silent chest."); + } + } + + if (anychest) + p.sendMessage("You are opening a blocked chest."); + + return true; + } +} diff --git a/src/com/lishid/openinv/internal/craftbukkit/InventoryAccess.java b/src/com/lishid/openinv/internal/craftbukkit/InventoryAccess.java new file mode 100644 index 0000000..600d6bf --- /dev/null +++ b/src/com/lishid/openinv/internal/craftbukkit/InventoryAccess.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.craftbukkit; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; + +import com.lishid.openinv.Permissions; +import com.lishid.openinv.internal.IInventoryAccess; + +//Volatile +import net.minecraft.server.*; +import org.bukkit.craftbukkit.inventory.*; + +public class InventoryAccess implements IInventoryAccess +{ + public boolean check(Inventory inventory, HumanEntity player) + { + IInventory inv = ((CraftInventory) inventory).getInventory(); + + if (inv instanceof SpecialPlayerInventory) + { + if (!player.hasPermission(Permissions.PERM_EDITINV)) + { + return false; + } + } + + else if (inv instanceof SpecialEnderChest) + { + if (!player.hasPermission(Permissions.PERM_EDITENDER)) + { + return false; + } + } + + return true; + } +} diff --git a/src/com/lishid/openinv/internal/craftbukkit/PlayerDataManager.java b/src/com/lishid/openinv/internal/craftbukkit/PlayerDataManager.java new file mode 100644 index 0000000..475ac05 --- /dev/null +++ b/src/com/lishid/openinv/internal/craftbukkit/PlayerDataManager.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.craftbukkit; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; + +//Volatile +import net.minecraft.server.*; +import org.bukkit.craftbukkit.*; + +public class PlayerDataManager implements IPlayerDataManager +{ + public Player loadPlayer(String name) + { + try + { + // Default player folder + File playerfolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "players"); + if (!playerfolder.exists()) + { + return null; + } + + String playername = matchUser(Arrays.asList(playerfolder.listFiles()), name); + + if (playername == null) + { + return null; + } + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Create an entity to load the player data + EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), playername, new ItemInWorldManager(server.getWorldServer(0))); + + // Get the bukkit entity + Player target = (entity == null) ? null : entity.getBukkitEntity(); + if (target != null) + { + // Load data + target.loadData(); + // Return the entity + return target; + } + } + catch (Exception e) + { + OpenInv.log(e); + } + + return null; + } + + /** + * @author Balor (aka Antoine Aflalo) + */ + private static String matchUser(final Collection container, final String search) + { + String found = null; + if (search == null) + { + return found; + } + final String lowerSearch = search.toLowerCase(); + int delta = Integer.MAX_VALUE; + for (final File file : container) + { + final String filename = file.getName(); + final String str = filename.substring(0, filename.length() - 4); + if (!str.toLowerCase().startsWith(lowerSearch)) + { + continue; + } + final int curDelta = str.length() - lowerSearch.length(); + if (curDelta < delta) + { + found = str; + delta = curDelta; + } + if (curDelta == 0) + { + break; + } + + } + return found; + } +} diff --git a/src/lishid/openinv/utils/SilentContainerChest.java b/src/com/lishid/openinv/internal/craftbukkit/SilentContainerChest.java similarity index 82% rename from src/lishid/openinv/utils/SilentContainerChest.java rename to src/com/lishid/openinv/internal/craftbukkit/SilentContainerChest.java index 9e9fe40..7abae06 100644 --- a/src/lishid/openinv/utils/SilentContainerChest.java +++ b/src/com/lishid/openinv/internal/craftbukkit/SilentContainerChest.java @@ -14,11 +14,10 @@ * along with this program. If not, see . */ -package lishid.openinv.utils; +package com.lishid.openinv.internal.craftbukkit; -import net.minecraft.server.ContainerChest; -import net.minecraft.server.EntityHuman; -import net.minecraft.server.IInventory; +//Volatile +import net.minecraft.server.*; public class SilentContainerChest extends ContainerChest { @@ -35,6 +34,6 @@ public class SilentContainerChest extends ContainerChest @Override public void b(EntityHuman paramEntityHuman) { - + // Don't send close signal twice, might screw up } } \ No newline at end of file diff --git a/src/lishid/openinv/utils/OpenInvEnderChest.java b/src/com/lishid/openinv/internal/craftbukkit/SpecialEnderChest.java similarity index 71% rename from src/lishid/openinv/utils/OpenInvEnderChest.java rename to src/com/lishid/openinv/internal/craftbukkit/SpecialEnderChest.java index 940eff5..9a36361 100644 --- a/src/lishid/openinv/utils/OpenInvEnderChest.java +++ b/src/com/lishid/openinv/internal/craftbukkit/SpecialEnderChest.java @@ -14,40 +14,46 @@ * along with this program. If not, see . */ -package lishid.openinv.utils; +package com.lishid.openinv.internal.craftbukkit; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; -import lishid.openinv.OpenInv; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.ISpecialEnderChest; -import org.bukkit.craftbukkit.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; -import net.minecraft.server.EntityHuman; -import net.minecraft.server.IInventory; -import net.minecraft.server.InventoryEnderChest; -import net.minecraft.server.InventorySubcontainer; -import net.minecraft.server.ItemStack; +//Volatile +import net.minecraft.server.*; +import org.bukkit.craftbukkit.entity.*; +import org.bukkit.craftbukkit.inventory.*; -public class OpenInvEnderChest extends InventorySubcontainer implements IInventory +public class SpecialEnderChest extends InventorySubcontainer implements IInventory, ISpecialEnderChest { public List transaction = new ArrayList(); public boolean playerOnline = false; private CraftPlayer owner; private InventoryEnderChest enderChest; private int maxStack = MAX_STACK; + private CraftInventory inventory = new CraftInventory(this); - public OpenInvEnderChest(CraftPlayer player, boolean online) + public SpecialEnderChest(Player p, Boolean online) { - super(player.getHandle().getEnderChest().getName(), player.getHandle().getEnderChest().getSize()); + super(((CraftPlayer) p).getHandle().getEnderChest().getName(), ((CraftPlayer) p).getHandle().getEnderChest().getSize()); + CraftPlayer player = (CraftPlayer) p; this.enderChest = player.getHandle().getEnderChest(); this.owner = player; this.items = enderChest.getContents(); - this.InventoryRemovalCheck(); + } + + public Inventory getBukkitInventory() + { + return inventory; } public void InventoryRemovalCheck() @@ -59,13 +65,13 @@ public class OpenInvEnderChest extends InventorySubcontainer implements IInvento } } - public void PlayerGoOnline(CraftPlayer p) + public void PlayerGoOnline(Player p) { if (!playerOnline) { try { - InventoryEnderChest playerEnderChest = p.getHandle().getEnderChest(); + InventoryEnderChest playerEnderChest = ((CraftPlayer) p).getHandle().getEnderChest(); Field field = playerEnderChest.getClass().getField("items"); field.setAccessible(true); field.set(playerEnderChest, this.items); diff --git a/src/lishid/openinv/utils/OpenInvPlayerInventory.java b/src/com/lishid/openinv/internal/craftbukkit/SpecialPlayerInventory.java similarity index 82% rename from src/lishid/openinv/utils/OpenInvPlayerInventory.java rename to src/com/lishid/openinv/internal/craftbukkit/SpecialPlayerInventory.java index 7171cca..f3dd95b 100644 --- a/src/lishid/openinv/utils/OpenInvPlayerInventory.java +++ b/src/com/lishid/openinv/internal/craftbukkit/SpecialPlayerInventory.java @@ -14,39 +14,42 @@ * along with this program. If not, see . */ -package lishid.openinv.utils; +package com.lishid.openinv.internal.craftbukkit; -import lishid.openinv.OpenInv; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; -import org.bukkit.craftbukkit.entity.CraftHumanEntity; -import org.bukkit.craftbukkit.entity.CraftPlayer; +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.ISpecialPlayerInventory; -import net.minecraft.server.EntityHuman; -import net.minecraft.server.ItemStack; -import net.minecraft.server.PlayerInventory; +//Volatile +import net.minecraft.server.*; +import org.bukkit.craftbukkit.entity.*; +import org.bukkit.craftbukkit.inventory.*; -public class OpenInvPlayerInventory extends PlayerInventory +public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory { CraftPlayer owner; public boolean playerOnline = false; private ItemStack[] extra = new ItemStack[5]; + private CraftInventory inventory = new CraftInventory(this); - public OpenInvPlayerInventory(CraftPlayer p, boolean online) + public SpecialPlayerInventory(Player p, Boolean online) { - super(p.getHandle()); - this.owner = p; + super(((CraftPlayer) p).getHandle()); + this.owner = ((CraftPlayer) p); this.playerOnline = online; this.items = player.inventory.items; this.armor = player.inventory.armor; } - + @Override - public void onClose(CraftHumanEntity who) + public Inventory getBukkitInventory() { - super.onClose(who); - this.InventoryRemovalCheck(); + return inventory; } + @Override public void InventoryRemovalCheck() { if (transaction.isEmpty() && !playerOnline) @@ -56,10 +59,12 @@ public class OpenInvPlayerInventory extends PlayerInventory } } - public void PlayerGoOnline(CraftPlayer p) + @Override + public void PlayerGoOnline(Player player) { if (!playerOnline) { + CraftPlayer p = (CraftPlayer) player; p.getHandle().inventory.items = this.items; p.getHandle().inventory.armor = this.armor; p.saveData(); @@ -67,11 +72,19 @@ public class OpenInvPlayerInventory extends PlayerInventory } } + @Override public void PlayerGoOffline() { playerOnline = false; } - + + @Override + public void onClose(CraftHumanEntity who) + { + super.onClose(who); + this.InventoryRemovalCheck(); + } + @Override public ItemStack[] getContents() { @@ -80,13 +93,13 @@ public class OpenInvPlayerInventory extends PlayerInventory System.arraycopy(items, 0, C, items.length, armor.length); return C; } - + @Override public int getSize() { return super.getSize() + 5; } - + @Override public ItemStack getItem(int i) { @@ -114,7 +127,7 @@ public class OpenInvPlayerInventory extends PlayerInventory return is[i]; } - + @Override public ItemStack splitStack(int i, int j) { @@ -166,7 +179,7 @@ public class OpenInvPlayerInventory extends PlayerInventory return null; } } - + @Override public ItemStack splitWithoutUpdate(int i) { @@ -204,7 +217,7 @@ public class OpenInvPlayerInventory extends PlayerInventory return null; } } - + @Override public void setItem(int i, ItemStack itemstack) { @@ -266,7 +279,7 @@ public class OpenInvPlayerInventory extends PlayerInventory else return i; } - + @Override public String getName() { diff --git a/src/com/lishid/openinv/internal/v1_4_5/AnySilentChest.java b/src/com/lishid/openinv/internal/v1_4_5/AnySilentChest.java new file mode 100644 index 0000000..153589c --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_4_5/AnySilentChest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.v1_4_5; + +import java.lang.reflect.Field; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import com.lishid.openinv.internal.IAnySilentChest; + +//Volatile +import net.minecraft.server.v1_4_5.*; +import org.bukkit.craftbukkit.v1_4_5.entity.*; + +public class AnySilentChest implements IAnySilentChest +{ + public boolean IsAnyChestNeeded(Player p, int x, int y, int z) + { + // FOR REFERENCE, LOOK AT net.minecraft.server.BlockChest + EntityPlayer player = ((CraftPlayer) p).getHandle(); + World world = player.world; + // If block on top + if (world.s(x, y + 1, z)) + return true; + + // If block next to chest is chest and has a block on top + if ((world.getTypeId(x - 1, y, z) == Block.CHEST.id) && (world.s(x - 1, y + 1, z))) + return true; + if ((world.getTypeId(x + 1, y, z) == Block.CHEST.id) && (world.s(x + 1, y + 1, z))) + return true; + if ((world.getTypeId(x, y, z - 1) == Block.CHEST.id) && (world.s(x, y + 1, z - 1))) + return true; + if ((world.getTypeId(x, y, z + 1) == Block.CHEST.id) && (world.s(x, y + 1, z + 1))) + return true; + + return false; + } + + public boolean ActivateChest(Player p, boolean anychest, boolean silentchest, int x, int y, int z) + { + EntityPlayer player = ((CraftPlayer) p).getHandle(); + World world = player.world; + Object chest = (TileEntityChest) world.getTileEntity(x, y, z); + if (chest == null) + return true; + + if (!anychest) + { + if (world.s(x, y + 1, z)) + return true; + if ((world.getTypeId(x - 1, y, z) == Block.CHEST.id) && (world.s(x - 1, y + 1, z))) + return true; + if ((world.getTypeId(x + 1, y, z) == Block.CHEST.id) && (world.s(x + 1, y + 1, z))) + return true; + if ((world.getTypeId(x, y, z - 1) == Block.CHEST.id) && (world.s(x, y + 1, z - 1))) + return true; + if ((world.getTypeId(x, y, z + 1) == Block.CHEST.id) && (world.s(x, y + 1, z + 1))) + return true; + } + + if (world.getTypeId(x - 1, y, z) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x - 1, y, z), (IInventory) chest); + if (world.getTypeId(x + 1, y, z) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x + 1, y, z)); + if (world.getTypeId(x, y, z - 1) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x, y, z - 1), (IInventory) chest); + if (world.getTypeId(x, y, z + 1) == Block.CHEST.id) + chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x, y, z + 1)); + + if (!silentchest) + { + player.openContainer((IInventory) chest); + } + else + { + try + { + int id = 0; + try + { + Field windowID = player.getClass().getDeclaredField("containerCounter"); + windowID.setAccessible(true); + id = windowID.getInt(player); + id = id % 100 + 1; + windowID.setInt(player, id); + } + catch (NoSuchFieldException e) + { + } + + player.netServerHandler.sendPacket(new Packet100OpenWindow(id, 0, ((IInventory) chest).getName(), ((IInventory) chest).getSize())); + player.activeContainer = new SilentContainerChest(player.inventory, ((IInventory) chest)); + player.activeContainer.windowId = id; + player.activeContainer.addSlotListener(player); + // event.getPlayer().sendMessage("You are opening a chest silently."); + return false; + } + catch (Exception e) + { + e.printStackTrace(); + p.sendMessage(ChatColor.RED + "Error while sending silent chest."); + } + } + + if (anychest) + p.sendMessage("You are opening a blocked chest."); + + return true; + } +} diff --git a/src/com/lishid/openinv/internal/v1_4_5/InventoryAccess.java b/src/com/lishid/openinv/internal/v1_4_5/InventoryAccess.java new file mode 100644 index 0000000..62cc418 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_4_5/InventoryAccess.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.v1_4_5; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; + +import com.lishid.openinv.Permissions; +import com.lishid.openinv.internal.IInventoryAccess; + +//Volatile +import net.minecraft.server.v1_4_5.*; +import org.bukkit.craftbukkit.v1_4_5.inventory.*; + +public class InventoryAccess implements IInventoryAccess +{ + public boolean check(Inventory inventory, HumanEntity player) + { + IInventory inv = ((CraftInventory) inventory).getInventory(); + + if (inv instanceof SpecialPlayerInventory) + { + if (!player.hasPermission(Permissions.PERM_EDITINV)) + { + return false; + } + } + + else if (inv instanceof SpecialEnderChest) + { + if (!player.hasPermission(Permissions.PERM_EDITENDER)) + { + return false; + } + } + + return true; + } +} diff --git a/src/com/lishid/openinv/internal/v1_4_5/PlayerDataManager.java b/src/com/lishid/openinv/internal/v1_4_5/PlayerDataManager.java new file mode 100644 index 0000000..5c889bd --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_4_5/PlayerDataManager.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.v1_4_5; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IPlayerDataManager; + +//Volatile +import net.minecraft.server.v1_4_5.*; +import org.bukkit.craftbukkit.v1_4_5.*; + +public class PlayerDataManager implements IPlayerDataManager +{ + public Player loadPlayer(String name) + { + try + { + // Default player folder + File playerfolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "players"); + if (!playerfolder.exists()) + { + return null; + } + + String playername = matchUser(Arrays.asList(playerfolder.listFiles()), name); + + if (playername == null) + { + return null; + } + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Create an entity to load the player data + EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), playername, new ItemInWorldManager(server.getWorldServer(0))); + + // Get the bukkit entity + Player target = (entity == null) ? null : entity.getBukkitEntity(); + if (target != null) + { + // Load data + target.loadData(); + // Return the entity + return target; + } + } + catch (Exception e) + { + OpenInv.log(e); + } + + return null; + } + + /** + * @author Balor (aka Antoine Aflalo) + */ + private static String matchUser(final Collection container, final String search) + { + String found = null; + if (search == null) + { + return found; + } + final String lowerSearch = search.toLowerCase(); + int delta = Integer.MAX_VALUE; + for (final File file : container) + { + final String filename = file.getName(); + final String str = filename.substring(0, filename.length() - 4); + if (!str.toLowerCase().startsWith(lowerSearch)) + { + continue; + } + final int curDelta = str.length() - lowerSearch.length(); + if (curDelta < delta) + { + found = str; + delta = curDelta; + } + if (curDelta == 0) + { + break; + } + + } + return found; + } +} diff --git a/src/com/lishid/openinv/internal/v1_4_5/SilentContainerChest.java b/src/com/lishid/openinv/internal/v1_4_5/SilentContainerChest.java new file mode 100644 index 0000000..44b79c7 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_4_5/SilentContainerChest.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.v1_4_5; + +//Volatile +import net.minecraft.server.v1_4_5.*; + +public class SilentContainerChest extends ContainerChest +{ + public IInventory inv; + + public SilentContainerChest(IInventory i1, IInventory i2) + { + super(i1, i2); + inv = i2; + // close signal + inv.f(); + } + + @Override + public void b(EntityHuman paramEntityHuman) + { + // Don't send close signal twice, might screw up + } +} \ No newline at end of file diff --git a/src/com/lishid/openinv/internal/v1_4_5/SpecialEnderChest.java b/src/com/lishid/openinv/internal/v1_4_5/SpecialEnderChest.java new file mode 100644 index 0000000..e114941 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_4_5/SpecialEnderChest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.v1_4_5; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.ISpecialEnderChest; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; + +//Volatile +import net.minecraft.server.v1_4_5.*; +import org.bukkit.craftbukkit.v1_4_5.entity.*; +import org.bukkit.craftbukkit.v1_4_5.inventory.*; + +public class SpecialEnderChest extends InventorySubcontainer implements IInventory, ISpecialEnderChest +{ + public List transaction = new ArrayList(); + public boolean playerOnline = false; + private CraftPlayer owner; + private InventoryEnderChest enderChest; + private int maxStack = MAX_STACK; + private CraftInventory inventory = new CraftInventory(this); + + public SpecialEnderChest(Player p, Boolean online) + { + super(((CraftPlayer) p).getHandle().getEnderChest().getName(), ((CraftPlayer) p).getHandle().getEnderChest().getSize()); + CraftPlayer player = (CraftPlayer) p; + this.enderChest = player.getHandle().getEnderChest(); + this.owner = player; + this.items = enderChest.getContents(); + } + + public Inventory getBukkitInventory() + { + return inventory; + } + + public void InventoryRemovalCheck() + { + if (transaction.isEmpty() && !playerOnline) + { + owner.saveData(); + OpenInv.enderChests.remove(owner.getName().toLowerCase()); + } + } + + public void PlayerGoOnline(Player p) + { + if (!playerOnline) + { + try + { + InventoryEnderChest playerEnderChest = ((CraftPlayer) p).getHandle().getEnderChest(); + Field field = playerEnderChest.getClass().getField("items"); + field.setAccessible(true); + field.set(playerEnderChest, this.items); + } + catch (Exception e) + { + } + p.saveData(); + playerOnline = true; + } + } + + public void PlayerGoOffline() + { + playerOnline = false; + } + + public ItemStack[] getContents() + { + return this.items; + } + + public void onOpen(CraftHumanEntity who) + { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) + { + transaction.remove(who); + } + + public List getViewers() + { + return transaction; + } + + public InventoryHolder getOwner() + { + return this.owner; + } + + public void setMaxStackSize(int size) + { + maxStack = size; + } + + public int getMaxStackSize() + { + return maxStack; + } + + public boolean a(EntityHuman entityhuman) + { + return true; + } + + public void startOpen() + { + + } + + public void f() + { + + } + + public void update() + { + enderChest.update(); + } +} diff --git a/src/com/lishid/openinv/internal/v1_4_5/SpecialPlayerInventory.java b/src/com/lishid/openinv/internal/v1_4_5/SpecialPlayerInventory.java new file mode 100644 index 0000000..5b81c4f --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_4_5/SpecialPlayerInventory.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2011-2012 lishid. All rights reserved. + * + * 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, version 3. + * + * 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 . + */ + +package com.lishid.openinv.internal.v1_4_5; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.ISpecialPlayerInventory; + +//Volatile +import net.minecraft.server.v1_4_5.*; +import org.bukkit.craftbukkit.v1_4_5.entity.*; +import org.bukkit.craftbukkit.v1_4_5.inventory.*; + +public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory +{ + CraftPlayer owner; + public boolean playerOnline = false; + private ItemStack[] extra = new ItemStack[5]; + private CraftInventory inventory = new CraftInventory(this); + + public SpecialPlayerInventory(Player p, Boolean online) + { + super(((CraftPlayer) p).getHandle()); + this.owner = ((CraftPlayer) p); + this.playerOnline = online; + this.items = player.inventory.items; + this.armor = player.inventory.armor; + } + + @Override + public Inventory getBukkitInventory() + { + return inventory; + } + + @Override + public void InventoryRemovalCheck() + { + if (transaction.isEmpty() && !playerOnline) + { + owner.saveData(); + OpenInv.inventories.remove(owner.getName().toLowerCase()); + } + } + + @Override + public void PlayerGoOnline(Player player) + { + if (!playerOnline) + { + CraftPlayer p = (CraftPlayer) player; + p.getHandle().inventory.items = this.items; + p.getHandle().inventory.armor = this.armor; + p.saveData(); + playerOnline = true; + } + } + + @Override + public void PlayerGoOffline() + { + playerOnline = false; + } + + @Override + public void onClose(CraftHumanEntity who) + { + super.onClose(who); + this.InventoryRemovalCheck(); + } + + @Override + public ItemStack[] getContents() + { + ItemStack[] C = new ItemStack[getSize()]; + System.arraycopy(items, 0, C, 0, items.length); + System.arraycopy(items, 0, C, items.length, armor.length); + return C; + } + + @Override + public int getSize() + { + return super.getSize() + 5; + } + + @Override + public ItemStack getItem(int i) + { + ItemStack[] is = this.items; + + if (i >= is.length) + { + i -= is.length; + is = this.armor; + } + else + { + i = getReversedItemSlotNum(i); + } + + if (i >= is.length) + { + i -= is.length; + is = this.extra; + } + else if (is == this.armor) + { + i = getReversedArmorSlotNum(i); + } + + return is[i]; + } + + @Override + public ItemStack splitStack(int i, int j) + { + ItemStack[] is = this.items; + + if (i >= is.length) + { + i -= is.length; + is = this.armor; + } + else + { + i = getReversedItemSlotNum(i); + } + + if (i >= is.length) + { + i -= is.length; + is = this.extra; + } + else if (is == this.armor) + { + i = getReversedArmorSlotNum(i); + } + + if (is[i] != null) + { + ItemStack itemstack; + + if (is[i].count <= j) + { + itemstack = is[i]; + is[i] = null; + return itemstack; + } + else + { + itemstack = is[i].a(j); + if (is[i].count == 0) + { + is[i] = null; + } + + return itemstack; + } + } + else + { + return null; + } + } + + @Override + public ItemStack splitWithoutUpdate(int i) + { + ItemStack[] is = this.items; + + if (i >= is.length) + { + i -= is.length; + is = this.armor; + } + else + { + i = getReversedItemSlotNum(i); + } + + if (i >= is.length) + { + i -= is.length; + is = this.extra; + } + else if (is == this.armor) + { + i = getReversedArmorSlotNum(i); + } + + if (is[i] != null) + { + ItemStack itemstack = is[i]; + + is[i] = null; + return itemstack; + } + else + { + return null; + } + } + + @Override + public void setItem(int i, ItemStack itemstack) + { + ItemStack[] is = this.items; + + if (i >= is.length) + { + i -= is.length; + is = this.armor; + } + else + { + i = getReversedItemSlotNum(i); + } + + if (i >= is.length) + { + i -= is.length; + is = this.extra; + } + else if (is == this.armor) + { + i = getReversedArmorSlotNum(i); + } + + /* + * + * //Effects + * if(is == this.extra) + * { + * if(i == 0) + * { + * itemstack.setData(0); + * } + * } + */ + + is[i] = itemstack; + } + + private int getReversedItemSlotNum(int i) + { + if (i >= 27) + return i - 27; + else + return i + 9; + } + + private int getReversedArmorSlotNum(int i) + { + if (i == 0) + return 3; + if (i == 1) + return 2; + if (i == 2) + return 1; + if (i == 3) + return 0; + else + return i; + } + + @Override + public String getName() + { + if (player.name.length() > 16) + { + return player.name.substring(0, 16); + } + return player.name; + } + + @Override + public boolean a_(EntityHuman entityhuman) + { + return true; + } +} \ No newline at end of file diff --git a/src/lishid/openinv/utils/Metrics.java b/src/com/lishid/openinv/utils/Metrics.java similarity index 96% rename from src/lishid/openinv/utils/Metrics.java rename to src/com/lishid/openinv/utils/Metrics.java index ec915b1..7bcce5b 100644 --- a/src/lishid/openinv/utils/Metrics.java +++ b/src/com/lishid/openinv/utils/Metrics.java @@ -1,4 +1,4 @@ -package lishid.openinv.utils; +package com.lishid.openinv.utils; /* * Copyright 2011 Tyler Blair. All rights reserved. diff --git a/src/com/lishid/openinv/utils/UpdateManager.java b/src/com/lishid/openinv/utils/UpdateManager.java new file mode 100644 index 0000000..e41f16f --- /dev/null +++ b/src/com/lishid/openinv/utils/UpdateManager.java @@ -0,0 +1,33 @@ +package com.lishid.openinv.utils; + +import java.io.File; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.utils.Updater.UpdateResult; +import com.lishid.openinv.utils.Updater.UpdateType; + +public class UpdateManager +{ + public Updater updater; + + public void Initialize(OpenInv plugin, File file) + { + updater = new Updater(plugin, OpenInv.logger, "openinv", file); + + // Create task to update + plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() + { + @Override + public void run() + { + // Check for updates + if (OpenInv.GetCheckForUpdates()) + { + UpdateResult result = updater.update(UpdateType.DEFAULT); + if (result != UpdateResult.NO_UPDATE) + OpenInv.log(result.toString()); + } + } + }, 0, 20 * 60 * 1000); // Update every once a while + } +} diff --git a/src/com/lishid/openinv/utils/Updater.java b/src/com/lishid/openinv/utils/Updater.java new file mode 100644 index 0000000..7edc8f0 --- /dev/null +++ b/src/com/lishid/openinv/utils/Updater.java @@ -0,0 +1,571 @@ +package com.lishid.openinv.utils; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; + +import com.google.common.base.Preconditions; + +/** + * Check dev.bukkit.org to find updates for a given plugin, and download the updates if needed. + *

+ * VERY, VERY IMPORTANT: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed + * auto-updating.
+ * It is a BUKKIT POLICY that you include a boolean value in your config that prevents the auto-updater from running AT ALL.
+ * If you fail to include this option in your config, your plugin will be REJECTED when you attempt to submit it to dev.bukkit.org. + *

+ * An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater.
+ * If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l + * + * @author H31IX + */ + +public class Updater +{ + // If the version number contains one of these, don't update. + private static final String[] noUpdateTag = { "test", "unstable" }; + + // Slugs will be appended to this to get to the project's RSS feed + private static final String DBOUrl = "http://dev.bukkit.org/server-mods/"; + private static final int BYTE_SIZE = 1024; // Used for downloading files + + private final Plugin plugin; + private final String slug; + + private volatile long totalSize; // Holds the total size of the file + private volatile int sizeLine; // Used for detecting file size + private volatile int multiplier; // Used for determining when to broadcast download updates + + private volatile URL url; // Connecting to RSS + + private volatile String updateFolder = YamlConfiguration.loadConfiguration(new File("bukkit.yml")).getString("settings.update-folder"); // The folder that downloads will be placed in + + // Used for determining the outcome of the update process + private volatile Updater.UpdateResult result = Updater.UpdateResult.SUCCESS; + + // Whether to announce file downloads + private volatile boolean announce = false; + + private volatile UpdateType type; + private volatile String versionTitle; + private volatile String versionLink; + + private volatile String versionDownloaded = ""; + private volatile File file; + + // Used to announce progress + private volatile Logger logger; + + // Strings for reading RSS + private static final String TITLE = "title"; + private static final String LINK = "link"; + private static final String ITEM = "item"; + + /** + * Gives the dev the result of the update process. Can be obtained by called getResult(). + */ + public enum UpdateResult + { + /** + * The updater found an update, and has readied it to be loaded the next time the server restarts/reloads. + */ + SUCCESS(1, "The updater found an update, and has readied it to be loaded the next time the server restarts/reloads."), + + /** + * The updater did not find an update, and nothing was downloaded. + */ + NO_UPDATE(2, "The updater did not find an update, and nothing was downloaded."), + + /** + * The updater found an update, but was unable to download it. + */ + FAIL_DOWNLOAD(3, "The updater found an update, but was unable to download it."), + + /** + * For some reason, the updater was unable to contact dev.bukkit.org to download the file. + */ + FAIL_DBO(4, "For some reason, the updater was unable to contact dev.bukkit.org to download the file."), + + /** + * When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'. + */ + FAIL_NOVERSION(5, "When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'."), + + /** + * The slug provided by the plugin running the updater was invalid and doesn't exist on DBO. + */ + FAIL_BADSLUG(6, "The slug provided by the plugin running the updater was invalid and doesn't exist on DBO."), + + /** + * The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded. + */ + UPDATE_AVAILABLE(7, "The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded."); + + private static final Map valueList = new HashMap(); + private final int value; + private final String description; + + private UpdateResult(int value, String description) + { + this.value = value; + this.description = description; + } + + public int getValue() + { + return this.value; + } + + public static Updater.UpdateResult getResult(int value) + { + return valueList.get(value); + } + + @Override + public String toString() + { + return description; + } + + static + { + for (Updater.UpdateResult result : Updater.UpdateResult.values()) + { + valueList.put(result.value, result); + } + } + } + + /** + * Allows the dev to specify the type of update that will be run. + */ + public enum UpdateType + { + /** + * Run a version check, and then if the file is out of date, download the newest version. + */ + DEFAULT(1), + /** + * Don't run a version check, just find the latest update and download it. + */ + NO_VERSION_CHECK(2), + /** + * Get information about the version and the download size, but don't actually download anything. + */ + NO_DOWNLOAD(3); + + private static final Map valueList = new HashMap(); + private final int value; + + private UpdateType(int value) + { + this.value = value; + } + + public int getValue() + { + return this.value; + } + + public static Updater.UpdateType getResult(int value) + { + return valueList.get(value); + } + + static + { + for (Updater.UpdateType result : Updater.UpdateType.values()) + { + valueList.put(result.value, result); + } + } + } + + /** + * Initialize the updater + * + * @param plugin + * The plugin that is checking for an update. + * @param slug + * The dev.bukkit.org slug of the project (http://dev.bukkit.org/server-mods/SLUG_IS_HERE) + * @param file + * The file that the plugin is running from, get this by doing this.getFile() from within your main class. + * @param permission + * Permission needed to read the output of the update process. + */ + public Updater(Plugin plugin, Logger logger, String slug, File file) + { + // I hate NULL + Preconditions.checkNotNull(plugin, "plugin"); + Preconditions.checkNotNull(logger, "logger"); + Preconditions.checkNotNull(slug, "slug"); + Preconditions.checkNotNull(file, "file"); + + this.plugin = plugin; + this.file = file; + this.slug = slug; + this.logger = logger; + } + + /** + * Update the plugin. + * + * @param type + * Specify the type of update this will be. See {@link UpdateType} + * @return The result of the update process. + */ + public synchronized UpdateResult update(UpdateType type) + { + this.type = type; + + try + { + // Obtain the results of the project's file feed + url = null; + url = new URL(DBOUrl + slug + "/files.rss"); + } + catch (MalformedURLException ex) + { + // The slug doesn't exist + logger.warning("The author of this plugin has misconfigured their Auto Update system"); + logger.warning("The project slug added ('" + slug + "') is invalid, and does not exist on dev.bukkit.org"); + result = Updater.UpdateResult.FAIL_BADSLUG; // Bad slug! Bad! + } + if (url != null) + { + // Obtain the results of the project's file feed + readFeed(); + if (!versionTitle.equals(versionDownloaded) && versionCheck(versionTitle)) + { + String fileLink = getFile(versionLink); + if (fileLink != null && type != UpdateType.NO_DOWNLOAD) + { + String name = file.getName(); + saveFile(new File("plugins/" + updateFolder), name, fileLink); + versionDownloaded = versionTitle; + } + else + { + result = UpdateResult.UPDATE_AVAILABLE; + } + } + } + + return result; + } + + /** + * Get the result of the update process. + */ + public Updater.UpdateResult getResult() + { + return result; + } + + /** + * Get the total bytes of the file (can only be used after running a version check or a normal run). + */ + public long getFileSize() + { + return totalSize; + } + + /** + * Get the version string latest file avaliable online. + */ + public String getLatestVersionString() + { + return versionTitle; + } + + /** + * Save an update from dev.bukkit.org into the server's update folder. + */ + private void saveFile(File folder, String file, String u) + { + if (!folder.exists()) + { + folder.mkdir(); + } + BufferedInputStream in = null; + FileOutputStream fout = null; + try + { + // Download the file + URL url = new URL(u); + int fileLength = url.openConnection().getContentLength(); + in = new BufferedInputStream(url.openStream()); + fout = new FileOutputStream(folder.getAbsolutePath() + "/" + file); + + byte[] data = new byte[BYTE_SIZE]; + int count; + if (announce) + logger.info("About to download a new update: " + versionTitle); + long downloaded = 0; + while ((count = in.read(data, 0, BYTE_SIZE)) != -1) + { + downloaded += count; + fout.write(data, 0, count); + int percent = (int) (downloaded * 100 / fileLength); + if (announce && (percent % 10 == 0)) + { + logger.info("Downloading update: " + percent + "% of " + fileLength + " bytes."); + } + } + + if (announce) + logger.info("Finished updating."); + } + catch (Exception ex) + { + logger.warning("The auto-updater tried to download a new update, but was unsuccessful."); + logger.log(Level.INFO, "Error message to submit as a ticket.", ex); + result = Updater.UpdateResult.FAIL_DOWNLOAD; + } + finally + { + try + { + if (in != null) + { + in.close(); + } + if (fout != null) + { + fout.close(); + } + } + catch (Exception ex) + { + } + } + } + + /** + * Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip. + */ + public boolean pluginFile(String name) + { + for (File file : new File("plugins").listFiles()) + { + if (file.getName().equals(name)) + { + return true; + } + } + return false; + } + + /** + * Obtain the direct download file url from the file's page. + */ + private String getFile(String link) + { + String download = null; + try + { + // Open a connection to the page + URL url = new URL(link); + URLConnection urlConn = url.openConnection(); + InputStreamReader inStream = new InputStreamReader(urlConn.getInputStream()); + BufferedReader buff = new BufferedReader(inStream); + + int counter = 0; + String line; + while ((line = buff.readLine()) != null) + { + counter++; + // Search for the download link + if (line.contains("

  • ")) + { + // Get the raw link + download = line.split("Download")[0]; + } + // Search for size + else if (line.contains("
    Size
    ")) + { + sizeLine = counter + 1; + } + else if (counter == sizeLine) + { + String size = line.replaceAll("
    ", "").replaceAll("
    ", ""); + multiplier = size.contains("MiB") ? 1048576 : 1024; + size = size.replace(" KiB", "").replace(" MiB", ""); + totalSize = (long) (Double.parseDouble(size) * multiplier); + } + } + urlConn = null; + inStream = null; + buff.close(); + buff = null; + } + catch (Exception ex) + { + ex.printStackTrace(); + logger.warning("The auto-updater tried to contact dev.bukkit.org, but was unsuccessful."); + result = Updater.UpdateResult.FAIL_DBO; + return null; + } + return download; + } + + /** + * Check to see if the program should continue by evaluation whether the plugin is already updated, or shouldn't be updated + */ + private boolean versionCheck(String title) + { + if (type != UpdateType.NO_VERSION_CHECK) + { + String[] parts = title.split(" "); + String version = plugin.getDescription().getVersion(); + + if (parts.length >= 2) + { + String remoteVersion = parts[1].split(" ")[0]; // Get the newest file's version number + int remVer = -1, curVer = 0; + try + { + remVer = calVer(remoteVersion); + curVer = calVer(version); + } + catch (NumberFormatException nfe) + { + remVer = -1; + } + + if (hasTag(version) || version.equalsIgnoreCase(remoteVersion) || curVer >= remVer) + { + // We already have the latest version, or this build is tagged for no-update + result = Updater.UpdateResult.NO_UPDATE; + return false; + } + } + else + { + // The file's name did not contain the string 'vVersion' + logger.warning("The author of this plugin has misconfigured their Auto Update system"); + logger.warning("Files uploaded to BukkitDev should contain the version number, seperated from the name by a 'v', such as PluginName v1.0"); + logger.warning("Please notify the author (" + plugin.getDescription().getAuthors().get(0) + ") of this error."); + result = Updater.UpdateResult.FAIL_NOVERSION; + return false; + } + } + return true; + } + + /** + * Used to calculate the version string as an Integer + */ + private Integer calVer(String s) throws NumberFormatException + { + if (s.contains(".")) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) + { + Character c = s.charAt(i); + if (Character.isLetterOrDigit(c)) + { + sb.append(c); + } + } + return Integer.parseInt(sb.toString()); + } + return Integer.parseInt(s); + } + + /** + * Evaluate whether the version number is marked showing that it should not be updated by this program + */ + private boolean hasTag(String version) + { + for (String string : noUpdateTag) + { + if (version.contains(string)) + { + return true; + } + } + return false; + } + + /** + * Part of RSS Reader by Vogella, modified by H31IX for use with Bukkit + */ + private void readFeed() + { + try + { + // Set header values intial to the empty string + String title = ""; + String link = ""; + // First create a new XMLInputFactory + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + // Setup a new eventReader + InputStream in = read(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(in); + // Read the XML document + while (eventReader.hasNext()) + { + XMLEvent event = eventReader.nextEvent(); + if (event.isStartElement()) + { + if (event.asStartElement().getName().getLocalPart().equals(TITLE)) + { + event = eventReader.nextEvent(); + title = event.asCharacters().getData(); + continue; + } + if (event.asStartElement().getName().getLocalPart().equals(LINK)) + { + event = eventReader.nextEvent(); + link = event.asCharacters().getData(); + continue; + } + } + else if (event.isEndElement()) + { + if (event.asEndElement().getName().getLocalPart().equals(ITEM)) + { + // Store the title and link of the first entry we get - the first file on the list is all we need + versionTitle = title; + versionLink = link; + // All done, we don't need to know about older files. + break; + } + } + } + } + catch (XMLStreamException e) + { + throw new RuntimeException(e); + } + } + + /** + * Open the RSS feed + */ + private InputStream read() + { + try + { + return url.openStream(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/src/lishid/openinv/OpenInvPlayerListener.java b/src/lishid/openinv/OpenInvPlayerListener.java deleted file mode 100644 index 1f4a070..0000000 --- a/src/lishid/openinv/OpenInvPlayerListener.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2011-2012 lishid. All rights reserved. - * - * 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, version 3. - * - * 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 . - */ - -package lishid.openinv; - -import java.lang.reflect.Field; - -import lishid.openinv.utils.OpenInvEnderChest; -import lishid.openinv.utils.OpenInvPlayerInventory; -import lishid.openinv.utils.SilentContainerChest; -import net.minecraft.server.Block; -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.IInventory; -import net.minecraft.server.InventoryLargeChest; -import net.minecraft.server.Packet100OpenWindow; -import net.minecraft.server.TileEntityChest; -import net.minecraft.server.World; - -import org.bukkit.ChatColor; -import org.bukkit.block.Chest; -import org.bukkit.block.Sign; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Event.Result; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -public class OpenInvPlayerListener implements Listener -{ - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerJoin(PlayerJoinEvent event) - { - OpenInvPlayerInventory inventory = OpenInv.inventories.get(event.getPlayer().getName().toLowerCase()); - - if (inventory != null) - { - inventory.PlayerGoOnline((CraftPlayer) event.getPlayer()); - } - - OpenInvEnderChest chest = OpenInv.enderChests.get(event.getPlayer().getName().toLowerCase()); - - if (chest != null) - { - chest.PlayerGoOnline((CraftPlayer) event.getPlayer()); - } - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerQuit(PlayerQuitEvent event) - { - OpenInvPlayerInventory inventory = OpenInv.inventories.get(event.getPlayer().getName().toLowerCase()); - if (inventory != null) - { - inventory.PlayerGoOffline(); - inventory.InventoryRemovalCheck(); - } - OpenInvEnderChest chest = OpenInv.enderChests.get(event.getPlayer().getName().toLowerCase()); - if (chest != null) - { - chest.PlayerGoOffline(); - chest.InventoryRemovalCheck(); - } - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerInteract(PlayerInteractEvent event) - { - if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.useInteractedBlock() == Result.DENY) - return; - - if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getState() instanceof Chest) - { - boolean silentchest = false; - boolean anychest = false; - int x = event.getClickedBlock().getX(); - int y = event.getClickedBlock().getY(); - int z = event.getClickedBlock().getZ(); - - if (event.getPlayer().hasPermission(Permissions.PERM_SILENT) && OpenInv.GetPlayerSilentChestStatus(event.getPlayer().getName())) - { - silentchest = true; - } - - if (event.getPlayer().hasPermission(Permissions.PERM_ANYCHEST) && OpenInv.GetPlayerAnyChestStatus(event.getPlayer().getName())) - { - try - { - // FOR REFERENCE, LOOK AT net.minecraft.server.BlockChest - EntityPlayer player = ((CraftPlayer) event.getPlayer()).getHandle(); - World world = player.world; - // If block on top - if (world.s(x, y + 1, z)) - anychest = true; - - // If block next to chest is chest and has a block on top - if ((world.getTypeId(x - 1, y, z) == Block.CHEST.id) && (world.s(x - 1, y + 1, z))) - anychest = true; - if ((world.getTypeId(x + 1, y, z) == Block.CHEST.id) && (world.s(x + 1, y + 1, z))) - anychest = true; - if ((world.getTypeId(x, y, z - 1) == Block.CHEST.id) && (world.s(x, y + 1, z - 1))) - anychest = true; - if ((world.getTypeId(x, y, z + 1) == Block.CHEST.id) && (world.s(x, y + 1, z + 1))) - anychest = true; - } - catch (Exception e) - { - event.getPlayer().sendMessage(ChatColor.RED + "Error while executing openinv. Unsupported CraftBukkit."); - e.printStackTrace(); - } - } - - // If the anychest or silentchest is active - if (anychest || silentchest) - { - EntityPlayer player = ((CraftPlayer) event.getPlayer()).getHandle(); - World world = player.world; - Object chest = (TileEntityChest) world.getTileEntity(x, y, z); - if (chest == null) - return; - - if (!anychest) - { - if (world.s(x, y + 1, z)) - return; - if ((world.getTypeId(x - 1, y, z) == Block.CHEST.id) && (world.s(x - 1, y + 1, z))) - return; - if ((world.getTypeId(x + 1, y, z) == Block.CHEST.id) && (world.s(x + 1, y + 1, z))) - return; - if ((world.getTypeId(x, y, z - 1) == Block.CHEST.id) && (world.s(x, y + 1, z - 1))) - return; - if ((world.getTypeId(x, y, z + 1) == Block.CHEST.id) && (world.s(x, y + 1, z + 1))) - return; - } - - if (world.getTypeId(x - 1, y, z) == Block.CHEST.id) - chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x - 1, y, z), (IInventory) chest); - if (world.getTypeId(x + 1, y, z) == Block.CHEST.id) - chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x + 1, y, z)); - if (world.getTypeId(x, y, z - 1) == Block.CHEST.id) - chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x, y, z - 1), (IInventory) chest); - if (world.getTypeId(x, y, z + 1) == Block.CHEST.id) - chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x, y, z + 1)); - - if (!silentchest) - { - player.openContainer((IInventory) chest); - } - else - { - try - { - int id = 0; - try - { - Field windowID = player.getClass().getDeclaredField("containerCounter"); - windowID.setAccessible(true); - id = windowID.getInt(player); - id = id % 100 + 1; - windowID.setInt(player, id); - } - catch (NoSuchFieldException e) - { - } - - player.netServerHandler.sendPacket(new Packet100OpenWindow(id, 0, ((IInventory) chest).getName(), ((IInventory) chest).getSize())); - player.activeContainer = new SilentContainerChest(player.inventory, ((IInventory) chest)); - player.activeContainer.windowId = id; - player.activeContainer.addSlotListener(player); - // event.getPlayer().sendMessage("You are opening a chest silently."); - event.setUseInteractedBlock(Result.DENY); - event.setCancelled(true); - } - catch (Exception e) - { - e.printStackTrace(); - event.getPlayer().sendMessage(ChatColor.RED + "Error while sending silent chest."); - } - } - - if (anychest) - event.getPlayer().sendMessage("You are opening a blocked chest."); - } - } - - if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getState() instanceof Sign) - { - Player player = event.getPlayer(); - try - { - Sign sign = ((Sign) event.getClickedBlock().getState()); - if (player.hasPermission(Permissions.PERM_OPENINV) && sign.getLine(0).equalsIgnoreCase("[openinv]")) - { - String text = sign.getLine(1).trim() + sign.getLine(2).trim() + sign.getLine(3).trim(); - player.performCommand("openinv " + text); - } - } - catch (Exception ex) - { - player.sendMessage("Internal Error."); - ex.printStackTrace(); - } - } - - if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) - { - Player player = event.getPlayer(); - - if (!(player.getItemInHand().getType().getId() == OpenInv.GetItemOpenInvItem()) || (!OpenInv.GetPlayerItemOpenInvStatus(player.getName())) || !player.hasPermission(Permissions.PERM_OPENINV)) - { - return; - } - - player.performCommand("openinv"); - } - } -} \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml index f131328..2570f5e 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,8 +1,7 @@ name: OpenInv -main: lishid.openinv.OpenInv -version: 1.9.0 +main: com.lishid.openinv.OpenInv +version: 1.9.2 author: lishid -website: http://forums.bukkit.org/threads/15379/ description: > This plugin allows you to open a player's inventory as a chest and interact with it in real time. commands: