From 0439dec66236c79b4f2dd597cd1204479a186618 Mon Sep 17 00:00:00 2001 From: Ampflower Date: Sat, 23 Dec 2023 07:41:06 -0600 Subject: [PATCH] Add allocation tweaks for low-mem and performance --- gradle.properties | 8 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../gay/ampflower/mcunsafe/MixinUnsafe.java | 64 +++++++++++++ .../mcunsafe/mixin/MixinModelLoader.java | 90 +++++++++++++++++++ .../mcunsafe/mixin/MixinNbtCompound.java | 37 ++++++++ src/main/resources/fabric.mod.json | 8 ++ src/main/resources/mcunsafe.mixin.json | 15 ++++ 7 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 src/main/java/gay/ampflower/mcunsafe/MixinUnsafe.java create mode 100644 src/main/java/gay/ampflower/mcunsafe/mixin/MixinModelLoader.java create mode 100644 src/main/java/gay/ampflower/mcunsafe/mixin/MixinNbtCompound.java create mode 100644 src/main/resources/mcunsafe.mixin.json diff --git a/gradle.properties b/gradle.properties index 48af61a..db4deea 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ projectVersion=0.0.0 -minecraftVersion=1.18.2 -yarnMappings=1.18.2+build.2 -loaderVersion=0.13.3 +minecraftVersion=1.19.2 +yarnMappings=1.19.2+build.28 +loaderVersion=0.14.11 org.gradle.jvmargs=-Xmx1G -systemProp.loomVersion=0.11.32 \ No newline at end of file +systemProp.loomVersion=1.+ \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb87..a595206 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/gay/ampflower/mcunsafe/MixinUnsafe.java b/src/main/java/gay/ampflower/mcunsafe/MixinUnsafe.java new file mode 100644 index 0000000..9e14c5a --- /dev/null +++ b/src/main/java/gay/ampflower/mcunsafe/MixinUnsafe.java @@ -0,0 +1,64 @@ +package gay.ampflower.mcunsafe; + +import net.gudenau.minecraft.asm.impl.ReflectionHelper; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import org.spongepowered.asm.mixin.transformer.ClassInfo; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +/** + * @author Ampflower + * @since ${version} + **/ +public class MixinUnsafe implements IMixinConfigPlugin { + static { + try { + var $cache = ReflectionHelper.findStaticGetter(ClassInfo.class, "cache", Map.class); + var oldCache = (Map) $cache.invoke(); + var newCache = new WeakHashMap<>(oldCache); + ReflectionHelper.findStaticSetter(ClassInfo.class, "cache", Map.class).invoke(newCache); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return false; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/src/main/java/gay/ampflower/mcunsafe/mixin/MixinModelLoader.java b/src/main/java/gay/ampflower/mcunsafe/mixin/MixinModelLoader.java new file mode 100644 index 0000000..8c67b61 --- /dev/null +++ b/src/main/java/gay/ampflower/mcunsafe/mixin/MixinModelLoader.java @@ -0,0 +1,90 @@ +package gay.ampflower.mcunsafe.mixin; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.AffineTransformation; +import org.apache.commons.lang3.tuple.Triple; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; + +import java.util.Map; +import java.util.Set; + +/** + * @author Ampflower + * @since ${version} + **/ +@Mixin(ModelLoader.class) +public class MixinModelLoader { + @Shadow + @Final + @Mutable + private Set modelsToLoad; + + @Shadow + @Final + @Mutable + private Map unbakedModels; + + @Shadow + @Final + @Mutable + private Map, BakedModel> bakedModelCache; + + @Shadow + @Final + @Mutable + private Map modelsToBake; + + @Shadow + @Final + @Mutable + private Map bakedModels; + + @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/model/ModelLoader;modelsToLoad:Ljava/util/Set;")) + private void mcunsafe$redirectModelsToLoad(ModelLoader self, Set set) { + modelsToLoad = new ObjectOpenHashSet<>(); + } + + @Redirect(method = "", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/model/ModelLoader;unbakedModels:Ljava/util/Map;"), + slice = @Slice(id = "primary", from = @At("HEAD"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;push(Ljava/lang/String;)V", ordinal = 0))) + private void mcunsafe$redirectUnbakedModels(ModelLoader self, Map map) { + unbakedModels = new Object2ObjectOpenHashMap<>(1024); + } + + @Redirect(method = "", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/model/ModelLoader;bakedModelCache:Ljava/util/Map;"), + slice = @Slice(id = "primary", from = @At("HEAD"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;push(Ljava/lang/String;)V", ordinal = 0))) + private void mcunsafe$redirectBakedModelCache(ModelLoader self, Map map) { + bakedModelCache = new Object2ObjectOpenHashMap<>(1024); + } + + @Redirect(method = "", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/model/ModelLoader;modelsToBake:Ljava/util/Map;"), + slice = @Slice(id = "primary", from = @At("HEAD"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;push(Ljava/lang/String;)V", ordinal = 0))) + private void mcunsafe$redirectModelsToBake(ModelLoader self, Map map) { + modelsToBake = new Object2ObjectOpenHashMap<>(64); + } + + @Redirect(method = "", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/model/ModelLoader;bakedModels:Ljava/util/Map;"), + slice = @Slice(id = "primary", from = @At("HEAD"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;push(Ljava/lang/String;)V", ordinal = 0))) + private void mcunsafe$redirectBakedModels(ModelLoader self, Map map) { + bakedModels = new Object2ObjectOpenHashMap<>(64); + } + +} diff --git a/src/main/java/gay/ampflower/mcunsafe/mixin/MixinNbtCompound.java b/src/main/java/gay/ampflower/mcunsafe/mixin/MixinNbtCompound.java new file mode 100644 index 0000000..708bc49 --- /dev/null +++ b/src/main/java/gay/ampflower/mcunsafe/mixin/MixinNbtCompound.java @@ -0,0 +1,37 @@ +package gay.ampflower.mcunsafe.mixin; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.nbt.NbtCompound; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Ampflower + * @since 0.1.0 + **/ +@Mixin(NbtCompound.class) +public class MixinNbtCompound { + /** + * Removes now unnecessary allocation of the map. + */ + @Redirect(method = "()V", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;")) + private static HashMap mcunsafe$nullifier() { + return null; + } + + /** + * Allocates FastUtil hashmap with a preallocation of 4 rather than 16. + */ + @ModifyArg(method = "()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NbtCompound;(Ljava/util/Map;)V")) + private static Map mcunsafe$unnullifier(Map map) { + if (map != null) { + throw new AssertionError(); + } + return new Object2ObjectOpenHashMap<>(4); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index f63fe7a..79a7d3d 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,7 +21,15 @@ "gay.ampflower.mcunsafe.asm.Asm" ] }, + "mixins": [ + "mcunsafe.mixin.json" + ], "depends": { "gud_asm": "*" + }, + "custom": { + "lithium:options": { + "mixin.alloc.nbt": false + } } } \ No newline at end of file diff --git a/src/main/resources/mcunsafe.mixin.json b/src/main/resources/mcunsafe.mixin.json new file mode 100644 index 0000000..4d8926e --- /dev/null +++ b/src/main/resources/mcunsafe.mixin.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "gay.ampflower.mcunsafe.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "MixinNbtCompound" + ], + "injectors": { + "defaultRequire": 1 + }, + "client": [ + "MixinModelLoader" + ] +} \ No newline at end of file