Merge remote-tracking branch 'origin/1.18' into 1.19.2

This commit is contained in:
embeddedt 2023-04-20 21:13:36 -04:00
commit d63b5acd6e
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
13 changed files with 285 additions and 10 deletions

View File

@ -1,26 +1,37 @@
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.event.server.ServerStartedEvent;
import net.minecraftforge.event.server.ServerStoppedEvent;
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.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
import net.minecraftforge.network.NetworkConstants;
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.util.ClassInfoManager;
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;
@ -66,12 +77,14 @@ public class ModernFix {
// 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(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class);
PacketHandler.register();
ModFileScanDataDeduplicator.deduplicate();
}
private static boolean dfuModPresent() {
@ -100,5 +113,32 @@ public class ModernFix {
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(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);
}
}
}

View File

@ -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();
}
}

View File

@ -37,6 +37,8 @@ public class ModernFixEarlyConfig {
/* Use a simpler ArrayMap if FerriteCore is using the map intelligently anyway */
this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore"));
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.compress_blockstate", false);
this.addMixinRule("bugfix.concurrency", true);

View File

@ -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);
}

View File

@ -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.");
}
}

View File

@ -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.");
}
}

View File

@ -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);
}
}

View File

@ -38,10 +38,7 @@ import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.tuple.Triple;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent;
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
import org.embeddedt.modernfix.dynamicresources.ResourcePackHandler;
import org.embeddedt.modernfix.dynamicresources.*;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
@ -291,10 +288,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
}
modelFiles.clear();
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
UVController.useDummyUv.set(Boolean.TRUE);
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> future : modelBytes) {
Pair<ResourceLocation, JsonElement> pair = future.join();
try {
if(pair.getSecond() != null) {
BlockModel model = ExtendedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class);
model.name = pair.getFirst().toString();
modelFiles.addAll(model.getDependencies());
@ -306,6 +305,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
}
basicModels.put(pair.getFirst(), (BlockModel)missingModel);
}
UVController.useDummyUv.set(Boolean.FALSE);
}
modelFiles = null;
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {

View File

@ -16,11 +16,11 @@ import java.util.concurrent.locks.ReentrantLock;
public class BlockColorsMixin {
private Lock mapLock = new ReentrantLock();
@Inject(method = "register", at = @At("HEAD"))
private void lockMapBeforeAccess(BlockColor pBlockColor, Block[] pBlocks, CallbackInfo ci) {
private void lockMapBeforeAccess(CallbackInfo ci) {
mapLock.lock();
}
@Inject(method = "register", at = @At("TAIL"))
private void unlockMap(BlockColor pBlockColor, Block[] pBlocks, CallbackInfo ci) {
private void unlockMap(CallbackInfo ci) {
mapLock.unlock();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -9,25 +9,29 @@ import org.slf4j.Logger;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
public class IntegratedWatchdog extends Thread {
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;
public IntegratedWatchdog(MinecraftServer server) {
this.server = server;
this.server = new WeakReference<>(server);
this.setDaemon(true);
this.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER));
this.setName("ModernFix integrated server watchdog");
}
public void run() {
while(server.isRunning()) {
long nextTick = this.server.getNextTickTime();
while(true) {
MinecraftServer server = this.server.get();
if(server == null || !server.isRunning())
return;
long nextTick = server.getNextTickTime();
long curTime = Util.getMillis();
long delta = curTime - nextTick;
if(delta > MAX_TICK_DELTA) {
@ -53,6 +57,7 @@ public class IntegratedWatchdog extends Thread {
nextTick = 0;
curTime = 0;
}
server = null; /* allow GC */
try {
Thread.sleep(nextTick + MAX_TICK_DELTA - curTime);
} catch(InterruptedException ignored) {

View File

@ -34,6 +34,8 @@
"perf.state_definition_construct.StateDefinitionMixin",
"perf.compress_blockstate.BlockStateBaseMixin",
"perf.compress_blockstate.BlockBehaviourMixin",
"perf.dedup_blockstate_flattening_map.BlockStateDataMixin",
"perf.dedup_blockstate_flattening_map.ChunkPalettedStorageFixMixin",
"devenv.MinecraftServerMixin"
],
"client": [
@ -42,6 +44,7 @@
"feature.measure_time.MinecraftMixin",
"feature.reduce_loading_screen_freezes.ModelBakeryMixin",
"bugfix.concurrency.MinecraftMixin",
"perf.dynamic_resources.BlockElementFaceDeserializerMixin",
"perf.dynamic_resources.BlockModelShaperMixin",
"perf.dynamic_resources.ItemModelShaperMixin",
"perf.dynamic_resources.ModelBakeryMixin",
@ -55,6 +58,7 @@
"perf.model_optimizations.PropertyMixin",
"perf.thread_priorities.IntegratedServerMixin",
"safety.BlockColorsMixin",
"safety.ItemColorsMixin",
"perf.flatten_model_predicates.AndConditionMixin",
"perf.flatten_model_predicates.OrConditionMixin",
"perf.flatten_model_predicates.PropertyValueConditionMixin",