diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/animations/AnimationCarl.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/animations/AnimationCarl.java index 6c966aedf..5e2fb892a 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/animations/AnimationCarl.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/animations/AnimationCarl.java @@ -158,6 +158,7 @@ public class AnimationCarl extends Animation @Override protected void onFinish() { _isDone = true; + _player = null; setTicks(0); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/memory/MemoryFix.java b/Plugins/Mineplex.Core/src/mineplex/core/memory/MemoryFix.java index 90eab086c..5ac6c423f 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/memory/MemoryFix.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/memory/MemoryFix.java @@ -10,10 +10,13 @@ import mineplex.core.MiniPlugin; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import net.minecraft.server.v1_8_R3.CraftingManager; -import net.minecraft.server.v1_8_R3.Enchantment; import net.minecraft.server.v1_8_R3.EnchantmentManager; +import net.minecraft.server.v1_8_R3.EntityInsentient; import net.minecraft.server.v1_8_R3.IInventory; +import net.minecraft.server.v1_8_R3.PathfinderGoal; +import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; +import net.minecraft.server.v1_8_R3.PathfinderGoalSelector; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.World; @@ -22,7 +25,6 @@ import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Entity; import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.entity.EntityDamageByBlockEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -52,8 +54,7 @@ public class MemoryFix extends MiniPlugin // Sanity check if (worlds.size() != worldList.size()) throw new RuntimeException("Error: Duplicated worlds?!?!"); - - + for (World world : worlds) { WorldServer worldServer = ((CraftWorld) world).getHandle(); @@ -96,15 +97,139 @@ public class MemoryFix extends MiniPlugin } } + private static Field PATHFINDER_GOAL_SELECTOR_B; + private static boolean PATHFINDER_GOAL_SELECTOR_B_SUCCESSFUL; + + private static Field PATHFINDER_GOAL_SELECTOR_C; + private static boolean PATHFINDER_GOAL_SELECTOR_C_SUCCESSFUL; + + private static Field PATHFINDER_GOAL_SELECTOR_ITEM_A; + private static boolean PATHFINDER_GOAL_SELECTOR_ITEM_A_SUCCESSFUL; + + private static Field PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D; + private static boolean PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D_SUCCESSFUL; + + static + { + try + { + PATHFINDER_GOAL_SELECTOR_ITEM_A = Class.forName(PathfinderGoalSelector.class.getName() + "$PathfinderGoalSelectorItem").getDeclaredField("a"); + PATHFINDER_GOAL_SELECTOR_ITEM_A.setAccessible(true); + PATHFINDER_GOAL_SELECTOR_ITEM_A_SUCCESSFUL = true; + } + catch (ReflectiveOperationException e) + { + e.printStackTrace(); + } + try + { + PATHFINDER_GOAL_SELECTOR_B = PathfinderGoalSelector.class.getDeclaredField("b"); + PATHFINDER_GOAL_SELECTOR_B.setAccessible(true); + PATHFINDER_GOAL_SELECTOR_B_SUCCESSFUL = true; + } + catch (ReflectiveOperationException e) + { + e.printStackTrace(); + } + try + { + PATHFINDER_GOAL_SELECTOR_C = PathfinderGoalSelector.class.getDeclaredField("c"); + PATHFINDER_GOAL_SELECTOR_C.setAccessible(true); + PATHFINDER_GOAL_SELECTOR_C_SUCCESSFUL = true; + } + catch (ReflectiveOperationException e) + { + e.printStackTrace(); + } + try + { + PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D = PathfinderGoalNearestAttackableTarget.class.getDeclaredField("d"); + PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D.setAccessible(true); + PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D_SUCCESSFUL = true; + } + catch (ReflectiveOperationException e) + { + e.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + @EventHandler + public void fixPathfinderGoalLeaks(UpdateEvent event) + { + if (event.getType() != UpdateType.SLOW) + return; + + List worldList = Bukkit.getWorlds(); + Set worlds = new HashSet<>(worldList); + + // Sanity check + if (worlds.size() != worldList.size()) + throw new RuntimeException("Error: Duplicated worlds?!?!"); + + for (World world : worlds) + { + WorldServer worldServer = ((CraftWorld) world).getHandle(); + + for (net.minecraft.server.v1_8_R3.Entity nmsentity : worldServer.entityList) + { + if (nmsentity instanceof EntityInsentient) + { + EntityInsentient ei = (EntityInsentient) nmsentity; + if (PATHFINDER_GOAL_SELECTOR_ITEM_A_SUCCESSFUL) + { + if (PATHFINDER_GOAL_SELECTOR_B_SUCCESSFUL) + { + try + { + PathfinderGoalSelector targetSelector = ei.targetSelector; + List list = (List) PATHFINDER_GOAL_SELECTOR_B.get(targetSelector); + for (Object object : list) + { + try + { + PathfinderGoal goal = (PathfinderGoal) PATHFINDER_GOAL_SELECTOR_ITEM_A.get(object); + if (goal instanceof PathfinderGoalNearestAttackableTarget && PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D_SUCCESSFUL) + { + net.minecraft.server.v1_8_R3.Entity original = (net.minecraft.server.v1_8_R3.Entity) PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D.get(goal); + boolean shouldClear = false; + + if (original != null) + { + if (!original.valid) + shouldClear = true; + } + + if (shouldClear) + PATHFINDER_GOAL_NEAREST_ATTACKABLE_TARGET_D.set(goal, null); + } + } + catch (ReflectiveOperationException ex) + { + ex.printStackTrace(); + } + } + } + catch (ReflectiveOperationException e) + { + e.printStackTrace(); + } + } + } + } + } + } + } + private static Object ENCHANTMENTMANAGER_D; private static Field ENCHANTMENT_MODIFIER_THORNS_A; private static Field ENCHANTMENT_MODIFIER_THORNS_B; - private static boolean ENCHANTMENTMANAGER_D_SUCCESFUL; + private static boolean ENCHANTMENTMANAGER_D_SUCCESSFUL; private static Object ENCHANTMENTMANAGER_E; private static Field ENCHANTMENT_MODIFIER_ARTHROPODS_A; private static Field ENCHANTMENT_MODIFIER_ARTHROPODS_B; - private static boolean ENCHANTMENTMANAGER_E_SUCCESFUL; + private static boolean ENCHANTMENTMANAGER_E_SUCCESSFUL; static { @@ -117,7 +242,7 @@ public class MemoryFix extends MiniPlugin ENCHANTMENT_MODIFIER_THORNS_A.setAccessible(true); ENCHANTMENT_MODIFIER_THORNS_B = ENCHANTMENTMANAGER_D.getClass().getDeclaredField("b"); ENCHANTMENT_MODIFIER_THORNS_B.setAccessible(true); - ENCHANTMENTMANAGER_D_SUCCESFUL = true; + ENCHANTMENTMANAGER_D_SUCCESSFUL = true; } catch (ReflectiveOperationException e) { @@ -132,7 +257,7 @@ public class MemoryFix extends MiniPlugin ENCHANTMENT_MODIFIER_ARTHROPODS_A.setAccessible(true); ENCHANTMENT_MODIFIER_ARTHROPODS_B = ENCHANTMENTMANAGER_E.getClass().getDeclaredField("b"); ENCHANTMENT_MODIFIER_ARTHROPODS_B.setAccessible(true); - ENCHANTMENTMANAGER_E_SUCCESFUL = true; + ENCHANTMENTMANAGER_E_SUCCESSFUL = true; } catch (ReflectiveOperationException e) { @@ -146,7 +271,7 @@ public class MemoryFix extends MiniPlugin if (event.getType() != UpdateType.SLOW) return; - if (ENCHANTMENTMANAGER_D_SUCCESFUL) + if (ENCHANTMENTMANAGER_D_SUCCESSFUL) { try { @@ -165,7 +290,7 @@ public class MemoryFix extends MiniPlugin } } - if (ENCHANTMENTMANAGER_E_SUCCESFUL) + if (ENCHANTMENTMANAGER_E_SUCCESSFUL) { try {