Merge branch 'unihex' into 1.20
This commit is contained in:
commit
6979b56d8c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.fix_loop_spin_waiting;
|
||||
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
// This should fix https://bugs.mojang.com/browse/MC-183518
|
||||
@Mixin(value = BlockableEventLoop.class, priority = 500)
|
||||
public class BlockableEventLoopMixin {
|
||||
private static final long MFIX$TICK_WAIT_TIME = TimeUnit.MILLISECONDS.toNanos(2);
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason yielding the thread is pretty pointless if we're about to park anyway
|
||||
*/
|
||||
@Overwrite
|
||||
protected void waitForTasks() {
|
||||
LockSupport.parkNanos("waiting for tasks", MFIX$TICK_WAIT_TIME);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.fix_loop_spin_waiting;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Mixin(value = MinecraftServer.class, priority = 500)
|
||||
public abstract class MinecraftServerMixin extends BlockableEventLoop<Runnable> {
|
||||
@Shadow private long nextTickTime;
|
||||
|
||||
protected MinecraftServerMixin(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean mfix$isWaitingForNextTick = false;
|
||||
|
||||
@WrapOperation(
|
||||
method = "waitUntilNextTick",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;managedBlock(Ljava/util/function/BooleanSupplier;)V")
|
||||
)
|
||||
private void managedBlock(MinecraftServer instance, BooleanSupplier isDone, Operation<Void> original) {
|
||||
try {
|
||||
this.mfix$isWaitingForNextTick = true;
|
||||
original.call(instance, isDone);
|
||||
} finally {
|
||||
this.mfix$isWaitingForNextTick = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void waitForTasks() {
|
||||
if (this.mfix$isWaitingForNextTick) {
|
||||
LockSupport.parkNanos("waiting for tasks", (this.nextTickTime * 1000000L) - Util.getNanos());
|
||||
} else {
|
||||
super.waitForTasks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
|
@ -24,6 +25,8 @@ import java.util.stream.Stream;
|
|||
*/
|
||||
public class PackResourcesCacheEngine {
|
||||
private static final Joiner SLASH_JOINER = Joiner.on('/');
|
||||
private static final ConcurrentHashMap<String, String> PATH_COMPONENT_INTERNER = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, String[]> CACHED_SPLIT_PATHS = new ConcurrentHashMap<>();
|
||||
|
||||
static class Node {
|
||||
Map<String, Node> children;
|
||||
|
|
@ -100,7 +103,6 @@ public class PackResourcesCacheEngine {
|
|||
// used for log message
|
||||
this.debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES).toAbsolutePath();
|
||||
this.root.children = new Object2ObjectOpenHashMap<>();
|
||||
ObjectOpenHashSet<String> pathKeys = new ObjectOpenHashSet<>();
|
||||
for(PackType type : PackType.values()) {
|
||||
var typeRoot = new Node();
|
||||
this.root.children.put(type.getDirectory(), typeRoot);
|
||||
|
|
@ -114,8 +116,12 @@ public class PackResourcesCacheEngine {
|
|||
.filter(PackResourcesCacheEngine::isValidCachedResourcePath)
|
||||
.forEach(path -> {
|
||||
var node = typeRoot;
|
||||
for (Path component : path) {
|
||||
String key = pathKeys.addOrGet(component.toString());
|
||||
int nameCount = path.getNameCount();
|
||||
for (int i = 0; i < nameCount; i++) {
|
||||
String key = path.getName(i).toString();
|
||||
if (i < (nameCount - 1)) {
|
||||
key = PATH_COMPONENT_INTERNER.computeIfAbsent(key, Function.identity());
|
||||
}
|
||||
if (node.children == null) {
|
||||
node.children = new Object2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
|
@ -213,4 +219,16 @@ public class PackResourcesCacheEngine {
|
|||
}
|
||||
node.collectResources(resourceNamespace, this.rootPathsByType.get(type).resolve(resourceNamespace), components, 0, maxDepth, output);
|
||||
}
|
||||
|
||||
private static String[] decompose(String path) {
|
||||
String[] components = path.split("/");
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
components[i] = PATH_COMPONENT_INTERNER.computeIfAbsent(components[i], Function.identity());
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
public static String[] decomposeCached(String path) {
|
||||
return CACHED_SPLIT_PATHS.computeIfAbsent(path, PackResourcesCacheEngine::decompose);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -102,6 +102,6 @@ public abstract class ForgePathPackResourcesMixin implements ICachingResourcePac
|
|||
if(!PackTypeHelper.isVanillaPackType(type))
|
||||
return;
|
||||
ci.cancel();
|
||||
this.generateResourceCache().collectResources(type, namespace, path.split("/"), Integer.MAX_VALUE, resourceOutput);
|
||||
this.generateResourceCache().collectResources(type, namespace, PackResourcesCacheEngine.decomposeCached(path), Integer.MAX_VALUE, resourceOutput);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user