Properly schedule updating the skin

This commit is contained in:
Matthew Messinger 2018-09-05 21:08:08 -04:00
parent d78bd02d7b
commit 898f5c9ff9
5 changed files with 35 additions and 52 deletions

View file

@ -38,6 +38,7 @@ import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.client.resources.SkinManager;
import net.minecraft.client.resources.SkinManager.SkinAvailableCallback;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.FileUtils;
import org.apache.http.impl.client.CloseableHttpClient;
@ -165,9 +166,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
public void fetchAndLoadSkins(GameProfile profile, SkinManager.SkinAvailableCallback callback) {
loadProfileTextures(profile).thenAcceptAsync(m -> m.forEach((type, pp) -> {
loadTexture(type, pp, (typeIn, location, profileTexture) -> {
parseSkin(profile, typeIn, location, profileTexture);
callback.skinAvailable(typeIn, location, profileTexture);
parseSkin(profile, typeIn, location, profileTexture, callback);
});
}), Minecraft.getMinecraft()::addScheduledTask);
}
@ -301,7 +300,8 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
.flatMap(a -> a.getPlayerInfoMap().stream());
}
public void parseSkin(GameProfile profile, Type type, ResourceLocation resource, MinecraftProfileTexture texture) {
public void parseSkin(GameProfile profile, Type type, ResourceLocation resource, MinecraftProfileTexture texture,
SkinAvailableCallback callback) {
CallableFutures.scheduleTask(() -> {
@ -325,6 +325,8 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
if (wasNull && !metadata.isEmpty()) {
ProfileTextureUtil.setMetadata(texture, metadata);
}
callback.skinAvailable(type, resource, texture);
});
}

View file

@ -1,41 +0,0 @@
package com.voxelmodpack.hdskins.mixin;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.INetworkPlayerInfo;
import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.client.resources.SkinManager;
import net.minecraft.util.ResourceLocation;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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.concurrent.CompletableFuture;
@Mixin(targets = "net.minecraft.client.network.NetworkPlayerInfo$1")
public abstract class MixinNetworkPlayerInfo$1 implements SkinManager.SkinAvailableCallback {
@Shadow(remap = false, aliases = {"this$0", "field_177224_a", "a"})
@Final
private NetworkPlayerInfo player;
@Inject(method = "skinAvailable("
+ "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture$Type;"
+ "Lnet/minecraft/util/ResourceLocation;"
+ "Lcom/mojang/authlib/minecraft/MinecraftProfileTexture;"
+ ")V",
at = @At(value = "HEAD"))
private void skinAvailable(MinecraftProfileTexture.Type typeIn, ResourceLocation location, MinecraftProfileTexture profileTexture, CallbackInfo ci) {
CompletableFuture.runAsync(() -> {
// schedule parsing next tick, texture may not be uploaded at this point
HDSkinManager.INSTANCE.parseSkin(player.getGameProfile(), typeIn, location, profileTexture);
// reset the skin type because vanilla has already set it
String model = profileTexture.getMetadata("model");
((INetworkPlayerInfo) player).setSkinType(model != null ? model : "default");
});
}
}

View file

@ -8,6 +8,7 @@ import com.voxelmodpack.hdskins.INetworkPlayerInfo;
import net.minecraft.client.Minecraft;
import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.client.resources.SkinManager;
import net.minecraft.util.ResourceLocation;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@ -81,6 +82,20 @@ public abstract class MixinNetworkPlayerInfo implements INetworkPlayerInfo {
});
}
@Redirect(method = "loadPlayerTextures",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/resources/SkinManager;loadProfileTextures("
+ "Lcom/mojang/authlib/GameProfile;"
+ "Lnet/minecraft/client/resources/SkinManager$SkinAvailableCallback;"
+ "Z)V"))
private void redirectLoadPlayerTextures(SkinManager skinManager, GameProfile profile, SkinManager.SkinAvailableCallback callback,
boolean requireSecure) {
skinManager.loadProfileTextures(profile, (typeIn, location, profileTexture) -> {
HDSkinManager.INSTANCE.parseSkin(profile, typeIn, location, profileTexture, callback);
}, requireSecure);
}
@Override
public void reloadTextures() {
synchronized (this) {

View file

@ -1,5 +1,6 @@
package com.voxelmodpack.hdskins.util;
import com.google.common.util.concurrent.Runnables;
import net.minecraft.client.Minecraft;
import java.util.concurrent.Callable;
@ -32,17 +33,24 @@ public class CallableFutures {
return ret;
}
public static <U, T> BiFunction<? super T, Throwable, ? extends U> callback(Runnable c) {
public static <T> BiFunction<? super T, Throwable, Void> callback(Runnable c) {
return (o, t) -> {
c.run();
if (t != null) {
t.printStackTrace();
} else {
c.run();
}
return null;
};
}
public static void scheduleTask(Runnable task) {
public static CompletableFuture<Void> scheduleTask(Runnable task) {
// schedule a task for next tick.
executor.schedule(() -> {
Minecraft.getMinecraft().addScheduledTask(task);
}, 50, TimeUnit.MILLISECONDS);
return CompletableFuture.runAsync(Runnables.doNothing(), delayed(50, TimeUnit.MILLISECONDS))
.handleAsync(callback(task), Minecraft.getMinecraft()::addScheduledTask);
}
private static Executor delayed(long time, TimeUnit unit) {
return (task) -> executor.schedule(task, time, unit);
}
}

View file

@ -8,7 +8,6 @@
"MixinGuiMainMenu",
"MixinImageBufferDownload",
"MixinNetworkPlayerInfo",
"MixinNetworkPlayerInfo$1",
"MixinSkullRenderer"
]
}