Skip to content

Commit

Permalink
- 添加一系列有关客户端内存泄露的修复。
Browse files Browse the repository at this point in the history
  • Loading branch information
KasumiNova committed Aug 8, 2024
1 parent e30b69f commit d3b73de
Show file tree
Hide file tree
Showing 14 changed files with 381 additions and 6 deletions.
5 changes: 4 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ plugins {

// Project properties
group = "github.kasuminova.stellarcore"
version = "1.1.8"
version = "1.1.11"

// Set the toolchain version to decouple the Java we run Gradle with from the Java used to compile and run the mod
java {
Expand Down Expand Up @@ -274,6 +274,9 @@ dependencies {
compileOnly(rfg.deobf("curse.maven:lazy-ae2-322347:3254160"))
compileOnly(rfg.deobf("curse.maven:electroblobs-wizardry-265642:5354477"))
compileOnly(rfg.deobf("curse.maven:ender-utilities-224320:2977010"))
compileOnly(rfg.deobf("curse.maven:ancient-spellcraft-358124:5413256"))
compileOnly(rfg.deobf("curse.maven:random-psideas-302313:3215550"))
compileOnly(rfg.deobf("curse.maven:journeymap-32274:5172461"))
}

// IDE Settings
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
package github.kasuminova.stellarcore.client.handler;

import blusunrize.immersiveengineering.ImmersiveEngineering;
import com.cleanroommc.neverenoughanimations.NEAConfig;
import com.cleanroommc.neverenoughanimations.animations.HotbarAnimation;
import com.kamefrede.rpsideas.items.components.ItemBioticSensor;
import com.llamalad7.betterchat.gui.GuiBetterChat;
import com.windanesz.ancientspellcraft.client.entity.ASFakePlayer;
import github.kasuminova.stellarcore.StellarCore;
import github.kasuminova.stellarcore.client.hudcaching.HUDCaching;
import github.kasuminova.stellarcore.client.util.TitleUtils;
import github.kasuminova.stellarcore.common.config.StellarCoreConfig;
import journeymap.common.feature.PlayerRadarManager;
import mekanism.client.ClientTickHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Optional;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import vazkii.botania.common.core.handler.ManaNetworkHandler;
import zmaster587.libVulpes.util.InputSyncHandler;

import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

@SuppressWarnings("MethodMayBeStatic")
public class ClientEventHandler {
public static final ClientEventHandler INSTANCE = new ClientEventHandler();

Expand Down Expand Up @@ -47,6 +64,96 @@ public void onClientRenderTick(TickEvent.RenderTickEvent event) {
}
}

/**
* Called by github.kasuminova.stellarcore.mixin.minecraft.world_load.MixinMinecraft<br/>
* 修复各种奇怪的模组导致 WorldClient 无法被 GC 导致内存泄露的问题。
*/
public void onClientWorldLoad(@Nullable final World world) {
if (Loader.isModLoaded("ancientspellcraft")) {
callAncientSpellCraftFakePlayerWorldChanged(world);
}
if (Loader.isModLoaded("libvulpes")) {
callLibVulpesWorldChanged();
}
if (Loader.isModLoaded("mekanism")) {
callMekanismClientTickHandlerWorldChanged();
}
if (Loader.isModLoaded("botania")) {
callBotaniaManaNetworkHandlerWorldChanged();
}
if (Loader.isModLoaded("rpsideas")) {
callRPSIdeasItemBioticSensorWorldChanged();
}
if (Loader.isModLoaded("journeymap")) {
callJourneyMapPlayerRadarManagerWorldChanged();
}
if (Loader.isModLoaded("immersiveengineering")) {
callImmersiveEngineeringWorldChanged();
}
}

@Optional.Method(modid = "immersiveengineering")
private static void callImmersiveEngineeringWorldChanged() {
if (!StellarCoreConfig.BUG_FIXES.immersiveEngineering.renderCache) {
return;
}
ImmersiveEngineering.proxy.clearRenderCaches();
}

@Optional.Method(modid = "journeymap")
private static void callJourneyMapPlayerRadarManagerWorldChanged() {
if (!StellarCoreConfig.BUG_FIXES.journeyMap.playerRadar) {
return;
}
PlayerRadarManager.getInstance().clearNetworkPlayers();
}

@Optional.Method(modid = "rpsideas")
private static void callRPSIdeasItemBioticSensorWorldChanged() {
if (!StellarCoreConfig.BUG_FIXES.rpsIdeas.itemBioticSensor) {
return;
}
try {
Field triggeredBioticsRemote = ItemBioticSensor.class.getDeclaredField("triggeredBioticsRemote");
triggeredBioticsRemote.setAccessible(true);
((Map<EntityPlayer, List<EntityLivingBase>>) triggeredBioticsRemote.get(null)).clear();
} catch (Throwable e) {
StellarCore.log.warn("Failed to clear triggeredBioticsRemote in ItemBioticSensor.", e);
}
}

@Optional.Method(modid = "botania")
private static void callBotaniaManaNetworkHandlerWorldChanged() {
if (!StellarCoreConfig.BUG_FIXES.botania.manaNetworkHandler) {
return;
}
ManaNetworkHandler.instance.clear();
}

@Optional.Method(modid = "mekanism")
private static void callMekanismClientTickHandlerWorldChanged() {
if (!StellarCoreConfig.BUG_FIXES.mekanism.portableTeleports) {
return;
}
ClientTickHandler.portableTeleports.remove(Minecraft.getMinecraft().player);
}

@Optional.Method(modid = "ancientspellcraft")
private static void callAncientSpellCraftFakePlayerWorldChanged(final World world) {
if (!StellarCoreConfig.BUG_FIXES.ancientSpellCraft.asFakePlayer) {
return;
}
ASFakePlayer.FAKE_PLAYER.setWorld(world);
}

@Optional.Method(modid = "libvulpes")
private static void callLibVulpesWorldChanged() {
if (!StellarCoreConfig.BUG_FIXES.libVulpes.inputSyncHandler) {
return;
}
InputSyncHandler.spaceDown.remove(Minecraft.getMinecraft().player);
}

@Optional.Method(modid = "betterchat")
private static void handleBetterChatAnim() {
Minecraft mc = Minecraft.getMinecraft();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.FMLLaunchHandler;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Mod.EventBusSubscriber(modid = StellarCore.MOD_ID)
@Config(modid = StellarCore.MOD_ID, name = StellarCore.MOD_ID)
public class StellarCoreConfig {
Expand Down Expand Up @@ -48,6 +44,12 @@ public static class BugFixes {
@Config.Name("Container")
public final Container container = new Container();

@Config.Name("AdvancedRocketry")
public final AdvancedRocketry advancedRocketry = new AdvancedRocketry();

@Config.Name("AncientSpellCraft")
public final AncientSpellCraft ancientSpellCraft = new AncientSpellCraft();

@Config.Name("ArmourersWorkshop")
public final ArmourersWorkshop armourersWorkshop = new ArmourersWorkshop();

Expand All @@ -57,6 +59,9 @@ public static class BugFixes {
@Config.Name("Avaritaddons")
public final Avaritaddons avaritaddons = new Avaritaddons();

@Config.Name("Botania")
public final Botania botania = new Botania();

@Config.Name("CoFHCore")
public final CoFHCore coFHCore = new CoFHCore();

Expand Down Expand Up @@ -84,6 +89,15 @@ public static class BugFixes {
@Config.Name("ImmersiveEngineering")
public final ImmersiveEngineering immersiveEngineering = new ImmersiveEngineering();

@Config.Name("JourneyMap")
public final JourneyMap journeyMap = new JourneyMap();

@Config.Name("LibVulpes")
public final LibVulpes libVulpes = new LibVulpes();

@Config.Name("Mekanism")
public final Mekanism mekanism = new Mekanism();

@Config.Name("ModularRouters")
public final ModularRouters modularRouters = new ModularRouters();

Expand All @@ -93,6 +107,9 @@ public static class BugFixes {
@Config.Name("MrCrayfishFurniture")
public final MrCrayfishFurniture mrCrayfishFurniture = new MrCrayfishFurniture();

@Config.Name("RPSIdeas")
public final RPSIdeas rpsIdeas = new RPSIdeas();

@Config.Name("ScalingGuis")
public final ScalingGuis scalingGuis = new ScalingGuis();

Expand Down Expand Up @@ -166,6 +183,33 @@ public static class Container {

}

public static class AdvancedRocketry {

@Config.Comment("Fix the NPE problem that occasionally occurs with BiomeChanger.")
@Config.Name("ItemBiomeChanger")
public boolean itemBiomeChanger = true;

@Config.Comment({
"When the planetDefs.xml file is corrupted, make it regenerate the file instead of letting it damn near crash.",
"This is usually only a problem if the game process is unexpectedly exited, and the file is usually unrecoverable without a backup."
})
@Config.Name("PreventDimensionManagerCrash")
public boolean dimensionManager = true;

}

public static class AncientSpellCraft {

@Config.Comment({
"(Client Only) Fix a memory leak caused by AncientSpellCraft's FakePlayer,",
"mainly in that it would cause the first world loaded not to be cleaned up by Java GC.",
"Experimental, if a crash occurs with anything related to ASFakePlayer, please report this issue immediately."
})
@Config.Name("ASFakePlayerFixes")
public boolean asFakePlayer = false;

}

public static class ArmourersWorkshop {

@Config.Comment("Cleanroom only, used to fix an issue that caused the game to crash when unloading skin texture files.")
Expand Down Expand Up @@ -195,6 +239,14 @@ public static class Avaritaddons {

}

public static class Botania {

@Config.Comment("(Client Only) Automatically clean up data when the player switches worlds, optional feature as WeakHashMap does not usually cause memory leaks.")
@Config.Name("AutoCleanManaNetworkHandler")
public boolean manaNetworkHandler = true;

}

public static class CoFHCore {

@Config.Comment("This option is used to fix some item duplication issues with any containers related to TE5.")
Expand Down Expand Up @@ -299,6 +351,43 @@ public static class ImmersiveEngineering {
@Config.Name("TileEntityArcFurnaceInventoryFixes")
public boolean tileEntityArcFurnace = true;

@Config.Comment({
"(Client Only) Clear the model cache when the player switches worlds to avoid memory leaks.",
"Minor performance impact. Mainly a problem when installing with other mods."
})
@Config.Name("AutoCleanRenderCache")
public boolean renderCache = true;

}

public static class JourneyMap {

@Config.Comment("(Client Only) Automatically clears the radar player cache when a player switches worlds to avoid memory leaks caused in the client.")
@Config.Name("AutoCleanPlayerRadar")
public boolean playerRadar = true;

}

public static class LibVulpes {

@Config.Comment({
"(Client Only) Automatically clean up InputSyncHandler's spaceDown data when the player switches worlds.",
"Although libvulpes has already coded this judgment, there is still a small chance that it will trigger a memory leak."
})
@Config.Name("AutoCleanInputSyncHandlerData")
public boolean inputSyncHandler = true;

}

public static class Mekanism {

@Config.Comment({
"(Client Only) Automatically clean up old player data when the player switches worlds to address some memory leaks,",
"and while Mekanism has written cleanup features, they will only clean up when returning to the main menu."
})
@Config.Name("AutoCleanPortableTeleports")
public boolean portableTeleports = true;

}

public static class ModularRouters {
Expand Down Expand Up @@ -334,6 +423,14 @@ public static class MrCrayfishFurniture {

}

public static class RPSIdeas {

@Config.Comment("(Client Only) Fix memory leaks caused by improper object management on the client side.")
@Config.Name("ItemBioticSensorMemoryLeakFixes")
public boolean itemBioticSensor = true;

}

public static class ScalingGuis {

@Config.Comment("Fixes an issue that caused a crash when deleting invalid GUI configurations.")
Expand Down Expand Up @@ -468,7 +565,6 @@ public static class Performance {
@Config.Name("TConstruct")
public final TConstruct tConstruct = new TConstruct();

@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
public static class Vanilla {

@Config.Comment({
Expand Down Expand Up @@ -714,6 +810,10 @@ public static class EnderIO {
@Config.Name("TileEntityBaseImprovements")
public boolean tileEntityBase = true;

@Config.Comment("(Server Performance) Improve the performance of item determination in FarmerStation using caching (mainly related to the canPlant() method).")
@Config.Name("FarmerImprovements")
public boolean commune = true;

}

public static class EnderIOConduits {
Expand Down Expand Up @@ -909,6 +1009,11 @@ public static class Vanilla {
@Config.Name("ShutUpModelLoader")
public boolean shutUpModelLoader = false;

@Config.Comment("(Client Only) Listening to clients loading/unloading new worlds, disabling this option will cause some features on memory leak fixing to fail.")
@Config.RequiresMcRestart
@Config.Name("HandleClientWorldLoad")
public boolean handleClientWorldLoad = true;

}

public static class FontScale {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class StellarCoreEarlyMixinLoader implements IFMLLoadingPlugin {
addMixinCFG("mixins.stellar_core_minecraft_noglerror.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.noGlError);
addMixinCFG("mixins.stellar_core_minecraft_renderglobal.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.alwaysDeferChunkUpdates);
addMixinCFG("mixins.stellar_core_minecraft_world.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.capturedBlockSnapshots);
addMixinCFG("mixins.stellar_core_minecraft_world_load.json", () -> StellarCoreConfig.FEATURES.vanilla.handleClientWorldLoad);
addMixinCFG("mixins.stellar_core_minecraft_statemapperbase.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.stateMapperBase);
addMixinCFG("mixins.stellar_core_minecraft_texturemap.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.parallelTextureMapLoad);
addMixinCFG("mixins.stellar_core_forge.json", () -> StellarCoreConfig.PERFORMANCE.customLoadingScreen.splashProgress);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class StellarCoreLateMixinLoader implements ILateMixinLoader {
static {
addModdedMixinCFG("mixins.stellar_core_advancedrocketry.json", "advancedrocketry");
addModdedMixinCFG("mixins.stellar_core_ae.json", "appliedenergistics2");
addModdedMixinCFG("mixins.stellar_core_ancientspellcraft.json", "ancientspellcraft");
addModdedMixinCFG("mixins.stellar_core_armourers_workshop.json", "armourers_workshop");
addModdedMixinCFG("mixins.stellar_core_astralsorcery.json", "astralsorcery");
addModdedMixinCFG("mixins.stellar_core_avaritia.json", "avaritia");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package github.kasuminova.stellarcore.mixin.advancedrocketry;

import github.kasuminova.stellarcore.StellarCore;
import github.kasuminova.stellarcore.common.config.StellarCoreConfig;
import net.minecraftforge.fml.common.FMLCommonHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import zmaster587.advancedRocketry.dimension.DimensionManager;

@SuppressWarnings("MethodMayBeStatic")
@Mixin(value = DimensionManager.class, remap = false)
public class MixinDimensionManager {

@Redirect(method = "createAndLoadDimensions", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/common/FMLCommonHandler;exitJava(IZ)V"))
private void redirectCreateAndLoadDimensions(final FMLCommonHandler instance, final int i, final boolean exitCode) {
if (!StellarCoreConfig.BUG_FIXES.advancedRocketry.dimensionManager) {
FMLCommonHandler.instance().exitJava(i, exitCode);
return;
}

StellarCore.log.warn("************************************************************************************************************************");
StellarCore.log.warn("* StellarCore has stopped the crash caused by AR's failure to read planetDefs.xml! File generation will now be restarted.");
StellarCore.log.warn("************************************************************************************************************************");
}

}
Loading

0 comments on commit d3b73de

Please sign in to comment.