From 270fec309eda01737855aa3830b1613979d36d7d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 4 May 2023 11:42:25 -0400 Subject: [PATCH 1/5] Complain once per mod ID if an outdated structure is found --- .../modernfix/structure/CachingStructureManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java index 73345285..b131bb3f 100644 --- a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java +++ b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java @@ -1,6 +1,7 @@ package org.embeddedt.modernfix.structure; import com.mojang.datafixers.DataFixer; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.SharedConstants; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtIo; @@ -15,6 +16,7 @@ import org.embeddedt.modernfix.util.FileUtil; import java.io.*; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Set; public class CachingStructureManager { private static ThreadLocal digestThreadLocal = ThreadLocal.withInitial(() -> { @@ -45,6 +47,8 @@ public class CachingStructureManager { return sb.toString(); } + private static final Set laggyStructureMods = new ObjectOpenHashSet<>(); + public static CompoundTag readStructureTag(ResourceLocation location, DataFixer datafixer, InputStream stream) throws IOException { byte[] structureBytes = toBytes(stream); CompoundTag currentTag = NbtIo.readCompressed(new ByteArrayInputStream(structureBytes)); @@ -53,6 +57,11 @@ public class CachingStructureManager { } int currentDataVersion = currentTag.getInt("DataVersion"); if(currentDataVersion < SharedConstants.getCurrentVersion().getWorldVersion()) { + synchronized (laggyStructureMods) { + if(laggyStructureMods.add(location.getNamespace())) { + ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files; please report this to them.", location.getNamespace()); + } + } /* Needs upgrade, try looking up from cache */ MessageDigest hasher = digestThreadLocal.get(); hasher.reset(); From 05901b4514b1128d794b8048d8419e8ecb3294cb Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 4 May 2023 11:43:06 -0400 Subject: [PATCH 2/5] Clearer message --- .../embeddedt/modernfix/structure/CachingStructureManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java index b131bb3f..b5ed3b88 100644 --- a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java +++ b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java @@ -59,7 +59,7 @@ public class CachingStructureManager { if(currentDataVersion < SharedConstants.getCurrentVersion().getWorldVersion()) { synchronized (laggyStructureMods) { if(laggyStructureMods.add(location.getNamespace())) { - ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files; please report this to them.", location.getNamespace()); + ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace()); } } /* Needs upgrade, try looking up from cache */ From 5260d55f91c86208c29fa040ac265994a880ad65 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 4 May 2023 14:06:17 -0400 Subject: [PATCH 3/5] New README [skip ci] --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index d9266842..e1543d82 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # ModernFix -A Forge 1.16 mod that uses mixins to make the game slightly more performant (and hopefully less buggy too). - -In the words of asiekierka, questionable "performance improvements" that are not in Forge for probably very good reasons. +A performance mod for modern Minecraft that significantly improves launch times, world load times, memory usage, etc. Some fixes are based on prior work in various Forge PRs (check commit history and/or code comments). The config system is directly derived from Sodium and used under the terms of the LGPL-3.0 license. From 2b8fc0827cc0f833abd6d7d4ac66f56a8002aa04 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 4 May 2023 15:55:52 -0400 Subject: [PATCH 4/5] Bake non-vanilla models on Fabric and then throw away the cache --- .../mixin/perf/dynamic_resources/ModelBakeryMixin.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index e902b4f0..83a50d35 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -40,6 +40,7 @@ import java.util.*; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.function.Predicate; /* high priority so that our injectors are added before other mods' */ @Mixin(value = ModelBakery.class, priority = 600) @@ -162,7 +163,13 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { }; // discard unwrapped models int oldSize = this.unbakedCache.size(); - this.unbakedCache.entrySet().removeIf(entry -> entry.getValue() instanceof BlockModel || entry.getValue() instanceof MultiVariant || entry.getValue() instanceof MultiPart); + Predicate> isVanillaModel = entry -> entry.getValue() instanceof BlockModel || entry.getValue() instanceof MultiVariant || entry.getValue() instanceof MultiPart; + // bake indigo models + this.topLevelModels.entrySet().forEach((entry) -> { + if(!isVanillaModel.test(entry)) + this.bake(entry.getKey(), BlockModelRotation.X0_Y0); + }); + this.unbakedCache.entrySet().removeIf(isVanillaModel); ModernFix.LOGGER.info("{} models evicted, {} custom models loaded permanently", oldSize - this.unbakedCache.size(), this.unbakedCache.size()); this.unbakedCache = new LayeredForwardingMap<>(new Map[] { this.unbakedCache, mutableBackingMap }); this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache); From 6c56096556262ebbdeabda46149d1847dd5142ca Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 4 May 2023 17:05:02 -0400 Subject: [PATCH 5/5] Emulate the vanilla block/item -> model maps for Fabric mods --- .../BlockModelShaperMixin.java | 20 ++++- .../ItemModelShaperMixin.java | 5 ++ .../modernfix/util/DynamicInt2ObjectMap.java | 61 ++++++++++++++ .../embeddedt/modernfix/util/DynamicMap.java | 81 +++++++++++++++++++ 4 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/util/DynamicInt2ObjectMap.java create mode 100644 common/src/main/java/org/embeddedt/modernfix/util/DynamicMap.java diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java index 6e4f35ba..129157b6 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java @@ -6,10 +6,13 @@ import net.minecraft.client.resources.model.ModelManager; import net.minecraft.world.level.block.state.BlockState; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; +import org.embeddedt.modernfix.util.DynamicMap; +import org.spongepowered.asm.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.Map; @Mixin(BlockModelShaper.class) @@ -17,6 +20,15 @@ import org.spongepowered.asm.mixin.Shadow; public class BlockModelShaperMixin { @Shadow @Final private ModelManager modelManager; + @Shadow @Final @Mutable + private Map modelByStateCache; + + @Inject(method = "", at = @At("RETURN")) + private void replaceModelMap(CallbackInfo ci) { + // replace the backing map for mods which will access it + this.modelByStateCache = new DynamicMap<>(state -> modelManager.getModel(ModelLocationCache.get(state))); + } + /** * @author embeddedt * @reason no need to rebuild model cache, and location cache is done elsewhere diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java index 7472760d..66a183f0 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java @@ -1,11 +1,13 @@ package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.renderer.ItemModelShaper; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.world.item.Item; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; +import org.embeddedt.modernfix.util.DynamicInt2ObjectMap; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -19,6 +21,8 @@ public abstract class ItemModelShaperMixin { @Shadow public abstract ModelManager getModelManager(); + @Shadow @Final @Mutable private Int2ObjectMap shapesCache; + private Map overrideLocationsVanilla; public ItemModelShaperMixin() { @@ -30,6 +34,7 @@ public abstract class ItemModelShaperMixin { @Inject(method = "", at = @At("RETURN")) private void replaceLocationMap(CallbackInfo ci) { overrideLocationsVanilla = new HashMap<>(); + this.shapesCache = new DynamicInt2ObjectMap<>(index -> getModelManager().getModel(ModelLocationCache.get(Item.byId(index)))); } @Unique diff --git a/common/src/main/java/org/embeddedt/modernfix/util/DynamicInt2ObjectMap.java b/common/src/main/java/org/embeddedt/modernfix/util/DynamicInt2ObjectMap.java new file mode 100644 index 00000000..5c44208e --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/util/DynamicInt2ObjectMap.java @@ -0,0 +1,61 @@ +package org.embeddedt.modernfix.util; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectSet; + +import java.util.Map; +import java.util.function.Function; + +public class DynamicInt2ObjectMap extends DynamicMap implements Int2ObjectMap { + public DynamicInt2ObjectMap(Function function) { + super(function); + } + + @Override + public IntSet keySet() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectCollection values() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectSet> entrySet() { + throw new UnsupportedOperationException(); + } + + @Override + public void defaultReturnValue(V rv) { + throw new UnsupportedOperationException(); + } + + @Override + public V defaultReturnValue() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectSet> int2ObjectEntrySet() { + throw new UnsupportedOperationException(); + } + + @Override + public V getOrDefault(int key, V defaultValue) { + V value = get(key); + return value == null ? defaultValue : value; + } + + @Override + public V get(int key) { + return function.apply(key); + } + + @Override + public boolean containsKey(int key) { + return true; + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/util/DynamicMap.java b/common/src/main/java/org/embeddedt/modernfix/util/DynamicMap.java new file mode 100644 index 00000000..e8803770 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/util/DynamicMap.java @@ -0,0 +1,81 @@ +package org.embeddedt.modernfix.util; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +public class DynamicMap implements Map { + protected final Function function; + + public DynamicMap(Function function) { + this.function = function; + } + + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean containsKey(Object o) { + return true; + } + + @Override + public boolean containsValue(Object o) { + return true; + } + + @Override + public V get(Object o) { + return function.apply((K)o); + } + + @Nullable + @Override + public V put(K k, V v) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(@NotNull Map map) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set keySet() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Collection values() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set> entrySet() { + throw new UnsupportedOperationException(); + } +}