Fix memory leak in carl, server

This commit is contained in:
samczsun 2016-10-01 21:51:09 -04:00 committed by Shaun Bennett
parent bd9aa38afa
commit 6f80e21372
2 changed files with 136 additions and 10 deletions

View File

@ -158,6 +158,7 @@ public class AnimationCarl extends Animation
@Override
protected void onFinish() {
_isDone = true;
_player = null;
setTicks(0);
}

View File

@ -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<World> worldList = Bukkit.getWorlds();
Set<World> 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<Object> list = (List<Object>) 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
{