|  |  | @ -2,8 +2,10 @@ package cx.sfy.LagAssist.stacker; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | import java.util.ArrayList; | 
			
		
	
		
			
				
					|  |  |  | import java.util.HashMap; | 
			
		
	
		
			
				
					|  |  |  | import java.util.HashSet; | 
			
		
	
		
			
				
					|  |  |  | import java.util.List; | 
			
		
	
		
			
				
					|  |  |  | import java.util.Map; | 
			
		
	
		
			
				
					|  |  |  | import java.util.Set; | 
			
		
	
		
			
				
					|  |  |  | import java.util.regex.Matcher; | 
			
		
	
		
			
				
					|  |  |  | import java.util.regex.Pattern; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -17,6 +19,7 @@ import org.bukkit.entity.EntityType; | 
			
		
	
		
			
				
					|  |  |  | import org.bukkit.entity.LivingEntity; | 
			
		
	
		
			
				
					|  |  |  | import org.bukkit.event.entity.EntityDeathEvent; | 
			
		
	
		
			
				
					|  |  |  | import org.bukkit.inventory.ItemStack; | 
			
		
	
		
			
				
					|  |  |  | import org.bukkit.metadata.FixedMetadataValue; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | import cx.sfy.LagAssist.Main; | 
			
		
	
		
			
				
					|  |  |  | import cx.sfy.LagAssist.utils.MathUtils; | 
			
		
	
	
		
			
				
					|  |  | @ -31,22 +34,22 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 	public static String regexpat = ""; | 
			
		
	
		
			
				
					|  |  |  | 	private static int splits = 8; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	private Map<EntityType, ArrayList<Entity>>[] ents; | 
			
		
	
		
			
				
					|  |  |  | 	 | 
			
		
	
		
			
				
					|  |  |  | 	private Map<EntityType, HashSet<Entity>>[] ents; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	public static void Enabler() { | 
			
		
	
		
			
				
					|  |  |  | 		splits = Main.config.getInt("smart-stacker.technical.splits"); | 
			
		
	
		
			
				
					|  |  |  | 		nameformat = ChatColor.translateAlternateColorCodes('&', | 
			
		
	
		
			
				
					|  |  |  | 				Main.config.getString("smart-stacker.gameplay.tag-format")); | 
			
		
	
		
			
				
					|  |  |  | 		regexpat = nameformat.replace("{size}", "(.*.)"); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 	 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	@SuppressWarnings("unchecked") | 
			
		
	
		
			
				
					|  |  |  | 	public StackChunk(Chunk chk) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		ents = (Map<EntityType, ArrayList<Entity>>[]) new HashMap[256 / splits]; | 
			
		
	
		
			
				
					|  |  |  | 		ents = (Map<EntityType, HashSet<Entity>>[]) new HashMap[256 / splits]; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		for (int i = 0; i < 256 / splits; i++) { | 
			
		
	
		
			
				
					|  |  |  | 			ents[i] = new HashMap<EntityType, ArrayList<Entity>>(); | 
			
		
	
		
			
				
					|  |  |  | 			ents[i] = new HashMap<EntityType, HashSet<Entity>>(); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -54,7 +57,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 	// kept alive.
 | 
			
		
	
		
			
				
					|  |  |  | 	public static boolean tryStacking(Location loc, EntityType type, Entity optional) { | 
			
		
	
		
			
				
					|  |  |  | 		Chunk chk = loc.getChunk(); | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		StackChunk stchk; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (chunks.containsKey(chk)) { | 
			
		
	
	
		
			
				
					|  |  | @ -82,7 +85,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 		Entity free = getMatch(stchk.ents[split], loc, type, optional); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		size += getStack(free); | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		Main.sendDebug("FINAL SIZE: " + size, 2); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		consumed = (free.equals(optional)) ? false : true; | 
			
		
	
	
		
			
				
					|  |  | @ -116,47 +119,55 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 		return consumed; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	private static Entity getMatch(Map<EntityType, ArrayList<Entity>> ents, Location loc, EntityType type, | 
			
		
	
		
			
				
					|  |  |  | 	private static Entity getMatch(Map<EntityType, HashSet<Entity>> ents, Location loc, EntityType type, | 
			
		
	
		
			
				
					|  |  |  | 			Entity optional) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (!ents.containsKey(type)) { | 
			
		
	
		
			
				
					|  |  |  | 			ents.put(type, new ArrayList<Entity>()); | 
			
		
	
		
			
				
					|  |  |  | 			ents.put(type, new HashSet<Entity>()); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		List<Entity> list = ents.get(type); | 
			
		
	
		
			
				
					|  |  |  | 		Set<Entity> list = ents.get(type); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		Entity ideal = null; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (optional == null) { | 
			
		
	
		
			
				
					|  |  |  | 			if (list.isEmpty()) { | 
			
		
	
		
			
				
					|  |  |  | 			if (list.isEmpty() || isUnderMinimum(list)) { | 
			
		
	
		
			
				
					|  |  |  | 				ideal = loc.getWorld().spawnEntity(loc, type); | 
			
		
	
		
			
				
					|  |  |  | 				list.add(ideal); | 
			
		
	
		
			
				
					|  |  |  | 				return ideal; | 
			
		
	
		
			
				
					|  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  | 				return list.get(0); | 
			
		
	
		
			
				
					|  |  |  | 				return list.iterator().next(); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} else if (isUnderMinimum(list)) { | 
			
		
	
		
			
				
					|  |  |  | 			list.add(optional); | 
			
		
	
		
			
				
					|  |  |  | 			return optional; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 		for (Entity ent : list) { | 
			
		
	
		
			
				
					|  |  |  | 			boolean similar = StackComparer.isSimilar(ent, optional); | 
			
		
	
		
			
				
					|  |  |  | 			if (similar) { | 
			
		
	
		
			
				
					|  |  |  | 				return ent; | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 		list.add(optional); | 
			
		
	
		
			
				
					|  |  |  | 		return optional; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	public static int getStack(Entity ent) { | 
			
		
	
		
			
				
					|  |  |  | 		if (!StackManager.smartstacker) { | 
			
		
	
		
			
				
					|  |  |  | 			return 0; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (ent == null) { | 
			
		
	
		
			
				
					|  |  |  | 			return 0; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (ent.hasMetadata("lagassist.stacksize")) { | 
			
		
	
		
			
				
					|  |  |  | 			return ent.getMetadata("lagassist.stacksize").get(0).asInt(); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		String name = ent.getCustomName(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (name == null) { | 
			
		
	
	
		
			
				
					|  |  | @ -165,7 +176,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		Pattern pat = Pattern.compile(regexpat.replace("{type}", Others.firstHighcase(ent.getType().toString())), | 
			
		
	
		
			
				
					|  |  |  | 				Pattern.MULTILINE); | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		Matcher match = pat.matcher(name); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (!match.find()) { | 
			
		
	
	
		
			
				
					|  |  | @ -185,6 +196,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 		String formatted = nameformat.replace("{type}", Others.firstHighcase(ent.getType().toString())) | 
			
		
	
		
			
				
					|  |  |  | 				.replace("{size}", "" + Math.min(size, Main.config.getInt("smart-stacker.technical.max-stack"))); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		ent.setMetadata("lagassist.stacksize", new FixedMetadataValue(Main.p, size)); | 
			
		
	
		
			
				
					|  |  |  | 		ent.setCustomName(formatted); | 
			
		
	
		
			
				
					|  |  |  | 		ent.setCustomNameVisible(Main.config.getBoolean("smart-stacker.gameplay.tag-visibility")); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
	
		
			
				
					|  |  | @ -201,7 +213,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 		if (stack < 2) { | 
			
		
	
		
			
				
					|  |  |  | 			return; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		List<ItemStack> drops = new ArrayList<ItemStack>(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		for (ItemStack itm : e.getDrops()) { | 
			
		
	
	
		
			
				
					|  |  | @ -216,7 +228,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		e.getDrops().clear(); | 
			
		
	
		
			
				
					|  |  |  | 		e.getDrops().addAll(drops); | 
			
		
	
		
			
				
					|  |  |  | 		e.setDroppedExp(e.getDroppedExp()*stack); | 
			
		
	
		
			
				
					|  |  |  | 		e.setDroppedExp(e.getDroppedExp() * stack); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	public static void runShutdown() { | 
			
		
	
	
		
			
				
					|  |  | @ -225,7 +237,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		for (StackChunk chk : chunks.values()) { | 
			
		
	
		
			
				
					|  |  |  | 			for (int i = 0; i < splits; i++) { | 
			
		
	
		
			
				
					|  |  |  | 				for (List<Entity> elist : chk.ents[i].values()) { | 
			
		
	
		
			
				
					|  |  |  | 				for (Set<Entity> elist : chk.ents[i].values()) { | 
			
		
	
		
			
				
					|  |  |  | 					for (Entity ent : elist) { | 
			
		
	
		
			
				
					|  |  |  | 						ent.remove(); | 
			
		
	
		
			
				
					|  |  |  | 					} | 
			
		
	
	
		
			
				
					|  |  | @ -262,25 +274,50 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 	 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	public static void unloadChunk(Chunk chk) { | 
			
		
	
		
			
				
					|  |  |  | 		StackChunk stack = chunks.get(chk); | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (stack == null) { | 
			
		
	
		
			
				
					|  |  |  | 			return; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 		for (Map<EntityType, ArrayList<Entity>> m : stack.ents) { | 
			
		
	
		
			
				
					|  |  |  | 			for (ArrayList<Entity> types : m.values()) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		for (Map<EntityType, HashSet<Entity>> m : stack.ents) { | 
			
		
	
		
			
				
					|  |  |  | 			for (HashSet<Entity> types : m.values()) { | 
			
		
	
		
			
				
					|  |  |  | 				for (Entity ent : types) { | 
			
		
	
		
			
				
					|  |  |  | 					ent.remove(); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		chunks.remove(chk); | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 		 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/* | 
			
		
	
		
			
				
					|  |  |  | 	 * Implement min stack feature in beta. | 
			
		
	
		
			
				
					|  |  |  | 	 * | 
			
		
	
		
			
				
					|  |  |  | 	 * TODO: TEST FUNCTIONALITY | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	protected static boolean isUnderMinimum(Set<Entity> ents) { | 
			
		
	
		
			
				
					|  |  |  | 		int minstack = Main.config.getInt("smart-stacker.technical.min-stack"); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (minstack <= 1) { | 
			
		
	
		
			
				
					|  |  |  | 			return false; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		int stacktotal = getStackTotal(ents); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		return minstack > 0 && stacktotal < minstack; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	private static int getStackTotal(Set<Entity> ents) { | 
			
		
	
		
			
				
					|  |  |  | 		int total = 0; | 
			
		
	
		
			
				
					|  |  |  | 		for (Entity ent : ents) { | 
			
		
	
		
			
				
					|  |  |  | 			total += getStack(ent); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		return total; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	// Setting clean to true makes it force it;
 | 
			
		
	
	
		
			
				
					|  |  | @ -291,7 +328,7 @@ public class StackChunk { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		StackChunk stchk = chunks.get(chk); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (!stchk.ents[split].containsKey(ent)) { | 
			
		
	
		
			
				
					|  |  |  | 		if (!stchk.ents[split].containsKey(ent) || isUnderMinimum(stchk.ents[split].get(ent))) { | 
			
		
	
		
			
				
					|  |  |  | 			return; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | 
 |