diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java deleted file mode 100644 index 114577c1..00000000 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.embeddedt.modernfix.common.mixin.feature.disable_unihex_font; - -import com.mojang.blaze3d.font.GlyphProvider; -import com.mojang.datafixers.util.Either; -import net.minecraft.client.gui.font.CodepointMap; -import net.minecraft.client.gui.font.providers.GlyphProviderDefinition; -import net.minecraft.client.gui.font.providers.UnihexProvider; -import net.minecraft.server.packs.resources.ResourceManager; -import org.embeddedt.modernfix.ModernFix; -import org.embeddedt.modernfix.annotation.ClientOnlyMixin; -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.CallbackInfoReturnable; - -import java.io.IOException; -import java.lang.reflect.Constructor; - -@Mixin(UnihexProvider.Definition.class) -@ClientOnlyMixin -public class UnihexProviderDefinitionMixin { - @Inject(method = "unpack", at = @At("HEAD"), cancellable = true) - private void disableProvider(CallbackInfoReturnable> cir) { - cir.setReturnValue(Either.left(this::mfix$loadEmpty)); - } - - private GlyphProvider mfix$loadEmpty(ResourceManager resourceManager) throws IOException { - try { - ModernFix.LOGGER.warn("Unihex provider is disabled, a number of Unicode characters will likely not render"); - Constructor constructor = UnihexProvider.class.getDeclaredConstructor(CodepointMap.class); - constructor.setAccessible(true); - return constructor.newInstance(new CodepointMap<>(Object[]::new, Object[][]::new)); - } catch(ReflectiveOperationException e) { - throw new IOException("Failed to create empty loader", e); - } - } -} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compress_unihex_font/UnihexProviderByteContentsMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compress_unihex_font/UnihexProviderByteContentsMixin.java new file mode 100644 index 00000000..f358dad2 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compress_unihex_font/UnihexProviderByteContentsMixin.java @@ -0,0 +1,22 @@ +package org.embeddedt.modernfix.common.mixin.perf.compress_unihex_font; + +import com.llamalad7.mixinextras.sugar.Local; +import it.unimi.dsi.fastutil.bytes.ByteList; +import net.minecraft.client.gui.font.providers.UnihexProvider; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.render.font.CompactUnihexContents; +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.CallbackInfoReturnable; + +@Mixin(targets = {"net/minecraft/client/gui/font/providers/UnihexProvider$ByteContents"}) +@ClientOnlyMixin +public class UnihexProviderByteContentsMixin { + @Inject(method = "read", at = @At(value = "NEW", target = "([B)Lnet/minecraft/client/gui/font/providers/UnihexProvider$ByteContents;"), cancellable = true) + private static void useCompactIfPossible(int index, ByteList byteList, CallbackInfoReturnable cir, @Local(ordinal = 0) byte[] contents) { + if (contents.length == 16) { + cir.setReturnValue(new CompactUnihexContents.Bytes(contents)); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compress_unihex_font/UnihexProviderShortContentsMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compress_unihex_font/UnihexProviderShortContentsMixin.java new file mode 100644 index 00000000..1f9abf47 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compress_unihex_font/UnihexProviderShortContentsMixin.java @@ -0,0 +1,22 @@ +package org.embeddedt.modernfix.common.mixin.perf.compress_unihex_font; + +import com.llamalad7.mixinextras.sugar.Local; +import it.unimi.dsi.fastutil.bytes.ByteList; +import net.minecraft.client.gui.font.providers.UnihexProvider; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.render.font.CompactUnihexContents; +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.CallbackInfoReturnable; + +@Mixin(targets = {"net/minecraft/client/gui/font/providers/UnihexProvider$ShortContents"}) +@ClientOnlyMixin +public class UnihexProviderShortContentsMixin { + @Inject(method = "read", at = @At(value = "NEW", target = "([S)Lnet/minecraft/client/gui/font/providers/UnihexProvider$ShortContents;"), cancellable = true) + private static void useCompactIfPossible(int index, ByteList byteList, CallbackInfoReturnable cir, @Local(ordinal = 0) short[] contents) { + if (contents.length == 16) { + cir.setReturnValue(new CompactUnihexContents.Shorts(contents)); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/render/font/CompactUnihexContents.java b/common/src/main/java/org/embeddedt/modernfix/render/font/CompactUnihexContents.java new file mode 100644 index 00000000..9adf848f --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/render/font/CompactUnihexContents.java @@ -0,0 +1,96 @@ +package org.embeddedt.modernfix.render.font; + +import net.minecraft.client.gui.font.providers.UnihexProvider; + +/** + * Implements more compact storage for LineData contents. + * + * Credit for the idea of using flattened fields rather than a backing array goes to @AnAwesomGuy. + */ +public class CompactUnihexContents { + private static long extract8Bytes(byte[] arr, int off) { + long l = 0; + for (int i = 0; i < 8; i++) { + l |= ((long)arr[off + i] << (i * 8)); + } + return l; + } + + private static byte extractByte(long compressed, int off) { + return (byte)((compressed >> (off * 8)) & 0xFF); + } + + private static long extract4Shorts(short[] arr, int off) { + long l = 0; + for (int i = 0; i < 4; i++) { + l |= ((long)arr[off + i] << (i * 16)); + } + return l; + } + + private static short extractShort(long compressed, int off) { + return (byte)((compressed >> (off * 16)) & 0xFF); + } + + public static class Bytes implements UnihexProvider.LineData { + private final long b0; + private final long b8; + + public Bytes(byte[] contents) { + this.b0 = extract8Bytes(contents, 0); + this.b8 = extract8Bytes(contents, 8); + } + + @Override + public int line(int index) { + if (index < 0 || index >= 16) { + throw new ArrayIndexOutOfBoundsException(); + } + if (index < 8) { + return extractByte(b0, index) << 24; + } else { + return extractByte(b8, index - 8) << 24; + } + } + + @Override + public int bitWidth() { + return 8; + } + } + + public static class Shorts implements UnihexProvider.LineData { + private final long b0; + private final long b4; + private final long b8; + private final long b12; + + public Shorts(short[] contents) { + this.b0 = extract4Shorts(contents, 0); + this.b4 = extract4Shorts(contents, 4); + this.b8 = extract4Shorts(contents, 8); + this.b12 = extract4Shorts(contents, 12); + } + + @Override + public int line(int index) { + if (index < 0 || index >= 16) { + throw new ArrayIndexOutOfBoundsException(); + } + if (index < 4) { + return extractShort(b0, index) << 16; + } else if (index < 8) { + return extractShort(b4, index - 4) << 16; + } else if (index < 12) { + return extractShort(b8, index - 8) << 16; + } else { + return extractShort(b12, index - 12) << 16; + } + } + + @Override + public int bitWidth() { + return 16; + } + } +} diff --git a/common/src/main/resources/assets/modernfix/lang/en_us.json b/common/src/main/resources/assets/modernfix/lang/en_us.json index c7e317c4..918d98ed 100644 --- a/common/src/main/resources/assets/modernfix/lang/en_us.json +++ b/common/src/main/resources/assets/modernfix/lang/en_us.json @@ -117,7 +117,7 @@ "modernfix.option.mixin.perf.twilightforest.structure_spawn_fix": "Fixes lag caused by Twilight Forest worldgen checking structures very inefficiently", "modernfix.option.mixin.perf.fast_forge_dummies": "Speeds up Forge registry freezing during launch by using a faster code path", "modernfix.option.mixin.perf.tag_id_caching": "Speeds up uses of tag entries by caching the location object instead of recreating it every time", - "modernfix.option.mixin.feature.disable_unihex_font": "Remove the Unicode font, saves 10MB but causes special characters to no longer render", + "modernfix.option.mixin.perf.compress_unihex_font": "Stores the glyphs for the Unicode font more efficiently. Kudos to @AnAwesomGuy for the trick.", "modernfix.option.mixin.bugfix.world_leaks": "Reduces the memory usage of old client-side worlds that aren't needed after switching dimensions. These are normally garbage collected in vanilla, but mods sometimes retain references to them.", "modernfix.option.mixin.perf.compact_mojang_registries": "(Fabric) Experimental option that reduces the memory usage of registries by roughly 50%. Not useful in most modpacks unless they contain millions of blocks and items.", "modernfix.option.mixin.perf.dynamic_block_codecs": "Avoids storing a codec for every block(state) and instead generates and caches it on the fly when needed. Generally not worth enabling unless you have a million blocks/items.",