Optimize skull rendering

This commit is contained in:
Phoenix-Starlight 2023-10-16 20:32:55 -07:00
parent 79751dac21
commit c4ac0e586c
5 changed files with 127 additions and 0 deletions

View File

@ -0,0 +1,5 @@
package org.embeddedt.modernfix.duck;
public interface ICachedProfileTexture {
public void setCachedHash(String url);
}

View File

@ -34,6 +34,7 @@
"modernfix.option.mixin.perf.boost_worker_count": "1.16 only. Removes the hardcoded cap on worker thread count, similarly to what Mojang did in 1.18.", "modernfix.option.mixin.perf.boost_worker_count": "1.16 only. Removes the hardcoded cap on worker thread count, similarly to what Mojang did in 1.18.",
"modernfix.option.mixin.perf.cache_blockstate_cache_arrays": "All versions. Avoids creating fresh copies of enum arrays each time a blockstate cache is initialized. Minor optimization, but easy to do.", "modernfix.option.mixin.perf.cache_blockstate_cache_arrays": "All versions. Avoids creating fresh copies of enum arrays each time a blockstate cache is initialized. Minor optimization, but easy to do.",
"modernfix.option.mixin.perf.cache_model_materials": "All versions. Memoizes the `RenderMaterial` (texture) collection and dependency list that models return instead of requiring them to be recalculated on each request. Helps accelerate the model load/bake process.", "modernfix.option.mixin.perf.cache_model_materials": "All versions. Memoizes the `RenderMaterial` (texture) collection and dependency list that models return instead of requiring them to be recalculated on each request. Helps accelerate the model load/bake process.",
"modernfix.option.mixin.perf.cache_profile_texture_url": "Fabric 1.20+. Avoids pointlessly creating a URL object and speeds up skull block rendering.",
"modernfix.option.mixin.perf.cache_strongholds": "All versions. Saves the generated list of stronghold positions with the world, instead of regenerating it on every world load. Saves a little bit of time on 1.16, and quite a bit more on 1.18 and 1.19.", "modernfix.option.mixin.perf.cache_strongholds": "All versions. Saves the generated list of stronghold positions with the world, instead of regenerating it on every world load. Saves a little bit of time on 1.16, and quite a bit more on 1.18 and 1.19.",
"modernfix.option.mixin.perf.cache_upgraded_structures": "All versions. Many mods ship outdated structure files, which requires the game to upgrade them using DFU every single time they are loaded. This can be quite slow. This patch adds logic to instead save the upgraded version of the structure, and reuse it on the next load. To handle the case that the mod changes a structure file but not the name, the original file's hash is compared against the cached version, and if they do not match the structure will be upgraded again.", "modernfix.option.mixin.perf.cache_upgraded_structures": "All versions. Many mods ship outdated structure files, which requires the game to upgrade them using DFU every single time they are loaded. This can be quite slow. This patch adds logic to instead save the upgraded version of the structure, and reuse it on the next load. To handle the case that the mod changes a structure file but not the name, the original file's hash is compared against the cached version, and if they do not match the structure will be upgraded again.",
"modernfix.option.mixin.perf.compress_biome_container": "1.16 only. Minor optimization borrowed from Hydrogen, which attempts to save space in the biome container when possible. This gets disabled automatically if conflicting mods like BetterEnd or Chocolate are installed.", "modernfix.option.mixin.perf.compress_biome_container": "1.16 only. Minor optimization borrowed from Hydrogen, which attempts to save space in the biome container when possible. This gets disabled automatically if conflicting mods like BetterEnd or Chocolate are installed.",

View File

@ -0,0 +1,44 @@
package org.embeddedt.modernfix.fabric.mixin.perf.cache_profile_texture_url;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import org.apache.commons.io.FilenameUtils;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.duck.ICachedProfileTexture;
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.CallbackInfo;
import java.util.Map;
import java.net.MalformedURLException;
import java.net.URL;
@Mixin(value = MinecraftProfileTexture.class, remap = false)
@ClientOnlyMixin
public abstract class MinecraftProfileTextureMixin implements ICachedProfileTexture {
/**
* @author Fury_Phoenix
* @see org.embeddedt.modernfix.common.mixin.perf.cache_profile_texture_url.YggdrasilGsonDeserializerMixin#setCachedURL
**/
private String modernfix$cachedHash;
@Inject(method = "<init>(Ljava/lang/String;Ljava/util/Map;)V", at = @At("RETURN"), cancellable = false)
private void cacheHash(String url, Map<String, String> metadata, CallbackInfo ci) {
try {
this.modernfix$cachedHash = FilenameUtils.getBaseName(new URL(url).getPath());
} catch (MalformedURLException e) {}
}
public void setCachedHash(String url) {
this.cacheHash(url, null, null);
}
// Overwrite - nuke new entirely
public String getHash() {
if (this.modernfix$cachedHash == null) {
throw new IllegalArgumentException("Invalid profile texture url");
}
return this.modernfix$cachedHash;
}
}

View File

@ -0,0 +1,33 @@
package org.embeddedt.modernfix.fabric.mixin.perf.cache_profile_texture_url;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.duck.ICachedProfileTexture;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(value=YggdrasilMinecraftSessionService.class, remap=false)
@ClientOnlyMixin
public abstract class YggdrasilGsonDeserializerMixin {
/**
* @author Fury_Phoenix
* @reason Unexpected deserialization
* **/
@WrapOperation
(method = "getTextures",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture;getUrl()Ljava/lang/String;"
)
)
private String setCachedHash(MinecraftProfileTexture texture, Operation<String> original) {
// Because we don't have it set from deserialization
String url = original.call(texture);
((ICachedProfileTexture)texture).setCachedHash(url);
return url;
}
}

View File

@ -0,0 +1,44 @@
package org.embeddedt.modernfix.forge.mixin.perf.cache_profile_texture_url;
import com.google.common.cache.CacheBuilder;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.resources.SkinManager;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import java.util.concurrent.TimeUnit;
import java.util.Map;
@Mixin(value=SkinManager.class)
@ClientOnlyMixin
public abstract class SkinManagerMixin {
/**
* @author Fury_Phoenix
* @reason No lib mixins on (neo)forge, yet
* **/
@Unique
private final Map<MinecraftProfileTexture, String> hashCache = CacheBuilder.newBuilder()
.expireAfterAccess(60, TimeUnit.SECONDS)
.concurrencyLevel(1)
// Excessive use of type hinting due to it assuming Object as the broadest correct type
.<MinecraftProfileTexture, String>build()
.asMap();
@WrapOperation
(
// Mixes (un)obfuscated types
method = "m_118828_",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture;getHash()Ljava/lang/String;"
),
remap = false
)
private String stashCachedHash(MinecraftProfileTexture texture, Operation<String> original) {
return hashCache.computeIfAbsent(texture, k -> original.call(k));
}
}