From 9271c50a84371dbd7333463c7d72939b08daedca Mon Sep 17 00:00:00 2001 From: lishid Date: Fri, 11 Jul 2014 20:41:28 -0400 Subject: [PATCH] 2.1.8 --- src/com/lishid/openinv/OpenInv.java | 11 - .../internal/v1_7_R3/PlayerDataManager.java | 218 ++++-- .../internal/v1_7_R4/AnySilentChest.java | 124 ++++ .../internal/v1_7_R4/InventoryAccess.java | 48 ++ .../internal/v1_7_R4/PlayerDataManager.java | 199 +++++ .../v1_7_R4/SilentContainerChest.java | 36 + .../internal/v1_7_R4/SpecialEnderChest.java | 126 ++++ .../v1_7_R4/SpecialPlayerInventory.java | 253 +++++++ src/com/lishid/openinv/utils/Metrics.java | 696 ------------------ .../lishid/openinv/utils/ReflectionUtil.java | 510 +++++++++++++ src/plugin.yml | 2 +- 11 files changed, 1454 insertions(+), 769 deletions(-) create mode 100644 src/com/lishid/openinv/internal/v1_7_R4/AnySilentChest.java create mode 100644 src/com/lishid/openinv/internal/v1_7_R4/InventoryAccess.java create mode 100644 src/com/lishid/openinv/internal/v1_7_R4/PlayerDataManager.java create mode 100644 src/com/lishid/openinv/internal/v1_7_R4/SilentContainerChest.java create mode 100644 src/com/lishid/openinv/internal/v1_7_R4/SpecialEnderChest.java create mode 100644 src/com/lishid/openinv/internal/v1_7_R4/SpecialPlayerInventory.java delete mode 100644 src/com/lishid/openinv/utils/Metrics.java create mode 100644 src/com/lishid/openinv/utils/ReflectionUtil.java diff --git a/src/com/lishid/openinv/OpenInv.java b/src/com/lishid/openinv/OpenInv.java index 8929243..59d9d6d 100644 --- a/src/com/lishid/openinv/OpenInv.java +++ b/src/com/lishid/openinv/OpenInv.java @@ -33,7 +33,6 @@ 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; /** @@ -46,7 +45,6 @@ public class OpenInv extends JavaPlugin { public static HashMap inventories = new HashMap(); public static HashMap enderChests = new HashMap(); - private static Metrics metrics; private UpdateManager updater = new UpdateManager(); @@ -99,15 +97,6 @@ public class OpenInv extends JavaPlugin { getCommand("openender").setExecutor(new OpenEnderPluginCommand(this)); updater.Initialize(this, getFile()); - - // Metrics - try { - metrics = new Metrics(this); - metrics.start(); - } - catch (Exception e) { - OpenInv.log(e); - } } public static boolean NotifySilentChest() { diff --git a/src/com/lishid/openinv/internal/v1_7_R3/PlayerDataManager.java b/src/com/lishid/openinv/internal/v1_7_R3/PlayerDataManager.java index 8075724..dc67739 100644 --- a/src/com/lishid/openinv/internal/v1_7_R3/PlayerDataManager.java +++ b/src/com/lishid/openinv/internal/v1_7_R3/PlayerDataManager.java @@ -17,87 +17,183 @@ package com.lishid.openinv.internal.v1_7_R3; import java.io.File; -import java.util.Arrays; -import java.util.Collection; - -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; - -import com.lishid.openinv.OpenInv; -import com.lishid.openinv.internal.IPlayerDataManager; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.UUID; import net.minecraft.util.com.mojang.authlib.GameProfile; -//Volatile -import net.minecraft.server.v1_7_R3.*; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; -import org.bukkit.craftbukkit.v1_7_R3.*; - -public class PlayerDataManager implements IPlayerDataManager { - @Override - public Player loadPlayer(String name) { +import com.lishid.openinv.utils.ReflectionUtil; +import com.lishid.openinv.utils.ReflectionUtil.PackageType; +import com.lishid.openinv.utils.ReflectionUtil.SubPackageType; + +/** + * @author lishid, JuicyDev (reflection) + */ +public class PlayerDataManager { + + private Plugin plugin; + private String versionString; + private int version; + private static String playerFolderName; + + public PlayerDataManager(Plugin plugin) { + this.plugin = plugin; + + this.versionString = this.plugin + .getServer() + .getClass() + .getPackage() + .getName() + .substring( + this.plugin.getServer().getClass().getPackage() + .getName().lastIndexOf('.') + 1); try { - // Default player folder - File playerfolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "playerdata"); - if (!playerfolder.exists()) { + this.version = Integer.valueOf(versionString.replace("v", "") + .replace("_", "").replace("R", "")); + } catch (NumberFormatException e) { // Fallback + this.version = 173; + } + playerFolderName = version >= 173 ? "playerdata" : "players"; + } + + /** + * @param uuid + * UUID of the player + * @return Instance of the player (null if doesn't exist) + */ + public Player loadPlayer(UUID uuid) { + try { + File playerFolder = new File( + ((World) Bukkit.getWorlds().get(0)).getWorldFolder(), + playerFolderName); + if (!playerFolder.exists()) { return null; } - - OfflinePlayer player = Bukkit.getOfflinePlayer(name); - - if (player == null || matchUser(Arrays.asList(playerfolder.listFiles()), player.getUniqueId().toString()) == null) { - return null; - } - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - - GameProfile profile = new GameProfile(player.getUniqueId(), player.getName()); - // Create an entity to load the player data - EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), profile, new PlayerInteractManager(server.getWorldServer(0))); - - // Get the bukkit entity - Player target = (entity == null) ? null : entity.getBukkitEntity(); + + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + if (player == null) + return null; + + GameProfile profile = new GameProfile(player.getUniqueId(), + player.getName()); + + Class obc_CraftServer = ReflectionUtil.getClass("CraftServer", + PackageType.CRAFTBUKKIT); + Object craftServer = obc_CraftServer.cast(Bukkit.getServer()); + Method m_getServer = ReflectionUtil.getMethod(obc_CraftServer, + "getServer"); + Class nms_MinecraftServer = ReflectionUtil.getClass( + "MinecraftServer", PackageType.MINECRAFT_SERVER); + Object minecraftServer = m_getServer.invoke(craftServer); + + Class nms_EntityPlayer = ReflectionUtil.getClass("EntityPlayer", + PackageType.MINECRAFT_SERVER); + Class nms_WorldServer = ReflectionUtil.getClass("WorldServer", + PackageType.MINECRAFT_SERVER); + Class nms_PlayerInteractManager = ReflectionUtil.getClass( + "PlayerInteractManager", PackageType.MINECRAFT_SERVER); + Object worldServer = ReflectionUtil.getMethod(nms_MinecraftServer, + "getWorldServer", Integer.class).invoke(minecraftServer, 0); + + Constructor c_EntityPlayer = ReflectionUtil.getConstructor( + nms_EntityPlayer, nms_MinecraftServer, nms_WorldServer, + GameProfile.class, nms_PlayerInteractManager); + Constructor c_PlayerInteractManager = ReflectionUtil + .getConstructor(nms_PlayerInteractManager, nms_WorldServer); + Object playerInteractManager = c_PlayerInteractManager + .newInstance(worldServer); + + Object entityPlayer = c_EntityPlayer.newInstance(minecraftServer, + worldServer, profile, playerInteractManager); + + Class obc_CraftPlayer = ReflectionUtil.getClass("CraftPlayer", + SubPackageType.ENTITY); + Method m_getBukkitEntity = ReflectionUtil.getMethod( + nms_EntityPlayer, "getBukkitEntity"); + + Player target = entityPlayer == null ? null + : (Player) obc_CraftPlayer.cast(m_getBukkitEntity + .invoke(entityPlayer)); + if (target != null) { - // Load data target.loadData(); - // Return the entity return target; } + } catch (Exception e) { + e.printStackTrace(); } - catch (Exception e) { - OpenInv.log(e); - } - + return null; } - + /** - * @author Balor (aka Antoine Aflalo) + * @param name + * Name of the player + * @return Instance of the player (null if doesn't exist) */ - private static String matchUser(final Collection container, final String search) { - String found = null; - if (search == null) { - return found; + public Player loadPlayer(String name) { + try { + UUID uuid = matchUser(name); + if (uuid == null) + return null; + + Player target = loadPlayer(uuid); + if (target != null) { + return target; + } + } catch (Exception e) { + e.printStackTrace(); } - 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)) { + + return null; + } + + private static UUID matchUser(String search) { + File playerFolder = new File( + ((World) Bukkit.getWorlds().get(0)).getWorldFolder(), + playerFolderName); + if (!playerFolder.exists() || !playerFolder.isDirectory()) + return null; + if (search == null) + return null; + + UUID found = null; + + String lowerSearch = search.toLowerCase(); + int delta = 2147483647; + + for (File f : playerFolder.listFiles()) { + if (!f.getName().endsWith(".dat")) continue; + String uuidString = f.getName().substring(0, + f.getName().length() - 4); + UUID uuid = UUID.fromString(uuidString); + + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + String name = player.getName(); + + if (name.equalsIgnoreCase(search)) + return uuid; + + if (name.toLowerCase().startsWith(lowerSearch)) { + int curDelta = name.length() - lowerSearch.length(); + if (curDelta < delta) { + found = player.getUniqueId(); + delta = curDelta; + } + if (curDelta == 0) { + break; + } } - 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_7_R4/AnySilentChest.java b/src/com/lishid/openinv/internal/v1_7_R4/AnySilentChest.java new file mode 100644 index 0000000..76efb80 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_7_R4/AnySilentChest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2011-2014 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_7_R4; + +import java.lang.reflect.Field; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.internal.IAnySilentChest; + +//Volatile +import net.minecraft.server.v1_7_R4.*; + +import org.bukkit.craftbukkit.v1_7_R4.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.getType(x, y + 1, z).c()) + return true; + + int id = Block.getId(world.getType(x, y, z)); + + // If block next to chest is chest and has a block on top + if ((Block.getId(world.getType(x - 1, y, z)) == id) && (world.getType(x - 1, y + 1, z).c())) + return true; + if ((Block.getId(world.getType(x + 1, y, z)) == id) && (world.getType(x + 1, y + 1, z).c())) + return true; + if ((Block.getId(world.getType(x, y, z - 1)) == id) && (world.getType(x, y + 1, z - 1).c())) + return true; + if ((Block.getId(world.getType(x, y, z + 1)) == id) && (world.getType(x, y + 1, z + 1).c())) + 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; + + int id = Block.getId(world.getType(x, y, z)); + + if (!anychest) { + if (world.getType(x, y + 1, z).c()) + return true; + if ((Block.getId(world.getType(x - 1, y, z)) == id) && (world.getType(x - 1, y + 1, z).c())) + return true; + if ((Block.getId(world.getType(x + 1, y, z)) == id) && (world.getType(x + 1, y + 1, z).c())) + return true; + if ((Block.getId(world.getType(x, y, z - 1)) == id) && (world.getType(x, y + 1, z - 1).c())) + return true; + if ((Block.getId(world.getType(x, y, z + 1)) == id) && (world.getType(x, y + 1, z + 1).c())) + return true; + } + + if (Block.getId(world.getType(x - 1, y, z)) == id) + chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x - 1, y, z), (IInventory) chest); + if (Block.getId(world.getType(x + 1, y, z)) == id) + chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x + 1, y, z)); + if (Block.getId(world.getType(x, y, z - 1)) == id) + chest = new InventoryLargeChest("Large chest", (TileEntityChest) world.getTileEntity(x, y, z - 1), (IInventory) chest); + if (Block.getId(world.getType(x, y, z + 1)) == id) + chest = new InventoryLargeChest("Large chest", (IInventory) chest, (TileEntityChest) world.getTileEntity(x, y, z + 1)); + + boolean returnValue = true; + if (!silentchest) { + player.openContainer((IInventory) chest); + } + else { + try { + int windowId = 0; + try { + Field windowID = player.getClass().getDeclaredField("containerCounter"); + windowID.setAccessible(true); + windowId = windowID.getInt(player); + windowId = windowId % 100 + 1; + windowID.setInt(player, windowId); + } + catch (NoSuchFieldException e) {} + + player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, 0, ((IInventory) chest).getInventoryName(), ((IInventory) chest).getSize(), true)); + player.activeContainer = new SilentContainerChest(player.inventory, ((IInventory) chest)); + player.activeContainer.windowId = windowId; + player.activeContainer.addSlotListener(player); + if (OpenInv.NotifySilentChest()) { + p.sendMessage("You are opening a chest silently."); + } + returnValue = false; + } + catch (Exception e) { + e.printStackTrace(); + p.sendMessage(ChatColor.RED + "Error while sending silent chest."); + } + } + + if (anychest && OpenInv.NotifyAnyChest()) { + p.sendMessage("You are opening a blocked chest."); + } + + return returnValue; + } +} diff --git a/src/com/lishid/openinv/internal/v1_7_R4/InventoryAccess.java b/src/com/lishid/openinv/internal/v1_7_R4/InventoryAccess.java new file mode 100644 index 0000000..cf9a172 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_7_R4/InventoryAccess.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011-2014 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_7_R4; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Inventory; + +import com.lishid.openinv.OpenInv; +import com.lishid.openinv.Permissions; +import com.lishid.openinv.internal.IInventoryAccess; + +//Volatile +import net.minecraft.server.v1_7_R4.*; +import org.bukkit.craftbukkit.v1_7_R4.inventory.*; + +public class InventoryAccess implements IInventoryAccess { + public boolean check(Inventory inventory, HumanEntity player) { + IInventory inv = ((CraftInventory) inventory).getInventory(); + + if (inv instanceof SpecialPlayerInventory) { + if (!OpenInv.hasPermission(player, Permissions.PERM_EDITINV)) { + return false; + } + } + + else if (inv instanceof SpecialEnderChest) { + if (!OpenInv.hasPermission(player, Permissions.PERM_EDITENDER)) { + return false; + } + } + + return true; + } +} diff --git a/src/com/lishid/openinv/internal/v1_7_R4/PlayerDataManager.java b/src/com/lishid/openinv/internal/v1_7_R4/PlayerDataManager.java new file mode 100644 index 0000000..3fe113d --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_7_R4/PlayerDataManager.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2011-2014 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_7_R4; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.UUID; + +import net.minecraft.util.com.mojang.authlib.GameProfile; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import com.lishid.openinv.utils.ReflectionUtil; +import com.lishid.openinv.utils.ReflectionUtil.PackageType; +import com.lishid.openinv.utils.ReflectionUtil.SubPackageType; + +/** + * @author lishid, JuicyDev (reflection) + */ +public class PlayerDataManager { + + private Plugin plugin; + private String versionString; + private int version; + private static String playerFolderName; + + public PlayerDataManager(Plugin plugin) { + this.plugin = plugin; + + this.versionString = this.plugin + .getServer() + .getClass() + .getPackage() + .getName() + .substring( + this.plugin.getServer().getClass().getPackage() + .getName().lastIndexOf('.') + 1); + try { + this.version = Integer.valueOf(versionString.replace("v", "") + .replace("_", "").replace("R", "")); + } catch (NumberFormatException e) { // Fallback + this.version = 173; + } + playerFolderName = version >= 173 ? "playerdata" : "players"; + } + + /** + * @param uuid + * UUID of the player + * @return Instance of the player (null if doesn't exist) + */ + public Player loadPlayer(UUID uuid) { + try { + File playerFolder = new File( + ((World) Bukkit.getWorlds().get(0)).getWorldFolder(), + playerFolderName); + if (!playerFolder.exists()) { + return null; + } + + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + if (player == null) + return null; + + GameProfile profile = new GameProfile(player.getUniqueId(), + player.getName()); + + Class obc_CraftServer = ReflectionUtil.getClass("CraftServer", + PackageType.CRAFTBUKKIT); + Object craftServer = obc_CraftServer.cast(Bukkit.getServer()); + Method m_getServer = ReflectionUtil.getMethod(obc_CraftServer, + "getServer"); + Class nms_MinecraftServer = ReflectionUtil.getClass( + "MinecraftServer", PackageType.MINECRAFT_SERVER); + Object minecraftServer = m_getServer.invoke(craftServer); + + Class nms_EntityPlayer = ReflectionUtil.getClass("EntityPlayer", + PackageType.MINECRAFT_SERVER); + Class nms_WorldServer = ReflectionUtil.getClass("WorldServer", + PackageType.MINECRAFT_SERVER); + Class nms_PlayerInteractManager = ReflectionUtil.getClass( + "PlayerInteractManager", PackageType.MINECRAFT_SERVER); + Object worldServer = ReflectionUtil.getMethod(nms_MinecraftServer, + "getWorldServer", Integer.class).invoke(minecraftServer, 0); + + Constructor c_EntityPlayer = ReflectionUtil.getConstructor( + nms_EntityPlayer, nms_MinecraftServer, nms_WorldServer, + GameProfile.class, nms_PlayerInteractManager); + Constructor c_PlayerInteractManager = ReflectionUtil + .getConstructor(nms_PlayerInteractManager, nms_WorldServer); + Object playerInteractManager = c_PlayerInteractManager + .newInstance(worldServer); + + Object entityPlayer = c_EntityPlayer.newInstance(minecraftServer, + worldServer, profile, playerInteractManager); + + Class obc_CraftPlayer = ReflectionUtil.getClass("CraftPlayer", + SubPackageType.ENTITY); + Method m_getBukkitEntity = ReflectionUtil.getMethod( + nms_EntityPlayer, "getBukkitEntity"); + + Player target = entityPlayer == null ? null + : (Player) obc_CraftPlayer.cast(m_getBukkitEntity + .invoke(entityPlayer)); + + if (target != null) { + target.loadData(); + return target; + } + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + /** + * @param name + * Name of the player + * @return Instance of the player (null if doesn't exist) + */ + public Player loadPlayer(String name) { + try { + UUID uuid = matchUser(name); + if (uuid == null) + return null; + + Player target = loadPlayer(uuid); + if (target != null) { + return target; + } + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + private static UUID matchUser(String search) { + File playerFolder = new File( + ((World) Bukkit.getWorlds().get(0)).getWorldFolder(), + playerFolderName); + if (!playerFolder.exists() || !playerFolder.isDirectory()) + return null; + if (search == null) + return null; + + UUID found = null; + + String lowerSearch = search.toLowerCase(); + int delta = 2147483647; + + for (File f : playerFolder.listFiles()) { + if (!f.getName().endsWith(".dat")) + continue; + String uuidString = f.getName().substring(0, + f.getName().length() - 4); + UUID uuid = UUID.fromString(uuidString); + + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + String name = player.getName(); + + if (name.equalsIgnoreCase(search)) + return uuid; + + if (name.toLowerCase().startsWith(lowerSearch)) { + int curDelta = name.length() - lowerSearch.length(); + if (curDelta < delta) { + found = player.getUniqueId(); + delta = curDelta; + } + if (curDelta == 0) { + break; + } + } + } + + return found; + } +} diff --git a/src/com/lishid/openinv/internal/v1_7_R4/SilentContainerChest.java b/src/com/lishid/openinv/internal/v1_7_R4/SilentContainerChest.java new file mode 100644 index 0000000..0cbf298 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_7_R4/SilentContainerChest.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011-2014 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_7_R4; + +//Volatile +import net.minecraft.server.v1_7_R4.*; + +public class SilentContainerChest extends ContainerChest { + public IInventory inv; + + public SilentContainerChest(IInventory i1, IInventory i2) { + super(i1, i2); + inv = i2; + // close signal + inv.closeContainer(); + } + + @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_7_R4/SpecialEnderChest.java b/src/com/lishid/openinv/internal/v1_7_R4/SpecialEnderChest.java new file mode 100644 index 0000000..8135307 --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_7_R4/SpecialEnderChest.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011-2014 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_7_R4; + +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_7_R4.*; +import org.bukkit.craftbukkit.v1_7_R4.entity.*; +import org.bukkit.craftbukkit.v1_7_R4.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().getInventoryName(), ((CraftPlayer) p).getHandle().getEnderChest().k_(), ((CraftPlayer) p).getHandle().getEnderChest().getSize()); + CraftPlayer player = (CraftPlayer) p; + this.enderChest = player.getHandle().getEnderChest(); + this.owner = player; + this.items = enderChest.getContents(); + OpenInv.enderChests.put(owner.getName().toLowerCase(), this); + } + + public Inventory getBukkitInventory() { + return inventory; + } + + public void InventoryRemovalCheck() { + owner.saveData(); + if (transaction.isEmpty() && !playerOnline) { + 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); + this.InventoryRemovalCheck(); + } + + 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_7_R4/SpecialPlayerInventory.java b/src/com/lishid/openinv/internal/v1_7_R4/SpecialPlayerInventory.java new file mode 100644 index 0000000..b36388b --- /dev/null +++ b/src/com/lishid/openinv/internal/v1_7_R4/SpecialPlayerInventory.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2011-2014 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_7_R4; + +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_7_R4.*; +import org.bukkit.craftbukkit.v1_7_R4.entity.*; +import org.bukkit.craftbukkit.v1_7_R4.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; + OpenInv.inventories.put(owner.getName().toLowerCase(), this); + } + + @Override + public Inventory getBukkitInventory() { + return inventory; + } + + @Override + public void InventoryRemovalCheck() { + owner.saveData(); + if (transaction.isEmpty() && !playerOnline) { + 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; + this.InventoryRemovalCheck(); + } + + @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) { + owner.getHandle().drop(itemstack, true); + itemstack = null; + } + + is[i] = itemstack; + + owner.getHandle().defaultContainer.b(); + } + + 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 getInventoryName() { + if (player.getName().length() > 16) { + return player.getName().substring(0, 16); + } + return player.getName(); + } + + @Override + public boolean a(EntityHuman entityhuman) { + return true; + } +} \ No newline at end of file diff --git a/src/com/lishid/openinv/utils/Metrics.java b/src/com/lishid/openinv/utils/Metrics.java deleted file mode 100644 index a4b69f0..0000000 --- a/src/com/lishid/openinv/utils/Metrics.java +++ /dev/null @@ -1,696 +0,0 @@ -package com.lishid.openinv.utils; - -/* - * Copyright 2011 Tyler Blair. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and contributors and should not be interpreted as representing official policies, - * either expressed or implied, of anybody else. - */ - -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.scheduler.BukkitTask; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.net.Proxy; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLEncoder; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; - -/** - *

- * The metrics class obtains data about a plugin and submits statistics about it to the metrics backend. - *

- *

- * Public methods provided by this class: - *

- * - * Graph createGraph(String name);
- * void addCustomData(Metrics.Plotter plotter);
- * void start();
- *
- */ -public class Metrics -{ - - /** - * The current revision number - */ - private final static int REVISION = 5; - - /** - * The base url of the metrics domain - */ - private static final String BASE_URL = "http://mcstats.org"; - - /** - * The url used to report a server's status - */ - private static final String REPORT_URL = "/report/%s"; - - /** - * The file where guid and opt out is stored in - */ - private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml"; - - /** - * The separator to use for custom data. This MUST NOT change unless you are hosting your own - * version of metrics and want to change it. - */ - private static final String CUSTOM_DATA_SEPARATOR = "~~"; - - /** - * Interval of time to ping (in minutes) - */ - private static final int PING_INTERVAL = 10; - - /** - * The plugin this metrics submits for - */ - private final Plugin plugin; - - /** - * All of the custom graphs to submit to metrics - */ - private final Set graphs = Collections.synchronizedSet(new HashSet()); - - /** - * The default graph, used for addCustomData when you don't want a specific graph - */ - private final Graph defaultGraph = new Graph("Default"); - - /** - * The plugin configuration file - */ - private final YamlConfiguration configuration; - - /** - * The plugin configuration file - */ - private final File configurationFile; - - /** - * Unique server id - */ - private final String guid; - - /** - * Lock for synchronization - */ - private final Object optOutLock = new Object(); - - /** - * Id of the scheduled task - */ - private volatile BukkitTask taskId; - - public Metrics(final Plugin plugin) throws IOException - { - if (plugin == null) - { - throw new IllegalArgumentException("Plugin cannot be null"); - } - - this.plugin = plugin; - - // load the config - configurationFile = new File(CONFIG_FILE); - configuration = YamlConfiguration.loadConfiguration(configurationFile); - - // add some defaults - configuration.addDefault("opt-out", false); - configuration.addDefault("guid", UUID.randomUUID().toString()); - - // Do we need to create the file? - if (configuration.get("guid", null) == null) - { - configuration.options().header("http://mcstats.org").copyDefaults(true); - configuration.save(configurationFile); - } - - // Load the guid then - guid = configuration.getString("guid"); - } - - /** - * Construct and create a Graph that can be used to separate specific plotters to their own graphs - * on the metrics website. Plotters can be added to the graph object returned. - * - * @param name - * @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given - */ - public Graph createGraph(final String name) - { - if (name == null) - { - throw new IllegalArgumentException("Graph name cannot be null"); - } - - // Construct the graph object - final Graph graph = new Graph(name); - - // Now we can add our graph - graphs.add(graph); - - // and return back - return graph; - } - - /** - * Add a Graph object to Metrics that represents data for the plugin that should be sent to the backend - * - * @param graph - */ - public void addGraph(final Graph graph) - { - if (graph == null) - { - throw new IllegalArgumentException("Graph cannot be null"); - } - - graphs.add(graph); - } - - /** - * Adds a custom data plotter to the default graph - * - * @param plotter - */ - public void addCustomData(final Plotter plotter) - { - if (plotter == null) - { - throw new IllegalArgumentException("Plotter cannot be null"); - } - - // Add the plotter to the graph o/ - defaultGraph.addPlotter(plotter); - - // Ensure the default graph is included in the submitted graphs - graphs.add(defaultGraph); - } - - /** - * Start measuring statistics. This will immediately create an async repeating task as the plugin and send - * the initial data to the metrics backend, and then after that it will post in increments of - * PING_INTERVAL * 1200 ticks. - * - * @return True if statistics measuring is running, otherwise false. - */ - public boolean start() - { - synchronized (optOutLock) - { - // Did we opt out? - if (isOptOut()) - { - return false; - } - - // Is metrics already running? - if (taskId != null) - { - return true; - } - - // Begin hitting the server with glorious data - taskId = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() - { - - private boolean firstPost = true; - - public void run() - { - try - { - // This has to be synchronized or it can collide with the disable method. - synchronized (optOutLock) - { - // Disable Task, if it is running and the server owner decided to opt-out - if (isOptOut() && taskId != null) - { - taskId.cancel(); - taskId = null; - // Tell all plotters to stop gathering information. - for (Graph graph : graphs) - { - graph.onOptOut(); - } - } - } - - // We use the inverse of firstPost because if it is the first time we are posting, - // it is not a interval ping, so it evaluates to FALSE - // Each time thereafter it will evaluate to TRUE, i.e PING! - postPlugin(!firstPost); - - // After the first post we set firstPost to false - // Each post thereafter will be a ping - firstPost = false; - } - catch (IOException e) - { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); - } - } - }, 0, PING_INTERVAL * 1200); - - return true; - } - } - - /** - * Has the server owner denied plugin metrics? - * - * @return - */ - public boolean isOptOut() - { - synchronized (optOutLock) - { - try - { - // Reload the metrics file - configuration.load(CONFIG_FILE); - } - catch (IOException ex) - { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); - return true; - } - catch (InvalidConfigurationException ex) - { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); - return true; - } - return configuration.getBoolean("opt-out", false); - } - } - - /** - * Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task. - * - * @throws IOException - */ - public void enable() throws IOException - { - // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) - { - // Check if the server owner has already set opt-out, if not, set it. - if (isOptOut()) - { - configuration.set("opt-out", false); - configuration.save(configurationFile); - } - - // Enable Task, if it is not running - if (taskId == null) - { - start(); - } - } - } - - /** - * Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task. - * - * @throws IOException - */ - public void disable() throws IOException - { - // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) - { - // Check if the server owner has already set opt-out, if not, set it. - if (!isOptOut()) - { - configuration.set("opt-out", true); - configuration.save(configurationFile); - } - - // Disable Task, if it is running - if (taskId != null) - { - taskId.cancel(); - taskId = null; - } - } - } - - /** - * Generic method that posts a plugin to the metrics website - */ - private void postPlugin(final boolean isPing) throws IOException - { - // The plugin's description file containg all of the plugin data such as name, version, author, etc - final PluginDescriptionFile description = plugin.getDescription(); - - // Construct the post data - final StringBuilder data = new StringBuilder(); - data.append(encode("guid")).append('=').append(encode(guid)); - encodeDataPair(data, "version", description.getVersion()); - encodeDataPair(data, "server", Bukkit.getVersion()); - encodeDataPair(data, "players", Integer.toString(Bukkit.getServer().getOnlinePlayers().length)); - encodeDataPair(data, "revision", String.valueOf(REVISION)); - - // If we're pinging, append it - if (isPing) - { - encodeDataPair(data, "ping", "true"); - } - - // Acquire a lock on the graphs, which lets us make the assumption we also lock everything - // inside of the graph (e.g plotters) - synchronized (graphs) - { - final Iterator iter = graphs.iterator(); - - while (iter.hasNext()) - { - final Graph graph = iter.next(); - - for (Plotter plotter : graph.getPlotters()) - { - // The key name to send to the metrics server - // The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top - // Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME - final String key = String.format("C%s%s%s%s", CUSTOM_DATA_SEPARATOR, graph.getName(), CUSTOM_DATA_SEPARATOR, plotter.getColumnName()); - - // The value to send, which for the foreseeable future is just the string - // value of plotter.getValue() - final String value = Integer.toString(plotter.getValue()); - - // Add it to the http post data :) - encodeDataPair(data, key, value); - } - } - } - - // Create the url - URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(plugin.getDescription().getName()))); - - // Connect to the website - URLConnection connection; - - // Mineshafter creates a socks proxy, so we can safely bypass it - // It does not reroute POST requests so we need to go around it - if (isMineshafterPresent()) - { - connection = url.openConnection(Proxy.NO_PROXY); - } - else - { - connection = url.openConnection(); - } - - connection.setDoOutput(true); - - // Write the data - final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); - writer.write(data.toString()); - writer.flush(); - - // Now read the response - final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); - final String response = reader.readLine(); - - // close resources - writer.close(); - reader.close(); - - if (response == null || response.startsWith("ERR")) - { - throw new IOException(response); // Throw the exception - } - else - { - // Is this the first update this hour? - if (response.contains("OK This is your first update this hour")) - { - synchronized (graphs) - { - final Iterator iter = graphs.iterator(); - - while (iter.hasNext()) - { - final Graph graph = iter.next(); - - for (Plotter plotter : graph.getPlotters()) - { - plotter.reset(); - } - } - } - } - } - } - - /** - * Check if mineshafter is present. If it is, we need to bypass it to send POST requests - * - * @return - */ - private boolean isMineshafterPresent() - { - try - { - Class.forName("mineshafter.MineServer"); - return true; - } - catch (Exception e) - { - return false; - } - } - - /** - *

- * Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first key/value pair MUST be included manually, e.g: - *

- * - * StringBuffer data = new StringBuffer(); - * data.append(encode("guid")).append('=').append(encode(guid)); - * encodeDataPair(data, "version", description.getVersion()); - * - * - * @param buffer - * @param key - * @param value - * @return - */ - private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException - { - buffer.append('&').append(encode(key)).append('=').append(encode(value)); - } - - /** - * Encode text as UTF-8 - * - * @param text - * @return - */ - private static String encode(final String text) throws UnsupportedEncodingException - { - return URLEncoder.encode(text, "UTF-8"); - } - - /** - * Represents a custom graph on the website - */ - public static class Graph - { - - /** - * The graph's name, alphanumeric and spaces only :) - * If it does not comply to the above when submitted, it is rejected - */ - private final String name; - - /** - * The set of plotters that are contained within this graph - */ - private final Set plotters = new LinkedHashSet(); - - private Graph(final String name) - { - this.name = name; - } - - /** - * Gets the graph's name - * - * @return - */ - public String getName() - { - return name; - } - - /** - * Add a plotter to the graph, which will be used to plot entries - * - * @param plotter - */ - public void addPlotter(final Plotter plotter) - { - plotters.add(plotter); - } - - /** - * Remove a plotter from the graph - * - * @param plotter - */ - public void removePlotter(final Plotter plotter) - { - plotters.remove(plotter); - } - - /** - * Gets an unmodifiable set of the plotter objects in the graph - * - * @return - */ - public Set getPlotters() - { - return Collections.unmodifiableSet(plotters); - } - - @Override - public int hashCode() - { - return name.hashCode(); - } - - @Override - public boolean equals(final Object object) - { - if (!(object instanceof Graph)) - { - return false; - } - - final Graph graph = (Graph) object; - return graph.name.equals(name); - } - - /** - * Called when the server owner decides to opt-out of Metrics while the server is running. - */ - protected void onOptOut() - { - } - - } - - /** - * Interface used to collect custom data for a plugin - */ - public static abstract class Plotter - { - - /** - * The plot's name - */ - private final String name; - - /** - * Construct a plotter with the default plot name - */ - public Plotter() - { - this("Default"); - } - - /** - * Construct a plotter with a specific plot name - * - * @param name - */ - public Plotter(final String name) - { - this.name = name; - } - - /** - * Get the current value for the plotted point - * - * @return - */ - public abstract int getValue(); - - /** - * Get the column name for the plotted point - * - * @return the plotted point's column name - */ - public String getColumnName() - { - return name; - } - - /** - * Called after the website graphs have been updated - */ - public void reset() - { - } - - @Override - public int hashCode() - { - return getColumnName().hashCode(); - } - - @Override - public boolean equals(final Object object) - { - if (!(object instanceof Plotter)) - { - return false; - } - - final Plotter plotter = (Plotter) object; - return plotter.name.equals(name) && plotter.getValue() == getValue(); - } - - } - -} \ No newline at end of file diff --git a/src/com/lishid/openinv/utils/ReflectionUtil.java b/src/com/lishid/openinv/utils/ReflectionUtil.java new file mode 100644 index 0000000..b701bd7 --- /dev/null +++ b/src/com/lishid/openinv/utils/ReflectionUtil.java @@ -0,0 +1,510 @@ +package com.lishid.openinv.utils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; + +public final class ReflectionUtil { + private ReflectionUtil() {} + + public static Class getClass(String name, PackageType type) throws Exception { + return Class.forName(type + "." + name); + } + + public static Class getClass(String name, SubPackageType type) throws Exception { + return Class.forName(type + "." + name); + } + + public static Constructor getConstructor(Class clazz, Class... parameterTypes) { + Class[] p = DataType.convertToPrimitive(parameterTypes); + for (Constructor c : clazz.getConstructors()) + if (DataType.equalsArray(DataType.convertToPrimitive(c.getParameterTypes()), p)) + return c; + return null; + } + + public static Constructor getConstructor(String className, PackageType type, Class... parameterTypes) throws Exception { + return getConstructor(getClass(className, type), parameterTypes); + } + + public static Constructor getConstructor(String className, SubPackageType type, Class... parameterTypes) throws Exception { + return getConstructor(getClass(className, type), parameterTypes); + } + + public static Object newInstance(Class clazz, Object... args) throws Exception { + return getConstructor(clazz, DataType.convertToPrimitive(args)).newInstance(args); + } + + public static Object newInstance(String className, PackageType type, Object... args) throws Exception { + return newInstance(getClass(className, type), args); + } + + public static Object newInstance(String className, SubPackageType type, Object... args) throws Exception { + return newInstance(getClass(className, type), args); + } + + public static Method getMethod(Class clazz, String name, Class... parameterTypes) { + Class[] p = DataType.convertToPrimitive(parameterTypes); + for (Method m : clazz.getMethods()) + if (m.getName().equals(name) && DataType.equalsArray(DataType.convertToPrimitive(m.getParameterTypes()), p)) + return m; + return null; + } + + public static Method getMethod(String className, PackageType type, String name, Class... parameterTypes) throws Exception { + return getMethod(getClass(className, type), name, parameterTypes); + } + + public static Method getMethod(String className, SubPackageType type, String name, Class... parameterTypes) throws Exception { + return getMethod(getClass(className, type), name, parameterTypes); + } + + public static Object invokeMethod(String name, Object instance, Object... args) throws Exception { + return getMethod(instance.getClass(), name, DataType.convertToPrimitive(args)).invoke(instance, args); + } + + public static Object invokeMethod(Class clazz, String name, Object instance, Object... args) throws Exception { + return getMethod(clazz, name, DataType.convertToPrimitive(args)).invoke(instance, args); + } + + public static Object invokeMethod(String className, PackageType type, String name, Object instance, Object... args) throws Exception { + return invokeMethod(getClass(className, type), name, instance, args); + } + + public static Object invokeMethod(String className, SubPackageType type, String name, Object instance, Object... args) throws Exception { + return invokeMethod(getClass(className, type), name, instance, args); + } + + public static Field getField(Class clazz, String name) throws Exception { + Field f = clazz.getField(name); + f.setAccessible(true); + return f; + } + + public static Field getField(String className, PackageType type, String name) throws Exception { + return getField(getClass(className, type), name); + } + + public static Field getField(String className, SubPackageType type, String name) throws Exception { + return getField(getClass(className, type), name); + } + + public static Field getDeclaredField(Class clazz, String name) throws Exception { + Field f = clazz.getDeclaredField(name); + f.setAccessible(true); + return f; + } + + public static Field getDeclaredField(String className, PackageType type, String name) throws Exception { + return getDeclaredField(getClass(className, type), name); + } + + public static Field getDeclaredField(String className, SubPackageType type, String name) throws Exception { + return getDeclaredField(getClass(className, type), name); + } + + public static Object getValue(Object instance, String fieldName) throws Exception { + return getField(instance.getClass(), fieldName).get(instance); + } + + public static Object getValue(Class clazz, Object instance, String fieldName) throws Exception { + return getField(clazz, fieldName).get(instance); + } + + public static Object getValue(String className, PackageType type, Object instance, String fieldName) throws Exception { + return getValue(getClass(className, type), instance, fieldName); + } + + public static Object getValue(String className, SubPackageType type, Object instance, String fieldName) throws Exception { + return getValue(getClass(className, type), instance, fieldName); + } + + public static Object getDeclaredValue(Object instance, String fieldName) throws Exception { + return getDeclaredField(instance.getClass(), fieldName).get(instance); + } + + public static Object getDeclaredValue(Class clazz, Object instance, String fieldName) throws Exception { + return getDeclaredField(clazz, fieldName).get(instance); + } + + public static Object getDeclaredValue(String className, PackageType type, Object instance, String fieldName) throws Exception { + return getDeclaredValue(getClass(className, type), instance, fieldName); + } + + public static Object getDeclaredValue(String className, SubPackageType type, Object instance, String fieldName) throws Exception { + return getDeclaredValue(getClass(className, type), instance, fieldName); + } + + public static void setValue(Object instance, String fieldName, Object fieldValue) throws Exception { + Field f = getField(instance.getClass(), fieldName); + f.set(instance, fieldValue); + } + + public static void setValue(Object instance, FieldPair pair) throws Exception { + setValue(instance, pair.getName(), pair.getValue()); + } + + public static void setValue(Class clazz, Object instance, String fieldName, Object fieldValue) throws Exception { + Field f = getField(clazz, fieldName); + f.set(instance, fieldValue); + } + + public static void setValue(Class clazz, Object instance, FieldPair pair) throws Exception { + setValue(clazz, instance, pair.getName(), pair.getValue()); + } + + public static void setValue(String className, PackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { + setValue(getClass(className, type), instance, fieldName, fieldValue); + } + + public static void setValue(String className, PackageType type, Object instance, FieldPair pair) throws Exception { + setValue(className, type, instance, pair.getName(), pair.getValue()); + } + + public static void setValue(String className, SubPackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { + setValue(getClass(className, type), instance, fieldName, fieldValue); + } + + public static void setValue(String className, SubPackageType type, Object instance, FieldPair pair) throws Exception { + setValue(className, type, instance, pair.getName(), pair.getValue()); + } + + public static void setValues(Object instance, FieldPair... pairs) throws Exception { + for (FieldPair pair : pairs) + setValue(instance, pair); + } + + public static void setValues(Class clazz, Object instance, FieldPair... pairs) throws Exception { + for (FieldPair pair : pairs) + setValue(clazz, instance, pair); + } + + public static void setValues(String className, PackageType type, Object instance, FieldPair... pairs) throws Exception { + setValues(getClass(className, type), instance, pairs); + } + + public static void setValues(String className, SubPackageType type, Object instance, FieldPair... pairs) throws Exception { + setValues(getClass(className, type), instance, pairs); + } + + public static void setDeclaredValue(Object instance, String fieldName, Object fieldValue) throws Exception { + Field f = getDeclaredField(instance.getClass(), fieldName); + f.set(instance, fieldValue); + } + + public static void setDeclaredValue(Object instance, FieldPair pair) throws Exception { + setDeclaredValue(instance, pair.getName(), pair.getValue()); + } + + public static void setDeclaredValue(Class clazz, Object instance, String fieldName, Object fieldValue) throws Exception { + Field f = getDeclaredField(clazz, fieldName); + f.set(instance, fieldValue); + } + + public static void setDeclaredValue(Class clazz, Object instance, FieldPair pair) throws Exception { + setDeclaredValue(clazz, instance, pair.getName(), pair.getValue()); + } + + public static void setDeclaredValue(String className, PackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { + setDeclaredValue(getClass(className, type), instance, fieldName, fieldValue); + } + + public static void setDeclaredValue(String className, PackageType type, Object instance, FieldPair pair) throws Exception { + setDeclaredValue(className, type, instance, pair.getName(), pair.getValue()); + } + + public static void setDeclaredValue(String className, SubPackageType type, Object instance, String fieldName, Object fieldValue) throws Exception { + setDeclaredValue(getClass(className, type), instance, fieldName, fieldValue); + } + + public static void setDeclaredValue(String className, SubPackageType type, Object instance, FieldPair pair) throws Exception { + setDeclaredValue(className, type, instance, pair.getName(), pair.getValue()); + } + + public static void setDeclaredValues(Object instance, FieldPair... pairs) throws Exception { + for (FieldPair pair : pairs) + setDeclaredValue(instance, pair); + } + + public static void setDeclaredValues(Class clazz, Object instance, FieldPair... pairs) throws Exception { + for (FieldPair pair : pairs) + setDeclaredValue(clazz, instance, pair); + } + + public static void setDeclaredValues(String className, PackageType type, Object instance, FieldPair... pairs) throws Exception { + setDeclaredValues(getClass(className, type), instance, pairs); + } + + public static void setDeclaredValues(String className, SubPackageType type, Object instance, FieldPair... pairs) throws Exception { + setDeclaredValues(getClass(className, type), instance, pairs); + } + + public enum DataType { + BYTE(byte.class, Byte.class), + SHORT(short.class, Short.class), + INTEGER(int.class, Integer.class), + LONG(long.class, Long.class), + CHARACTER(char.class, Character.class), + FLOAT(float.class, Float.class), + DOUBLE(double.class, Double.class), + BOOLEAN(boolean.class, Boolean.class); + + private static final Map, DataType> CLASS_MAP = new HashMap, DataType>(); + private final Class primitive; + private final Class reference; + + static { + for (DataType t : values()) { + CLASS_MAP.put(t.primitive, t); + CLASS_MAP.put(t.reference, t); + } + } + + private DataType(Class primitive, Class reference) { + this.primitive = primitive; + this.reference = reference; + } + + public Class getPrimitive() { + return this.primitive; + } + + public Class getReference() { + return this.reference; + } + + public static DataType fromClass(Class c) { + return CLASS_MAP.get(c); + } + + public static Class getPrimitive(Class c) { + DataType t = fromClass(c); + return t == null ? c : t.getPrimitive(); + } + + public static Class getReference(Class c) { + DataType t = fromClass(c); + return t == null ? c : t.getReference(); + } + + public static Class[] convertToPrimitive(Class[] classes) { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for (int i = 0; i < length; i++) + types[i] = getPrimitive(classes[i]); + return types; + } + + public static Class[] convertToPrimitive(Object[] objects) { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for (int i = 0; i < length; i++) + types[i] = getPrimitive(objects[i].getClass()); + return types; + } + + public static boolean equalsArray(Class[] a1, Class[] a2) { + if (a1 == null || a2 == null || a1.length != a2.length) + return false; + for (int i = 0; i < a1.length; i++) + if (!a1[i].equals(a2[i]) && !a1[i].isAssignableFrom(a2[i])) + return false; + return true; + } + } + + public final class FieldPair { + private final String name; + private final Object value; + + public FieldPair(String name, Object value) { + this.name = name; + this.value = value; + } + + public String getName() { + return this.name; + } + + public Object getValue() { + return this.value; + } + } + + public enum PackageType { + MINECRAFT_SERVER("net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().substring(23)), + CRAFTBUKKIT(Bukkit.getServer().getClass().getPackage().getName()); + + private final String name; + + private PackageType(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return name; + } + } + + public enum SubPackageType { + BLOCK, + CHUNKIO, + COMMAND, + CONVERSATIONS, + ENCHANTMENS, + ENTITY, + EVENT, + GENERATOR, + HELP, + INVENTORY, + MAP, + METADATA, + POTION, + PROJECTILES, + SCHEDULER, + SCOREBOARD, + UPDATER, + UTIL; + + private final String name; + + private SubPackageType() { + name = PackageType.CRAFTBUKKIT + "." + name().toLowerCase(); + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return name; + } + } + + public enum PacketType { + HANDSHAKING_IN_SET_PROTOCOL("PacketHandshakingInSetProtocol"), + LOGIN_IN_ENCRYPTION_BEGIN("PacketLoginInEncryptionBegin"), + LOGIN_IN_START("PacketLoginInStart"), + LOGIN_OUT_DISCONNECT("PacketLoginOutDisconnect"), + LOGIN_OUT_ENCRYPTION_BEGIN("PacketLoginOutEncryptionBegin"), + LOGIN_OUT_SUCCESS("PacketLoginOutSuccess"), + PLAY_IN_ABILITIES("PacketPlayInAbilities"), + PLAY_IN_ARM_ANIMATION("PacketPlayInArmAnimation"), + PLAY_IN_BLOCK_DIG("PacketPlayInBlockDig"), + PLAY_IN_BLOCK_PLACE("PacketPlayInBlockPlace"), + PLAY_IN_CHAT("PacketPlayInChat"), + PLAY_IN_CLIENT_COMMAND("PacketPlayInClientCommand"), + PLAY_IN_CLOSE_WINDOW("PacketPlayInCloseWindow"), + PLAY_IN_CUSTOM_PAYLOAD("PacketPlayInCustomPayload"), + PLAY_IN_ENCHANT_ITEM("PacketPlayInEnchantItem"), + PLAY_IN_ENTITY_ACTION("PacketPlayInEntityAction"), + PLAY_IN_FLYING("PacketPlayInFlying"), + PLAY_IN_HELD_ITEM_SLOT("PacketPlayInHeldItemSlot"), + PLAY_IN_KEEP_ALIVE("PacketPlayInKeepAlive"), + PLAY_IN_LOOK("PacketPlayInLook"), + PLAY_IN_POSITION("PacketPlayInPosition"), + PLAY_IN_POSITION_LOOK("PacketPlayInPositionLook"), + PLAY_IN_SET_CREATIVE_SLOT("PacketPlayInSetCreativeSlot "), + PLAY_IN_SETTINGS("PacketPlayInSettings"), + PLAY_IN_STEER_VEHICLE("PacketPlayInSteerVehicle"), + PLAY_IN_TAB_COMPLETE("PacketPlayInTabComplete"), + PLAY_IN_TRANSACTION("PacketPlayInTransaction"), + PLAY_IN_UPDATE_SIGN("PacketPlayInUpdateSign"), + PLAY_IN_USE_ENTITY("PacketPlayInUseEntity"), + PLAY_IN_WINDOW_CLICK("PacketPlayInWindowClick"), + PLAY_OUT_ABILITIES("PacketPlayOutAbilities"), + PLAY_OUT_ANIMATION("PacketPlayOutAnimation"), + PLAY_OUT_ATTACH_ENTITY("PacketPlayOutAttachEntity"), + PLAY_OUT_BED("PacketPlayOutBed"), + PLAY_OUT_BLOCK_ACTION("PacketPlayOutBlockAction"), + PLAY_OUT_BLOCK_BREAK_ANIMATION("PacketPlayOutBlockBreakAnimation"), + PLAY_OUT_BLOCK_CHANGE("PacketPlayOutBlockChange"), + PLAY_OUT_CHAT("PacketPlayOutChat"), + PLAY_OUT_CLOSE_WINDOW("PacketPlayOutCloseWindow"), + PLAY_OUT_COLLECT("PacketPlayOutCollect"), + PLAY_OUT_CRAFT_PROGRESS_BAR("PacketPlayOutCraftProgressBar"), + PLAY_OUT_CUSTOM_PAYLOAD("PacketPlayOutCustomPayload"), + PLAY_OUT_ENTITY("PacketPlayOutEntity"), + PLAY_OUT_ENTITY_DESTROY("PacketPlayOutEntityDestroy"), + PLAY_OUT_ENTITY_EFFECT("PacketPlayOutEntityEffect"), + PLAY_OUT_ENTITY_EQUIPMENT("PacketPlayOutEntityEquipment"), + PLAY_OUT_ENTITY_HEAD_ROTATION("PacketPlayOutEntityHeadRotation"), + PLAY_OUT_ENTITY_LOOK("PacketPlayOutEntityLook"), + PLAY_OUT_ENTITY_METADATA("PacketPlayOutEntityMetadata"), + PLAY_OUT_ENTITY_STATUS("PacketPlayOutEntityStatus"), + PLAY_OUT_ENTITY_TELEPORT("PacketPlayOutEntityTeleport"), + PLAY_OUT_ENTITY_VELOCITY("PacketPlayOutEntityVelocity"), + PLAY_OUT_EXPERIENCE("PacketPlayOutExperience"), + PLAY_OUT_EXPLOSION("PacketPlayOutExplosion"), + PLAY_OUT_GAME_STATE_CHANGE("PacketPlayOutGameStateChange"), + PLAY_OUT_HELD_ITEM_SLOT("PacketPlayOutHeldItemSlot"), + PLAY_OUT_KEEP_ALIVE("PacketPlayOutKeepAlive"), + PLAY_OUT_KICK_DISCONNECT("PacketPlayOutKickDisconnect"), + PLAY_OUT_LOGIN("PacketPlayOutLogin"), + PLAY_OUT_MAP("PacketPlayOutMap"), + PLAY_OUT_MAP_CHUNK("PacketPlayOutMapChunk"), + PLAY_OUT_MAP_CHUNK_BULK("PacketPlayOutMapChunkBulk"), + PLAY_OUT_MULTI_BLOCK_CHANGE("PacketPlayOutMultiBlockChange"), + PLAY_OUT_NAMED_ENTITY_SPAWN("PacketPlayOutNamedEntitySpawn"), + PLAY_OUT_NAMED_SOUND_EFFECT("PacketPlayOutNamedSoundEffect"), + PLAY_OUT_OPEN_SIGN_EDITOR("PacketPlayOutOpenSignEditor"), + PLAY_OUT_OPEN_WINDOW("PacketPlayOutOpenWindow"), + PLAY_OUT_PLAYER_INFO("PacketPlayOutPlayerInfo"), + PLAY_OUT_POSITION("PacketPlayOutPosition"), + PLAY_OUT_REL_ENTITY_MOVE("PacketPlayOutRelEntityMove"), + PLAY_OUT_REL_ENTITY_MOVE_LOOK("PacketPlayOutRelEntityMoveLook"), + PLAY_OUT_REMOVE_ENTITY_EFFECT("PacketPlayOutRemoveEntityEffect"), + PLAY_OUT_RESPAWN("PacketPlayOutRespawn"), + PLAY_OUT_SCOREBOARD_DISPLAY_OBJECTIVE("PacketPlayOutScoreboardDisplayObjective"), + PLAY_OUT_SCOREBOARD_OBJECTIVE("PacketPlayOutScoreboardObjective"), + PLAY_OUT_SCOREBOARD_SCORE("PacketPlayOutScoreboardScore"), + PLAY_OUT_SCOREBOARD_TEAM("PacketPlayOutScoreboardTeam"), + PLAY_OUT_SET_SLOT("PacketPlayOutSetSlot"), + PLAY_OUT_SPAWN_ENTITY("PacketPlayOutSpawnEntity"), + PLAY_OUT_SPAWN_ENTITY_EXPERIENCE_ORB("PacketPlayOutSpawnEntityExperienceOrb"), + PLAY_OUT_SPAWN_ENTITY_LIVING("PacketPlayOutSpawnEntityLiving"), + PLAY_OUT_SPAWN_ENTITY_PAINTING("PacketPlayOutSpawnEntityPainting"), + PLAY_OUT_SPAWN_ENTITY_WEATHER("PacketPlayOutSpawnEntityWeather"), + PLAY_OUT_SPAWN_POSITION("PacketPlayOutSpawnPosition"), + PLAY_OUT_STATISTIC("PacketPlayOutStatistic"), + PLAY_OUT_TAB_COMPLETE("PacketPlayOutTabComplete"), + PLAY_OUT_TILE_ENTITY_DATA("PacketPlayOutTileEntityData"), + PLAY_OUT_TRANSACTION("PacketPlayOutTransaction"), + PLAY_OUT_UPDATE_ATTRIBUTES("PacketPlayOutUpdateAttributes"), + PLAY_OUT_UPDATE_HEALTH("PacketPlayOutUpdateHealth"), + PLAY_OUT_UPDATE_SIGN("PacketPlayOutUpdateSign"), + PLAY_OUT_UPDATE_TIME("PacketPlayOutUpdateTime"), + PLAY_OUT_WINDOW_ITEMS("PacketPlayOutWindowItems"), + PLAY_OUT_WORLD_EVENT("PacketPlayOutWorldEvent"), + PLAY_OUT_WORLD_PARTICLES("PacketPlayOutWorldParticles"), + STATUS_IN_PING("PacketStatusInPing"), + STATUS_IN_START("PacketStatusInStart"), + STATUS_OUT_PONG("PacketStatusOutPong"), + STATUS_OUT_SERVER_INFO("PacketStatusOutServerInfo"); + + private final String name; + private Class packet; + + private PacketType(String name) { + this.name = name; + } + + public String getName() { + return this.getName(); + } + + public Class getPacket() throws Exception { + return packet == null ? packet = ReflectionUtil.getClass(name, PackageType.MINECRAFT_SERVER) : packet; + } + } +} \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml index bc30a41..0815f19 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,6 +1,6 @@ name: OpenInv main: com.lishid.openinv.OpenInv -version: 2.1.7 +version: 2.1.9 author: lishid description: > This plugin allows you to open a player's inventory as a chest and interact with it in real time.