From ec0e1b9849acb32973a649212686a854bf2b1ae4 Mon Sep 17 00:00:00 2001 From: samczsun Date: Fri, 20 May 2016 22:51:29 -0400 Subject: [PATCH] New invsee implementation --- .../game/clans/clans/ClansManager.java | 4 +- .../game/clans/clans/invsee/Invsee.java | 23 -- .../clans/clans/invsee/InvseeManager.java | 43 +++ .../clans/invsee/commands/InvseeCommand.java | 69 +++- .../clans/invsee/ui/InvseeInventory.java | 325 ++++++++++++++---- .../repository/SiegeWeaponRepository.java | 2 +- 6 files changed, 364 insertions(+), 102 deletions(-) delete mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/Invsee.java create mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/InvseeManager.java diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java index b580655a5..988919ca7 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java @@ -44,7 +44,7 @@ import mineplex.game.clans.clans.commands.*; import mineplex.game.clans.clans.data.PlayerClan; import mineplex.game.clans.clans.event.ClansPlayerDeathEvent; import mineplex.game.clans.clans.gui.ClanShop; -import mineplex.game.clans.clans.invsee.Invsee; +import mineplex.game.clans.clans.invsee.InvseeManager; import mineplex.game.clans.clans.loot.LootManager; import mineplex.game.clans.clans.map.ItemMapManager; import mineplex.game.clans.clans.nameblacklist.ClansBlacklist; @@ -260,7 +260,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati new TntGeneratorManager(plugin, this); new SupplyDropManager(plugin, this); - new Invsee(this); + new InvseeManager(this); _explosion = new Explosion(plugin, blockRestore); _warPointEvasion = new WarPointEvasion(plugin); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/Invsee.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/Invsee.java deleted file mode 100644 index 3409089ea..000000000 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/Invsee.java +++ /dev/null @@ -1,23 +0,0 @@ -package mineplex.game.clans.clans.invsee; - -import mineplex.core.MiniPlugin; -import mineplex.game.clans.clans.ClansManager; -import mineplex.game.clans.clans.invsee.commands.InvseeCommand; - -public class Invsee extends MiniPlugin -{ - private ClansManager _clansManager; - - public Invsee(ClansManager clansManager) - { - super("Inventory Viewer", clansManager.getPlugin()); - - _clansManager = clansManager; - } - - public void addCommands() - { - addCommand(new InvseeCommand(this)); - } - -} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/InvseeManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/InvseeManager.java new file mode 100644 index 000000000..c126b3ac0 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/InvseeManager.java @@ -0,0 +1,43 @@ +package mineplex.game.clans.clans.invsee; + +import mineplex.core.MiniPlugin; +import mineplex.game.clans.clans.ClansManager; +import mineplex.game.clans.clans.invsee.commands.InvseeCommand; +import mineplex.game.clans.clans.invsee.ui.InvseeInventory; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class InvseeManager extends MiniPlugin +{ + private Map viewing = new HashMap<>(); + + public InvseeManager(ClansManager manager) + { + super("Invsee Manager", manager.getPlugin()); + } + + @Override + public void addCommands() + { + addCommand(new InvseeCommand(this)); + } + + public void doInvsee(OfflinePlayer target, Player requester) + { + InvseeInventory invseeInventory = viewing.computeIfAbsent(target.getUniqueId(), key -> new InvseeInventory(this, target)); + invseeInventory.addAndShowViewer(requester); + } + + public void close(UUID target) + { + InvseeInventory invseeInventory = viewing.remove(target); + if (invseeInventory == null) + { + log("Expected non-null inventory when closing " + target); + } + } +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/commands/InvseeCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/commands/InvseeCommand.java index f26393708..d8ee6d416 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/commands/InvseeCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/commands/InvseeCommand.java @@ -1,50 +1,83 @@ package mineplex.game.clans.clans.invsee.commands; +import com.mojang.authlib.GameProfile; import mineplex.core.command.CommandBase; import mineplex.core.common.Rank; import mineplex.core.common.util.F; import mineplex.core.common.util.UtilPlayer; -import mineplex.game.clans.clans.invsee.Invsee; +import mineplex.game.clans.clans.invsee.InvseeManager; import mineplex.game.clans.clans.invsee.ui.InvseeInventory; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import net.minecraft.server.v1_8_R3.NBTTagCompound; +import net.minecraft.server.v1_8_R3.WorldNBTStorage; +import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_8_R3.CraftOfflinePlayer; import org.bukkit.entity.Player; -public class InvseeCommand extends CommandBase +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.UUID; + +public class InvseeCommand extends CommandBase { - public InvseeCommand(Invsee plugin) + public InvseeCommand(InvseeManager plugin) { super(plugin, Rank.ADMIN, "invsee"); } - @SuppressWarnings("deprecation") @Override public void Execute(Player caller, String[] args) { if (args.length == 0) { - UtilPlayer.message(caller, F.help("/invsee ", "View a player's inventory", Rank.ADMIN)); + UtilPlayer.message(caller, F.help("/invsee ", "View a player's inventory", Rank.ADMIN)); + return; } - else + UUID uuid = null; + try { - String name = args[0]; + uuid = UUID.fromString(args[0]); + } + catch (IllegalArgumentException failed) + { + } - OfflinePlayer player = Bukkit.getServer().getPlayer(name); - - if (player == null) + OfflinePlayer exactPlayer = Bukkit.getServer().getPlayerExact(args[0]); + if (exactPlayer == null) + { + if (uuid == null) { - player = Bukkit.getServer().getOfflinePlayer(name); + // We don't want to open the wrong OfflinePlayer's inventory, so if we can't fetch the UUID then abort + GameProfile gameProfile = MinecraftServer.getServer().getUserCache().getProfile(args[0]); + if (gameProfile == null) + { + UtilPlayer.message(caller, F.main("Invsee", "Player is offline and we could not find the UUID. Aborting")); + return; + } + uuid = gameProfile.getId(); } - - if (player == null) + if (uuid == null) { - UtilPlayer.message(caller, F.main("Clans", "Specified player is neither online nor offline. Perhaps they changed their name?")); + UtilPlayer.message(caller, F.main("Invsee", "Something has gone very wrong. Please report the username/uuid you tried to look up")); return; } - - new InvseeInventory(player).ShowTo(caller); + // We need to check if we actually have data on this player + NBTTagCompound compound = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()).getPlayerData(uuid.toString()); + if (compound == null) + { + UtilPlayer.message(caller, F.main("Invsee", "The player exists, but has never joined this server. No inventory to show")); + return; + } + exactPlayer = Bukkit.getServer().getOfflinePlayer(uuid); } + if (exactPlayer == null) + { + UtilPlayer.message(caller, F.main("Invsee", "Could not load offline player data. Does the player exist?")); + return; + } + + Plugin.doInvsee(exactPlayer, caller); } - - } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/ui/InvseeInventory.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/ui/InvseeInventory.java index eb605e17b..06cb159e7 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/ui/InvseeInventory.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/invsee/ui/InvseeInventory.java @@ -1,54 +1,236 @@ package mineplex.game.clans.clans.invsee.ui; +import mineplex.core.common.util.*; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.game.clans.clans.ClansManager; +import mineplex.game.clans.clans.invsee.InvseeManager; +import net.minecraft.server.v1_8_R3.*; +import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftInventoryCrafting; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftInventoryPlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; -import mineplex.core.common.util.C; -import mineplex.core.common.util.UtilCollections; -import mineplex.core.common.util.UtilServer; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import java.io.File; +import java.io.FileOutputStream; +import java.util.*; + public class InvseeInventory implements Listener { - private OfflinePlayer _player; + private final InvseeManager invseeManager; + private final UUID uuid; + + // This is the current player. It will switch when the player joins/quits + private OfflinePlayer targetPlayer; + private Inventory _inventory; - - private boolean _online; - - private Player _admin; - - public InvseeInventory(OfflinePlayer player) + + private net.minecraft.server.v1_8_R3.PlayerInventory playerInventory; + + private List viewers = new ArrayList<>(); + private boolean dontUpdate = false; + + public InvseeInventory(InvseeManager manager, OfflinePlayer player) { - _online = (_player = player) instanceof Player; - - _inventory = UtilServer.getServer().createInventory(null, 54, player.getName() + " " + (_online ? C.cGreen + "ONLINE" : C.cRed + "OFFLINE")); - + invseeManager = manager; + uuid = player.getUniqueId(); + targetPlayer = player; + updateInventory(); + + _inventory = UtilServer.getServer().createInventory(null, 6 * 9, player.getName()); + + for (int index = 38; index < 45; index++) + { + _inventory.setItem(index, ItemStackFactory.Instance.CreateStack(Material.BARRIER, (byte) 0, 1, C.Bold)); + } + UtilServer.RegisterEvents(this); } - - public void ShowTo(Player admin) + + /* + * Add the player to the list of viewers and open the inventory for him + */ + public void addAndShowViewer(Player requester) { - _admin = admin; - admin.openInventory(_inventory); + viewers.add(requester); + requester.openInventory(_inventory); } - - @EventHandler - public void quit(PlayerQuitEvent event) + + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(PlayerJoinEvent event) { - if (_online && event.getPlayer().equals(_player)) + if (uuid.equals(event.getPlayer().getUniqueId())) { - _admin.closeInventory(); + targetPlayer = event.getPlayer(); + updateInventory(); } } - + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(PlayerQuitEvent event) + { + // If a viewer quit, this will clean it up + viewers.remove(event.getPlayer()); + if (viewers.size() == 0) + { + invseeManager.close(uuid); + } + else + { + // This should always work + targetPlayer = Bukkit.getOfflinePlayer(uuid); + updateInventory(); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(InventoryCloseEvent event) + { + if (_inventory.equals(event.getInventory())) + { + viewers.remove(event.getPlayer()); + if (viewers.size() == 0) + { + invseeManager.close(uuid); + } + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on(InventoryClickEvent event) + { + if (_inventory.equals(event.getClickedInventory())) + { + if (event.getCurrentItem() != null && event.getCurrentItem().getType() == Material.BARRIER + && event.getCurrentItem().getItemMeta() != null + && event.getCurrentItem().getItemMeta().getDisplayName().equals(C.Bold)) + { + event.setCancelled(true); + return; + } + + if (MAPPING_INVENTORY_REVERSE.containsKey(event.getRawSlot())) + { + dontUpdate = true; + ClansManager.getInstance().runSync(() -> + { + IInventory iInventoryThis = ((CraftInventory) _inventory).getInventory(); + playerInventory.setItem(MAPPING_INVENTORY_REVERSE.get(event.getRawSlot()), iInventoryThis.getItem(event.getRawSlot())); + saveInventory(); + dontUpdate = false; + }); + } + else if (MAPPING_CRAFTING_REVERSE.containsKey(event.getRawSlot())) + { + if (targetPlayer.isOnline()) + { + dontUpdate = true; + ClansManager.getInstance().runSync(() -> + { + IInventory iInventoryThis = ((CraftInventory) _inventory).getInventory(); + EntityPlayer entityPlayer = ((CraftPlayer) targetPlayer).getHandle(); + ContainerPlayer containerPlayer = (ContainerPlayer) entityPlayer.defaultContainer; + containerPlayer.craftInventory.setItem(MAPPING_CRAFTING_REVERSE.get(event.getRawSlot()), iInventoryThis.getItem(event.getRawSlot())); + dontUpdate = false; + }); + } + else + { + event.setCancelled(true); + } + } + else if (event.getRawSlot() == 49) + { + if (targetPlayer.isOnline()) + { + dontUpdate = true; + ClansManager.getInstance().runSync(() -> + { + IInventory iInventoryThis = ((CraftInventory) _inventory).getInventory(); + playerInventory.setCarried(iInventoryThis.getItem(49)); + saveInventory(); + ((Player) targetPlayer).updateInventory(); + dontUpdate = false; + }); + } + else + { + event.setCancelled(true); + } + } + } + } + + /* + * Updates the inventory instance + */ + private void updateInventory() + { + if (targetPlayer.isOnline()) + { + playerInventory = ((CraftPlayer) targetPlayer).getHandle().inventory; + } + else + { + NBTTagCompound compound = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()).getPlayerData(uuid.toString()); + // Should not matter if null + playerInventory = new PlayerInventory(null); + if (compound.hasKeyOfType("Inventory", 9)) + { + playerInventory.b(compound.getList("Inventory", 10)); + } + } + } + + private void saveInventory() + { + if (!targetPlayer.isOnline()) + { + try + { + WorldNBTStorage worldNBTStorage = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()); + NBTTagCompound compound = worldNBTStorage.getPlayerData(uuid.toString()); + compound.set("Inventory", new NBTTagList()); + playerInventory.a(compound.getList("Inventory", 10)); + File file = new File(worldNBTStorage.getPlayerDir(), targetPlayer.getUniqueId().toString() + ".dat.tmp"); + File file1 = new File(worldNBTStorage.getPlayerDir(), targetPlayer.getUniqueId().toString() + ".dat"); + NBTCompressedStreamTools.a(compound, new FileOutputStream(file)); + if (file1.exists()) + { + file1.delete(); + } + + file.renameTo(file1); + } + catch (Exception var5) + { + invseeManager.log("Failed to save player inventory for " + targetPlayer.getName()); + for (Player player : viewers) + { + UtilPlayer.message(player, F.main("Invsee", "Could not save inventory for " + targetPlayer.getName())); + } + var5.printStackTrace(System.out); + } + } + } + @EventHandler public void update(UpdateEvent event) { @@ -56,44 +238,71 @@ public class InvseeInventory implements Listener { return; } - - if (_online) + if (dontUpdate) { - if (!UtilCollections.equal(_inventory.getContents(), ((Player) _player).getInventory().getContents())) + return; + } + + IInventory iInventoryThis = ((CraftInventory) _inventory).getInventory(); + + // Update items on hotbar + for (int otherSlot = 0; otherSlot < 9; otherSlot++) + { + iInventoryThis.setItem(MAPPING_INVENTORY.get(otherSlot), playerInventory.getItem(otherSlot)); + } + // Update main inventory + for (int otherSlot = 9; otherSlot < 36; otherSlot++) + { + iInventoryThis.setItem(MAPPING_INVENTORY.get(otherSlot), playerInventory.getItem(otherSlot)); + } + // Update armor + for (int otherSlot = 36; otherSlot < 40; otherSlot++) + { + iInventoryThis.setItem(MAPPING_INVENTORY.get(otherSlot), playerInventory.getItem(otherSlot)); + } + + if (targetPlayer.isOnline()) + { + ContainerPlayer containerPlayer = (ContainerPlayer) ((CraftPlayer) targetPlayer).getHandle().defaultContainer; + for (int craftingIndex = 0; craftingIndex < 4; craftingIndex++) { - _inventory.setContents(((Player) _player).getInventory().getContents()); - } - } - } - - @EventHandler - public void inventoryClick(InventoryClickEvent event) - { - if (event.getClickedInventory().equals(((Player) _player).getInventory())) - { - _inventory.setContents(((Player) _player).getInventory().getContents()); - } - else if (event.getClickedInventory().equals(_inventory)) - { - if (_online) - { - ((Player) _player).getInventory().setContents(_inventory.getContents()); - } - } - } - - @EventHandler - public void closeInventory(InventoryCloseEvent event) - { - if (event.getInventory().equals(_inventory)) - { - UtilServer.Unregister(this); - - if (!_online) - { - // save offline inv + iInventoryThis.setItem(MAPPING_CRAFTING.get(craftingIndex), containerPlayer.craftInventory.getItem(craftingIndex)); } } + iInventoryThis.setItem(49, playerInventory.getCarried()); } + // Maps slot indices of player inventories to slot indices of double chests + private static final Map MAPPING_INVENTORY = new HashMap<>(); + private static final Map MAPPING_INVENTORY_REVERSE = new HashMap<>(); + private static final Map MAPPING_CRAFTING = new HashMap<>(); + private static final Map MAPPING_CRAFTING_REVERSE = new HashMap<>(); + + static + { + int[] inventoryMapping = new int[] + { + 27, 28, 29, 30, 31, 32, 33, 34, 35, //Hotbar + 0, 1, 2, 3, 4, 5, 6, 7, 8, // Top row inventory + 9, 10, 11, 12, 13, 14, 15, 16, 17, //Second row inventory + 18, 19, 20, 21, 22, 23, 24, 25, 26, //Third row inventory + 53, 52, 51, 50 //Armor + }; + int[] craftingMapping = new int[] + { + 36, 37, //Top crafting + 45, 46 //Bottom crafting + }; + for (int i = 0; i < inventoryMapping.length; i++) + { + MAPPING_INVENTORY.put(i, inventoryMapping[i]); + MAPPING_INVENTORY_REVERSE.put(inventoryMapping[i], i); + } + + for (int i = 0; i < craftingMapping.length; i++) + { + MAPPING_CRAFTING.put(i, craftingMapping[i]); + MAPPING_CRAFTING_REVERSE.put(craftingMapping[i], i); + } + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java index 302329ccb..c8a03daec 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java @@ -132,7 +132,7 @@ public class SiegeWeaponRepository extends MinecraftRepository public void updateWeapon(SiegeWeaponToken token) { - System.out.println("Siege Repo> Updating weapon " + token.UniqueId); +// System.out.println("Siege Repo> Updating weapon " + token.UniqueId); _siegeManager.runAsync(() -> executeUpdate(UPDATE_WEAPON,