Merge remote-tracking branch 'origin/1.18' into 1.19.2
This commit is contained in:
commit
d63b5acd6e
|
|
@ -1,26 +1,37 @@
|
||||||
package org.embeddedt.modernfix;
|
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.api.distmarker.Dist;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||||
|
import net.minecraftforge.event.server.ServerStoppedEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.EventPriority;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.*;
|
import net.minecraftforge.fml.*;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.config.ModConfig;
|
import net.minecraftforge.fml.config.ModConfig;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
|
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
|
||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
import net.minecraftforge.fml.loading.FMLConfig;
|
import net.minecraftforge.fml.loading.FMLConfig;
|
||||||
import net.minecraftforge.fml.loading.FMLLoader;
|
import net.minecraftforge.fml.loading.FMLLoader;
|
||||||
|
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||||
import net.minecraftforge.network.NetworkConstants;
|
import net.minecraftforge.network.NetworkConstants;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.embeddedt.modernfix.classloading.ModFileScanDataDeduplicator;
|
||||||
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
||||||
import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler;
|
import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler;
|
||||||
import org.embeddedt.modernfix.packet.PacketHandler;
|
import org.embeddedt.modernfix.packet.PacketHandler;
|
||||||
import org.embeddedt.modernfix.registry.ObjectHolderClearer;
|
import org.embeddedt.modernfix.registry.ObjectHolderClearer;
|
||||||
|
import org.embeddedt.modernfix.util.ClassInfoManager;
|
||||||
|
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
@ -66,12 +77,14 @@ public class ModernFix {
|
||||||
// Register ourselves for server and other game events we are interested in
|
// Register ourselves for server and other game events we are interested in
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup);
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup);
|
||||||
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onLoadComplete);
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient()));
|
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient()));
|
||||||
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
||||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
|
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class);
|
MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class);
|
||||||
PacketHandler.register();
|
PacketHandler.register();
|
||||||
|
ModFileScanDataDeduplicator.deduplicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean dfuModPresent() {
|
private static boolean dfuModPresent() {
|
||||||
|
|
@ -100,5 +113,32 @@ public class ModernFix {
|
||||||
float gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
float gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
||||||
ModernFix.LOGGER.warn("Dedicated server took " + gameStartTime + " seconds to load");
|
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(ServerStoppedEvent 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, "f_140129_");
|
||||||
|
Field visibleMapField = ObfuscationReflectionHelper.findField(ChunkMap.class, "f_140130_");
|
||||||
|
Field pendingUnloadsField = ObfuscationReflectionHelper.findField(ChunkMap.class, "f_140131_");
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
package org.embeddedt.modernfix.classloading;
|
||||||
|
|
||||||
|
import com.google.common.collect.Interner;
|
||||||
|
import com.google.common.collect.Interners;
|
||||||
|
import net.minecraftforge.fml.ModList;
|
||||||
|
import net.minecraftforge.forgespi.language.ModFileScanData;
|
||||||
|
import net.minecraftforge.forgespi.locating.IModFile;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ModFileScanDataDeduplicator {
|
||||||
|
private final Interner<Type> typeInterner = Interners.newStrongInterner();
|
||||||
|
|
||||||
|
private final Function<Type, Type> internerFn = type -> type != null ? typeInterner.intern(type) : null;
|
||||||
|
|
||||||
|
private static Field classClazzField, parentField, interfacesField, annotationClazzField, annotationTypeField;
|
||||||
|
private static final boolean reflectionSuccessful;
|
||||||
|
|
||||||
|
static {
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
classClazzField = ModFileScanData.ClassData.class.getDeclaredField("clazz");
|
||||||
|
classClazzField.setAccessible(true);
|
||||||
|
parentField = ModFileScanData.ClassData.class.getDeclaredField("parent");
|
||||||
|
parentField.setAccessible(true);
|
||||||
|
interfacesField = ModFileScanData.ClassData.class.getDeclaredField("interfaces");
|
||||||
|
interfacesField.setAccessible(true);
|
||||||
|
annotationClazzField = ModFileScanData.AnnotationData.class.getDeclaredField("clazz");
|
||||||
|
annotationClazzField.setAccessible(true);
|
||||||
|
annotationTypeField = ModFileScanData.AnnotationData.class.getDeclaredField("annotationType");
|
||||||
|
annotationTypeField.setAccessible(true);
|
||||||
|
success = true;
|
||||||
|
} catch(ReflectiveOperationException | RuntimeException e) {
|
||||||
|
}
|
||||||
|
reflectionSuccessful = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModFileScanDataDeduplicator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runDeduplication() {
|
||||||
|
ModList.get().forEachModFile(this::deduplicateFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deduplicateFile(IModFile file) {
|
||||||
|
ModFileScanData data = file.getScanResult();
|
||||||
|
if(data != null) {
|
||||||
|
data.getClasses().forEach(this::deduplicateClass);
|
||||||
|
data.getAnnotations().forEach(this::deduplicateAnnotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deduplicateClass(ModFileScanData.ClassData data) {
|
||||||
|
try {
|
||||||
|
Type type = (Type)classClazzField.get(data);
|
||||||
|
type = internerFn.apply(type);
|
||||||
|
classClazzField.set(data, type);
|
||||||
|
type = (Type)parentField.get(data);
|
||||||
|
type = internerFn.apply(type);
|
||||||
|
parentField.set(data, type);
|
||||||
|
Set<Type> types = (Set<Type>)interfacesField.get(data);
|
||||||
|
types = types.stream().map(internerFn).collect(Collectors.toSet());
|
||||||
|
interfacesField.set(data, types);
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deduplicateAnnotation(ModFileScanData.AnnotationData data) {
|
||||||
|
try {
|
||||||
|
Type type = (Type)annotationClazzField.get(data);
|
||||||
|
type = internerFn.apply(type);
|
||||||
|
annotationClazzField.set(data, type);
|
||||||
|
type = (Type)annotationTypeField.get(data);
|
||||||
|
type = internerFn.apply(type);
|
||||||
|
annotationTypeField.set(data, type);
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deduplicate() {
|
||||||
|
if(!reflectionSuccessful)
|
||||||
|
return;
|
||||||
|
new ModFileScanDataDeduplicator().runDeduplication();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,6 +37,8 @@ public class ModernFixEarlyConfig {
|
||||||
/* Use a simpler ArrayMap if FerriteCore is using the map intelligently anyway */
|
/* Use a simpler ArrayMap if FerriteCore is using the map intelligently anyway */
|
||||||
this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore"));
|
this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore"));
|
||||||
this.addMixinRule("perf.cache_strongholds", true);
|
this.addMixinRule("perf.cache_strongholds", true);
|
||||||
|
this.addMixinRule("perf.dedup_blockstate_flattening_map", false);
|
||||||
|
this.addMixinRule("perf.clear_mixin_classinfo", false);
|
||||||
this.addMixinRule("perf.cache_upgraded_structures", true);
|
this.addMixinRule("perf.cache_upgraded_structures", true);
|
||||||
this.addMixinRule("perf.compress_blockstate", false);
|
this.addMixinRule("perf.compress_blockstate", false);
|
||||||
this.addMixinRule("bugfix.concurrency", true);
|
this.addMixinRule("bugfix.concurrency", true);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.embeddedt.modernfix.dynamicresources;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockFaceUV;
|
||||||
|
|
||||||
|
public class UVController {
|
||||||
|
public static final ThreadLocal<Boolean> useDummyUv = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||||
|
public static final BlockFaceUV dummyUv = new BlockFaceUV(new float[4], 0);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.perf.dedup_blockstate_flattening_map;
|
||||||
|
|
||||||
|
import net.minecraft.util.datafix.fixes.BlockStateData;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(BlockStateData.class)
|
||||||
|
public class BlockStateDataMixin {
|
||||||
|
@Inject(method = {"register", "finalizeMaps"}, at = @At("HEAD"), cancellable = true)
|
||||||
|
private static void noFlattening(CallbackInfo ci) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = {"upgradeBlockStateTag", "upgradeBlock(I)Ljava/lang/String;", "upgradeBlock(Ljava/lang/String;)Ljava/lang/String;", "getTag"}, at = @At("HEAD"), require = 4)
|
||||||
|
private static void preventCorruption(CallbackInfoReturnable<?> cir) {
|
||||||
|
throw new UnsupportedOperationException("Performing the Flattening is currently disabled in the ModernFix config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.perf.dedup_blockstate_flattening_map;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Dynamic;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
|
import net.minecraft.util.datafix.fixes.ChunkPalettedStorageFix;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@Mixin(ChunkPalettedStorageFix.class)
|
||||||
|
public class ChunkPalettedStorageFixMixin {
|
||||||
|
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/mojang/datafixers/DataFixUtils;make(Ljava/lang/Object;Ljava/util/function/Consumer;)Ljava/lang/Object;"))
|
||||||
|
private static Object skipMakingMap(Object o, Consumer<?> consumer) {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/datafix/fixes/BlockStateData;getTag(I)Lcom/mojang/serialization/Dynamic;"))
|
||||||
|
private static Dynamic<?> getFakeAirTag(int id) {
|
||||||
|
return new Dynamic<>(NbtOps.INSTANCE, new CompoundTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "fix", at = @At("HEAD"))
|
||||||
|
private void skipFix(CallbackInfoReturnable<Dynamic<?>> cir) {
|
||||||
|
throw new UnsupportedOperationException("No Flattening for you.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.perf.dynamic_resources;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockElementFace;
|
||||||
|
import org.embeddedt.modernfix.dynamicresources.UVController;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
@Mixin(BlockElementFace.Deserializer.class)
|
||||||
|
public class BlockElementFaceDeserializerMixin {
|
||||||
|
|
||||||
|
@Redirect(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/renderer/block/model/BlockElementFace;",
|
||||||
|
at = @At(value = "INVOKE", target = "Lcom/google/gson/JsonDeserializationContext;deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;)Ljava/lang/Object;", ordinal = 0))
|
||||||
|
private Object skipUvsForInitialLoad(JsonDeserializationContext context, JsonElement element, Type type) {
|
||||||
|
return UVController.useDummyUv.get() ? UVController.dummyUv : context.deserialize(element, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,10 +38,7 @@ import net.minecraftforge.registries.ForgeRegistries;
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
import org.apache.commons.lang3.tuple.Triple;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
import org.embeddedt.modernfix.dynamicresources.*;
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.ResourcePackHandler;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.spongepowered.asm.mixin.*;
|
import org.spongepowered.asm.mixin.*;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
@ -291,10 +288,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
}
|
}
|
||||||
modelFiles.clear();
|
modelFiles.clear();
|
||||||
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
|
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
|
||||||
|
UVController.useDummyUv.set(Boolean.TRUE);
|
||||||
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> future : modelBytes) {
|
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> future : modelBytes) {
|
||||||
Pair<ResourceLocation, JsonElement> pair = future.join();
|
Pair<ResourceLocation, JsonElement> pair = future.join();
|
||||||
try {
|
try {
|
||||||
if(pair.getSecond() != null) {
|
if(pair.getSecond() != null) {
|
||||||
|
|
||||||
BlockModel model = ExtendedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class);
|
BlockModel model = ExtendedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class);
|
||||||
model.name = pair.getFirst().toString();
|
model.name = pair.getFirst().toString();
|
||||||
modelFiles.addAll(model.getDependencies());
|
modelFiles.addAll(model.getDependencies());
|
||||||
|
|
@ -306,6 +305,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
}
|
}
|
||||||
basicModels.put(pair.getFirst(), (BlockModel)missingModel);
|
basicModels.put(pair.getFirst(), (BlockModel)missingModel);
|
||||||
}
|
}
|
||||||
|
UVController.useDummyUv.set(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
modelFiles = null;
|
modelFiles = null;
|
||||||
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {
|
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||||
public class BlockColorsMixin {
|
public class BlockColorsMixin {
|
||||||
private Lock mapLock = new ReentrantLock();
|
private Lock mapLock = new ReentrantLock();
|
||||||
@Inject(method = "register", at = @At("HEAD"))
|
@Inject(method = "register", at = @At("HEAD"))
|
||||||
private void lockMapBeforeAccess(BlockColor pBlockColor, Block[] pBlocks, CallbackInfo ci) {
|
private void lockMapBeforeAccess(CallbackInfo ci) {
|
||||||
mapLock.lock();
|
mapLock.lock();
|
||||||
}
|
}
|
||||||
@Inject(method = "register", at = @At("TAIL"))
|
@Inject(method = "register", at = @At("TAIL"))
|
||||||
private void unlockMap(BlockColor pBlockColor, Block[] pBlocks, CallbackInfo ci) {
|
private void unlockMap(CallbackInfo ci) {
|
||||||
mapLock.unlock();
|
mapLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.safety;
|
||||||
|
|
||||||
|
import net.minecraft.client.color.item.ItemColors;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
@Mixin(value = ItemColors.class, priority = 700)
|
||||||
|
public class ItemColorsMixin {
|
||||||
|
private Lock mapLock = new ReentrantLock();
|
||||||
|
@Inject(method = "register", at = @At("HEAD"))
|
||||||
|
private void lockMapBeforeAccess(CallbackInfo ci) {
|
||||||
|
mapLock.lock();
|
||||||
|
}
|
||||||
|
@Inject(method = "register", at = @At("TAIL"))
|
||||||
|
private void unlockMap(CallbackInfo ci) {
|
||||||
|
mapLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.embeddedt.modernfix.util;
|
||||||
|
|
||||||
|
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||||
|
import org.spongepowered.asm.mixin.transformer.ClassInfo;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ClassInfoManager {
|
||||||
|
private static Map<String, ClassInfo> classInfoCache = null;
|
||||||
|
public static void clear() {
|
||||||
|
if(!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager"))
|
||||||
|
return;
|
||||||
|
if(classInfoCache == null) {
|
||||||
|
try {
|
||||||
|
Field field = ClassInfo.class.getDeclaredField("cache");
|
||||||
|
field.setAccessible(true);
|
||||||
|
classInfoCache = (Map<String, ClassInfo>)field.get(null);
|
||||||
|
} catch(ReflectiveOperationException | RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object") && (entry.getValue() == null || !entry.getValue().isMixin()));
|
||||||
|
} catch(RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,25 +9,29 @@ import org.slf4j.Logger;
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
import java.lang.management.ThreadInfo;
|
import java.lang.management.ThreadInfo;
|
||||||
import java.lang.management.ThreadMXBean;
|
import java.lang.management.ThreadMXBean;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class IntegratedWatchdog extends Thread {
|
public class IntegratedWatchdog extends Thread {
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
private final MinecraftServer server;
|
private final WeakReference<MinecraftServer> server;
|
||||||
|
|
||||||
private static final long MAX_TICK_DELTA = 40*1000;
|
private static final long MAX_TICK_DELTA = 40*1000;
|
||||||
|
|
||||||
public IntegratedWatchdog(MinecraftServer server) {
|
public IntegratedWatchdog(MinecraftServer server) {
|
||||||
this.server = server;
|
this.server = new WeakReference<>(server);
|
||||||
this.setDaemon(true);
|
this.setDaemon(true);
|
||||||
this.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER));
|
this.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER));
|
||||||
this.setName("ModernFix integrated server watchdog");
|
this.setName("ModernFix integrated server watchdog");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
while(server.isRunning()) {
|
while(true) {
|
||||||
long nextTick = this.server.getNextTickTime();
|
MinecraftServer server = this.server.get();
|
||||||
|
if(server == null || !server.isRunning())
|
||||||
|
return;
|
||||||
|
long nextTick = server.getNextTickTime();
|
||||||
long curTime = Util.getMillis();
|
long curTime = Util.getMillis();
|
||||||
long delta = curTime - nextTick;
|
long delta = curTime - nextTick;
|
||||||
if(delta > MAX_TICK_DELTA) {
|
if(delta > MAX_TICK_DELTA) {
|
||||||
|
|
@ -53,6 +57,7 @@ public class IntegratedWatchdog extends Thread {
|
||||||
nextTick = 0;
|
nextTick = 0;
|
||||||
curTime = 0;
|
curTime = 0;
|
||||||
}
|
}
|
||||||
|
server = null; /* allow GC */
|
||||||
try {
|
try {
|
||||||
Thread.sleep(nextTick + MAX_TICK_DELTA - curTime);
|
Thread.sleep(nextTick + MAX_TICK_DELTA - curTime);
|
||||||
} catch(InterruptedException ignored) {
|
} catch(InterruptedException ignored) {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
"perf.state_definition_construct.StateDefinitionMixin",
|
"perf.state_definition_construct.StateDefinitionMixin",
|
||||||
"perf.compress_blockstate.BlockStateBaseMixin",
|
"perf.compress_blockstate.BlockStateBaseMixin",
|
||||||
"perf.compress_blockstate.BlockBehaviourMixin",
|
"perf.compress_blockstate.BlockBehaviourMixin",
|
||||||
|
"perf.dedup_blockstate_flattening_map.BlockStateDataMixin",
|
||||||
|
"perf.dedup_blockstate_flattening_map.ChunkPalettedStorageFixMixin",
|
||||||
"devenv.MinecraftServerMixin"
|
"devenv.MinecraftServerMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
|
@ -42,6 +44,7 @@
|
||||||
"feature.measure_time.MinecraftMixin",
|
"feature.measure_time.MinecraftMixin",
|
||||||
"feature.reduce_loading_screen_freezes.ModelBakeryMixin",
|
"feature.reduce_loading_screen_freezes.ModelBakeryMixin",
|
||||||
"bugfix.concurrency.MinecraftMixin",
|
"bugfix.concurrency.MinecraftMixin",
|
||||||
|
"perf.dynamic_resources.BlockElementFaceDeserializerMixin",
|
||||||
"perf.dynamic_resources.BlockModelShaperMixin",
|
"perf.dynamic_resources.BlockModelShaperMixin",
|
||||||
"perf.dynamic_resources.ItemModelShaperMixin",
|
"perf.dynamic_resources.ItemModelShaperMixin",
|
||||||
"perf.dynamic_resources.ModelBakeryMixin",
|
"perf.dynamic_resources.ModelBakeryMixin",
|
||||||
|
|
@ -55,6 +58,7 @@
|
||||||
"perf.model_optimizations.PropertyMixin",
|
"perf.model_optimizations.PropertyMixin",
|
||||||
"perf.thread_priorities.IntegratedServerMixin",
|
"perf.thread_priorities.IntegratedServerMixin",
|
||||||
"safety.BlockColorsMixin",
|
"safety.BlockColorsMixin",
|
||||||
|
"safety.ItemColorsMixin",
|
||||||
"perf.flatten_model_predicates.AndConditionMixin",
|
"perf.flatten_model_predicates.AndConditionMixin",
|
||||||
"perf.flatten_model_predicates.OrConditionMixin",
|
"perf.flatten_model_predicates.OrConditionMixin",
|
||||||
"perf.flatten_model_predicates.PropertyValueConditionMixin",
|
"perf.flatten_model_predicates.PropertyValueConditionMixin",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user