146 lines
6.4 KiB
Java
146 lines
6.4 KiB
Java
package org.embeddedt.modernfix;
|
|
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|
import net.minecraft.server.level.ChunkHolder;
|
|
import net.minecraft.server.level.ChunkMap;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.eventbus.api.EventPriority;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.*;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
|
import net.minecraftforge.fml.config.ModConfig;
|
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
|
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
|
|
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
|
|
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
|
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
|
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
|
import net.minecraftforge.fml.loading.FMLLoader;
|
|
import net.minecraftforge.fml.network.FMLNetworkConstants;
|
|
import org.apache.commons.lang3.tuple.Pair;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.embeddedt.modernfix.classloading.ModFileScanDataDeduplicator;
|
|
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
|
import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler;
|
|
import org.embeddedt.modernfix.packet.PacketHandler;
|
|
import org.embeddedt.modernfix.registry.ObjectHolderClearer;
|
|
import org.embeddedt.modernfix.structure.AsyncLocator;
|
|
import org.embeddedt.modernfix.util.ClassInfoManager;
|
|
import org.embeddedt.modernfix.util.KubeUtil;
|
|
|
|
import java.lang.management.ManagementFactory;
|
|
import java.lang.reflect.Field;
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.Semaphore;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.function.BooleanSupplier;
|
|
|
|
// The value here should match an entry in the META-INF/mods.toml file
|
|
@Mod(ModernFix.MODID)
|
|
public class ModernFix {
|
|
|
|
// Directly reference a log4j logger.
|
|
public static final Logger LOGGER = LogManager.getLogger("ModernFix");
|
|
|
|
public static final String MODID = "modernfix";
|
|
|
|
public static ModernFix INSTANCE;
|
|
|
|
// Used to skip computing the blockstate caches twice
|
|
public static boolean runningFirstInjection = false;
|
|
|
|
public static CountDownLatch worldLoadSemaphore = null;
|
|
|
|
/**
|
|
* Simple mechanism used to delay some background processes until the client is actually in-game, to reduce
|
|
* launch time.
|
|
*/
|
|
public static void waitForWorldLoad(BooleanSupplier exitEarly) {
|
|
CountDownLatch latch = worldLoadSemaphore;
|
|
if(latch != null) {
|
|
try {
|
|
while(!latch.await(100, TimeUnit.MILLISECONDS)) {
|
|
if(exitEarly.getAsBoolean())
|
|
return;
|
|
}
|
|
} catch(InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public ModernFix() {
|
|
INSTANCE = this;
|
|
// Register ourselves for server and other game events we are interested in
|
|
MinecraftForge.EVENT_BUS.register(this);
|
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup);
|
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onLoadComplete);
|
|
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient()));
|
|
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
|
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
|
|
if(ModList.get().isLoaded("kubejs"))
|
|
MinecraftForge.EVENT_BUS.register(KubeUtil.class);
|
|
MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class);
|
|
PacketHandler.register();
|
|
ModFileScanDataDeduplicator.deduplicate();
|
|
}
|
|
|
|
private static boolean dfuModPresent() {
|
|
for(String modId : new String[] { "lazydfu", "datafixerslayer" }) {
|
|
if(ModList.get().isLoaded(modId))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void commonSetup(FMLCommonSetupEvent event) {
|
|
if(!dfuModPresent()) {
|
|
event.enqueueWork(() -> {
|
|
ModLoader.get().addWarning(new ModLoadingWarning(ModLoadingContext.get().getActiveContainer().getModInfo(), ModLoadingStage.COMMON_SETUP, "modernfix.no_lazydfu"));
|
|
});
|
|
}
|
|
ObjectHolderClearer.clearThrowables();
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onServerStarted(FMLServerStartedEvent event) {
|
|
if(FMLLoader.getDist() == Dist.DEDICATED_SERVER) {
|
|
float gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
|
ModernFix.LOGGER.warn("Dedicated server took " + gameStartTime + " seconds to load");
|
|
}
|
|
ClassInfoManager.clear();
|
|
}
|
|
|
|
@SubscribeEvent(priority = EventPriority.LOWEST)
|
|
public void onLoadComplete(FMLLoadCompleteEvent event) {
|
|
ClassInfoManager.clear();
|
|
}
|
|
|
|
@SubscribeEvent(priority = EventPriority.LOWEST)
|
|
public void onServerDead(FMLServerStoppedEvent event) {
|
|
/* Clear as much data from the integrated server as possible, in case a mod holds on to it */
|
|
try {
|
|
Field updatingMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "updatingChunkMap");
|
|
Field visibleMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "visibleChunkMap");
|
|
Field pendingUnloadsField = ObfuscationReflectionHelper.findField(ChunkMap.class, "pendingUnloads");
|
|
for(ServerLevel level : event.getServer().getAllLevels()) {
|
|
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
|
Long2ObjectMap<ChunkHolder> map = (Long2ObjectMap<ChunkHolder>)updatingMapField.get(chunkMap);
|
|
map.clear();
|
|
map = (Long2ObjectMap<ChunkHolder>)visibleMapField.get(chunkMap);
|
|
map.clear();
|
|
map = (Long2ObjectMap<ChunkHolder>)pendingUnloadsField.get(chunkMap);
|
|
map.clear();
|
|
}
|
|
} catch(RuntimeException | IllegalAccessException e) {
|
|
ModernFix.LOGGER.error("Couldn't clear chunk data", e);
|
|
}
|
|
}
|
|
}
|