From 2675789f592773dd689c2af13a39c497dbaf04af Mon Sep 17 00:00:00 2001 From: samczsun Date: Thu, 12 May 2016 17:54:23 -0400 Subject: [PATCH 01/33] Compare commands with equals. Fixes PC-116 --- .../src/mineplex/game/clans/clans/ClansManager.java | 2 +- .../src/nautilus/game/arcade/managers/MiscManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 6ee70c96e..95cf0e6ae 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 @@ -1175,7 +1175,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati @EventHandler public void hubCommand(PlayerCommandPreprocessEvent event) { - if (event.getMessage().toLowerCase().startsWith("/lobby") || event.getMessage().toLowerCase().startsWith("/hub") || event.getMessage().toLowerCase().startsWith("/leave")) + if (event.getMessage().toLowerCase().equals("/lobby") || event.getMessage().toLowerCase().equals("/hub") || event.getMessage().toLowerCase().equals("/leave")) { Portal.getInstance().sendPlayerToServer(event.getPlayer(), "Lobby"); event.setCancelled(true); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/MiscManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/MiscManager.java index e68656e2c..b4d2993d1 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/MiscManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/MiscManager.java @@ -140,7 +140,7 @@ public class MiscManager implements Listener @EventHandler public void HubCommand(PlayerCommandPreprocessEvent event) { - if (event.getMessage().toLowerCase().startsWith("/lobby") || event.getMessage().toLowerCase().startsWith("/hub") || event.getMessage().toLowerCase().startsWith("/leave")) + if (event.getMessage().toLowerCase().equals("/lobby") || event.getMessage().toLowerCase().equals("/hub") || event.getMessage().toLowerCase().equals("/leave")) { Manager.GetPortal().sendPlayerToServer(event.getPlayer(), "Lobby"); event.setCancelled(true); From 173a6bb1433d4f9e14340054b1d4d5c3bcbbf709 Mon Sep 17 00:00:00 2001 From: samczsun Date: Fri, 13 May 2016 23:04:51 -0400 Subject: [PATCH 02/33] Delete IncognitoHidePlayerEvent --- .../events/IncognitoHidePlayerEvent.java | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/core/incognito/events/IncognitoHidePlayerEvent.java diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/core/incognito/events/IncognitoHidePlayerEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/core/incognito/events/IncognitoHidePlayerEvent.java deleted file mode 100644 index 54dabeebc..000000000 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/core/incognito/events/IncognitoHidePlayerEvent.java +++ /dev/null @@ -1,47 +0,0 @@ -package mineplex.core.incognito.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Called when an Incognito player is getting hidden from all other players. - */ -public class IncognitoHidePlayerEvent extends Event -{ - private static final HandlerList handlers = new HandlerList(); - - private Player _player; - private boolean _cancelled; - - public IncognitoHidePlayerEvent(Player player) - { - _player = player; - } - - public Player getPlayer() - { - return _player; - } - - public void setCancelled(boolean cancelled) - { - _cancelled = cancelled; - } - - public boolean isCancelled() - { - return _cancelled; - } - - public HandlerList getHandlers() - { - return handlers; - } - - public static HandlerList getHandlerList() - { - return handlers; - } - -} \ No newline at end of file From 7c66c98338a57188ff11092100e6c18e560a6fec Mon Sep 17 00:00:00 2001 From: samczsun Date: Sat, 14 May 2016 00:14:49 -0400 Subject: [PATCH 03/33] Clean up Farming --- .../src/mineplex/game/clans/Farming.java | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java index f7145451e..1027a2253 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java @@ -1,73 +1,72 @@ package mineplex.game.clans; +import com.google.common.collect.Sets; import mineplex.core.MiniPlugin; +import mineplex.core.common.util.UtilItem; import mineplex.core.itemstack.ItemStackFactory; import mineplex.core.common.util.F; import mineplex.core.common.util.UtilPlayer; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.plugin.java.JavaPlugin; +import java.util.Set; + public class Farming extends MiniPlugin { + private static final Set PLANTABLE = Sets.newHashSet( + Material.WHEAT, + Material.SUGAR_CANE_BLOCK, + Material.PUMPKIN_STEM, + Material.MELON_STEM, + Material.COCOA, + Material.CARROT, + Material.POTATO + ); + public Farming(JavaPlugin plugin) { super("Farming", plugin); } - @EventHandler + @EventHandler (ignoreCancelled = true) public void BlockBreak(BlockBreakEvent event) { - if (event.isCancelled()) - return; - if (event.getBlock().getType() != Material.LEAVES) return; - if (event.getPlayer().getItemInHand() != null) - if (event.getPlayer().getItemInHand().getType() == Material.SHEARS) - return; - + if (UtilItem.matchesMaterial(event.getPlayer().getItemInHand(), Material.SHEARS)) + return; + + Location dropLocation = event.getBlock().getLocation().add(0.5, 0.5, 0.5); + if (Math.random() > 0.9) - event.getBlock().getWorld().dropItemNaturally( - event.getBlock().getLocation().add(0.5, 0.5, 0.5), - ItemStackFactory.Instance.CreateStack(Material.APPLE)); + event.getBlock().getWorld().dropItemNaturally(dropLocation, ItemStackFactory.Instance.CreateStack(Material.APPLE)); if (Math.random() > 0.999) - event.getBlock().getWorld().dropItemNaturally( - event.getBlock().getLocation().add(0.5, 0.5, 0.5), - ItemStackFactory.Instance.CreateStack(Material.GOLDEN_APPLE)); + event.getBlock().getWorld().dropItemNaturally(dropLocation, ItemStackFactory.Instance.CreateStack(Material.GOLDEN_APPLE)); } - @SuppressWarnings("deprecation") - @EventHandler + @EventHandler (ignoreCancelled = true) public void BlockPlace(BlockPlaceEvent event) { - if (event.isCancelled()) + if (!PLANTABLE.contains(event.getBlock().getType())) return; - if ( - event.getBlock().getTypeId() != 59 && - event.getBlock().getTypeId() != 83 && - event.getBlock().getTypeId() != 104 && - event.getBlock().getTypeId() != 105 && - event.getBlock().getTypeId() != 127 && - event.getBlock().getTypeId() != 141 && - event.getBlock().getTypeId() != 142 - ) - return; + double blockY = event.getBlock().getLocation().getY(); + double seaLevel = event.getBlock().getWorld().getSeaLevel(); - if (event.getBlock().getLocation().getY() < event.getBlock().getWorld().getSeaLevel() - 12) + if (blockY < seaLevel - 12) { UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot plant " + F.item(ItemStackFactory.Instance.GetName(event.getPlayer().getItemInHand(), true)) + " this deep underground.")); event.setCancelled(true); } - - else if (event.getBlock().getLocation().getY() > event.getBlock().getWorld().getSeaLevel() + 24) + else if (blockY > seaLevel + 24) { UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot plant " + F.item(ItemStackFactory.Instance.GetName(event.getPlayer().getItemInHand(), true)) + " at this altitude.")); From 89da8790bfef40e1741650b3c62e635bd21f313d Mon Sep 17 00:00:00 2001 From: samczsun Date: Sun, 15 May 2016 16:17:59 -0400 Subject: [PATCH 04/33] Clans optimizations Key notes: * RAM usage decreased on startup * Startup speed much quicker * Map is entirely rendered on startup Details: Changed TutorialWorldManager Stack -> LinkedList because no need for synchronization Documented map methods and magic numbers Remove loading all chunks on startup Render map on startup Optimize map rendering by replacing ArrayList with LinkedList Optimize map rendering by reading chunk directly from disk and caching to prevent entity ticking Optimize map rendering by using a global BlockPosition Save results for showing zoom --- .../game/clans/clans/map/ItemMapManager.java | 541 ++++++++++-------- .../game/clans/clans/map/ItemMapRenderer.java | 4 +- .../clans/map/events/PlayerGetMapEvent.java | 3 + .../clans/clans/regions/ClansRegions.java | 13 +- .../clans/tutorial/TutorialWorldManager.java | 5 +- 5 files changed, 312 insertions(+), 254 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java index f73eb2280..d2aaddd87 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java @@ -1,30 +1,26 @@ package mineplex.game.clans.clans.map; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.PrintWriter; +import java.io.*; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; +import java.util.*; import java.util.Map.Entry; +import mineplex.core.common.util.*; import mineplex.game.clans.tutorial.TutorialManager; -import mineplex.game.clans.tutorial.map.TutorialMapManager; +import net.minecraft.server.v1_8_R3.*; import org.apache.commons.io.FileUtils; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.util.LongHash; +import org.bukkit.craftbukkit.v1_8_R3.util.LongObjectHashMap; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.PlayerDeathEvent; @@ -35,6 +31,8 @@ import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.map.MapRenderer; @@ -46,13 +44,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Multisets; import mineplex.core.MiniPlugin; -import mineplex.core.common.util.C; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilInv; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -import mineplex.core.common.util.UtilTextBottom; -import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilTime.TimeUnit; import mineplex.core.itemstack.ItemBuilder; import mineplex.core.portal.ServerTransferEvent; @@ -62,82 +53,119 @@ import mineplex.game.clans.clans.ClansManager; import mineplex.game.clans.clans.ClansUtility; import mineplex.game.clans.clans.map.events.PlayerGetMapEvent; import mineplex.game.clans.clans.worldevent.WorldEventManager; -import net.minecraft.server.v1_8_R3.Block; -import net.minecraft.server.v1_8_R3.BlockPosition; -import net.minecraft.server.v1_8_R3.Blocks; -import net.minecraft.server.v1_8_R3.IBlockData; -import net.minecraft.server.v1_8_R3.MaterialMapColor; -import net.minecraft.server.v1_8_R3.PersistentCollection; +/* + * This class manages what the Clans map will show. + * It will scan all relevant chunks (eg players nearby) every ticks + */ public class ItemMapManager extends MiniPlugin { - private int _blocksScan = 16 * 3; + // Every BLOCK_SCAN_INTERVAL we add as a new region to scan + private static final int BLOCK_SCAN_INTERVAL = 16 * 3; + // 1536 is the width of the entire world from one borderland to the other + private static final int HALF_WORLD_SIZE = 1536 / 2; + // This slot is where the Clans Map will go by default + private static final int CLANS_MAP_SLOT = 8; + + private static final String[] ZOOM_INFO; + + static + { + ZOOM_INFO = new String[4]; + for (int zoomLevel = 0; zoomLevel <= 3; zoomLevel++) + { + StringBuilder progressBar = new StringBuilder(C.cBlue); + + boolean colorChange = false; + for (int i = 2; i >= 0; i--) + { + if (!colorChange && i < zoomLevel) + { + progressBar.append(C.cGray); + colorChange = true; + } + char c; + switch (i) + { + case 0: + c = '█'; + break; + case 1: + c = '▆'; + break; + default: + c = '▄'; + break; + } + for (int a = 0; a < 4; a++) + { + progressBar.append(c); + } + + if (i > 0) + { + progressBar.append(" "); + } + } + ZOOM_INFO[zoomLevel] = progressBar.toString(); + } + } + private ClansUtility _clansUtility; private Comparator> _comparator; - private int _halfMapSize = 1536 / 2; - private int[][] _heightMap = new int[(_halfMapSize * 2) + 16][]; - private boolean _loadWorld = true; + private int[][] _heightMap = new int[(HALF_WORLD_SIZE * 2) + 16][]; private HashMap _map = new HashMap(); private short _mapId = -1; private HashMap _mapInfo = new HashMap(); private HashMap _scale = new HashMap(); - private ArrayList> _scanList = new ArrayList>(); + // Use LinkedList because operations are either add(Entry) which is O(1) and remove(0) which is O(1) on LinkedList but O(n) on ArrayList + private LinkedList> _scanList = new LinkedList>(); private World _world; + private WorldServer _nmsWorld; + private ChunkProviderServer _chunkProviderServer; + private ChunkRegionLoader _chunkRegionLoader; private WorldEventManager _eventManager; private TutorialManager _tutorial; public ItemMapManager(ClansManager clansManager, TutorialManager tutorial, WorldEventManager eventManager) { super("ItemMapManager", clansManager.getPlugin()); - + _clansUtility = clansManager.getClanUtility(); _eventManager = eventManager; _tutorial = tutorial; - _comparator = new Comparator>() + _comparator = (o1, o2) -> { + // Render the places outside the map first to speed up visual errors fixing + int outsideMap = Boolean.compare(o1.getValue() < -HALF_WORLD_SIZE, o2.getValue() < -HALF_WORLD_SIZE); - @Override - public int compare(Entry o1, Entry o2) + if (outsideMap != 0) { - // Render the places outside the map first to speed up visual errors fixing - int outsideMap = Boolean.compare(o1.getValue() < -_halfMapSize, o2.getValue() < -_halfMapSize); + return -outsideMap; + } - if (outsideMap != 0) - { - return -outsideMap; - } + double dist1 = 0; + double dist2 = 0; - double dist1 = 0; - double dist2 = 0; - - for (Player player : UtilServer.getPlayers()) - { - dist1 += getDistance(o1, player.getLocation().getX(), player.getLocation().getZ()); - dist2 += getDistance(o2, player.getLocation().getX(), player.getLocation().getZ()); - } - - if (dist1 != dist2) - { - return Double.compare(dist1, dist2); - } - - dist1 = getDistance(o1, 0, 0); - dist2 = getDistance(o2, 0, 0); + for (Player player : UtilServer.getPlayers()) + { + dist1 += getDistance(o1, player.getLocation().getX(), player.getLocation().getZ()); + dist2 += getDistance(o2, player.getLocation().getX(), player.getLocation().getZ()); + } + if (dist1 != dist2) + { return Double.compare(dist1, dist2); - } + + dist1 = getDistance(o1, 0, 0); + dist2 = getDistance(o2, 0, 0); + + return Double.compare(dist1, dist2); + }; - for (int x = -_halfMapSize; x < _halfMapSize; x += _blocksScan) - { - for (int z = -_halfMapSize - 16; z < _halfMapSize; z += (z < -_halfMapSize ? 16 : _blocksScan)) - { - _scanList.add(new HashMap.SimpleEntry(x, z)); - } - } - _scale.put(0, 1); // _scale.put(1, 2); _scale.put(1, 4); @@ -147,7 +175,7 @@ public class ItemMapManager extends MiniPlugin for (Entry entry : _scale.entrySet()) { - int size = (_halfMapSize * 2) / entry.getValue(); + int size = (HALF_WORLD_SIZE * 2) / entry.getValue(); Byte[][] bytes = new Byte[size][]; for (int i = 0; i < size; i++) @@ -165,6 +193,23 @@ public class ItemMapManager extends MiniPlugin _world = Bukkit.getWorld("world"); + try + { + Field chunkLoader = ChunkProviderServer.class.getDeclaredField("chunkLoader"); + chunkLoader.setAccessible(true); + _nmsWorld = ((CraftWorld) _world).getHandle(); + _chunkProviderServer = _nmsWorld.chunkProviderServer; + _chunkRegionLoader = (ChunkRegionLoader) chunkLoader.get(_chunkProviderServer); + if (_chunkRegionLoader == null) + { + throw new RuntimeException("Did not expect null chunkLoader"); + } + } + catch (ReflectiveOperationException e) + { + throw new RuntimeException("Could not reflectively access ChunkRegionLoader", e); + } + try { File file = new File("world/clans_map_id"); @@ -237,7 +282,59 @@ public class ItemMapManager extends MiniPlugin ex.printStackTrace(); } - rebuildScan(); + rebuildScan(true); + initialScan(); + } + + private void initialScan() + { + System.out.println("Beginning initial scan. There are " + _scanList.size() + " regions to scan"); + + // How many regions before logging an update (Currently set to every 20%) + int logPer = _scanList.size() / 5; + + while (!_scanList.isEmpty()) + { + Entry entry = _scanList.remove(0); + if (_scanList.size() % logPer == 0) + { + System.out.println("Running initial render... " + _scanList.size() + " sections to go"); + } + + int startingX = entry.getKey(); + int startingZ = entry.getValue(); + + boolean outsideMap = startingZ < -HALF_WORLD_SIZE; + + scanWorldMap(startingX, startingZ, !outsideMap); + + if (outsideMap) + { + continue; + } + + for (int scale = 1; scale < _scale.size(); scale++) + { + if (scale == 3) + continue; + + drawWorldScale(scale, startingX, startingZ); + colorWorldHeight(scale, startingX, startingZ); + } + + colorWorldHeight(0, startingX, startingZ); + } + + for (int x = -HALF_WORLD_SIZE; x < HALF_WORLD_SIZE; x += BLOCK_SCAN_INTERVAL) + { + for (int z = -HALF_WORLD_SIZE; z < HALF_WORLD_SIZE; z += BLOCK_SCAN_INTERVAL) + { + drawWorldScale(3, x, z); + colorWorldHeight(3, x, z); + } + } + + System.out.println("Finished first map scan and render"); } private void setupRenderer(MapView view) @@ -256,10 +353,7 @@ public class ItemMapManager extends MiniPlugin if (!(event.getRightClicked() instanceof ItemFrame)) return; - ItemStack item = event.getPlayer().getItemInHand(); - - if (item == null || item.getType() != Material.MAP || item.getDurability() < _mapId - || item.getDurability() > _mapId + 100) + if (!isItemClansMap(event.getPlayer().getItemInHand())) return; event.setCancelled(true); @@ -270,7 +364,7 @@ public class ItemMapManager extends MiniPlugin */ public int calcMapCenter(int zoom, int cord) { - int mapSize = _halfMapSize / zoom; // This is how large the map is in pixels + int mapSize = HALF_WORLD_SIZE / zoom; // This is how large the map is in pixels int mapCord = cord / zoom; // This is pixels from true center of map, not held map @@ -309,7 +403,7 @@ public class ItemMapManager extends MiniPlugin Byte[][] map = _map.get(scale); int zoom = getZoom(scale); - for (int x = startingX; x < startingX + _blocksScan; x += zoom) + for (int x = startingX; x < startingX + BLOCK_SCAN_INTERVAL; x += zoom) { double d0 = 0; @@ -319,10 +413,10 @@ public class ItemMapManager extends MiniPlugin { for (int addZ = 0; addZ < zoom; addZ++) { - int hX = x + addX + _halfMapSize; - int hZ = (startingZ - zoom) + addZ + _halfMapSize; + int hX = x + addX + HALF_WORLD_SIZE; + int hZ = (startingZ - zoom) + addZ + HALF_WORLD_SIZE; - if (hX >= _halfMapSize * 2 || hZ >= _halfMapSize * 2) + if (hX >= HALF_WORLD_SIZE * 2 || hZ >= HALF_WORLD_SIZE * 2) { continue; } @@ -331,7 +425,7 @@ public class ItemMapManager extends MiniPlugin } } - for (int z = startingZ; z < startingZ + _blocksScan; z += zoom) + for (int z = startingZ; z < startingZ + BLOCK_SCAN_INTERVAL; z += zoom) { // Water depth colors not included double d1 = 0; @@ -340,10 +434,10 @@ public class ItemMapManager extends MiniPlugin { for (int addZ = 0; addZ < zoom; addZ++) { - int hX = x + addX + _halfMapSize; - int hZ = z + addZ + _halfMapSize; + int hX = x + addX + HALF_WORLD_SIZE; + int hZ = z + addZ + HALF_WORLD_SIZE; - if (hX >= _halfMapSize * 2 || hZ >= _halfMapSize * 2) + if (hX >= HALF_WORLD_SIZE * 2 || hZ >= HALF_WORLD_SIZE * 2) { continue; } @@ -370,7 +464,7 @@ public class ItemMapManager extends MiniPlugin b0 = 0; } - int origColor = map[(x + _halfMapSize) / zoom][(z + _halfMapSize) / zoom] - 1; + int origColor = map[(x + HALF_WORLD_SIZE) / zoom][(z + HALF_WORLD_SIZE) / zoom] - 1; /*if (color < 4) { @@ -388,7 +482,7 @@ public class ItemMapManager extends MiniPlugin }*/ byte color = (byte) (origColor + b0); - map[(x + _halfMapSize) / zoom][(z + _halfMapSize) / zoom] = color; + map[(x + HALF_WORLD_SIZE) / zoom][(z + HALF_WORLD_SIZE) / zoom] = color; } } } @@ -399,9 +493,9 @@ public class ItemMapManager extends MiniPlugin Byte[][] second = _map.get(scale); int zoom = getZoom(scale); - for (int x = startingX; x < startingX + _blocksScan; x += zoom) + for (int x = startingX; x < startingX + BLOCK_SCAN_INTERVAL; x += zoom) { - for (int z = startingZ; z < startingZ + _blocksScan; z += zoom) + for (int z = startingZ; z < startingZ + BLOCK_SCAN_INTERVAL; z += zoom) { HashMultiset hashmultiset = HashMultiset.create(); @@ -409,8 +503,8 @@ public class ItemMapManager extends MiniPlugin { for (int addZ = 0; addZ < zoom; addZ++) { - int pX = x + addX + _halfMapSize; - int pZ = z + addZ + _halfMapSize; + int pX = x + addX + HALF_WORLD_SIZE; + int pZ = z + addZ + HALF_WORLD_SIZE; if (pX >= first.length || pZ >= first.length) { @@ -432,7 +526,7 @@ public class ItemMapManager extends MiniPlugin { color = (byte) 0; } - second[(x + _halfMapSize) / zoom][(z + _halfMapSize) / zoom] = color; + second[(x + HALF_WORLD_SIZE) / zoom][(z + HALF_WORLD_SIZE) / zoom] = color; } } } @@ -440,25 +534,16 @@ public class ItemMapManager extends MiniPlugin @EventHandler public void dropItem(ItemSpawnEvent event) { - ItemStack item = event.getEntity().getItemStack(); - - if (item != null && item.getType() == Material.MAP && item.getDurability() >= _mapId - && item.getDurability() <= _mapId + 100) - { + if (isItemClansMap(event.getEntity().getItemStack())) event.getEntity().remove(); - } } - + public void removeMap(Player player) { for (int slot = 0; slot < player.getInventory().getSize(); slot++) { - ItemStack item = player.getInventory().getItem(slot); - - if (item != null && item.getType() == Material.MAP && item.getDurability() >= _mapId && item.getDurability() <= _mapId + 100) - { + if (isItemClansMap(player.getInventory().getItem(slot))) player.getInventory().setItem(slot, null); - } } } @@ -477,7 +562,7 @@ public class ItemMapManager extends MiniPlugin private double getDistance(Entry entry, double x1, double z1) { - return getDistance(x1, z1, entry.getKey() + (_blocksScan / 2), entry.getValue() + (_blocksScan / 2)); + return getDistance(x1, z1, entry.getKey() + (BLOCK_SCAN_INTERVAL / 2), entry.getValue() + (BLOCK_SCAN_INTERVAL / 2)); } public Byte[][] getMap(int scale) @@ -492,7 +577,7 @@ public class ItemMapManager extends MiniPlugin public int getMapSize() { - return _halfMapSize; + return HALF_WORLD_SIZE; } public int getZoom(int scale) @@ -500,6 +585,7 @@ public class ItemMapManager extends MiniPlugin return _scale.get(scale); } + //fixme Spam left click in a chest and this won't work @EventHandler public void preventMapMoveInventories(InventoryClickEvent event) { @@ -510,12 +596,11 @@ public class ItemMapManager extends MiniPlugin // Yeah, the loop looks a little weird.. for (ItemStack item : new ItemStack[] - { - event.getCurrentItem(), event.getCursor() - }) + { + event.getCurrentItem(), event.getCursor() + }) { - if (item == null || item.getType() != Material.MAP || item.getDurability() < _mapId - || item.getDurability() > _mapId + 100) + if (!isItemClansMap(item)) continue; if (inv.getHolder() instanceof Player ? !event.isShiftClick() : Objects.equal(event.getCurrentItem(), item)) @@ -529,6 +614,7 @@ public class ItemMapManager extends MiniPlugin } } + //fixme So what appears to happen is that after you die, if your map is is the same then the map is frozen @EventHandler public void onDeath(PlayerDeathEvent event) { @@ -542,14 +628,10 @@ public class ItemMapManager extends MiniPlugin { Player player = event.getPlayer(); - ItemStack item = player.getInventory().getItem(event.getNewSlot()); - - if (item == null || item.getType() != Material.MAP || item.getDurability() < _mapId - || item.getDurability() > _mapId + 100) + if (!isItemClansMap(player.getInventory().getItem(event.getNewSlot()))) return; showZoom(player, getMap(player)); - } @EventHandler @@ -558,10 +640,7 @@ public class ItemMapManager extends MiniPlugin if (event.getAction() == Action.PHYSICAL) return; - ItemStack item = event.getItem(); - - if (item == null || item.getType() != Material.MAP || item.getDurability() < _mapId - || item.getDurability() > _mapId + 100) + if (!isItemClansMap(event.getItem())) return; event.setCancelled(true); @@ -664,17 +743,17 @@ public class ItemMapManager extends MiniPlugin p.sendMessage(C.cYellow + "If you want to play on Clans again, rejoin the Mineplex server!"); } - private void rebuildScan() + private void rebuildScan(boolean firstScan) { - for (int x = -_halfMapSize; x < _halfMapSize; x += _blocksScan) + for (int x = -HALF_WORLD_SIZE; x < HALF_WORLD_SIZE; x += BLOCK_SCAN_INTERVAL) { - for (int z = -_halfMapSize - 16; z < _halfMapSize; z += (z < -_halfMapSize ? 16 : _blocksScan)) + for (int z = -HALF_WORLD_SIZE - 16; z < HALF_WORLD_SIZE; z += (z < -HALF_WORLD_SIZE ? 16 : BLOCK_SCAN_INTERVAL)) { - _scanList.add(new HashMap.SimpleEntry(x, z)); + _scanList.add(new HashMap.SimpleEntry<>(x, z)); } } - if (!_loadWorld) + if (!firstScan) { Iterator> itel = _scanList.iterator(); @@ -744,101 +823,113 @@ public class ItemMapManager extends MiniPlugin if (event.getType() != UpdateType.FAST) return; - if (_scanList.isEmpty()) + if (_scanList.isEmpty() && UtilServer.getPlayers().length > 0) { - if (_loadWorld) - { - for (int x = -_halfMapSize; x < _halfMapSize; x += _blocksScan) - { - for (int z = -_halfMapSize; z < _halfMapSize; z += _blocksScan) - { - drawWorldScale(3, x, z); - colorWorldHeight(3, x, z); - } - } - - System.out.print("Finished first map scan and render"); - } - - _loadWorld = false; - - if (UtilServer.getPlayers().length == 0) - return; - - rebuildScan(); + rebuildScan(false); } - else if (_scanList.size() % 20 == 0) + + if (_scanList.size() % 20 == 0) { Collections.sort(_scanList, _comparator); } - + if (_scanList.isEmpty()) + { return; + } Entry entry = _scanList.remove(0); int startingX = entry.getKey(); int startingZ = entry.getValue(); - boolean outsideMap = startingZ < -_halfMapSize; + boolean outsideMap = startingZ < -HALF_WORLD_SIZE; scanWorldMap(startingX, startingZ, !outsideMap); - + if (outsideMap) - { return; - } for (int scale = 1; scale < _scale.size(); scale++) { - if (scale == 3 && _loadWorld) - continue; - - if (!outsideMap) - { - drawWorldScale(scale, startingX, startingZ); - } - + drawWorldScale(scale, startingX, startingZ); colorWorldHeight(scale, startingX, startingZ); } - + colorWorldHeight(0, startingX, startingZ); } + + // Let's not create hundreds of thousands of BlockPositions + // Single thread = should be thread safe + private BlockPosition.MutableBlockPosition _blockPosition = new BlockPosition.MutableBlockPosition(); + + // Maps the cached chunks which were loaded from disk to save IO operations + private LongObjectHashMap _chunkCache = new LongObjectHashMap<>(); + + /* + * Remove the cached chunks when the real chunks are loaded in + */ + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void LoadChunk(ChunkLoadEvent event) + { + _chunkCache.remove(LongHash.toLong(event.getChunk().getX(), event.getChunk().getZ())); + } + + /* + * Given a particular coordinate, this method will scan up to BLOCK_SCAN_INTERVAL and record the color of ever 16th block + * If a chunk has not been loaded, the following steps will be taken: + * * Attempt to load the chunk from disk. + * * If the chunk could not be loaded, generate it froms scratch + * Otherwise, the loaded chunk will be used + */ public void scanWorldMap(int startingX, int startingZ, boolean setColors) { Byte[][] map = _map.get(0); - - for (int beginX = startingX; beginX < startingX + _blocksScan; beginX += 16) + for (int beginX = startingX; beginX < startingX + BLOCK_SCAN_INTERVAL; beginX += 16) { - for (int beginZ = startingZ - (startingZ > -_halfMapSize ? 16 : 0); beginZ < startingZ - + (setColors ? _blocksScan : 16); beginZ += 16) + for (int beginZ = startingZ - (startingZ > -HALF_WORLD_SIZE ? 16 : 0); beginZ < startingZ + + (setColors ? BLOCK_SCAN_INTERVAL : 16); beginZ += 16) { - Chunk chunk = _world.getChunkAt(beginX / 16, beginZ / 16); - boolean loaded = false; - - if (!chunk.isLoaded()) + int chunkX = beginX / 16; + int chunkZ = beginZ / 16; + net.minecraft.server.v1_8_R3.Chunk nmsChunk = _chunkProviderServer.getChunkIfLoaded(chunkX, chunkZ); + if (nmsChunk == null) { - if (_loadWorld) + long key = LongHash.toLong(chunkX, chunkZ); + nmsChunk = _chunkCache.get(key); + if (nmsChunk == null) { - loaded = chunk.load(); - } - else - { - continue; + try + { + Object[] data = _chunkRegionLoader.loadChunk(_nmsWorld, chunkX, chunkZ); + if (data == null) + { + // Something is wrong with the chunk + System.out.println("Chunk is not generated or missing level/block data. Regenerating (" + chunkX + "," + chunkZ + ")"); + nmsChunk = ((CraftChunk) _world.getChunkAt(chunkX, chunkZ)).getHandle(); + } + else + { + nmsChunk = (net.minecraft.server.v1_8_R3.Chunk) data[0]; + } + } + catch (IOException e) + { + throw new RuntimeException("Chunk is corrupt or not readable!", e); + } + _chunkCache.put(key, nmsChunk); } } - net.minecraft.server.v1_8_R3.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); - - for (int x = beginX; x < beginX + 16; x++) + if (!nmsChunk.isEmpty()) { - for (int z = beginZ; z < beginZ + 16; z++) + for (int x = beginX; x < beginX + 16; x++) { - int color = 0; - - if (!nmsChunk.isEmpty()) + for (int z = beginZ; z < beginZ + 16; z++) { + int color = 0; + int k3 = x & 0xF; int l3 = z & 0xF; @@ -850,7 +941,8 @@ public class ItemMapManager extends MiniPlugin do { l4--; - iblockdata= nmsChunk.getBlockData(new BlockPosition(k3, l4, l3)); + _blockPosition.c(k3, l4, l3); + iblockdata = nmsChunk.getBlockData(_blockPosition); } while (iblockdata.getBlock().g(iblockdata) == MaterialMapColor.b && (l4 > 0)); @@ -860,34 +952,31 @@ public class ItemMapManager extends MiniPlugin Block block1; do { - block1 = nmsChunk.getType(new BlockPosition(k3, j5--, l3)); + _blockPosition.c(k3, j5--, l3); + block1 = nmsChunk.getType(_blockPosition); } while ((j5 > 0) && (block1.getMaterial().isLiquid())); } } - _heightMap[x + _halfMapSize + 16][z + _halfMapSize + 16] = l4; + _heightMap[x + HALF_WORLD_SIZE + 16][z + HALF_WORLD_SIZE + 16] = l4; if (setColors) { //color = block.f(i5).M; - IBlockData data = nmsChunk.getBlockData(new BlockPosition(k3, l4, l3)); + _blockPosition.c(k3, l4, l3); + IBlockData data = nmsChunk.getBlockData(_blockPosition); color = data.getBlock().g(data).M; color = (byte) ((color * 4) + 1); } - } - if (setColors && beginZ >= startingZ) - { - map[x + _halfMapSize][z + _halfMapSize] = (byte) color; + if (setColors && beginZ >= startingZ) + { + map[x + HALF_WORLD_SIZE][z + HALF_WORLD_SIZE] = (byte) color; + } } } - - if (loaded) - { - chunk.unload(); - } } } } @@ -898,10 +987,10 @@ public class ItemMapManager extends MiniPlugin PlayerGetMapEvent event = UtilServer.CallEvent(new PlayerGetMapEvent(player)); if (event.isCancelled()) return; - + for (ItemStack item : UtilInv.getItems(player)) { - if (item.getType() == Material.MAP && (item.getDurability() >= _mapId && item.getDurability() <= _mapId + 100)) + if (isItemClansMap(item)) { return; } @@ -909,62 +998,38 @@ public class ItemMapManager extends MiniPlugin ItemStack item = new ItemBuilder(Material.MAP, 1, (short) getMap(player).getMap()).setTitle("Clans Map").build(); - int slot = player.getInventory().firstEmpty(); + int slot = CLANS_MAP_SLOT; + + ItemStack mapSlot = player.getInventory().getItem(slot); + if (mapSlot != null && mapSlot.getType() != Material.AIR) + { + slot = player.getInventory().firstEmpty(); + } if (slot >= 0) { - ItemStack mapSlot = player.getInventory().getItem(8); - - if (mapSlot == null || mapSlot.getType() == Material.AIR) - { - slot = 8; - } - player.getInventory().setItem(slot, item); } } + /* + * Displays the action bar to a player given their zoom level. Implementation may change + */ private void showZoom(Player player, MapInfo info) { - String progressBar = C.cBlue + ""; - - boolean colorChange = false; - - for (int i = 2; i >= 0; i--) - { - if (!colorChange && i < info.getScale()) - { - progressBar += C.cGray; - colorChange = true; - } - - char c; - - switch (i) - { - case 0: - c = '█'; - break; - case 1: - c = '▆'; - break; - default: - c = '▄'; - break; - } - - for (int a = 0; a < 4; a++) - { - progressBar += c; - } - - if (i > 0) - { - progressBar += " "; - } - } - - UtilTextBottom.display(progressBar, player); + UtilTextBottom.display(ZOOM_INFO[info.getScale()], player); } + /* + * Check whether an {@link ItemStack} is also a Clans Map + * + * @param itemStack The {@link ItemStack} to check + * @returns Whether the {@link ItemStack} is also a Clans Map + */ + private boolean isItemClansMap(ItemStack itemStack) + { + return UtilItem.matchesMaterial(itemStack, Material.MAP) + && itemStack.getDurability() >= _mapId + && itemStack.getDurability() <= _mapId + 100; + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java index 746f48e7e..955249127 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java @@ -50,7 +50,7 @@ public class ItemMapRenderer extends MapRenderer // } // else // { - renderNormalMap(mapView, canvas, player); + renderNormalMap(mapView, canvas, player); // } } @@ -135,7 +135,7 @@ public class ItemMapRenderer extends MapRenderer if (_manager.getClansUtility().relPT(player, chunk) == ClansUtility.ClanRelation.SAFE) clanColor2 = new Color(50, 150, 255); } - else if (owningClan.getName().equals("Spawn")) + else if (owningClan.getName().equals("Spawn")) { clanColor = Color.WHITE; clanColor2 = new Color(0, 255, 100); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/events/PlayerGetMapEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/events/PlayerGetMapEvent.java index 5e5bccc4a..e13645b8a 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/events/PlayerGetMapEvent.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/events/PlayerGetMapEvent.java @@ -4,6 +4,9 @@ import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +/* + * This event is called when a Player is about to receive a Clans Map + */ public class PlayerGetMapEvent extends Event { private static final HandlerList handlers = new HandlerList(); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java index 797f63f24..6c9424634 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java @@ -197,18 +197,7 @@ public class ClansRegions extends MiniPlugin { int x = chunkX + xOffset; int z = chunkZ + zOffset; - Chunk chunk; - try - { //Corrupted chunk will hold up whole server - chunk = location.getWorld().getChunkAt(x, z); - } - catch(Exception e) - { - System.out.println("UNABLE TO LOAD CHUNK AT " + x + " , " + z); - e.printStackTrace(); - continue; - } - String chunkStr = UtilWorld.chunkToStr(chunk); + String chunkStr = location.getWorld().getName() + "," + x + "," + z; if (addNegative) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/TutorialWorldManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/TutorialWorldManager.java index 40ac68fc6..e6714847a 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/TutorialWorldManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/TutorialWorldManager.java @@ -2,6 +2,7 @@ package mineplex.game.clans.tutorial; import java.io.File; import java.io.IOException; +import java.util.LinkedList; import java.util.Stack; import org.bukkit.Bukkit; @@ -25,7 +26,7 @@ public class TutorialWorldManager extends MiniPlugin private final World _tutorialWorld; private final Schematic _schematic; - private Stack _regionStack; + private LinkedList _regionStack; private TutorialRegion _centerRegion; public TutorialWorldManager(JavaPlugin plugin, String worldName, String schematicName) throws IOException @@ -56,7 +57,7 @@ public class TutorialWorldManager extends MiniPlugin private void populateRegionStack() { - _regionStack = new Stack<>(); + _regionStack = new LinkedList<>(); // Populate the stack with 100 available tutorial regions for (int x = 0; x < 10; x++) From d29d5dd5e46cbdd7ac4d6d3bed8d147c91e589f7 Mon Sep 17 00:00:00 2001 From: samczsun Date: Mon, 16 May 2016 14:26:00 -0400 Subject: [PATCH 05/33] Actually fix PC-279 --- .../src/mineplex/core/common/util/UtilWorld.java | 7 ++++++- .../src/mineplex/game/clans/clans/ClansUtility.java | 10 ++++++++-- .../src/mineplex/game/clans/spawn/Spawn.java | 9 +++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java index cef329774..e9ee2c856 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java @@ -28,7 +28,12 @@ public class UtilWorld if (chunk == null) return ""; - return chunk.getWorld().getName() + "," + chunk.getX() + "," + chunk.getZ(); + return chunkToStr(chunk.getWorld().getName(), chunk.getX(), chunk.getZ()); + } + + public static String chunkToStr(String world, int x, int z) + { + return world + "," + x + "," + z; } public static String chunkToStrClean(Chunk chunk) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java index bb9567721..6b9e8352c 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java @@ -259,9 +259,15 @@ public class ClansUtility public boolean isSafe(Location loc) { - if (!_clansManager.getClaimMap().containsKey(UtilWorld.chunkToStr(loc.getChunk()))) return false; + // Fix for PC-279 + // Do not change to getChunk + // PlayerList#updatePlayers -> iterator -> PlayerVelocityEvent -> getChunk -> loadChunk -> loadPersistentEntities -> addTracker -> ITERATE ON SAME SET + int chunkX = loc.getBlockX() >> 4; + int chunkZ = loc.getBlockZ() >> 4; + String chunkStr = UtilWorld.chunkToStr(loc.getWorld().getName(), chunkX, chunkZ); + if (!_clansManager.getClaimMap().containsKey(chunkStr)) return false; - return _clansManager.getClaimMap().get(UtilWorld.chunkToStr(loc.getChunk())).isSafe(loc); + return _clansManager.getClaimMap().get(chunkStr).isSafe(loc); } public boolean isChunkHome(ClanInfo clan, Chunk chunk) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java index 59d1070a5..af4c7dfd0 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java @@ -213,6 +213,15 @@ public class Spawn extends MiniPlugin } } + @EventHandler + public void ignoreVelocity(PlayerVelocityEvent event) + { + if (_clansManager.getClanUtility().isSafe(event.getPlayer())) + { + event.setCancelled(true); + } + } + @EventHandler public void onSkill(SkillTriggerEvent event) { From ea43dca9af308f7372f295e8c7e5026239591448 Mon Sep 17 00:00:00 2001 From: samczsun Date: Mon, 16 May 2016 15:26:00 -0400 Subject: [PATCH 06/33] Don't allow placing TNT in tutorial. Fixes PC-307 --- .../goals/attackenemy/LoadCannonGoal.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/tutorials/clans/objective/goals/attackenemy/LoadCannonGoal.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/tutorials/clans/objective/goals/attackenemy/LoadCannonGoal.java index 81ca051c6..21b69d371 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/tutorials/clans/objective/goals/attackenemy/LoadCannonGoal.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/tutorials/clans/objective/goals/attackenemy/LoadCannonGoal.java @@ -1,5 +1,7 @@ package mineplex.game.clans.tutorial.tutorials.clans.objective.goals.attackenemy; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -8,6 +10,8 @@ import mineplex.core.common.util.UtilInv; import mineplex.game.clans.clans.siege.events.LoadSiegeWeaponEvent; import mineplex.game.clans.tutorial.objective.ObjectiveGoal; import mineplex.game.clans.tutorial.tutorials.clans.objective.AttackEnemyObjective; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; public class LoadCannonGoal extends ObjectiveGoal { @@ -43,4 +47,15 @@ public class LoadCannonGoal extends ObjectiveGoal finish(event.getPlayer()); } + + @EventHandler (priority = EventPriority.MONITOR) + public void onBlockPlace(BlockPlaceEvent event) + { + if (!contains(event.getPlayer())) + { + return; + } + UtilPlayer.message(event.getPlayer(), F.main("Clans", "Are you sure? That's the only TNT you have!")); + event.setCancelled(true); + } } From 9141ed645acbfc5aa3bb7262b10287cd63641d9e Mon Sep 17 00:00:00 2001 From: samczsun Date: Mon, 16 May 2016 16:08:37 -0400 Subject: [PATCH 07/33] Fix fissure anvil repair exploit. Fixes PC-312 --- .../src/mineplex/game/clans/gameplay/Gameplay.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/gameplay/Gameplay.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/gameplay/Gameplay.java index 8f2a72d4a..207b16d16 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/gameplay/Gameplay.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/gameplay/Gameplay.java @@ -867,6 +867,12 @@ public class Gameplay extends MiniPlugin return; } } + + if (_blockRestore.contains(event.getClickedBlock())) + { + UtilPlayer.message(player, F.main("Repair", "You cannot repair using that anvil")); + return; + } // Repair! UtilPlayer.message(player, F.main("Repair", "You repaired " + F.item(item.getItemMeta().getDisplayName()) + ".")); From cd0e59087a97946feac275069e9f05bbb10b4bb4 Mon Sep 17 00:00:00 2001 From: Sam Sun Date: Tue, 17 May 2016 12:39:09 -0400 Subject: [PATCH 08/33] Don't drop items from hidden slimes. Fixes PC-276 --- .../Mineplex.Core/src/mineplex/core/creature/Creature.java | 5 +++++ .../mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java b/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java index f5bc05d1b..e892c9f4d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java @@ -103,6 +103,11 @@ public class Creature extends MiniPlugin event.setDroppedExp(0); List drops = event.getDrops(); + if (event.getEntity().hasMetadata("Creature.DoNotDrop")) + { + drops.clear(); + return; + } if (event.getEntityType() == EntityType.PLAYER) drops.add(ItemStackFactory.Instance.CreateStack(Material.BONE, 1)); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java index 451477876..33c7a5cba 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java @@ -27,6 +27,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.EulerAngle; import org.spigotmc.event.entity.EntityDismountEvent; @@ -559,6 +560,7 @@ public abstract class SiegeWeapon implements Listener { entity.setCustomName(Integer.toString(_uniqueId)); entity.setCustomNameVisible(false); + entity.setMetadata("Creature.DoNotDrop", new FixedMetadataValue(_clans.getPlugin(), true)); _comprisedOf.add(entity); @@ -569,6 +571,8 @@ public abstract class SiegeWeapon implements Listener { Entity entity = _entityMapping.get(uniqueName); + entity.removeMetadata("Creature.DoNotDrop", _clans.getPlugin()); + _entityMapping.remove(uniqueName); _comprisedOf.remove(entity); From 786c60537ee4e33bd5910aa2d11b48d960d43bd4 Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 17 May 2016 20:02:55 -0400 Subject: [PATCH 09/33] Remove /c trust from help. Fixes PC-280 --- .../src/mineplex/game/clans/clans/ClansAdmin.java | 1 - .../src/mineplex/game/clans/clans/commands/ClansCommand.java | 1 - .../game/clans/items/legendaries/GiantsBroadsword.java | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java index b7d073814..c4ffef408 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java @@ -114,7 +114,6 @@ public class ClansAdmin UtilPlayer.message(caller, F.help("/c x demote ", "Demote Player in Mimic", Rank.CMOD)); UtilPlayer.message(caller, F.help("/c x kick ", "Kick Player from Mimic", Rank.CMOD)); UtilPlayer.message(caller, F.help("/c x ally ", "Send Alliance to Mimic", Rank.CMOD)); - UtilPlayer.message(caller, F.help("/c x trust ", "Give Trust to Clan", Rank.CMOD)); UtilPlayer.message(caller, F.help("/c x neutral ", "Set Neutrality", Rank.CMOD)); UtilPlayer.message(caller, F.help("/c x enemy ", "Start Invasion", Rank.CMOD)); UtilPlayer.message(caller, F.help("/c x rename ", "Change the name of Mimic", Rank.CMOD)); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java index 741fc365a..059e55d54 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java @@ -233,7 +233,6 @@ public class ClansCommand extends CommandBase UtilPlayer.message(caller, F.help("/c neutral ", "Request Neutrality with Clan", Rank.ADMIN)); UtilPlayer.message(caller, F.help("/c enemy ", "Declare ClanWar with Clan", Rank.ADMIN)); UtilPlayer.message(caller, F.help("/c ally ", "Send Alliance to Clan", Rank.ADMIN)); - UtilPlayer.message(caller, F.help("/c trust ", "Give Trust to Clan", Rank.ADMIN)); UtilPlayer.message(caller, F.help("/c claim", "Claim Territory", Rank.ADMIN)); UtilPlayer.message(caller, F.help("/c unclaim (all)", "Unclaim Territory", Rank.ADMIN)); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java index 746ac5312..762536d94 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java @@ -14,7 +14,7 @@ import mineplex.minecraft.game.core.damage.CustomDamageEvent; public class GiantsBroadsword extends LegendaryItem { public static final int SLOW_AMPLIFIER = 43; - public static final int REGEN_AMPLIFIER = 3; + public static final int REGEN_AMPLIFIER = 1; public GiantsBroadsword() { @@ -60,6 +60,6 @@ public class GiantsBroadsword extends LegendaryItem private void buffPlayer(Player player) { grantPotionEffect(player, PotionEffectType.SLOW, 40, SLOW_AMPLIFIER); - grantPotionEffect(player, PotionEffectType.REGENERATION, 2, REGEN_AMPLIFIER); //Regen + grantPotionEffect(player, PotionEffectType.REGENERATION, 5, REGEN_AMPLIFIER); //Regen } } From 08784d3f0a77081d3c3fbf3ca1bdbfa044558815 Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 17 May 2016 21:20:12 -0400 Subject: [PATCH 10/33] Ignore float kick for Wind Blade. Fixes PC-314 --- .../src/mineplex/game/clans/clans/ClansManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 95cf0e6ae..b580655a5 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 @@ -562,7 +562,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati // Players using wind blade should not get kicked if (event.getPlayer().getItemInHand() != null && event.getPlayer().getItemInHand().getItemMeta() != null && (C.cGold + "Wind Blade").equals(event.getPlayer().getItemInHand().getItemMeta().getDisplayName())) { - if (event.getReason().contains("flying is not enabled")) + if (event.getReason().contains("flying is not enabled") || event.getReason().contains("floating too long")) { event.setCancelled(true); } From c172d226c40e80cfd355ff9e8eb5187b102a7e2d Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 17 May 2016 21:53:30 -0400 Subject: [PATCH 11/33] Add bypass for testing servers to skip tutorials --- .../game/clans/tutorial/command/FinishCommand.java | 10 ++++++---- .../game/clans/tutorial/command/TutorialCommand.java | 12 +++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java index 954db2c0d..723e6974f 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java @@ -10,14 +10,16 @@ public class FinishCommand extends CommandBase { public FinishCommand(TutorialManager plugin) { - super(plugin, Rank.JNR_DEV, "finish", "end"); + super(plugin, Rank.ALL, "finish", "end"); } @Override public void Execute(Player caller, String[] args) { - Plugin.finishTutorial(caller); - - + boolean testServer = Plugin.getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing"); + if (CommandCenter.Instance.GetClientManager().hasRank(caller, testServer ? Rank.ALL : Rank.JNR_DEV)) + { + Plugin.finishTutorial(caller); + } } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java index c9722a1bf..d444a81b9 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java @@ -13,7 +13,7 @@ public class TutorialCommand extends MultiCommandBase { public TutorialCommand(TutorialManager plugin) { - super(plugin, Rank.JNR_DEV, "tutorial", "tut"); + super(plugin, Rank.ALL, "tutorial", "tut"); AddCommand(new StartCommand(plugin)); AddCommand(new FinishCommand(plugin)); @@ -24,4 +24,14 @@ public class TutorialCommand extends MultiCommandBase { UtilPlayer.message(caller, F.main("Tutorial", "/tutorial start ")); } + + @Override + public void Execute(Player caller, String[] args) + { + boolean testServer = Plugin.getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing"); + if (CommandCenter.GetClientManager().hasRank(caller, testServer ? Rank.ALL : Rank.JNR_DEV)) + { + super.Execute(caller, args); + } + } } From 41846f835d7ffc1aa9aae2f11b3d264a765d398d Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 17 May 2016 21:53:50 -0400 Subject: [PATCH 12/33] Bump listener priority, change wording. Fixes PC-308 --- .../src/mineplex/game/clans/spawn/Spawn.java | 4 ++-- .../mineplex/minecraft/game/core/damage/DamageManager.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java index af4c7dfd0..92f29b3bf 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/spawn/Spawn.java @@ -400,13 +400,13 @@ public class Spawn extends MiniPlugin if (isInSpawn(victim)) { event.SetCancelled("Safe Zone"); - attemptNotify(attacker, "You cannot attack players who are in spawn!"); + attemptNotify(attacker, "You cannot attack players who are in a safe zone!"); return; } else if (isInSpawn(attacker) && !isCombatTagged(attacker)) { event.SetCancelled("Safe Zone"); - attemptNotify(attacker, "You cannot attack untagged players while in spawn!"); + attemptNotify(attacker, "You cannot attack untagged players while in a safe zone!"); return; } } diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java index de559f25b..8feccdccf 100644 --- a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java @@ -529,7 +529,7 @@ public class DamageManager extends MiniPlugin } } - @EventHandler + @EventHandler (priority = EventPriority.MONITOR) public void DamageSound(CustomDamageEvent event) { if (event.IsCancelled()) From 51c93017999e217fef99d6018601f8d040e38ef7 Mon Sep 17 00:00:00 2001 From: samczsun Date: Wed, 18 May 2016 15:45:42 -0400 Subject: [PATCH 13/33] Consider leap level. Fixes PC-330 --- .../minecraft/game/classcombat/Skill/Assassin/Leap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Leap.java b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Leap.java index 06bdda17a..f1dcbb780 100644 --- a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Leap.java +++ b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Leap.java @@ -78,7 +78,7 @@ public class Leap extends SkillActive { //Action if (!wallkick) - UtilAction.velocity(player, 1.2, 0.2, 1, true); + UtilAction.velocity(player, 1 + 0.15 * level, 0.2, 1, true); else { Vector vec = player.getLocation().getDirection(); From 14c60ec3bacd1f2969bbee3b4ebce0b80abfdcd6 Mon Sep 17 00:00:00 2001 From: samczsun Date: Wed, 18 May 2016 16:06:52 -0400 Subject: [PATCH 14/33] Delay recall by one tick. Fixes PC-328 --- .../classcombat/Skill/Assassin/Recall.java | 76 ++++++++----------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Recall.java b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Recall.java index b675e3a58..dc3fd9dde 100644 --- a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Recall.java +++ b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Assassin/Recall.java @@ -59,12 +59,7 @@ public class Recall extends Skill public void use(PlayerDropItemEvent event) { Player player = event.getPlayer(); - - if (!(player.getOpenInventory().getTopInventory() instanceof CraftInventoryCrafting)) - { - return; - } - + int level = getLevel(player); if (level == 0) return; @@ -87,49 +82,40 @@ public class Recall extends Skill LinkedList locs = _locMap.remove(player); if (locs == null) return; - + LinkedList health = _healthMap.remove(player); if (health == null) return; - - //Heal - double newHealth = Math.min(health.getLast(), player.getHealth() + 3 + level); - player.setHealth(newHealth); - - //Effect - player.getWorld().playSound(player.getLocation(), Sound.ZOMBIE_UNFECT, 2f, 2f); - - //Teleport - Location current = player.getLocation(); - Location target = locs.getLast(); - - player.teleport(target); - - //Inform - UtilPlayer.message(player, F.main(GetClassType().name(), "You used " + F.skill(GetName(level)) + ".")); - - //Effect - player.getWorld().playSound(player.getLocation(), Sound.ZOMBIE_UNFECT, 2f, 2f); - - while (UtilMath.offset(current, target) > 0.5) - { - UtilParticle.PlayParticle(ParticleType.WITCH_MAGIC, current, 0, 1f, 0, 0, 1, - ViewDist.LONGER, UtilServer.getPlayers()); - current = current.add(UtilAlg.getTrajectory(current, target).multiply(0.1)); - } - } - - @EventHandler - public void closeInv(InventoryCloseEvent event) - { - if (getLevel(event.getPlayer()) == 0) - { - return; - } - - event.getPlayer().getInventory().addItem(event.getPlayer().getItemOnCursor()); - event.getPlayer().setItemOnCursor(null); + + Factory.runSync(() -> { + //Heal + double newHealth = Math.min(health.getLast(), player.getHealth() + 3 + level); + player.setHealth(newHealth); + + //Effect + player.getWorld().playSound(player.getLocation(), Sound.ZOMBIE_UNFECT, 2f, 2f); + + //Teleport + Location current = player.getLocation(); + Location target = locs.getLast(); + + player.teleport(target); + + //Inform + UtilPlayer.message(player, F.main(GetClassType().name(), "You used " + F.skill(GetName(level)) + ".")); + + //Effect + player.getWorld().playSound(player.getLocation(), Sound.ZOMBIE_UNFECT, 2f, 2f); + + while (UtilMath.offset(current, target) > 0.5) + { + UtilParticle.PlayParticle(ParticleType.WITCH_MAGIC, current, 0, 1f, 0, 0, 1, + ViewDist.LONGER, UtilServer.getPlayers()); + current = current.add(UtilAlg.getTrajectory(current, target).multiply(0.1)); + } + }); } + @EventHandler public void storeLocation(UpdateEvent event) From e0f4c9cbc882bde8b5588dfd47d5a824f91a9958 Mon Sep 17 00:00:00 2001 From: samczsun Date: Wed, 18 May 2016 16:49:41 -0400 Subject: [PATCH 15/33] Update Broadsword regen --- .../game/clans/items/legendaries/GiantsBroadsword.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java index 762536d94..d3581ebc7 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/GiantsBroadsword.java @@ -1,5 +1,6 @@ package mineplex.game.clans.items.legendaries; +import mineplex.core.recharge.Recharge; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.entity.Player; @@ -60,6 +61,7 @@ public class GiantsBroadsword extends LegendaryItem private void buffPlayer(Player player) { grantPotionEffect(player, PotionEffectType.SLOW, 40, SLOW_AMPLIFIER); - grantPotionEffect(player, PotionEffectType.REGENERATION, 5, REGEN_AMPLIFIER); //Regen + if (Recharge.Instance.use(player, "Giants Broadsword Regen", 250L, false, false, false)) + grantPotionEffect(player, PotionEffectType.REGENERATION, 5, REGEN_AMPLIFIER); //Regen } } From 981bed5e3717234ad362afd9d786840e9bc45240 Mon Sep 17 00:00:00 2001 From: samczsun Date: Wed, 18 May 2016 17:39:09 -0400 Subject: [PATCH 16/33] Limit clan searching. Fixes PC-331 --- .../game/clans/clans/ClansUtility.java | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java index 6b9e8352c..bc6ad05bb 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java @@ -28,6 +28,9 @@ import mineplex.game.clans.spawn.Spawn; public class ClansUtility { + private static final int MAX_CLAN_SEARCH = 10; + private static final int MAX_PLAYER_SEARCH = 10; + private ClansManager _clansManager; public ClansUtility(ClansManager clans) @@ -114,54 +117,78 @@ public class ClansUtility { // CLAN LinkedList clanMatchList = new LinkedList(); - + for (ClanInfo cur : _clansManager.getClanMap().values()) { if (cur.getName().equalsIgnoreCase(name)) return cur; - + if (cur.getName().toLowerCase().contains(name.toLowerCase())) clanMatchList.add(cur); } - + if (clanMatchList.size() == 1) return clanMatchList.get(0); - + // No / Non-Unique - String clanMatchString = "None"; + String clanMatchString = ""; if (clanMatchList.size() > 1) { for (ClanInfo cur : clanMatchList) clanMatchString += cur.getName() + " "; } - + + if (clanMatchString.length() == 0) + { + clanMatchString = "None"; + } + // PLAYER LinkedList playerMatchList = new LinkedList(); - + for (ClanInfo clanInfo : _clansManager.getClanMap().values()) { for (ClansPlayer player : clanInfo.getMembers().values()) { if (player.getPlayerName().equalsIgnoreCase(name)) return clanInfo; - + if (player.getPlayerName().toLowerCase().contains(name.toLowerCase())) playerMatchList.add(clanInfo); - + } } - + if (playerMatchList.size() == 1) return playerMatchList.get(0); - + // No / Non-Unique - String playerMatchString = "None"; + String playerMatchString = ""; if (playerMatchList.size() > 1) { for (ClanInfo cur : playerMatchList) playerMatchString += cur.getName() + " "; } + + if (playerMatchString.length() == 0) + { + playerMatchString = "None"; + } if (inform) { UtilPlayer.message(caller, F.main("Clan Search", "" + C.mCount + (clanMatchList.size() + playerMatchList.size()) + C.mBody + " matches for [" + C.mElem + name + C.mBody + "].")); - - UtilPlayer.message(caller, F.desc("Matches via Clan", clanMatchString)); - UtilPlayer.message(caller, F.desc("Matches via Player", playerMatchString)); + + if (clanMatchList.size() > MAX_CLAN_SEARCH) + { + UtilPlayer.message(caller, F.main("Clan Search", "Too many clans matched. Try a more specific search")); + } + else + { + UtilPlayer.message(caller, F.desc("Matches via Clan", clanMatchString)); + } + if (playerMatchList.size() > MAX_PLAYER_SEARCH) + { + UtilPlayer.message(caller, F.main("Clan Search", "Too many players matched. Try a more specific search")); + } + else + { + UtilPlayer.message(caller, F.desc("Matches via Player", playerMatchString)); + } } return null; From 72a2aa926f0143c105a90902a3e39b83c092b82b Mon Sep 17 00:00:00 2001 From: samczsun Date: Wed, 18 May 2016 19:22:09 -0400 Subject: [PATCH 17/33] Change event priority again. Fixes PC-216 --- .../src/mineplex/core/account/CoreClientManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java index 69a745818..f2c320b74 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java @@ -491,7 +491,7 @@ public class CoreClientManager extends MiniPlugin } } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.MONITOR) public void Quit(PlayerQuitEvent event) { // When an account is logged in to this server and the same account name logs in From 516ad5a6403a822d089d4c3a1251808587957138 Mon Sep 17 00:00:00 2001 From: samczsun Date: Thu, 19 May 2016 17:33:20 -0400 Subject: [PATCH 18/33] Check cancellation before continuing Takedown. Fixes PC-277 --- .../classcombat/Skill/Brute/Takedown.java | 60 ++++++++++--------- .../game/core/damage/DamageManager.java | 47 +++++++++------ 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Brute/Takedown.java b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Brute/Takedown.java index dde2e6a1b..09faffdd8 100644 --- a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Brute/Takedown.java +++ b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Brute/Takedown.java @@ -2,6 +2,7 @@ package mineplex.minecraft.game.classcombat.Skill.Brute; import java.util.HashMap; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.Sound; @@ -34,21 +35,21 @@ public class Takedown extends SkillActive { private HashMap _live = new HashMap(); - public Takedown(SkillFactory skills, String name, ClassType classType, SkillType skillType, - int cost, int levels, - int energy, int energyMod, - long recharge, long rechargeMod, boolean rechargeInform, - Material[] itemArray, - Action[] actionArray) + public Takedown(SkillFactory skills, String name, ClassType classType, SkillType skillType, + int cost, int levels, + int energy, int energyMod, + long recharge, long rechargeMod, boolean rechargeInform, + Material[] itemArray, + Action[] actionArray) { super(skills, name, classType, skillType, cost, levels, - energy, energyMod, - recharge, rechargeMod, rechargeInform, + energy, energyMod, + recharge, rechargeMod, rechargeInform, itemArray, actionArray); - SetDesc(new String[] + SetDesc(new String[] { "Hurl yourself towards an opponent.", "If you collide with them, you deal", @@ -58,7 +59,7 @@ public class Takedown extends SkillActive } @Override - public boolean CustomCheck(Player player, int level) + public boolean CustomCheck(Player player, int level) { if (player.getLocation().getBlock().getTypeId() == 8 || player.getLocation().getBlock().getTypeId() == 9) { @@ -76,7 +77,7 @@ public class Takedown extends SkillActive } @Override - public void Skill(Player player, int level) + public void Skill(Player player, int level) { //Action Vector vec = player.getLocation().getDirection(); @@ -108,11 +109,11 @@ public class Takedown extends SkillActive int level = getLevel(player); if (level == 0) continue; - if (!UtilTime.elapsed(_live.get(player), 1000)) + if (!UtilTime.elapsed(_live.get(player), 1000)) continue; - _live.remove(player); - } + _live.remove(player); + } //Collide for (Player player : GetUsers()) @@ -167,25 +168,28 @@ public class Takedown extends SkillActive int damage = 3 + (level); //Damage Event - Factory.Damage().NewDamageEvent(damagee, damager, null, + CustomDamageEvent customDamageEvent = Factory.Damage().NewDamageEvent(damagee, damager, null, DamageCause.CUSTOM, damage, false, true, false, - damager.getName(), GetName()); + damager.getName(), GetName()); - //Damage Event - Factory.Damage().NewDamageEvent(damager, damagee, null, - DamageCause.CUSTOM, damage/2, false, true, false, - damager.getName(), GetName() + " Recoil"); + if (!customDamageEvent.IsCancelled()) + { + //Damage Event + Factory.Damage().NewDamageEvent(damager, damagee, null, + DamageCause.CUSTOM, damage / 2, false, true, false, + damager.getName(), GetName() + " Recoil"); - //Conditions - Factory.Condition().Factory().Slow(GetName(), damagee, damager, 2.5 + 0.5*level, 3, false, true, true, true); - Factory.Condition().Factory().Slow(GetName(), damager, damager, 2.5 + 0.5*level, 3, false, true, true, true); + //Conditions + Factory.Condition().Factory().Slow(GetName(), damagee, damager, 2.5 + 0.5 * level, 3, false, true, true, true); + Factory.Condition().Factory().Slow(GetName(), damager, damager, 2.5 + 0.5 * level, 3, false, true, true, true); - //Inform - UtilPlayer.message(damager, F.main(GetClassType().name(), "You hit " + F.name(UtilEnt.getName(damagee)) + " with " + F.skill(GetName(level)) + ".")); - UtilPlayer.message(damagee, F.main(GetClassType().name(), F.name(damager.getName()) + " hit you with " + F.skill(GetName(level)) + ".")); + //Inform + UtilPlayer.message(damager, F.main(GetClassType().name(), "You hit " + F.name(UtilEnt.getName(damagee)) + " with " + F.skill(GetName(level)) + ".")); + UtilPlayer.message(damagee, F.main(GetClassType().name(), F.name(damager.getName()) + " hit you with " + F.skill(GetName(level)) + ".")); - //Sound - damager.getWorld().playSound(damager.getLocation(), Sound.ZOMBIE_WOOD, 1f, 0.5f); + //Sound + damager.getWorld().playSound(damager.getLocation(), Sound.ZOMBIE_WOOD, 1f, 0.5f); + } } @EventHandler diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java index 8feccdccf..daba8449a 100644 --- a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/DamageManager.java @@ -171,37 +171,39 @@ public class DamageManager extends MiniPlugin } */ - public void NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, + public CustomDamageEvent NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, DamageCause cause, double damage, boolean knockback, boolean ignoreRate, boolean ignoreArmor, String source, String reason) { - NewDamageEvent(damagee, damager, proj, + return NewDamageEvent(damagee, damager, proj, cause, damage, knockback, ignoreRate, ignoreArmor, source, reason, false); } - public void NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, + public CustomDamageEvent NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, DamageCause cause, double damage, boolean knockback, boolean ignoreRate, boolean ignoreArmor, String source, String reason, boolean cancelled) { - NewDamageEvent(damagee, damager, proj, null, cause, damage, knockback, ignoreRate, ignoreArmor, source, reason, cancelled); + return NewDamageEvent(damagee, damager, proj, null, cause, damage, knockback, ignoreRate, ignoreArmor, source, reason, cancelled); } - - public void NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, Location knockbackOrigin, + + public CustomDamageEvent NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, Location knockbackOrigin, DamageCause cause, double damage, boolean knockback, boolean ignoreRate, boolean ignoreArmor, String source, String reason) { - NewDamageEvent(damagee, damager, proj, knockbackOrigin, cause, damage, knockback, ignoreRate, ignoreArmor, source, + return NewDamageEvent(damagee, damager, proj, knockbackOrigin, cause, damage, knockback, ignoreRate, ignoreArmor, source, reason, false); } - public void NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, Location knockbackOrigin, + public CustomDamageEvent NewDamageEvent(LivingEntity damagee, LivingEntity damager, Projectile proj, Location knockbackOrigin, DamageCause cause, double damage, boolean knockback, boolean ignoreRate, boolean ignoreArmor, String source, String reason, boolean cancelled) - { - _plugin.getServer().getPluginManager().callEvent(new CustomDamageEvent(damagee, damager, proj, knockbackOrigin, cause, - damage, knockback, ignoreRate, ignoreArmor, source, reason, cancelled)); - } + { + CustomDamageEvent customDamageEvent = new CustomDamageEvent(damagee, damager, proj, knockbackOrigin, cause, + damage, knockback, ignoreRate, ignoreArmor, source, reason, cancelled); + _plugin.getServer().getPluginManager().callEvent(customDamageEvent); + return customDamageEvent; + } @EventHandler(priority = EventPriority.LOW) public void CancelDamageEvent(CustomDamageEvent event) @@ -282,21 +284,21 @@ public class DamageManager extends MiniPlugin if (e.equals(Enchantment.PROTECTION_ENVIRONMENTAL)) event.AddMod("Ench Prot", damagee.getName(), 0.5 * (double)enchants.get(e), false); - else if (e.equals(Enchantment.PROTECTION_FIRE) && + else if (e.equals(Enchantment.PROTECTION_FIRE) && event.GetCause() == DamageCause.FIRE && event.GetCause() == DamageCause.FIRE_TICK && event.GetCause() == DamageCause.LAVA) event.AddMod("Ench Prot", damagee.getName(), 0.5 * (double)enchants.get(e), false); - else if (e.equals(Enchantment.PROTECTION_FALL) && + else if (e.equals(Enchantment.PROTECTION_FALL) && event.GetCause() == DamageCause.FALL) event.AddMod("Ench Prot", damagee.getName(), 0.5 * (double)enchants.get(e), false); - else if (e.equals(Enchantment.PROTECTION_EXPLOSIONS) && + else if (e.equals(Enchantment.PROTECTION_EXPLOSIONS) && event.GetCause() == DamageCause.ENTITY_EXPLOSION) event.AddMod("Ench Prot", damagee.getName(), 0.5 * (double)enchants.get(e), false); - else if (e.equals(Enchantment.PROTECTION_PROJECTILE) && + else if (e.equals(Enchantment.PROTECTION_PROJECTILE) && event.GetCause() == DamageCause.PROJECTILE) event.AddMod("Ench Prot", damagee.getName(), 0.5 * (double)enchants.get(e), false); } @@ -322,7 +324,7 @@ public class DamageManager extends MiniPlugin else if (e.equals(Enchantment.FIRE_ASPECT)) if (_conditionManager != null) - _conditionManager.Factory().Ignite("Ench Fire", event.GetDamageeEntity(), damager, + _conditionManager.Factory().Ignite("Ench Fire", event.GetDamageeEntity(), damager, 4 * (double)enchants.get(e), false, false); } } @@ -351,8 +353,15 @@ public class DamageManager extends MiniPlugin } } } - - //Debug + } + + /* + * Should only be used to debug the damage event + * No modification of the event should take place + */ + @EventHandler (priority = EventPriority.MONITOR) + public void debugDamageEvent(CustomDamageEvent event) + { DisplayDamage(event); } From 1dc5a0d7121076103b34f2dfd2b9dc68ca7a1e47 Mon Sep 17 00:00:00 2001 From: AlexTheCoder Date: Thu, 19 May 2016 18:39:51 -0400 Subject: [PATCH 19/33] Revamped Meridian Scepter attack --- .../items/legendaries/MeridianScepter.java | 116 +++++++++++++----- 1 file changed, 87 insertions(+), 29 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java index c333f642e..f4eb03356 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java @@ -1,17 +1,6 @@ package mineplex.game.clans.items.legendaries; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.EntityDamageEvent.DamageCause; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; +import java.util.concurrent.ConcurrentHashMap; import mineplex.core.common.util.C; import mineplex.core.common.util.F; @@ -20,18 +9,30 @@ import mineplex.core.common.util.RGBData; import mineplex.core.common.util.UtilBlock; import mineplex.core.common.util.UtilCollections; import mineplex.core.common.util.UtilColor; -import mineplex.core.common.util.UtilEnt; import mineplex.core.common.util.UtilParticle; import mineplex.core.common.util.UtilParticle.ParticleType; import mineplex.core.common.util.UtilParticle.ViewDist; -import mineplex.core.incognito.IncognitoManager; import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilShapes; import mineplex.core.common.util.UtilText; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.UtilTime.TimeUnit; import mineplex.core.recharge.Recharge; import mineplex.game.clans.clans.ClansManager; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + public class MeridianScepter extends LegendaryItem { private long _lastFire = System.currentTimeMillis(); @@ -39,7 +40,7 @@ public class MeridianScepter extends LegendaryItem private RGBData[] colors = { UtilColor.RgbPurple, UtilColor.RgbPurple.Lighten(), UtilColor.RgbPurple.Darken() }; - private int _witherDamageTimes = 5; + private ConcurrentHashMap _animations = new ConcurrentHashMap(); public MeridianScepter() { @@ -100,21 +101,14 @@ public class MeridianScepter extends LegendaryItem // If they are less than 0.5 blocks away if (player.getEyeLocation().subtract(0, .3, 0).distance(projectile) <= 2) - { - player.addPotionEffect(new PotionEffect(PotionEffectType.WITHER, 20 * _witherDamageTimes, 0)); + { + AttackAnimation aa = new AttackAnimation(shooter, player); + int i = UtilServer.getServer().getScheduler().scheduleSyncRepeatingTask(UtilServer.getPlugin(), () -> { + aa.update(); + }, 0, 1); + _animations.put(aa, i); - int time = 0; - - for (int i = 0; i < _witherDamageTimes; i++) - { - UtilServer.getServer().getScheduler().scheduleSyncDelayedTask(UtilServer.getPlugin(), () -> { - ClansManager.getInstance().getDamageManager().NewDamageEvent(player, shooter, null, - DamageCause.CUSTOM, 1.75, false, true, true, - shooter.getName(), "Meridian Scepter"); - }, ++time * 20); - } - - UtilPlayer.message(player, F.main("Clans", F.elem(player.getName()) + " hit you with a " + F.elem("Meridian Scepter") + C.mBody + ".")); + UtilPlayer.message(player, F.main("Clans", F.elem(shooter.getName()) + " hit you with a " + F.elem("Meridian Scepter") + C.mBody + ".")); UtilPlayer.message(shooter, F.main("Clans", "You hit " + F.elem(player.getName()) + " with your " + F.elem("Meridian Scepter") + C.mBody + ".")); } } @@ -258,4 +252,68 @@ public class MeridianScepter extends LegendaryItem UtilParticle.PlayParticleToAll(ParticleType.RED_DUST, loc, UtilCollections.random(colors).ToVector(), 1f, 0, ViewDist.LONG); } } + + private class AttackAnimation + { + private Player _hit, _shooter; + private double _step; + private double _radius; + private long _start, _lastStepIncrease; + + public AttackAnimation(Player hit, Player shooter) + { + _step = 0; + _start = System.currentTimeMillis(); + _lastStepIncrease = System.currentTimeMillis(); + _hit = hit; + _shooter = shooter; + _radius = 2; + } + + public void update() + { + if (_hit == null) + { + end(); + return; + } + if (UtilTime.elapsed(_lastStepIncrease, UtilTime.convert(1, TimeUnit.SECONDS, TimeUnit.MILLISECONDS))) + { + _step++; + _lastStepIncrease = System.currentTimeMillis(); + } + drawHelix(); + + if (UtilTime.elapsed(_start, 4000)) + { + _hit.getWorld().strikeLightningEffect(_hit.getLocation()); + ClansManager.getInstance().getDamageManager().NewDamageEvent(_hit, _shooter, null, + DamageCause.CUSTOM, 6, false, true, true, + _shooter.getName(), "Meridian Scepter"); + + end(); + return; + } + } + + private void end() + { + int id = _animations.remove(this); + Bukkit.getScheduler().cancelTask(id); + } + + private void drawHelix() + { + double height = Math.min(_step * 2, 8D); + + for (double y = 0; y <= height; y += .5) + { + double x = _radius * Math.cos(y); + double z = _radius * Math.sin(y); + Location play = _hit.getLocation().add(x, y, z); + + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, play, null, 0, 3, ViewDist.MAX); + } + } + } } From d8b5dba3fcf5b6bb091550eaab84e2faaed622b3 Mon Sep 17 00:00:00 2001 From: samczsun Date: Thu, 19 May 2016 19:09:04 -0400 Subject: [PATCH 20/33] Fix Meridian Scepter --- .../game/clans/items/legendaries/MeridianScepter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java index f4eb03356..39b63a037 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java @@ -21,6 +21,8 @@ import mineplex.core.common.util.UtilTime.TimeUnit; import mineplex.core.recharge.Recharge; import mineplex.game.clans.clans.ClansManager; +import mineplex.minecraft.game.core.condition.Condition; +import mineplex.minecraft.game.core.condition.ConditionManager; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -102,7 +104,7 @@ public class MeridianScepter extends LegendaryItem // If they are less than 0.5 blocks away if (player.getEyeLocation().subtract(0, .3, 0).distance(projectile) <= 2) { - AttackAnimation aa = new AttackAnimation(shooter, player); + AttackAnimation aa = new AttackAnimation(player, shooter); int i = UtilServer.getServer().getScheduler().scheduleSyncRepeatingTask(UtilServer.getPlugin(), () -> { aa.update(); }, 0, 1); @@ -290,7 +292,7 @@ public class MeridianScepter extends LegendaryItem ClansManager.getInstance().getDamageManager().NewDamageEvent(_hit, _shooter, null, DamageCause.CUSTOM, 6, false, true, true, _shooter.getName(), "Meridian Scepter"); - + ClansManager.getInstance().getCondition().Factory().Blind("Meridian Scepter", _hit, _shooter, 1, 0, true, true, true); end(); return; } From 63e3cc8e129c489d4b73d3eb03a612c957c48c27 Mon Sep 17 00:00:00 2001 From: samczsun Date: Thu, 19 May 2016 21:33:40 -0400 Subject: [PATCH 21/33] Add nullcheck --- .../clans/clans/gui/page/ClanMainPage.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java index a1cde46af..7db99c36b 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java @@ -269,26 +269,33 @@ public class ClanMainPage extends ClanPageBase { String enemyName = clanWar.getClanA().equals(clan.getName()) ? clanWar.getClanB() : clanWar.getClanA(); final ClanInfo enemy = getPlugin().getClan(enemyName); - String itemName = enemyName; - Material material = USE_RESOURCE_ICONS ? ClanIcon.WAR.getMaterial() : Material.DIAMOND_SWORD; - byte data = USE_RESOURCE_ICONS ? ClanIcon.WAR.getData() : 0; - int warPoints = clanWar.getPoints(clan.getName()); - - ArrayList lore = new ArrayList(5); - lore.add(" "); - lore.add(C.Reset + C.cYellow + "War Points " + clan.getFormattedWarPoints(enemy)); - lore.add(" "); - lore.add(ChatColor.RESET + C.cGray + "Left Click " + C.cWhite + "Clan Info"); - - ShopItem shopItem = new ShopItem(material, data, itemName, lore.toArray(new String[0]), 0, false, false); - addButtonFakeCount(slot, shopItem, new IButton() + if (enemy != null) { - @Override - public void onClick(Player player, ClickType clickType) + String itemName = enemyName; + Material material = USE_RESOURCE_ICONS ? ClanIcon.WAR.getMaterial() : Material.DIAMOND_SWORD; + byte data = USE_RESOURCE_ICONS ? ClanIcon.WAR.getData() : 0; + int warPoints = clanWar.getPoints(clan.getName()); + + ArrayList lore = new ArrayList(5); + lore.add(" "); + lore.add(C.Reset + C.cYellow + "War Points " + clan.getFormattedWarPoints(enemy)); + lore.add(" "); + lore.add(ChatColor.RESET + C.cGray + "Left Click " + C.cWhite + "Clan Info"); + + ShopItem shopItem = new ShopItem(material, data, itemName, lore.toArray(new String[0]), 0, false, false); + addButtonFakeCount(slot, shopItem, new IButton() { - getShop().openPageForPlayer(player, new ClanWhoPage(getPlugin(), getShop(), getClientManager(), getDonationManager(), player, enemy, true)); - } - }, warPoints); + @Override + public void onClick(Player player, ClickType clickType) + { + getShop().openPageForPlayer(player, new ClanWhoPage(getPlugin(), getShop(), getClientManager(), getDonationManager(), player, enemy, true)); + } + }, warPoints); + } + else + { + System.err.println("Could not find enemy clan: " + enemyName); + } } private void addAllyButton(int slot, final ClanInfo ally) From ec0e1b9849acb32973a649212686a854bf2b1ae4 Mon Sep 17 00:00:00 2001 From: samczsun Date: Fri, 20 May 2016 22:51:29 -0400 Subject: [PATCH 22/33] 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, From 4ba3148df75b9122ca6965b822d490bfd100ff43 Mon Sep 17 00:00:00 2001 From: samczsun Date: Sat, 21 May 2016 17:41:39 -0400 Subject: [PATCH 23/33] Finish invsee --- .../clans/clans/invsee/InvseeManager.java | 26 +- .../clans/invsee/commands/InvseeCommand.java | 20 +- .../clans/invsee/ui/InvseeInventory.java | 307 ++++++++++++------ 3 files changed, 241 insertions(+), 112 deletions(-) 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 index c126b3ac0..ab8af7853 100644 --- 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 @@ -1,6 +1,7 @@ package mineplex.game.clans.clans.invsee; import mineplex.core.MiniPlugin; +import mineplex.core.common.util.UtilServer; import mineplex.game.clans.clans.ClansManager; import mineplex.game.clans.clans.invsee.commands.InvseeCommand; import mineplex.game.clans.clans.invsee.ui.InvseeInventory; @@ -13,7 +14,7 @@ import java.util.UUID; public class InvseeManager extends MiniPlugin { - private Map viewing = new HashMap<>(); + private final Map _viewing = new HashMap<>(); public InvseeManager(ClansManager manager) { @@ -28,16 +29,35 @@ public class InvseeManager extends MiniPlugin public void doInvsee(OfflinePlayer target, Player requester) { - InvseeInventory invseeInventory = viewing.computeIfAbsent(target.getUniqueId(), key -> new InvseeInventory(this, target)); + InvseeInventory invseeInventory = _viewing.computeIfAbsent(target.getUniqueId(), key -> new InvseeInventory(this, target)); invseeInventory.addAndShowViewer(requester); } + public boolean isBeingInvseen(OfflinePlayer player) + { + return _viewing.containsKey(player.getUniqueId()); + } + + public boolean isInvseeing(Player player) + { + for (InvseeInventory invseeInventory : _viewing.values()) + { + if (invseeInventory.isViewer(player)) + { + return true; + } + } + return false; + } + public void close(UUID target) { - InvseeInventory invseeInventory = viewing.remove(target); + InvseeInventory invseeInventory = _viewing.remove(target); if (invseeInventory == null) { log("Expected non-null inventory when closing " + target); + return; } + UtilServer.Unregister(invseeInventory); } } 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 d8ee6d416..ebbce2c9d 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 @@ -6,18 +6,13 @@ import mineplex.core.common.Rank; import mineplex.core.common.util.F; import mineplex.core.common.util.UtilPlayer; 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; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.UUID; public class InvseeCommand extends CommandBase @@ -77,6 +72,21 @@ public class InvseeCommand extends CommandBase UtilPlayer.message(caller, F.main("Invsee", "Could not load offline player data. Does the player exist?")); return; } + if (exactPlayer.getUniqueId().equals(caller.getUniqueId())) + { + UtilPlayer.message(caller, F.main("Invsee", "You cannot invsee yourself!")); + return; + } + if (Plugin.isBeingInvseen(caller)) + { + UtilPlayer.message(caller, F.main("Invsee", "You cannot use invsee right now. Someone is invseeing you!")); + return; + } + if (exactPlayer.isOnline() && Plugin.isInvseeing((Player) exactPlayer)) + { + UtilPlayer.message(caller, F.main("Invsee", "You cannot use invsee right now. That person is currently using invsee!")); + 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 06cb159e7..69283e71a 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 @@ -10,22 +10,15 @@ 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.inventory.*; 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.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; +import org.bukkit.inventory.meta.ItemMeta; import java.io.File; import java.io.FileOutputStream; @@ -33,34 +26,49 @@ import java.util.*; public class InvseeInventory implements Listener { - private final InvseeManager invseeManager; - private final UUID uuid; + private final InvseeManager _invseeManager; + // This is the UUID of the target player. This should stay constant. Use this for comparison + private final UUID _uuid; // This is the current player. It will switch when the player joins/quits - private OfflinePlayer targetPlayer; - + private OfflinePlayer _targetPlayer; + // This is the inventory of said player. If the player is not online then this inventory is a fake PlayerInventory + private net.minecraft.server.v1_8_R3.PlayerInventory _playerInventory; + // This is the set of all admins viewing this player + private Set _viewers = new HashSet<>(); + // This is the inventory that all admins will be looking at private Inventory _inventory; - - private net.minecraft.server.v1_8_R3.PlayerInventory playerInventory; - - private List viewers = new ArrayList<>(); - private boolean dontUpdate = false; + // This is whether the target player should be allowed to open any inventories + private boolean _canOpenInventory = true; public InvseeInventory(InvseeManager manager, OfflinePlayer player) { - invseeManager = manager; - uuid = player.getUniqueId(); - targetPlayer = player; - updateInventory(); + _invseeManager = manager; + _uuid = player.getUniqueId(); + _targetPlayer = player; _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)); + _inventory.setItem(index, ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, (byte) 14, 1, C.Bold)); } + _inventory.setItem(47, ItemStackFactory.Instance.CreateStack(Material.STONE_BUTTON, (byte) 0, 1, C.cGreenB + "Inventory Control", generateLore(_canOpenInventory))); + + _inventory.setItem(48, ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, (byte) 14, 1, C.Bold)); UtilServer.RegisterEvents(this); + updateInventory(); + update(true); + } + + private String[] generateLore(boolean canOpenInventory) + { + return UtilText.splitLinesToArray(new String[]{ + C.cYellow + "Left-Click" + C.cWhite + " to force close any open inventories the target has open", + "", + C.cYellow + "Right-Click" + C.cWhite + " to " + (canOpenInventory ? "disable inventory opening" : "enable inventory opening") + }, LineFormat.LORE); } /* @@ -68,17 +76,24 @@ public class InvseeInventory implements Listener */ public void addAndShowViewer(Player requester) { - viewers.add(requester); + _viewers.add(requester); requester.openInventory(_inventory); } + /* + * Check whether the given player is currently viewing this InvseeInventory + */ + public boolean isViewer(Player check) + { + return _viewers.contains(check); + } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void on(PlayerJoinEvent event) { - if (uuid.equals(event.getPlayer().getUniqueId())) + if (_uuid.equals(event.getPlayer().getUniqueId())) { - targetPlayer = event.getPlayer(); + _targetPlayer = event.getPlayer(); updateInventory(); } } @@ -87,93 +102,142 @@ public class InvseeInventory implements Listener public void on(PlayerQuitEvent event) { // If a viewer quit, this will clean it up - viewers.remove(event.getPlayer()); - if (viewers.size() == 0) + _viewers.remove(event.getPlayer()); + if (_viewers.size() == 0) { - invseeManager.close(uuid); + _invseeManager.close(_uuid); } else { // This should always work - targetPlayer = Bukkit.getOfflinePlayer(uuid); + _targetPlayer = Bukkit.getOfflinePlayer(_uuid); updateInventory(); } } + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void on(InventoryOpenEvent event) + { + if (event.getPlayer().getUniqueId().equals(_targetPlayer.getUniqueId()) && !_canOpenInventory) + { + event.setCancelled(true); + } + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void on(InventoryCloseEvent event) { if (_inventory.equals(event.getInventory())) { - viewers.remove(event.getPlayer()); - if (viewers.size() == 0) + _viewers.remove(event.getPlayer()); + if (_viewers.size() == 0) { - invseeManager.close(uuid); + _invseeManager.close(_uuid); } } } + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on(InventoryDragEvent event) + { + if (_inventory.equals(event.getInventory())) + { + ClansManager.getInstance().runSync(() -> + { + update(false); + saveInventory(); + }); + } + else if (event.getWhoClicked().getUniqueId().equals(_targetPlayer.getUniqueId())) + { + ClansManager.getInstance().runSync(() -> + { + update(true); + saveInventory(); + }); + } + } + @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 + if (event.getCurrentItem() != null && event.getCurrentItem().getType() == Material.STAINED_GLASS_PANE && event.getCurrentItem().getItemMeta() != null + && event.getCurrentItem().getItemMeta().getDisplayName() != null && event.getCurrentItem().getItemMeta().getDisplayName().equals(C.Bold)) { event.setCancelled(true); return; } + if (event.getCurrentItem() != null && event.getCurrentItem().getType() == Material.STONE_BUTTON + && event.getCurrentItem().getItemMeta() != null + && event.getCurrentItem().getItemMeta().getDisplayName() != null + && event.getCurrentItem().getItemMeta().getDisplayName().equals(C.cGreenB + "Inventory Control")) + { + event.setCancelled(true); + if (event.getClick() == ClickType.LEFT) + { + if (_targetPlayer.isOnline()) + { + ((Player) _targetPlayer).closeInventory(); + } + } + else if (event.getClick() == ClickType.RIGHT) + { + if (_targetPlayer.isOnline()) + { + _canOpenInventory = !_canOpenInventory; + ItemMeta meta = event.getCurrentItem().getItemMeta(); + meta.setLore(Arrays.asList(generateLore(_canOpenInventory))); + event.getCurrentItem().setItemMeta(meta); + if (!_canOpenInventory) + { + ((Player) _targetPlayer).closeInventory(); + } + } + } + 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())); + update(false); saveInventory(); - dontUpdate = false; }); } else if (MAPPING_CRAFTING_REVERSE.containsKey(event.getRawSlot())) { - if (targetPlayer.isOnline()) + 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; + update(false); }); } - else - { - event.setCancelled(true); - } } else if (event.getRawSlot() == 49) { - if (targetPlayer.isOnline()) + if (_targetPlayer.isOnline()) { - dontUpdate = true; ClansManager.getInstance().runSync(() -> { - IInventory iInventoryThis = ((CraftInventory) _inventory).getInventory(); - playerInventory.setCarried(iInventoryThis.getItem(49)); - saveInventory(); - ((Player) targetPlayer).updateInventory(); - dontUpdate = false; + update(false); }); } - else + } + } + else + { + if (event.getWhoClicked().getUniqueId().equals(_targetPlayer.getUniqueId())) + { + ClansManager.getInstance().runSync(() -> { - event.setCancelled(true); - } + update(true); + }); } } } @@ -183,34 +247,34 @@ public class InvseeInventory implements Listener */ private void updateInventory() { - if (targetPlayer.isOnline()) + if (_targetPlayer.isOnline()) { - playerInventory = ((CraftPlayer) targetPlayer).getHandle().inventory; + _playerInventory = ((CraftPlayer) _targetPlayer).getHandle().inventory; } else { - NBTTagCompound compound = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()).getPlayerData(uuid.toString()); + NBTTagCompound compound = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()).getPlayerData(_uuid.toString()); // Should not matter if null - playerInventory = new PlayerInventory(null); + _playerInventory = new PlayerInventory(null); if (compound.hasKeyOfType("Inventory", 9)) { - playerInventory.b(compound.getList("Inventory", 10)); + _playerInventory.b(compound.getList("Inventory", 10)); } } } private void saveInventory() { - if (!targetPlayer.isOnline()) + if (!_targetPlayer.isOnline()) { try { WorldNBTStorage worldNBTStorage = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()); - NBTTagCompound compound = worldNBTStorage.getPlayerData(uuid.toString()); + 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"); + _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()) { @@ -221,60 +285,95 @@ public class InvseeInventory implements Listener } catch (Exception var5) { - invseeManager.log("Failed to save player inventory for " + targetPlayer.getName()); - for (Player player : viewers) + _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())); + UtilPlayer.message(player, F.main("Invsee", "Could not save inventory for " + _targetPlayer.getName())); } var5.printStackTrace(System.out); } } } - @EventHandler - public void update(UpdateEvent event) + /* + * Update the player inventory and invsee inventory. + * + * @param targetClick If true, then it means the player being invseen has modified their inventory. Otherwise, it's the admin who has modified something + */ + private void update(boolean targetClick) { - if (event.getType() != UpdateType.TICK) - { - return; - } - if (dontUpdate) - { - return; - } - IInventory iInventoryThis = ((CraftInventory) _inventory).getInventory(); - // Update items on hotbar - for (int otherSlot = 0; otherSlot < 9; otherSlot++) + if (targetClick) { - 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++) + // Update items on hotbar + for (int otherSlot = 0; otherSlot < 9; otherSlot++) { - iInventoryThis.setItem(MAPPING_CRAFTING.get(craftingIndex), containerPlayer.craftInventory.getItem(craftingIndex)); + 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++) + { + iInventoryThis.setItem(MAPPING_CRAFTING.get(craftingIndex), containerPlayer.craftInventory.getItem(craftingIndex)); + } + } + iInventoryThis.setItem(49, _playerInventory.getCarried()); + } + else + { + // Update items on hotbar + for (int otherSlot = 0; otherSlot < 9; otherSlot++) + { + _playerInventory.setItem(otherSlot, iInventoryThis.getItem(MAPPING_INVENTORY.get(otherSlot))); + } + // Update main inventory + for (int otherSlot = 9; otherSlot < 36; otherSlot++) + { + _playerInventory.setItem(otherSlot, iInventoryThis.getItem(MAPPING_INVENTORY.get(otherSlot))); + } + // Update armor + for (int otherSlot = 36; otherSlot < 40; otherSlot++) + { + _playerInventory.setItem(otherSlot, iInventoryThis.getItem(MAPPING_INVENTORY.get(otherSlot))); + } + + if (_targetPlayer.isOnline()) + { + ContainerPlayer containerPlayer = (ContainerPlayer) ((CraftPlayer) _targetPlayer).getHandle().defaultContainer; + for (int craftingIndex = 0; craftingIndex < 4; craftingIndex++) + { + containerPlayer.craftInventory.setItem(craftingIndex, iInventoryThis.getItem(MAPPING_CRAFTING.get(craftingIndex))); + } + } + _playerInventory.setCarried(iInventoryThis.getItem(49)); + } + for (Player viewing : _viewers) + { + viewing.updateInventory(); + } + if (_targetPlayer.isOnline()) + { + ((Player) _targetPlayer).updateInventory(); } - 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<>(); + // Maps slot indices of player inventories to slot indices of crafting window private static final Map MAPPING_CRAFTING = new HashMap<>(); private static final Map MAPPING_CRAFTING_REVERSE = new HashMap<>(); From 2f993dbe66a7c063b2fb1f2502201f732c449246 Mon Sep 17 00:00:00 2001 From: samczsun Date: Sat, 21 May 2016 20:17:32 -0400 Subject: [PATCH 24/33] Fix Wind Blade, Hyper Axe --- .../game/clans/clans/ClansManager.java | 13 --- .../game/clans/clans/map/ItemMapManager.java | 29 ----- .../mineplex/game/clans/items/CustomItem.java | 3 +- .../clans/items/legendaries/HyperAxe.java | 2 +- .../clans/items/legendaries/WindBlade.java | 104 +++++++++++++----- 5 files changed, 77 insertions(+), 74 deletions(-) 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 988919ca7..69af91170 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 @@ -555,19 +555,6 @@ public class ClansManager extends MiniClientPluginimplements IRelati _classManager.GetRepository().SaveCustomBuild(activeBuild); } } - - @EventHandler - public void onPlayerKick(PlayerKickEvent event) - { - // Players using wind blade should not get kicked - if (event.getPlayer().getItemInHand() != null && event.getPlayer().getItemInHand().getItemMeta() != null && (C.cGold + "Wind Blade").equals(event.getPlayer().getItemInHand().getItemMeta().getDisplayName())) - { - if (event.getReason().contains("flying is not enabled") || event.getReason().contains("floating too long")) - { - event.setCancelled(true); - } - } - } @EventHandler public void StaffIncognito(IncognitoStatusChangeEvent event) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java index d2aaddd87..510a1b219 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java @@ -585,35 +585,6 @@ public class ItemMapManager extends MiniPlugin return _scale.get(scale); } - //fixme Spam left click in a chest and this won't work - @EventHandler - public void preventMapMoveInventories(InventoryClickEvent event) - { - Inventory inv = event.getClickedInventory(); - - if (inv == null) - return; - - // Yeah, the loop looks a little weird.. - for (ItemStack item : new ItemStack[] - { - event.getCurrentItem(), event.getCursor() - }) - { - if (!isItemClansMap(item)) - continue; - - if (inv.getHolder() instanceof Player ? !event.isShiftClick() : Objects.equal(event.getCurrentItem(), item)) - continue; - - event.setCancelled(true); - - UtilPlayer.message(event.getWhoClicked(), - F.main("Inventory", "You cannot move " + F.item("Clans Map") + " between inventories.")); - return; - } - } - //fixme So what appears to happen is that after you die, if your map is is the same then the map is frozen @EventHandler public void onDeath(PlayerDeathEvent event) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java index d52ebc928..281846d4e 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/CustomItem.java @@ -29,7 +29,7 @@ import mineplex.minecraft.game.core.damage.CustomDamageEvent; * @author MrTwiggy * */ -public class CustomItem +public class CustomItem implements Listener { private static final ChatColor TITLE_COLOR = ChatColor.GOLD; // Chat color @@ -73,6 +73,7 @@ public class CustomItem _material = material; _attributes = new AttributeContainer(); _uuid = UUID.randomUUID().toString(); + UtilServer.RegisterEvents(this); } public CustomItem(Material material) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/HyperAxe.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/HyperAxe.java index 085cc7fb4..5a695ba27 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/HyperAxe.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/HyperAxe.java @@ -31,7 +31,7 @@ public class HyperAxe extends LegendaryItem C.cWhite + "blade can rip through any opponent.", C.cWhite + " ", C.cWhite + "Hit delay is reduced by " + C.cYellow + "50%", - C.cWhite + "Deals " + C.cYellow + "10 Damage" + C.cWhite + " with attack", + C.cWhite + "Deals " + C.cYellow + "3 Damage" + C.cWhite + " with attack", C.cYellow + "Right-Click" + C.cWhite + " to use " + C.cGreen + "Dash", }, Material.RECORD_3); _speedAmount = amountGen.generateIntValue(); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java index 1ef288b15..a467146bd 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/WindBlade.java @@ -1,9 +1,14 @@ package mineplex.game.clans.items.legendaries; +import mineplex.game.clans.items.GearManager; +import mineplex.game.clans.items.PlayerGear; +import net.minecraft.server.v1_8_R3.PlayerConnection; import org.bukkit.Material; import org.bukkit.Sound; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.util.Vector; import mineplex.core.common.util.C; @@ -16,85 +21,101 @@ import mineplex.core.common.util.UtilParticle.ParticleType; import mineplex.core.common.util.UtilParticle.ViewDist; import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilTextBottom; -import mineplex.core.common.util.UtilTextMiddle; import mineplex.core.common.util.UtilTime; import mineplex.core.recharge.Recharge; import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import java.lang.reflect.Field; + public class WindBlade extends LegendaryItem { + private static final Field G_FIELD; + + static + { + try + { + G_FIELD = PlayerConnection.class.getDeclaredField("g"); + G_FIELD.setAccessible(true); + } + catch (ReflectiveOperationException exception) + { + throw new RuntimeException("Could not reflectively access field", exception); + } + } + public static final double FLIGHT_VELOCITY = 0.75d; - + private double _power; private double _burnoutThreshold; - + private int _messageTimer; - + public WindBlade() { - super("Wind Blade", new String[] { + super("Wind Blade", new String[]{ C.cWhite + "Long ago, a race of cloud dwellers", C.cWhite + "terrorized the skies. A remnant of", C.cWhite + "their tyranny, this airy blade is", C.cWhite + "the last surviving memorium from", C.cWhite + "their final battle against the Titans.", " ", - C.cYellow + "Right-Click" + C.cWhite + " to use" + C.cGreen + " Fly", + C.cYellow + "Right-Click" + C.cWhite + " to use" + C.cGreen + " Fly", }, Material.GREEN_RECORD); } - + @Override public void update(Player wielder) { long burnoutRemaining = -1L; - + if (Recharge.Instance.Get(wielder) != null && Recharge.Instance.Get(wielder).containsKey("clans_legendary_windblade_burnout")) { burnoutRemaining = Recharge.Instance.Get(wielder).get("clans_legendary_windblade_burnout").GetRemaining(); } - + // Check if player is attempting to fly and activate if (isHoldingRightClick()) { if (canPropel(wielder)) { wielder.setFallDistance(0f); - + if (burnoutRemaining > 0) { _messageTimer++; - + if (_messageTimer % 4 == 0) { UtilParticle.PlayParticle(ParticleType.SMOKE, wielder.getLocation(), 0.f, 0.f, 0.f, .1f, 1, ViewDist.NORMAL); wielder.playSound(wielder.getLocation(), Sound.FIZZ, .5f, 1.f); - + removePower(0.15); - + _burnoutThreshold = 0; } - + if (_messageTimer % 5 == 0) { UtilPlayer.message(wielder, F.main("Wind Blade", "Flight power damaged whilst scraping the ground! Repairs will be finish in " + F.time(UtilTime.MakeStr(burnoutRemaining)) + ".")); } - + if (_messageTimer % 10 == 0) { wielder.playSound(wielder.getLocation(), Sound.ANVIL_USE, .5f, 1.5f); } - + return; } - + removePower(UtilEnt.isGrounded(wielder) ? 1.17 : .88); - + propelPlayer(wielder); UtilParticle.PlayParticle(ParticleType.EXPLODE, wielder.getLocation().add(0, 1, 0), 0, 0, 0, .1f, 3, ViewDist.NORMAL); - + wielder.playSound(wielder.getLocation(), Sound.FIRE, .25f, 1.75f); } - + if (UtilEnt.isGrounded(wielder)) { _burnoutThreshold++; @@ -109,44 +130,67 @@ public class WindBlade extends LegendaryItem { _burnoutThreshold = UtilMath.clamp(_burnoutThreshold - .5, 0, _burnoutThreshold); } - + if (UtilEnt.isGrounded(wielder, wielder.getLocation()) || UtilEnt.isGrounded(wielder, wielder.getLocation().subtract(0, 1, 0))) { addPower(0.65); } - + if (_burnoutThreshold > 15 && burnoutRemaining <= 0) { Recharge.Instance.use(wielder, "clans_legendary_windblade_burnout", 2500, false, false); } - + UtilTextBottom.displayProgress(UtilMath.clamp(_power, .0, 80.) / 80., wielder); } - + @Override public void onAttack(CustomDamageEvent event, Player wielder) { event.AddMod("Wind Blade", 6); } - + + @EventHandler + public void onFall(CustomDamageEvent event) + { + if (event.GetDamageePlayer() != null && event.GetCause() == EntityDamageEvent.DamageCause.FALL) + { + PlayerGear playerGear = GearManager.getInstance().getPlayerGear(event.GetDamageePlayer()); + if (playerGear.getWeapon() instanceof WindBlade) + { + event.SetCancelled("Wind Blade No Fall Damage"); + } + } + } + private void propelPlayer(Player player) { Vector direction = player.getLocation().getDirection().normalize(); direction.multiply(FLIGHT_VELOCITY); - + player.setVelocity(direction); + + PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection; + try + { + G_FIELD.set(connection, 0); + } + catch (IllegalAccessException e) + { + new RuntimeException("Could not update g field", e).printStackTrace(); + } } - + private boolean canPropel(Player player) { return _power > 0 && !UtilItem.isLiquid(player.getLocation().getBlock().getType()); } - + private void addPower(double power) { _power = UtilMath.clamp(_power + power, -20, 80); } - + private void removePower(double power) { _power = UtilMath.clamp(_power - power, -20, 80); From f32e648691d49cc33cd7b98f1b9e2285bcff3da0 Mon Sep 17 00:00:00 2001 From: samczsun Date: Sun, 22 May 2016 12:20:04 -0400 Subject: [PATCH 25/33] QA Pass #1 Remove potential main thread IO in ItemMapManager Don't construct search string if limit is reached Also cleaned up WorldManager to be more efficient --- .../mineplex/core/common/util/UtilWorld.java | 13 ++ .../game/clans/clans/ClansUtility.java | 39 ++-- .../clans/invsee/commands/InvseeCommand.java | 1 + .../game/clans/clans/map/ItemMapManager.java | 41 +--- .../game/clans/world/WorldManager.java | 203 +++++++++--------- 5 files changed, 149 insertions(+), 148 deletions(-) diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java index e9ee2c856..fe44de9c8 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java @@ -10,6 +10,8 @@ import org.bukkit.World.Environment; import org.bukkit.WorldBorder; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; +import org.bukkit.entity.Entity; import org.bukkit.util.Vector; import com.google.common.collect.Lists; @@ -294,4 +296,15 @@ public class UtilWorld return startX >= minX && startZ <= maxX && endX >= minZ && endZ <= maxZ; } + public static double distanceSquared(Entity a, Entity b) + { + if (a.getWorld() != b.getWorld()) + throw new IllegalArgumentException("Different worlds: " + a.getWorld().getName() + " and " + b.getWorld().getName()); + net.minecraft.server.v1_8_R3.Entity entityA = ((CraftEntity) a).getHandle(); + net.minecraft.server.v1_8_R3.Entity entityB = ((CraftEntity) b).getHandle(); + double dx = entityA.locX - entityB.locX; + double dy = entityA.locY - entityB.locY; + double dz = entityA.locZ - entityB.locZ; + return (dx * dx) + (dy * dy) + (dz * dz); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java index bc6ad05bb..9e4e2e1af 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java @@ -123,27 +123,32 @@ public class ClansUtility if (cur.getName().equalsIgnoreCase(name)) return cur; if (cur.getName().toLowerCase().contains(name.toLowerCase())) clanMatchList.add(cur); + + if (clanMatchList.size() > MAX_CLAN_SEARCH) break; } if (clanMatchList.size() == 1) return clanMatchList.get(0); // No / Non-Unique String clanMatchString = ""; - if (clanMatchList.size() > 1) + if (clanMatchList.size() <= MAX_CLAN_SEARCH) { - for (ClanInfo cur : clanMatchList) - clanMatchString += cur.getName() + " "; - } + if (clanMatchList.size() > 1) + { + for (ClanInfo cur : clanMatchList) + clanMatchString += cur.getName() + " "; + } - if (clanMatchString.length() == 0) - { - clanMatchString = "None"; + if (clanMatchString.length() == 0) + { + clanMatchString = "None"; + } } // PLAYER LinkedList playerMatchList = new LinkedList(); - for (ClanInfo clanInfo : _clansManager.getClanMap().values()) + outer: for (ClanInfo clanInfo : _clansManager.getClanMap().values()) { for (ClansPlayer player : clanInfo.getMembers().values()) { @@ -151,6 +156,7 @@ public class ClansUtility if (player.getPlayerName().toLowerCase().contains(name.toLowerCase())) playerMatchList.add(clanInfo); + if (playerMatchList.size() > MAX_PLAYER_SEARCH) break outer; } } @@ -158,15 +164,18 @@ public class ClansUtility // No / Non-Unique String playerMatchString = ""; - if (playerMatchList.size() > 1) + if (playerMatchList.size() <= MAX_PLAYER_SEARCH) { - for (ClanInfo cur : playerMatchList) - playerMatchString += cur.getName() + " "; - } + if (playerMatchList.size() > 1) + { + for (ClanInfo cur : playerMatchList) + playerMatchString += cur.getName() + " "; + } - if (playerMatchString.length() == 0) - { - playerMatchString = "None"; + if (playerMatchString.length() == 0) + { + playerMatchString = "None"; + } } if (inform) 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 ebbce2c9d..00f0e24b8 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 @@ -59,6 +59,7 @@ public class InvseeCommand extends CommandBase return; } // We need to check if we actually have data on this player + // fixme main thread file IO but it's what the server does...? NBTTagCompound compound = ((WorldNBTStorage) MinecraftServer.getServer().worlds.get(0).getDataManager()).getPlayerData(uuid.toString()); if (compound == null) { diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java index 510a1b219..04e2fb410 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapManager.java @@ -282,7 +282,7 @@ public class ItemMapManager extends MiniPlugin ex.printStackTrace(); } - rebuildScan(true); + rebuildScan(); initialScan(); } @@ -306,7 +306,7 @@ public class ItemMapManager extends MiniPlugin boolean outsideMap = startingZ < -HALF_WORLD_SIZE; - scanWorldMap(startingX, startingZ, !outsideMap); + scanWorldMap(startingX, startingZ, !outsideMap, true); if (outsideMap) { @@ -714,7 +714,7 @@ public class ItemMapManager extends MiniPlugin p.sendMessage(C.cYellow + "If you want to play on Clans again, rejoin the Mineplex server!"); } - private void rebuildScan(boolean firstScan) + private void rebuildScan() { for (int x = -HALF_WORLD_SIZE; x < HALF_WORLD_SIZE; x += BLOCK_SCAN_INTERVAL) { @@ -724,31 +724,6 @@ public class ItemMapManager extends MiniPlugin } } - if (!firstScan) - { - Iterator> itel = _scanList.iterator(); - - while (itel.hasNext()) - { - Entry entry = itel.next(); - boolean removeEntry = true; - - for (Player player : UtilServer.getPlayers()) - { - if (Math.sqrt(getDistance(entry, player.getLocation().getX(), player.getLocation().getZ())) < 200) - { - removeEntry = false; - break; - } - } - - if (removeEntry) - { - itel.remove(); - } - } - } - Collections.sort(_scanList, _comparator); } @@ -796,7 +771,7 @@ public class ItemMapManager extends MiniPlugin if (_scanList.isEmpty() && UtilServer.getPlayers().length > 0) { - rebuildScan(false); + rebuildScan(); } if (_scanList.size() % 20 == 0) @@ -816,7 +791,7 @@ public class ItemMapManager extends MiniPlugin boolean outsideMap = startingZ < -HALF_WORLD_SIZE; - scanWorldMap(startingX, startingZ, !outsideMap); + scanWorldMap(startingX, startingZ, !outsideMap, false); if (outsideMap) return; @@ -854,7 +829,7 @@ public class ItemMapManager extends MiniPlugin * * If the chunk could not be loaded, generate it froms scratch * Otherwise, the loaded chunk will be used */ - public void scanWorldMap(int startingX, int startingZ, boolean setColors) + public void scanWorldMap(int startingX, int startingZ, boolean setColors, boolean isFirstScan) { Byte[][] map = _map.get(0); for (int beginX = startingX; beginX < startingX + BLOCK_SCAN_INTERVAL; beginX += 16) @@ -871,6 +846,10 @@ public class ItemMapManager extends MiniPlugin nmsChunk = _chunkCache.get(key); if (nmsChunk == null) { + if (!isFirstScan) + { + continue; + } try { Object[] data = _chunkRegionLoader.loadChunk(_nmsWorld, chunkX, chunkZ); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java index f2761bab3..6bc3b41f5 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java @@ -1,150 +1,149 @@ package mineplex.game.clans.world; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.*; -import org.bukkit.Bukkit; +import mineplex.core.common.util.UtilWorld; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.plugin.java.JavaPlugin; import mineplex.core.MiniPlugin; -import mineplex.core.common.util.UtilMath; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; -import mineplex.game.clans.clans.ClansManager; public class WorldManager extends MiniPlugin -{ - public WorldManager(JavaPlugin plugin) +{ + private static final Map CULL_LIMITS = new HashMap<>(); + private static final Set MINECART_TYPES = new HashSet<>(); + private static final int MIN_RANGE = 64; + private static final int MIN_RANGE_SQUARED = MIN_RANGE * MIN_RANGE; + + static + { + // Animals + CULL_LIMITS.put(EntityType.BAT, 50); + CULL_LIMITS.put(EntityType.CHICKEN, 150); + CULL_LIMITS.put(EntityType.COW, 150); + CULL_LIMITS.put(EntityType.HORSE, 50); + CULL_LIMITS.put(EntityType.IRON_GOLEM, 50); + CULL_LIMITS.put(EntityType.MUSHROOM_COW, 50); + CULL_LIMITS.put(EntityType.OCELOT, 50); + CULL_LIMITS.put(EntityType.PIG, 150); + CULL_LIMITS.put(EntityType.RABBIT, 50); + CULL_LIMITS.put(EntityType.SHEEP, 150); + CULL_LIMITS.put(EntityType.WOLF, 150); + + // Monsters + CULL_LIMITS.put(EntityType.CAVE_SPIDER, 100); + CULL_LIMITS.put(EntityType.CREEPER, 100); + CULL_LIMITS.put(EntityType.ENDERMAN, 50); + CULL_LIMITS.put(EntityType.ENDERMITE, 50); + CULL_LIMITS.put(EntityType.SILVERFISH, 50); + CULL_LIMITS.put(EntityType.SKELETON, 100); + CULL_LIMITS.put(EntityType.SLIME, 50); + CULL_LIMITS.put(EntityType.SPIDER, 100); + CULL_LIMITS.put(EntityType.ZOMBIE, 100); + + // Nether + CULL_LIMITS.put(EntityType.BLAZE, 50); + CULL_LIMITS.put(EntityType.GHAST, 50); + CULL_LIMITS.put(EntityType.MAGMA_CUBE, 50); + CULL_LIMITS.put(EntityType.PIG_ZOMBIE, 50); + + MINECART_TYPES.add(EntityType.MINECART); + MINECART_TYPES.add(EntityType.MINECART_CHEST); + MINECART_TYPES.add(EntityType.MINECART_COMMAND); + MINECART_TYPES.add(EntityType.MINECART_FURNACE); + MINECART_TYPES.add(EntityType.MINECART_HOPPER); + MINECART_TYPES.add(EntityType.MINECART_MOB_SPAWNER); + MINECART_TYPES.add(EntityType.MINECART_TNT); + } + + public WorldManager(JavaPlugin plugin) { super("Clan World Manager", plugin); } - + @EventHandler public void cullMobs(UpdateEvent event) { if (event.getType() != UpdateType.SLOW) return; - + for (World world : getPlugin().getServer().getWorlds()) { - HashMap> _ents = new HashMap>(); - - for (EntityType type : EntityType.values()) - _ents.put(type, new ArrayList()); - - for (Entity ent : world.getEntities()) + List players = world.getPlayers(); + Map> entities = new HashMap<>(); + + for (Entity entity : world.getEntities()) { - if (ent.getCustomName() == null) + if (entity.getCustomName() != null) + { + continue; + } + + EntityType entityType = entity.getType(); + + if (entityType == EntityType.ARROW) + { + if (entity.getTicksLived() > 800) + { + entity.remove(); + } + } + else if (entityType == EntityType.DROPPED_ITEM) + { + if (entity.getTicksLived() > 2400) + { + entity.remove(); + } + } + else if (CULL_LIMITS.containsKey(entityType)) { boolean cull = true; - - for (Player player : world.getPlayers()) + for (Player player : players) { - if (player.getLocation().distance(ent.getLocation()) <= 64) + if (UtilWorld.distanceSquared(player, entity) <= MIN_RANGE_SQUARED) { cull = false; break; } } - if (cull) { - _ents.get(ent.getType()).add(ent); + entities.computeIfAbsent(entityType, key -> new HashSet<>()).add(entity); + } + } + else if (MINECART_TYPES.contains(entityType)) + { + if (entity.getTicksLived() > 800) + { + entity.remove(); } } } - - for (EntityType type : _ents.keySet()) + + for (Map.Entry> entry : entities.entrySet()) { - ArrayList ents = _ents.get(type); - - //Clean Old Arrows - if (type == EntityType.ARROW) - { - for (Entity ent : ents) - if (ent.getTicksLived() > 800) - ent.remove(); - } - - //Clean Old Items - if (type == EntityType.DROPPED_ITEM) - { - for (Entity ent : ents) - if (ent.getTicksLived() > 2400) - ent.remove(); - } - - //Animals - else if (type == EntityType.BAT) cull(ents, 50); - else if (type == EntityType.CHICKEN) cull(ents, 150); - else if (type == EntityType.COW) cull(ents, 150); - else if (type == EntityType.HORSE) cull(ents, 50); - else if (type == EntityType.IRON_GOLEM) cull(ents, 50); - else if (type == EntityType.MUSHROOM_COW) cull(ents, 50); - else if (type == EntityType.OCELOT) cull(ents, 50); - else if (type == EntityType.PIG) cull(ents, 150); - else if (type == EntityType.RABBIT) cull(ents, 50); - else if (type == EntityType.SHEEP) cull(ents, 150); - else if (type == EntityType.WOLF) cull(ents, 150); - - //Monster - else if (type == EntityType.CAVE_SPIDER) cull(ents, 100); - else if (type == EntityType.CREEPER) cull(ents, 100); - else if (type == EntityType.ENDERMAN) cull(ents, 50); - else if (type == EntityType.ENDERMITE) cull(ents, 50); - else if (type == EntityType.SILVERFISH) cull(ents, 50); - else if (type == EntityType.SKELETON) cull(ents, 100); - else if (type == EntityType.SLIME) cull(ents, 50); - else if (type == EntityType.SPIDER) cull(ents, 100); - else if (type == EntityType.ZOMBIE) cull(ents, 100); - - //Nether - else if (type == EntityType.BLAZE) cull(ents, 50); - else if (type == EntityType.GHAST) cull(ents, 50); - else if (type == EntityType.MAGMA_CUBE) cull(ents, 50); - else if (type == EntityType.PIG_ZOMBIE) cull(ents, 50); - - //Clean Old Minecarts - if (type == EntityType.MINECART || - type == EntityType.MINECART_CHEST || - type == EntityType.MINECART_COMMAND || - type == EntityType.MINECART_FURNACE || - type == EntityType.MINECART_HOPPER || - type == EntityType.MINECART_MOB_SPAWNER || - type == EntityType.MINECART_TNT) - { - for (Entity ent : ents) - if (ent.getTicksLived() > 800) - ent.remove(); - } + cull(entry.getKey(), entry.getValue(), CULL_LIMITS.get(entry.getKey())); } } } - - public void cull(ArrayList ents, int limit) - { - int culled = 0; - EntityType type = null; - while (ents.size() > limit) - { - Entity ent = ents.remove(UtilMath.r(ents.size())); - - type = ent.getType(); - ent.remove(); - + private void cull(EntityType type, Set ents, int limit) + { + Iterator iterator = ents.iterator(); + int culled = 0; + while (iterator.hasNext() && ents.size() > limit) + { + Entity entity = iterator.next(); + entity.remove(); + iterator.remove(); culled++; } - - if (type != null) - { - System.out.println("Culled " + culled + " " + type); - } + log("Culled " + culled + " " + type); } } From b952de856ea23124c2af81e5aae5b72bb08b03b8 Mon Sep 17 00:00:00 2001 From: AlexTheCoder Date: Sun, 22 May 2016 18:42:12 -0400 Subject: [PATCH 26/33] Add a description for the Magnetic Maul and switch ConcurrentHashMap to HashMap in the Meridian Scepter --- .../clans/items/legendaries/MagneticMaul.java | 21 +++++++++++-------- .../items/legendaries/MeridianScepter.java | 7 ++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MagneticMaul.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MagneticMaul.java index 1494de126..3fb814e50 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MagneticMaul.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MagneticMaul.java @@ -1,11 +1,6 @@ package mineplex.game.clans.items.legendaries; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - +import mineplex.core.common.util.C; import mineplex.core.common.util.UtilAction; import mineplex.core.common.util.UtilAlg; import mineplex.core.common.util.UtilMath; @@ -18,6 +13,12 @@ import mineplex.core.common.util.UtilWorld; import mineplex.game.clans.clans.ClansManager; import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + public class MagneticMaul extends LegendaryItem { public static final double PULL_RANGE = 10d; @@ -27,9 +28,11 @@ public class MagneticMaul extends LegendaryItem public MagneticMaul() { - super("Magnetic Maul", new String[]{ - - }, Material.RECORD_5); + super("Magnetic Maul", new String[] { + C.cWhite + "This brutal weapon allows you to pull your enemies towards you with magnetic force!" + + " ", + C.cYellow + "Right-Click" + C.cWhite + " to use Maul." + }, Material.RECORD_5); } @Override diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java index 39b63a037..8cc649c12 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/legendaries/MeridianScepter.java @@ -1,6 +1,6 @@ package mineplex.game.clans.items.legendaries; -import java.util.concurrent.ConcurrentHashMap; +import java.util.HashMap; import mineplex.core.common.util.C; import mineplex.core.common.util.F; @@ -21,8 +21,6 @@ import mineplex.core.common.util.UtilTime.TimeUnit; import mineplex.core.recharge.Recharge; import mineplex.game.clans.clans.ClansManager; -import mineplex.minecraft.game.core.condition.Condition; -import mineplex.minecraft.game.core.condition.ConditionManager; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -37,12 +35,11 @@ import org.bukkit.util.Vector; public class MeridianScepter extends LegendaryItem { - private long _lastFire = System.currentTimeMillis(); private long _interactWait; private RGBData[] colors = { UtilColor.RgbPurple, UtilColor.RgbPurple.Lighten(), UtilColor.RgbPurple.Darken() }; - private ConcurrentHashMap _animations = new ConcurrentHashMap(); + private HashMap _animations = new HashMap(); public MeridianScepter() { From 9853ef824e92dbc1fa0b87bd2e2c7c6d91b26a2e Mon Sep 17 00:00:00 2001 From: Sam Sun Date: Tue, 24 May 2016 12:58:49 -0400 Subject: [PATCH 27/33] QA Pass #2 - Comment WorldManager, optimize searching --- .../game/clans/clans/ClansUtility.java | 70 +++++++++---------- .../clans/tutorial/command/FinishCommand.java | 2 +- .../tutorial/command/TutorialCommand.java | 6 +- .../game/clans/world/WorldManager.java | 2 + 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java index 9e4e2e1af..ff6c1fc70 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import org.bukkit.ChatColor; import org.bukkit.Chunk; @@ -28,7 +29,9 @@ import mineplex.game.clans.spawn.Spawn; public class ClansUtility { + // The maximum number of clans to search before exiting early. Inclusive private static final int MAX_CLAN_SEARCH = 10; + // The maximum number of players to search before exiting early. Inclusive private static final int MAX_PLAYER_SEARCH = 10; private ClansManager _clansManager; @@ -116,7 +119,7 @@ public class ClansUtility public ClanInfo searchClanPlayer(Player caller, String name, boolean inform) { // CLAN - LinkedList clanMatchList = new LinkedList(); + List clanMatchList = new ArrayList<>(MAX_CLAN_SEARCH); for (ClanInfo cur : _clansManager.getClanMap().values()) { @@ -128,25 +131,9 @@ public class ClansUtility } if (clanMatchList.size() == 1) return clanMatchList.get(0); - - // No / Non-Unique - String clanMatchString = ""; - if (clanMatchList.size() <= MAX_CLAN_SEARCH) - { - if (clanMatchList.size() > 1) - { - for (ClanInfo cur : clanMatchList) - clanMatchString += cur.getName() + " "; - } - - if (clanMatchString.length() == 0) - { - clanMatchString = "None"; - } - } - + // PLAYER - LinkedList playerMatchList = new LinkedList(); + List playerMatchList = new ArrayList<>(MAX_PLAYER_SEARCH); outer: for (ClanInfo clanInfo : _clansManager.getClanMap().values()) { @@ -154,7 +141,12 @@ public class ClansUtility { if (player.getPlayerName().equalsIgnoreCase(name)) return clanInfo; - if (player.getPlayerName().toLowerCase().contains(name.toLowerCase())) playerMatchList.add(clanInfo); + if (player.getPlayerName().toLowerCase().contains(name.toLowerCase())) + { + playerMatchList.add(clanInfo); + // No duplicate results please + continue outer; + } if (playerMatchList.size() > MAX_PLAYER_SEARCH) break outer; } @@ -162,22 +154,6 @@ public class ClansUtility if (playerMatchList.size() == 1) return playerMatchList.get(0); - // No / Non-Unique - String playerMatchString = ""; - if (playerMatchList.size() <= MAX_PLAYER_SEARCH) - { - if (playerMatchList.size() > 1) - { - for (ClanInfo cur : playerMatchList) - playerMatchString += cur.getName() + " "; - } - - if (playerMatchString.length() == 0) - { - playerMatchString = "None"; - } - } - if (inform) { UtilPlayer.message(caller, F.main("Clan Search", "" + C.mCount + (clanMatchList.size() + playerMatchList.size()) + C.mBody + " matches for [" + C.mElem + name + C.mBody + "].")); @@ -186,17 +162,35 @@ public class ClansUtility { UtilPlayer.message(caller, F.main("Clan Search", "Too many clans matched. Try a more specific search")); } + else if (clanMatchList.size() == 0) + { + UtilPlayer.message(caller, F.main("Clan Search", "No clans matched. Try a more specific search")); + } else { - UtilPlayer.message(caller, F.desc("Matches via Clan", clanMatchString)); + StringBuilder clanMatchString = new StringBuilder(); + for (ClanInfo clanInfo : clanMatchList) + { + clanMatchString.append(clanInfo.getName()).append(" "); + } + UtilPlayer.message(caller, F.desc("Matches via Clan", clanMatchString.toString())); } if (playerMatchList.size() > MAX_PLAYER_SEARCH) { UtilPlayer.message(caller, F.main("Clan Search", "Too many players matched. Try a more specific search")); } + else if (playerMatchList.size() == 0) + { + UtilPlayer.message(caller, F.main("Clan Search", "No players matched. Try a more specific search")); + } else { - UtilPlayer.message(caller, F.desc("Matches via Player", playerMatchString)); + StringBuilder playerMatchString = new StringBuilder(); + for (ClanInfo clanInfo : playerMatchList) + { + playerMatchString.append(clanInfo.getName()).append(" "); + } + UtilPlayer.message(caller, F.desc("Matches via Player", playerMatchString.toString())); } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java index 723e6974f..e0e32c1dc 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/FinishCommand.java @@ -17,7 +17,7 @@ public class FinishCommand extends CommandBase public void Execute(Player caller, String[] args) { boolean testServer = Plugin.getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing"); - if (CommandCenter.Instance.GetClientManager().hasRank(caller, testServer ? Rank.ALL : Rank.JNR_DEV)) + if (_commandCenter.GetClientManager().hasRank(caller, testServer ? Rank.ALL : Rank.JNR_DEV)) { Plugin.finishTutorial(caller); } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java index d444a81b9..f13e5bfde 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorial/command/TutorialCommand.java @@ -1,13 +1,11 @@ package mineplex.game.clans.tutorial.command; -import org.bukkit.entity.Player; - -import mineplex.core.command.CommandBase; import mineplex.core.command.MultiCommandBase; import mineplex.core.common.Rank; import mineplex.core.common.util.F; import mineplex.core.common.util.UtilPlayer; import mineplex.game.clans.tutorial.TutorialManager; +import org.bukkit.entity.Player; public class TutorialCommand extends MultiCommandBase { @@ -29,7 +27,7 @@ public class TutorialCommand extends MultiCommandBase public void Execute(Player caller, String[] args) { boolean testServer = Plugin.getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing"); - if (CommandCenter.GetClientManager().hasRank(caller, testServer ? Rank.ALL : Rank.JNR_DEV)) + if (_commandCenter.GetClientManager().hasRank(caller, testServer ? Rank.ALL : Rank.JNR_DEV)) { super.Execute(caller, args); } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java index 6bc3b41f5..e6b7bf983 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/world/WorldManager.java @@ -106,6 +106,8 @@ public class WorldManager extends MiniPlugin boolean cull = true; for (Player player : players) { + // Using NMS because this is going to be called quite a few times + // and each getLocation() call creates a new Location object if (UtilWorld.distanceSquared(player, entity) <= MIN_RANGE_SQUARED) { cull = false; From 9acdbd7cbeb8741b36fdd651750d9e877816c176 Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 24 May 2016 15:38:03 -0400 Subject: [PATCH 28/33] Don't allow placing banners and string. Fixes PC-333 --- .../mineplex/game/clans/clans/ClansGame.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java index 00d3f6229..6f47a5525 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java @@ -303,7 +303,28 @@ public class ClansGame extends MiniPlugin UtilPlayer.message(player, F.main("Clans", "You cannot place blocks in " + F.elem("Borderlands") + ".")); return; } - + + // Banners/String + if (player.getGameMode() != GameMode.CREATIVE && player.getItemInHand() != null) + { + if (player.getItemInHand().getType() == Material.BANNER || player.getItemInHand().getType() == Material.STRING) + { + Location destLocation = event.getClickedBlock().getRelative(event.getBlockFace()).getLocation(); + ClanTerritory territory = _clans.getClanUtility().getClaim(destLocation); + if (territory != null) + { + if (territory.Owner.equals("Shops") || territory.Owner.equals("Fields") || territory.Owner.equals("Spawn") || territory.Owner.equals("Borderlands")) { + // Disallow + event.setCancelled(true); + + // Inform + UtilPlayer.message(player, F.main("Clans", "You cannot place that in " + F.elem(_clans.getClanUtility().getOwnerStringRel(destLocation, player)) + ".")); + return; + } + } + } + } + ClanRelation access = _clans.getClanUtility().getAccess(player, loc); ClanInfo clan = _clans.getClan(player); ClanInfo blockClan = _clans.getClanUtility().getClaim(loc) == null ? null : _clans.getClan(_clans.getClanUtility().getClaim(loc).Owner); From 9af2c7e9f42303fcac64b89767bb01bed6c57dcb Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 24 May 2016 15:38:18 -0400 Subject: [PATCH 29/33] Restore hunger after Hold. Fixes PC-334 --- .../Skill/Knight/HoldPosition.java | 38 ++++++++++++++++++- .../game/core/condition/ConditionManager.java | 6 +++ .../events/ConditionExpireEvent.java | 33 ++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/events/ConditionExpireEvent.java diff --git a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Knight/HoldPosition.java b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Knight/HoldPosition.java index 4aea8ddfd..9741ea52d 100644 --- a/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Knight/HoldPosition.java +++ b/Plugins/Mineplex.Minecraft.Game.ClassCombat/src/mineplex/minecraft/game/classcombat/Skill/Knight/HoldPosition.java @@ -1,5 +1,6 @@ package mineplex.minecraft.game.classcombat.Skill.Knight; +import mineplex.minecraft.game.core.condition.events.ConditionExpireEvent; import org.bukkit.Effect; import org.bukkit.Material; import org.bukkit.Sound; @@ -22,6 +23,10 @@ import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import mineplex.minecraft.game.classcombat.Skill.SkillActive; import mineplex.minecraft.game.classcombat.Skill.SkillFactory; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.HashMap; +import java.util.Map; public class HoldPosition extends SkillActive { @@ -47,10 +52,13 @@ public class HoldPosition extends SkillActive }); } + private final Map _foodLevel = new HashMap<>(); + @Override public boolean CustomCheck(Player player, int level) { - if (player.getLocation().getBlock().getTypeId() == 8 || player.getLocation().getBlock().getTypeId() == 9) + Material type = player.getLocation().getBlock().getType(); + if (type == Material.WATER || type == Material.STATIONARY_WATER) { UtilPlayer.message(player, F.main("Skill", "You cannot use " + F.skill(GetName()) + " in water.")); return false; @@ -75,6 +83,8 @@ public class HoldPosition extends SkillActive //Effect player.getWorld().playSound(player.getLocation(), Sound.ENDERMAN_SCREAM, 1.5f, 0f); player.getWorld().playEffect(player.getLocation(), Effect.STEP_SOUND, 49); + + _foodLevel.put(player, player.getFoodLevel()); } @EventHandler(priority = EventPriority.HIGH) @@ -123,8 +133,32 @@ public class HoldPosition extends SkillActive } } + @EventHandler + public void on(ConditionExpireEvent event) + { + if (event.getCondition().GetReason().equals(GetName()) && event.getCondition().GetEnt() instanceof Player) + { + if (event.getCondition().GetType() == ConditionType.DAMAGE_RESISTANCE) + { + Player player = ((Player) event.getCondition().GetEnt()); + if (_foodLevel.get(player) != null) + { + player.setFoodLevel(_foodLevel.get(player)); + } + // Could be null value. Sanity check + _foodLevel.remove(player); + } + } + } + + @EventHandler + public void on(PlayerQuitEvent event) + { + _foodLevel.remove(event.getPlayer()); + } + @Override - public void Reset(Player player) + public void Reset(Player player) { player.setFoodLevel(20); } diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/ConditionManager.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/ConditionManager.java index 82f16e341..dbac07668 100644 --- a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/ConditionManager.java +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/ConditionManager.java @@ -7,6 +7,7 @@ import java.util.Map.Entry; import java.util.WeakHashMap; import mineplex.core.MiniPlugin; +import mineplex.core.common.util.UtilServer; import mineplex.core.recharge.Recharge; import mineplex.core.updater.event.UpdateEvent; import mineplex.core.updater.UpdateType; @@ -18,6 +19,7 @@ import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilTime.TimeUnit; import mineplex.minecraft.game.core.condition.Condition.ConditionType; import mineplex.minecraft.game.core.condition.events.ConditionApplyEvent; +import mineplex.minecraft.game.core.condition.events.ConditionExpireEvent; import mineplex.minecraft.game.core.damage.DamageManager; import org.bukkit.Material; @@ -189,7 +191,11 @@ public class ConditionManager extends MiniPlugin Condition cond = conditionIterator.next(); if (cond.Tick()) + { + ConditionExpireEvent conditionExpireEvent = new ConditionExpireEvent(cond); + UtilServer.CallEvent(conditionExpireEvent); conditionIterator.remove(); + } } } diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/events/ConditionExpireEvent.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/events/ConditionExpireEvent.java new file mode 100644 index 000000000..9640d445a --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/condition/events/ConditionExpireEvent.java @@ -0,0 +1,33 @@ +package mineplex.minecraft.game.core.condition.events; + +import mineplex.minecraft.game.core.condition.Condition; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class ConditionExpireEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private Condition _cond; + + public ConditionExpireEvent(Condition cond) + { + _cond = cond; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + public Condition getCondition() + { + return _cond; + } + +} From 2680c2b244fd788f8e39d5eebfe9a06a50e3ae92 Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 24 May 2016 15:58:44 -0400 Subject: [PATCH 30/33] Don't apply attributes on friendlies. Fixes PC-369 --- .../clans/items/attributes/ItemAttribute.java | 21 +++++++++++++++++++ .../attributes/weapon/FlamingAttribute.java | 1 + .../attributes/weapon/FrostedAttribute.java | 1 + .../attributes/weapon/HasteAttribute.java | 1 + .../attributes/weapon/JaggedAttribute.java | 1 + .../attributes/weapon/VampiricAttribute.java | 2 ++ 6 files changed, 27 insertions(+) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java index a2593c271..ab0cc3957 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/ItemAttribute.java @@ -1,8 +1,12 @@ package mineplex.game.clans.items.attributes; +import mineplex.game.clans.clans.ClansManager; +import mineplex.game.clans.clans.ClansUtility; import mineplex.game.clans.items.generation.ValueDistribution; import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -127,4 +131,21 @@ public abstract class ItemAttribute } return s; } + + protected boolean isTeammate(Entity attacker, Entity defender) + { + if (attacker == null || defender == null) return false; + // Don't count attacks towards teammates + if (attacker instanceof Player && defender instanceof Player) + { + ClansUtility.ClanRelation relation = ClansManager.getInstance().getRelation((Player) attacker, (Player) defender); + if (relation == ClansUtility.ClanRelation.ALLY + || relation == ClansUtility.ClanRelation.SAFE + || relation == ClansUtility.ClanRelation.SELF) + { + return true; + } + } + return false; + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java index ec37a112a..d6a25bb23 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FlamingAttribute.java @@ -41,6 +41,7 @@ public class FlamingAttribute extends AttackAttribute if(attacker instanceof Player && ClansManager.getInstance().isSafe((Player) attacker)) return; if(defender instanceof Player && ClansManager.getInstance().isSafe((Player) defender)) return; if(attacker instanceof Player && ((Player)attacker).getGameMode().equals(GameMode.CREATIVE)) return; + if (isTeammate(attacker, defender)) return; defender.setFireTicks(_fireDuration); } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java index ce21cacfd..0e8b8a8ac 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/FrostedAttribute.java @@ -54,6 +54,7 @@ public class FrostedAttribute extends ItemAttribute if (victim != null) { + if (isTeammate(event.GetDamagerPlayer(true), victim)) return; victim.addPotionEffect(generateSlowEffect()); // Slow attacking player } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java index c476fc2b5..0abc5d253 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/HasteAttribute.java @@ -42,6 +42,7 @@ public class HasteAttribute extends AttackAttribute @Override public void triggerAttack(Entity attacker, Entity defender) { + if (isTeammate(attacker, defender)) return; if (attacker instanceof Player) { Player player = (Player) attacker; diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java index 1b532943b..0bdce1eba 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/JaggedAttribute.java @@ -28,6 +28,7 @@ public class JaggedAttribute extends AttackAttribute { @Override public void triggerAttack(Entity attacker, Entity defender) { + if (isTeammate(attacker, defender)) return; defender.setVelocity(new Vector(0, 0, 0)); if (defender instanceof LivingEntity) ((LivingEntity) defender).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20, 1, false, false)); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java index 3589216a8..ea4279dab 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/attributes/weapon/VampiricAttribute.java @@ -37,6 +37,8 @@ public class VampiricAttribute extends ItemAttribute public void onAttack(CustomDamageEvent event) { Player damager = event.GetDamagerPlayer(false); + + if (isTeammate(damager, event.GetDamageePlayer())) return; double damage = event.GetDamage(); double healAmount = damage * (_healPercent / 100d); From 2991bec44de29e867a001a0e33821f00909afed7 Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 24 May 2016 16:04:15 -0400 Subject: [PATCH 31/33] Fix listener priorities (again). Fixes PC-370 --- .../src/mineplex/game/clans/clans/murder/MurderManager.java | 2 +- .../src/mineplex/game/clans/clans/observer/ObserverManager.java | 2 +- .../src/mineplex/game/clans/economy/GoldManager.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/murder/MurderManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/murder/MurderManager.java index 2f5fcaf30..8f10f9f0b 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/murder/MurderManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/murder/MurderManager.java @@ -73,7 +73,7 @@ public class MurderManager extends MiniClientPlugin } } - @EventHandler + @EventHandler (ignoreCancelled = true) public void onPickup(PlayerPickupItemEvent event) { refreshClient(event.getPlayer()); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/observer/ObserverManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/observer/ObserverManager.java index b5e97bdbc..606c1ec68 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/observer/ObserverManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/observer/ObserverManager.java @@ -131,7 +131,7 @@ public class ObserverManager extends MiniPlugin } } - @EventHandler + @EventHandler (priority = EventPriority.LOWEST) public void onPickup(PlayerPickupItemEvent event) { ObserverData data = _observerMap.get(event.getPlayer()); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/economy/GoldManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/economy/GoldManager.java index ab3a0b03c..a86f41fd2 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/economy/GoldManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/economy/GoldManager.java @@ -113,7 +113,7 @@ public class GoldManager extends MiniPlugin } } - @EventHandler + @EventHandler (ignoreCancelled = true) public void onPickup(PlayerPickupItemEvent event) { if (_itemSet.contains(event.getItem())) From 9da9dce3980bad0f8b22d8abd74c6223539045ac Mon Sep 17 00:00:00 2001 From: samczsun Date: Tue, 24 May 2016 16:40:25 -0400 Subject: [PATCH 32/33] Fix mimic, allow chests and invite. Fixes PC-375 --- .../src/mineplex/game/clans/clans/ClansAdmin.java | 6 ------ .../src/mineplex/game/clans/clans/ClansGame.java | 5 ++++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java index c4ffef408..4f0017ea9 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java @@ -378,12 +378,6 @@ public class ClansAdmin if (target == null) return; - if (target.getName().equals(caller.getName())) - { - UtilPlayer.message(caller, F.main("Clans Admin", "You cannot invite yourself.")); - return; - } - //Inform clan.inform(caller.getName() + " invited " + target.getName() + " to join Clan " + clan.getName() + ".", caller.getName()); UtilPlayer.message(caller, F.main("Clans Admin", "You invited " + target.getName() + " to join " + F.elem("Clan " + clan.getName()) + ".")); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java index 6f47a5525..8247f16c0 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansGame.java @@ -327,13 +327,16 @@ public class ClansGame extends MiniPlugin ClanRelation access = _clans.getClanUtility().getAccess(player, loc); ClanInfo clan = _clans.getClan(player); + ClanInfo mimicClan = _clans.getClanAdmin().getMimic(player, false); ClanInfo blockClan = _clans.getClanUtility().getClaim(loc) == null ? null : _clans.getClan(_clans.getClanUtility().getClaim(loc).Owner); + if (blockClan.equals(mimicClan)) access = ClanRelation.SELF; // Doors, chests, & furnaces - if (blockClan != null && !blockClan.equals(clan) && (event.getAction() == Action.RIGHT_CLICK_BLOCK && (loc.getBlock().getType().name().contains("DOOR") || UtilItem.doesHaveGUI(loc.getBlock().getType())))) + if (blockClan != null && (!blockClan.equals(clan) && !blockClan.equals(mimicClan)) && (event.getAction() == Action.RIGHT_CLICK_BLOCK && (loc.getBlock().getType().name().contains("DOOR") || UtilItem.doesHaveGUI(loc.getBlock().getType())))) { UtilPlayer.message(player, F.main("Clans", "You are not allowed to use that here.")); event.setCancelled(true); + return; } // Hoe Return From 857cf6ad30912eb1f9b7cd4f49a07b6c92f43d97 Mon Sep 17 00:00:00 2001 From: cnr Date: Tue, 24 May 2016 19:18:40 -0500 Subject: [PATCH 33/33] Add PlayerKeyValueRepository and BukkitFuture PlayerKeyValueRepository is a key/value store whose keys are Strings and whose value type is parameterized by V. Each repository is backed by a MySQL table in the Accounts database. Access to PlayerKeyValueRepository's values is restricted via CompletableFuture to enforce async database access. BukkitFuture contains helpful utilities for producing, transforming, and terminating CompletableFutures with actions on the main thread. A typical PlayerKeyValueRepository action may look similar to the following, where we retrieve all key/value pairs for a player and perform an action with the result on the main thread: PlayerKeyValueRepository repo = [...]; // init repo UUID uuid = [...]; // a player's UUID repo.getAll(uuid).thenCompose(BukkitFuture.accept(values -> { // this will be run on the main thread! // `values` is of type `Map` })); --- .../core/common/util/BukkitFuture.java | 111 +++++++ .../database/PlayerKeyValueRepository.java | 291 ++++++++++++++++++ 2 files changed, 402 insertions(+) create mode 100644 Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/BukkitFuture.java create mode 100644 Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/BukkitFuture.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/BukkitFuture.java new file mode 100644 index 000000000..e63644ac2 --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/BukkitFuture.java @@ -0,0 +1,111 @@ +package mineplex.core.common.util; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Utilities for interleaving Bukkit scheduler operations as + * intermediate and terminal operations in a {@link CompletionStage} + * pipeline. + *

+ * Any {@link Function}s returned by methods are suitable for use + * in {@link CompletionStage#thenCompose(Function)} + * + * @see CompletableFuture#thenCompose(Function) + */ +public class BukkitFuture +{ + private static final Plugin LOADING_PLUGIN = JavaPlugin.getProvidingPlugin(BukkitFuture.class); + + private static void runBlocking(Runnable action) + { + Bukkit.getScheduler().runTask(LOADING_PLUGIN, action); + } + + /** + * Finalize a {@link CompletionStage} by consuming its value + * on the main thread. + * + * @param action the {@link Consumer} to call on the main thread + * @return a {@link Function} to be passed as an argument to + * {@link CompletionStage#thenCompose(Function)} + * @see CompletableFuture#thenCompose(Function) + */ + public static Function> accept(Consumer action) + { + return val -> + { + CompletableFuture future = new CompletableFuture<>(); + runBlocking(() -> + { + action.accept(val); + future.complete(null); + }); + return future; + }; + } + + /** + * Finalize a {@link CompletionStage} by executing code on the + * main thread after its completion. + * + * @param action the {@link Runnable} that will execute + * @return a {@link Function} to be passed as an argument to + * {@link CompletionStage#thenCompose(Function)} + * @see CompletableFuture#thenCompose(Function) + */ + public static Function> run(Runnable action) + { + return val -> + { + CompletableFuture future = new CompletableFuture<>(); + runBlocking(() -> + { + action.run(); + future.complete(null); + }); + return future; + }; + } + + /** + * Transform a value contained within a {@link CompletionStage} + * by executing a mapping {@link Function} on the main thread. + * + * @param fn the {@link Function} used to transform the value + * @return a {@link Function} to be passed as an argument to + * {@link CompletionStage#thenCompose(Function)} + * @see CompletableFuture#thenCompose(Function) + */ + public static Function> map(Function fn) + { + return val -> + { + CompletableFuture future = new CompletableFuture<>(); + runBlocking(() -> future.complete(fn.apply(val))); + return future; + }; + } + + /** + * Create a {@link CompletionStage} from a supplier executed on the + * main thread. + * + * @param supplier the supplier to run on the main thread + * @return a {@link CompletionStage} whose value will be supplied + * during the next Minecraft tick + */ + public static CompletionStage supply(Supplier supplier) + { + CompletableFuture future = new CompletableFuture<>(); + runBlocking(() -> future.complete(supplier.get())); + return future; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java new file mode 100644 index 000000000..e0148bd0a --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java @@ -0,0 +1,291 @@ +package mineplex.core.database; + +import com.google.common.collect.ImmutableMap; +import mineplex.serverdata.database.DBPool; + +import java.sql.*; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +/** + * A SQL-backed repository supporting {@link String} keys and + * values of type {@link V} + *

+ * Each java primitive (sans char) and String are supported by default. + * Serializing functions for any additional types can be supplied + * to {@link PlayerKeyValueRepository(String, Serializer, Deserializer)}. + * For example, if {@link String} was not supported, one could use: + *

+ * {@code new PlayerKeyValueRepository("tableName", PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)")} + *

+ * NOTE: EACH CONSTRUCTOR IS BLOCKING, and initializes a backing table + * if one does not yet exist + * + * @param The value type to use for this repository + */ +public class PlayerKeyValueRepository +{ + private static final ImmutableMap, ValueMapper> PRIM_MAPPERS = ImmutableMap., ValueMapper>builder() + .put(String.class, new ValueMapper<>(PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)")) + .put(Boolean.class, new ValueMapper<>(PreparedStatement::setBoolean, ResultSet::getBoolean, "BOOL")) + .put(Byte.class, new ValueMapper<>(PreparedStatement::setByte, ResultSet::getByte, "TINYINT")) + .put(Short.class, new ValueMapper<>(PreparedStatement::setShort, ResultSet::getShort, "SMALLINT")) + .put(Integer.class, new ValueMapper<>(PreparedStatement::setInt, ResultSet::getInt, "INTEGER")) + .put(Long.class, new ValueMapper<>(PreparedStatement::setLong, ResultSet::getLong, "BIGINT")) + .put(Float.class, new ValueMapper<>(PreparedStatement::setFloat, ResultSet::getFloat, "REAL")) + .put(Double.class, new ValueMapper<>(PreparedStatement::setDouble, ResultSet::getDouble, "DOUBLE")) + .build(); + private final String _tableName; + private final ValueMapper _mapper; + + /** + * Build a PlayerKeyValueRepository with the given class' + * built-in deserializer. + * + * @param tableName the underlying table's name + * @param clazz the type of values to used + * @throws IllegalArgumentException if the provided class isn't a supported type + */ + @SuppressWarnings("unchecked") // java's generics are garbage. + public PlayerKeyValueRepository(String tableName, Class clazz) // we could infer the type parameter at runtime, but it's super ugly + { + this(tableName, (ValueMapper) PRIM_MAPPERS.get(clazz)); + } + + /** + * Build a PlayerKeyValueRepository with an explicit deserializer. + * This is the constructor to use if the type you're deserializing + * isn't supported by default. + * + * @param tableName the underlying table's name + * @param serializer the serializing function used to insert values + * @param deserializer the deserializing function used to retrieve + * values + * @param columnDef the value type's SQL datatype declaration, e.g., {@code "VARCHAR(255)"} for Strings. + */ + public PlayerKeyValueRepository(String tableName, Serializer serializer, Deserializer deserializer, String columnDef) + { + this(tableName, new ValueMapper(serializer, deserializer, columnDef)); + } + + private PlayerKeyValueRepository(String tableName, ValueMapper mapper) + { + this._tableName = tableName; + this._mapper = mapper; + + // Create a table to back this repository + try (Connection conn = DBPool.getAccount().getConnection()) + { + Statement stmt = conn.createStatement(); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS " + _tableName + "(" + + "accountId INT NOT NULL," + + "kvKey VARCHAR(255) NOT NULL," + + "kvValue " + _mapper._columnDef + "," + + "PRIMARY KEY (accountId,kvKey)," + + "INDEX acc_ind (accountId)," + + "FOREIGN KEY (accountId) REFERENCES accounts(id) ON DELETE NO ACTION ON UPDATE NO ACTION" + + ")"); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } + + /** + * Get all value for a player's key + * + * @param uuid the {@link UUID} of the player + * @return a CompletableFuture containing all key/value pairs + * associated with the player + */ + public CompletableFuture get(UUID uuid, String key) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection conn = DBPool.getAccount().getConnection()) + { + PreparedStatement stmt = conn.prepareStatement("SELECT kvValue FROM " + _tableName + " WHERE accountId = (SELECT id FROM accounts WHERE uuid=?) AND kvKey=?"); + stmt.setString(1, uuid.toString()); + stmt.setString(2, key); + + ResultSet set = stmt.executeQuery(); + if (set.next()) + { + return _mapper._deserializer.read(set, 1); + } + return null; + } catch (SQLException ignored) {} + + return null; // yuck + }); + } + + /** + * Get all key/value pairs for a player + * + * @param uuid the {@link UUID} of the player + * @return a CompletableFuture containing all key/value pairs + * associated with the player + */ + public CompletableFuture> getAll(UUID uuid) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection conn = DBPool.getAccount().getConnection()) + { + PreparedStatement stmt = conn.prepareStatement("SELECT kvKey, kvValue FROM " + _tableName + " WHERE accountId = (SELECT id FROM accounts WHERE uuid=?)"); + stmt.setString(1, uuid.toString()); + + ResultSet set = stmt.executeQuery(); + Map results = new HashMap<>(); + while (set.next()) + { + results.put(set.getString(1), _mapper._deserializer.read(set, 2)); + } + return results; + } catch (SQLException ignored) {} + + return new HashMap<>(); // yuck + }); + } + + /** + * Insert a key/value pair for a player + * + * @param uuid the {@link UUID} of the player + * @param key the key to insert + * @param value the value to insert + * @return a {@link CompletableFuture} whose value indicates + * success or failure + */ + public CompletableFuture put(UUID uuid, String key, V value) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection conn = DBPool.getAccount().getConnection()) + { + PreparedStatement stmt = conn.prepareStatement("REPLACE INTO " + _tableName + " (accountId, kvKey, kvValue) SELECT accounts.id, ?, ? FROM accounts WHERE uuid=?"); + stmt.setString(1, key); + _mapper._serializer.write(stmt, 2, value); + stmt.setString(3, uuid.toString()); + stmt.executeUpdate(); + return true; + + } catch (SQLException ignored) {} + + return false; + }); + } + + /** + * Insert many key/value pairs for a player + * + * @param uuid the {@link UUID} of the player + * @param values the map whose entries will be inserted for the + * player + * @return a {@link CompletableFuture} whose value indicates + * success or failure + */ + public CompletableFuture putAll(UUID uuid, Map values) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection conn = DBPool.getAccount().getConnection()) + { + PreparedStatement stmt = conn.prepareStatement("REPLACE INTO " + _tableName + " (accountId, kvKey, kvValue) SELECT accounts.id, ?, ? FROM accounts WHERE uuid=?"); + stmt.setString(3, uuid.toString()); + + for (Map.Entry entry : values.entrySet()) + { + stmt.setString(1, entry.getKey()); + _mapper._serializer.write(stmt, 2, entry.getValue()); + stmt.addBatch(); + } + stmt.executeBatch(); + return true; + + } catch (SQLException ignored) {} + + return false; + }); + } + + /** + * Remove a key's value for a player + * + * @param uuid the {@link UUID} of the player + * @param key the key to remove + * @return a {@link CompletableFuture} whose value indicates + * success or failure + */ + public CompletableFuture remove(UUID uuid, String key) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection conn = DBPool.getAccount().getConnection()) + { + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + _tableName + " WHERE accountId=(SELECT id FROM accounts WHERE uuid=?) AND kvKey=?"); + stmt.setString(1, uuid.toString()); + stmt.setString(2, key); + stmt.executeUpdate(); + return true; + + } catch (SQLException ignored) {} + + return false; + }); + } + + /** + * Remove all key/value pairs for a player + * + * @param uuid the {@link UUID} of the player + * @return a {@link CompletableFuture} whose value indicates + * success or failure + */ + public CompletableFuture removeAll(UUID uuid) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection conn = DBPool.getAccount().getConnection()) + { + PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + _tableName + " WHERE accountId=(SELECT id FROM accounts WHERE uuid=?)"); + stmt.setString(1, uuid.toString()); + stmt.executeUpdate(); + return true; + + } catch (SQLException ignored) {} + + return false; + }); + } + + private static class ValueMapper + { + private final Serializer _serializer; + private final Deserializer _deserializer; + private final String _columnDef; + + private ValueMapper(Serializer serializer, Deserializer deserializer, String columnDef) + { + _serializer = serializer; + _deserializer = deserializer; + _columnDef = columnDef; + } + } + + @FunctionalInterface + public interface Serializer + { + void write(PreparedStatement statement, int index, V value) throws SQLException; + } + + @FunctionalInterface + public interface Deserializer + { + V read(ResultSet resultSet, int index) throws SQLException; + } +}