Replace mixin.feature.disable_unihex_font with mixin.perf.compress_unihex_font

The font still takes up some memory, but less than before
This commit is contained in:
embeddedt 2025-05-15 22:11:58 -04:00
parent f70fb212f7
commit 82535da861
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
5 changed files with 141 additions and 38 deletions

View File

@ -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<Either<GlyphProviderDefinition.Loader, GlyphProviderDefinition.Reference>> 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<UnihexProvider> 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);
}
}
}

View File

@ -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<UnihexProvider.LineData> cir, @Local(ordinal = 0) byte[] contents) {
if (contents.length == 16) {
cir.setReturnValue(new CompactUnihexContents.Bytes(contents));
}
}
}

View File

@ -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<UnihexProvider.LineData> cir, @Local(ordinal = 0) short[] contents) {
if (contents.length == 16) {
cir.setReturnValue(new CompactUnihexContents.Shorts(contents));
}
}
}

View File

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

View File

@ -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.",