Awkward code is awkward

This commit is contained in:
Sollace 2018-07-19 22:25:53 +02:00
parent 712c98bb6b
commit cba69ae1f5
13 changed files with 147 additions and 185 deletions

View file

@ -11,14 +11,11 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.Property;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.util.UUIDTypeAdapter;
import com.mumfrey.liteloader.core.LiteLoader; import com.mumfrey.liteloader.core.LiteLoader;
import com.mumfrey.liteloader.util.log.LiteLoaderLogger; import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import com.voxelmodpack.hdskins.gui.GuiSkins; import com.voxelmodpack.hdskins.gui.GuiSkins;
@ -31,7 +28,6 @@ import com.voxelmodpack.hdskins.skins.SkinServer;
import com.voxelmodpack.hdskins.skins.ValhallaSkinServer; import com.voxelmodpack.hdskins.skins.ValhallaSkinServer;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IImageBuffer; import net.minecraft.client.renderer.IImageBuffer;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManager;
@ -63,9 +59,6 @@ import javax.annotation.Nonnull;
public final class HDSkinManager implements IResourceManagerReloadListener { public final class HDSkinManager implements IResourceManagerReloadListener {
private static final ResourceLocation LOADING = new ResourceLocation("LOADING"); private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
.create();
private static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8); private static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
public static final ListeningExecutorService skinUploadExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); public static final ListeningExecutorService skinUploadExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
@ -91,12 +84,14 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
private List<ISkinModifier> skinModifiers = Lists.newArrayList(); private List<ISkinModifier> skinModifiers = Lists.newArrayList();
private SkinResourceManager resources = new SkinResourceManager(); private SkinResourceManager resources = new SkinResourceManager();
// private ExecutorService executor = Executors.newCachedThreadPool();
private Class<? extends GuiSkins> skinsClass = null; private Class<? extends GuiSkins> skinsClass = null;
private HDSkinManager() { public static PreviewTextureManager getPreviewTextureManager(GameProfile profile) {
return new PreviewTextureManager(INSTANCE.getGatewayServer().getPreviewTextures(profile));
}
private HDSkinManager() {
// register default skin server types // register default skin server types
addSkinServerType(LegacySkinServer.class); addSkinServerType(LegacySkinServer.class);
addSkinServerType(ValhallaSkinServer.class); addSkinServerType(ValhallaSkinServer.class);
@ -134,7 +129,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
Property textures = Iterables.getFirst(profile1.getProperties().get("textures"), null); Property textures = Iterables.getFirst(profile1.getProperties().get("textures"), null);
if (textures != null) { if (textures != null) {
String json = new String(Base64.getDecoder().decode(textures.getValue()), StandardCharsets.UTF_8); String json = new String(Base64.getDecoder().decode(textures.getValue()), StandardCharsets.UTF_8);
MinecraftTexturesPayload texturePayload = GSON.fromJson(json, MinecraftTexturesPayload.class); MinecraftTexturesPayload texturePayload = SkinServer.gson.fromJson(json, MinecraftTexturesPayload.class);
if (texturePayload != null) { if (texturePayload != null) {
// name is optional // name is optional
String name = texturePayload.getProfileName(); String name = texturePayload.getProfileName();
@ -176,75 +171,70 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
return url + (url.indexOf('?') > -1 ? '&' : '?') + Long.toString(new Date().getTime() / 1000); return url + (url.indexOf('?') > -1 ? '&' : '?') + Long.toString(new Date().getTime() / 1000);
} }
private void loadTexture(GameProfile profile, final Type type, final SkinAvailableCallback callback) { private void loadTexture(GameProfile profile, Type type, SkinAvailableCallback callback) {
if (profile.getId() != null) { if (profile.getId() == null) {
Map<Type, MinecraftProfileTexture> data = getProfileData(profile); return;
final MinecraftProfileTexture texture = data.get(type);
String skinDir = type.toString().toLowerCase() + "s/";
final ResourceLocation skin = new ResourceLocation("hdskins", skinDir + texture.getHash());
File file2 = new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash());
final IImageBuffer imagebufferdownload = type == Type.SKIN ? new ImageBufferDownloadHD() : null;
ITextureObject texObject = new ThreadDownloadImageETag(file2, bustCache(texture.getUrl()),
DefaultPlayerSkin.getDefaultSkinLegacy(),
new IImageBuffer() {
@Nonnull
@Override
public BufferedImage parseUserSkin(@Nonnull BufferedImage image) {
BufferedImage image1 = image;
if (imagebufferdownload != null) {
image1 = imagebufferdownload.parseUserSkin(image);
}
return image1 == null ? image : image1;
}
@Override
public void skinAvailable() {
if (imagebufferdownload != null) {
imagebufferdownload.skinAvailable();
}
callback.skinAvailable(type, skin, texture);
}
});
// schedule texture loading on the main thread.
TextureLoader.loadTexture(skin, texObject);
} }
MinecraftProfileTexture texture = getProfileData(profile).get(type);
String skinDir = type.toString().toLowerCase() + "s/";
ResourceLocation skin = new ResourceLocation("hdskins", skinDir + texture.getHash());
File etag = new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash());
IImageBuffer buffer = new ImageBufferDownloadHD() {
@Nonnull
@Override
public BufferedImage parseUserSkin(@Nonnull BufferedImage image) {
if (type != Type.SKIN) {
return image;
}
BufferedImage converted = super.parseUserSkin(image);
return converted == null ? image : converted;
}
}.withCallback(() -> callback.skinAvailable(type, skin, texture));
// schedule texture loading on the main thread.
TextureLoader.loadTexture(skin, new ThreadDownloadImageETag(etag, bustCache(texture.getUrl()), DefaultPlayerSkin.getDefaultSkinLegacy(), buffer));
} }
private Map<Type, MinecraftProfileTexture> loadProfileData(GameProfile profile) { private Map<Type, MinecraftProfileTexture> loadProfileData(GameProfile profile) {
Map<Type, MinecraftProfileTexture> textures = Maps.newEnumMap(Type.class); Map<Type, MinecraftProfileTexture> textures = Maps.newEnumMap(Type.class);
for (SkinServer server : skinServers) {
Optional<MinecraftTexturesPayload> profileData = server.loadProfileData(profile);
profileData.map(MinecraftTexturesPayload::getTextures).ifPresent(it -> it.forEach(textures::putIfAbsent));
if (textures.size() == Type.values().length) {
break;
}
} skinServers.forEach(server -> server
.loadProfileData(profile)
.map(MinecraftTexturesPayload::getTextures)
.ifPresent(a -> a.forEach(textures::putIfAbsent)));
return textures; return textures;
} }
public Map<Type, MinecraftProfileTexture> getProfileData(GameProfile profile) { public Map<Type, MinecraftProfileTexture> getProfileData(GameProfile profile) {
boolean was = !skins.asMap().containsKey(profile); boolean was = !skins.asMap().containsKey(profile);
Map<Type, MinecraftProfileTexture> textures = skins.getUnchecked(profile); Map<Type, MinecraftProfileTexture> textures = skins.getUnchecked(profile);
// This is the initial value. Refreshing will load it asynchronously. // This is the initial value. Refreshing will load it asynchronously.
if (was) { if (was) {
skins.refresh(profile); skins.refresh(profile);
} }
return textures; return textures;
} }
public void addSkinServerType(Class<? extends SkinServer> type) { public void addSkinServerType(Class<? extends SkinServer> type) {
Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface"); Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface");
Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract"); Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract");
ServerType st = type.getAnnotation(ServerType.class); ServerType st = type.getAnnotation(ServerType.class);
if (st == null) {
throw new IllegalArgumentException("class is not annotated with @ServerType"); Preconditions.checkArgument(st != null, "class is not annotated with @ServerType");
}
this.skinServerTypes.put(st.value(), type); skinServerTypes.put(st.value(), type);
} }
public Class<? extends SkinServer> getSkinServerClass(String type) { public Class<? extends SkinServer> getSkinServerClass(String type) {
@ -264,15 +254,11 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
this.enabled = enabled; this.enabled = enabled;
} }
public static PreviewTextureManager getPreviewTextureManager(GameProfile profile) {
return new PreviewTextureManager(INSTANCE.getGatewayServer().getPreviewTextures(profile));
}
public void addClearListener(ISkinCacheClearListener listener) { public void addClearListener(ISkinCacheClearListener listener) {
clearListeners.add(listener); clearListeners.add(listener);
} }
public static void clearSkinCache() { public void clearSkinCache() {
LiteLoaderLogger.info("Clearing local player skin cache"); LiteLoaderLogger.info("Clearing local player skin cache");
try { try {
@ -281,20 +267,17 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
TextureManager textures = Minecraft.getMinecraft().getTextureManager(); TextureManager textures = Minecraft.getMinecraft().getTextureManager();
INSTANCE.skinCache.values().stream().flatMap(m -> m.values().stream()) skinCache.values().stream().flatMap(m -> m.values().stream()).forEach(textures::deleteTexture);
.forEach(textures::deleteTexture); skinCache.clear();
INSTANCE.skinCache.clear(); skins.invalidateAll();
INSTANCE.skins.invalidateAll();
} catch (IOException var1) { } catch (IOException var1) {
var1.printStackTrace(); var1.printStackTrace();
} }
INSTANCE.clearListeners = INSTANCE.clearListeners.stream() clearListeners = clearListeners.stream().filter(this::onSkinCacheCleared).collect(Collectors.toList());
.filter(HDSkinManager::onSkinCacheCleared)
.collect(Collectors.toList());
} }
private static boolean onSkinCacheCleared(ISkinCacheClearListener callback) { private boolean onSkinCacheCleared(ISkinCacheClearListener callback) {
try { try {
return callback.onSkinCacheCleared(); return callback.onSkinCacheCleared();
} catch (Exception e) { } catch (Exception e) {
@ -313,6 +296,12 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
return loc == null ? res : loc; return loc == null ? res : loc;
} }
public void convertSkin(BufferedImage image) {
Graphics graphics = image.getGraphics();
convertSkin(image, graphics);
graphics.dispose();
}
public void convertSkin(BufferedImage image, Graphics dest) { public void convertSkin(BufferedImage image, Graphics dest) {
skinModifiers.forEach(a -> a.convertSkin(image, dest)); skinModifiers.forEach(a -> a.convertSkin(image, dest));
} }

View file

@ -3,6 +3,7 @@ package com.voxelmodpack.hdskins;
import net.minecraft.client.renderer.IImageBuffer; import net.minecraft.client.renderer.IImageBuffer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -12,6 +13,13 @@ public class ImageBufferDownloadHD implements IImageBuffer {
private Graphics graphics; private Graphics graphics;
private BufferedImage image; private BufferedImage image;
private Runnable callback;
public ImageBufferDownloadHD withCallback(Runnable callback) {
this.callback = callback;
return this;
}
@Override @Override
@Nullable @Nullable
@SuppressWarnings({"SuspiciousNameCombination", "NullableProblems"}) @SuppressWarnings({"SuspiciousNameCombination", "NullableProblems"})
@ -19,6 +27,7 @@ public class ImageBufferDownloadHD implements IImageBuffer {
if (downloadedImage == null) { if (downloadedImage == null) {
return null; return null;
} }
int imageWidth = downloadedImage.getWidth(); int imageWidth = downloadedImage.getWidth();
int imageHeight = downloadedImage.getHeight(); int imageHeight = downloadedImage.getHeight();
if (imageHeight == imageWidth) { if (imageHeight == imageWidth) {
@ -61,5 +70,8 @@ public class ImageBufferDownloadHD implements IImageBuffer {
@Override @Override
public void skinAvailable() { public void skinAvailable() {
if (callback != null) {
callback.run();
}
} }
} }

View file

@ -55,7 +55,7 @@ public class LiteModHDSkins implements InitCompleteListener, ViewportListener, C
@Override @Override
public void upgradeSettings(String version, File configPath, File oldConfigPath) { public void upgradeSettings(String version, File configPath, File oldConfigPath) {
HDSkinManager.clearSkinCache(); HDSkinManager.INSTANCE.clearSkinCache();
} }
@Override @Override

View file

@ -24,7 +24,7 @@ public class PreviewTexture extends ThreadDownloadImageData {
} }
public boolean isTextureUploaded() { public boolean isTextureUploaded() {
return uploaded && this.getGlTextureId() > -1; return uploaded && getGlTextureId() > -1;
} }
@Override @Override

View file

@ -6,10 +6,9 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IImageBuffer; import net.minecraft.client.renderer.IImageBuffer;
import net.minecraft.client.resources.SkinManager; import net.minecraft.client.resources.SkinManager.SkinAvailableCallback;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import java.awt.image.BufferedImage;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -26,37 +25,21 @@ public class PreviewTextureManager {
this.textures = textures; this.textures = textures;
} }
private IImageBuffer getPreviewImageBuffer(MinecraftProfileTexture texture, ResourceLocation location, Type type, SkinManager.SkinAvailableCallback callback) {
if (type != Type.SKIN) {
return null;
}
IImageBuffer buffer = new ImageBufferDownloadHD();
return new IImageBuffer() {
@Override
@Nullable
public BufferedImage parseUserSkin(BufferedImage image) {
return buffer.parseUserSkin(image);
}
@Override
public void skinAvailable() {
if (callback != null) {
callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap()));
}
}
};
}
@Nullable @Nullable
public PreviewTexture getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinManager.SkinAvailableCallback callback) { public PreviewTexture getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
if (!textures.containsKey(type)) { if (!textures.containsKey(type)) {
return null; return null;
} }
MinecraftProfileTexture texture = textures.get(type); MinecraftProfileTexture texture = textures.get(type);
PreviewTexture skinTexture = new PreviewTexture(texture, def, getPreviewImageBuffer(texture, location, type, callback));
IImageBuffer buffer = type != Type.SKIN ? null : new ImageBufferDownloadHD().withCallback(() -> {
if (callback != null) {
callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap()));
}
});
PreviewTexture skinTexture = new PreviewTexture(texture, def, buffer);
Minecraft.getMinecraft().getTextureManager().loadTexture(location, skinTexture); Minecraft.getMinecraft().getTextureManager().loadTexture(location, skinTexture);

View file

@ -12,9 +12,9 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mumfrey.liteloader.util.log.LiteLoaderLogger; import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import com.voxelmodpack.hdskins.HDSkinManager; import com.voxelmodpack.hdskins.HDSkinManager;
import com.voxelmodpack.hdskins.skins.SkinServer;
import com.voxelmodpack.hdskins.skins.SkinUploadResponse; import com.voxelmodpack.hdskins.skins.SkinUploadResponse;
import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFilePNG; import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFilePNG;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
@ -93,20 +93,23 @@ public class GuiSkins extends GuiScreen {
private boolean thinArmType = false; private boolean thinArmType = false;
public GuiSkins() { public GuiSkins() {
instance = this;
Minecraft minecraft = Minecraft.getMinecraft(); Minecraft minecraft = Minecraft.getMinecraft();
GameProfile profile = minecraft.getSession().getProfile(); GameProfile profile = minecraft.getSession().getProfile();
localPlayer = getModel(profile); localPlayer = getModel(profile);
remotePlayer = getModel(profile); remotePlayer = getModel(profile);
RenderManager rm = Minecraft.getMinecraft().getRenderManager();
RenderManager rm = minecraft.getRenderManager();
rm.renderEngine = minecraft.getTextureManager(); rm.renderEngine = minecraft.getTextureManager();
rm.options = minecraft.gameSettings; rm.options = minecraft.gameSettings;
rm.renderViewEntity = localPlayer; rm.renderViewEntity = localPlayer;
reloadRemoteSkin();
fetchingSkin = true;
instance = this; reloadRemoteSkin();
fetchingSkin = true;
panorama = new CubeMap(this); panorama = new CubeMap(this);
initPanorama(); initPanorama();
@ -126,6 +129,7 @@ public class GuiSkins extends GuiScreen {
if (!(Keyboard.isKeyDown(Keyboard.KEY_LEFT) || Keyboard.isKeyDown(Keyboard.KEY_RIGHT))) { if (!(Keyboard.isKeyDown(Keyboard.KEY_LEFT) || Keyboard.isKeyDown(Keyboard.KEY_RIGHT))) {
updateCounter++; updateCounter++;
} }
panorama.update(); panorama.update();
localPlayer.updateModel(); localPlayer.updateModel();
@ -186,7 +190,9 @@ public class GuiSkins extends GuiScreen {
@Override @Override
public void initGui() { public void initGui() {
enableDnd(); GLWindow.current().setDropTargetListener((FileDropListener) files -> {
files.stream().findFirst().ifPresent(instance::loadLocalFile);
});
panorama.init(); panorama.init();
@ -215,18 +221,12 @@ public class GuiSkins extends GuiScreen {
} }
private void enableDnd() {
GLWindow.current().setDropTargetListener((FileDropListener) files -> {
files.stream().findFirst().ifPresent(instance::loadLocalFile);
});
}
@Override @Override
public void onGuiClosed() { public void onGuiClosed() {
super.onGuiClosed(); super.onGuiClosed();
localPlayer.releaseTextures(); localPlayer.releaseTextures();
remotePlayer.releaseTextures(); remotePlayer.releaseTextures();
HDSkinManager.clearSkinCache(); HDSkinManager.INSTANCE.clearSkinCache();
GLWindow.current().clearDropTargetListener(); GLWindow.current().clearDropTargetListener();
} }
@ -438,8 +438,7 @@ public class GuiSkins extends GuiScreen {
drawHoveringText(I18n.format(text), mouseX, y); drawHoveringText(I18n.format(text), mouseX, y);
} }
if (btnAbout.isMouseOver()) { if (btnAbout.isMouseOver()) {
SkinServer gateway = HDSkinManager.INSTANCE.getGatewayServer(); drawHoveringText(Splitter.on("\r\n").splitToList(HDSkinManager.INSTANCE.getGatewayServer().toString()), mouseX, mouseY);
drawHoveringText(Splitter.on("\r\n").splitToList(gateway.toString()), mouseX, mouseY);
} }
if (fetchingSkin) { if (fetchingSkin) {

View file

@ -41,7 +41,7 @@ public class HDSkinsConfigPanel implements ConfigPanel {
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
if (button.mousePressed(mc, mouseX, mouseY)) { if (button.mousePressed(mc, mouseX, mouseY)) {
HDSkinManager.clearSkinCache(); HDSkinManager.INSTANCE.clearSkinCache();
} else if (checkbox.mousePressed(mc, mouseX, mouseY)) { } else if (checkbox.mousePressed(mc, mouseX, mouseY)) {
checkbox.checked = !checkbox.checked; checkbox.checked = !checkbox.checked;
mod.experimentalSkinDrop = checkbox.checked; mod.experimentalSkinDrop = checkbox.checked;

View file

@ -8,7 +8,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.awt.Graphics;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@Mixin(ImageBufferDownload.class) @Mixin(ImageBufferDownload.class)
@ -20,11 +19,7 @@ public abstract class MixinImageBufferDownload implements IImageBuffer {
private void update(BufferedImage image, CallbackInfoReturnable<BufferedImage> ci) { private void update(BufferedImage image, CallbackInfoReturnable<BufferedImage> ci) {
// convert skins from mojang server // convert skins from mojang server
if (image.getHeight() == 32) { if (image.getHeight() == 32) {
BufferedImage image2 = ci.getReturnValue(); HDSkinManager.INSTANCE.convertSkin(ci.getReturnValue());
Graphics graphics = image2.getGraphics();
HDSkinManager.INSTANCE.convertSkin(image2, graphics);
graphics.dispose();
} }
} }
} }

View file

@ -12,8 +12,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Optional;
@Mixin(NetworkPlayerInfo.class) @Mixin(NetworkPlayerInfo.class)
public abstract class MixinPlayerInfo { public abstract class MixinPlayerInfo {
@ -42,8 +40,7 @@ public abstract class MixinPlayerInfo {
} }
private void getTextureLocation(CallbackInfoReturnable<ResourceLocation> ci, Type type) { private void getTextureLocation(CallbackInfoReturnable<ResourceLocation> ci, Type type) {
Optional<ResourceLocation> texture = HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), type, true); HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), type, true).ifPresent(ci::setReturnValue);
texture.ifPresent(ci::setReturnValue);
} }
@Inject(method = "getSkinType", @Inject(method = "getSkinType",
@ -52,13 +49,11 @@ public abstract class MixinPlayerInfo {
private void getSkinType(CallbackInfoReturnable<String> ci) { private void getSkinType(CallbackInfoReturnable<String> ci) {
MinecraftProfileTexture skin = HDSkinManager.INSTANCE.getProfileData(getGameProfile()).get(Type.SKIN); MinecraftProfileTexture skin = HDSkinManager.INSTANCE.getProfileData(getGameProfile()).get(Type.SKIN);
if (skin != null) { if (skin != null) {
String type = skin.getMetadata("model"); HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), Type.SKIN, false).ifPresent(res -> {
if (type == null) String type = skin.getMetadata("model");
type = "default";
String type1 = type;
Optional<ResourceLocation> texture = HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), Type.SKIN, false);
texture.ifPresent((res) -> ci.setReturnValue(type1)); ci.setReturnValue(type == null ? "default" : type);
});
} }
} }
} }

View file

@ -3,6 +3,7 @@ package com.voxelmodpack.hdskins.mixin;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.voxelmodpack.hdskins.HDSkinManager; import com.voxelmodpack.hdskins.HDSkinManager;
import net.minecraft.client.renderer.tileentity.TileEntitySkullRenderer; import net.minecraft.client.renderer.tileentity.TileEntitySkullRenderer;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntitySkull; import net.minecraft.tileentity.TileEntitySkull;
@ -13,27 +14,20 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Optional;
@Mixin(TileEntitySkullRenderer.class) @Mixin(TileEntitySkullRenderer.class)
public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileEntitySkull> { public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileEntitySkull> {
@Redirect( @Redirect(method = "renderSkull",
method = "renderSkull", at = @At(value = "INVOKE",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/tileentity/TileEntitySkullRenderer;bindTexture(Lnet/minecraft/util/ResourceLocation;)V", target = "Lnet/minecraft/client/renderer/tileentity/TileEntitySkullRenderer;bindTexture(Lnet/minecraft/util/ResourceLocation;)V",
ordinal = 4)) ordinal = 4))
private void onBindTexture(TileEntitySkullRenderer tesr, ResourceLocation rl, float x, float y, float z, EnumFacing facing, float rotation, int meta, private void onBindTexture(TileEntitySkullRenderer tesr, ResourceLocation rl, float x, float y, float z, // ow my back
@Nullable GameProfile profile, int p_180543_8_, float ticks) { EnumFacing facing, float rotation, int meta, @Nullable GameProfile profile, int a, float ticks) {
if (profile != null) { if (profile != null) {
Optional<ResourceLocation> skin = HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true); bindTexture(HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true).orElse(rl));
if (skin.isPresent()) } else {
// rebind
bindTexture(skin.get());
else
bindTexture(rl);
} else
bindTexture(rl); bindTexture(rl);
}
} }
} }

View file

@ -21,7 +21,7 @@ public class ImageLoader implements Supplier<ResourceLocation> {
private final ResourceLocation original; private final ResourceLocation original;
public ImageLoader(ResourceLocation loc) { public ImageLoader(ResourceLocation loc) {
this.original = loc; original = loc;
} }
@Override @Override
@ -49,7 +49,6 @@ public class ImageLoader implements Supplier<ResourceLocation> {
@Nullable @Nullable
private static BufferedImage getImage(ResourceLocation res) { private static BufferedImage getImage(ResourceLocation res) {
try (InputStream in = mc.getResourceManager().getResource(res).getInputStream()) { try (InputStream in = mc.getResourceManager().getResource(res).getInputStream()) {
return TextureUtil.readBufferedImage(in); return TextureUtil.readBufferedImage(in);
} catch (IOException e) { } catch (IOException e) {
@ -59,9 +58,9 @@ public class ImageLoader implements Supplier<ResourceLocation> {
@Nullable @Nullable
private ResourceLocation loadSkin(BufferedImage image) { private ResourceLocation loadSkin(BufferedImage image) {
ResourceLocation conv = new ResourceLocation(original.getResourceDomain() + "-converted", original.getResourcePath()); ResourceLocation conv = new ResourceLocation(original.getResourceDomain() + "-converted", original.getResourcePath());
boolean success = mc.getTextureManager().loadTexture(conv, new DynamicTextureImage(image)); boolean success = mc.getTextureManager().loadTexture(conv, new DynamicTextureImage(image));
return success ? conv : null; return success ? conv : null;
} }

View file

@ -17,6 +17,7 @@ import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -25,8 +26,9 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
public class SkinResourceManager implements IResourceManagerReloadListener { public class SkinResourceManager implements IResourceManagerReloadListener {
private final Gson GSON = new Gson();
private ExecutorService executor = Executors.newSingleThreadExecutor(); private ExecutorService executor;
private Map<UUID, Skin> uuidSkins = Maps.newHashMap(); private Map<UUID, Skin> uuidSkins = Maps.newHashMap();
private Map<String, Skin> namedSkins = Maps.newHashMap(); private Map<String, Skin> namedSkins = Maps.newHashMap();
@ -41,15 +43,16 @@ public class SkinResourceManager implements IResourceManagerReloadListener {
executor = Executors.newSingleThreadExecutor(); executor = Executors.newSingleThreadExecutor();
inProgress.clear(); inProgress.clear();
converted.clear(); converted.clear();
for (String domain : resourceManager.getResourceDomains()) { for (String domain : resourceManager.getResourceDomains()) {
try { try {
for (IResource res : resourceManager.getAllResources(new ResourceLocation(domain, "textures/skins/skins.json"))) { for (IResource res : resourceManager.getAllResources(new ResourceLocation(domain, "textures/skins/skins.json"))) {
try { try {
SkinData data = getSkinData(res.getInputStream()); for (Skin s : getSkinData(res.getInputStream())) {
for (Skin s : data.skins) {
if (s.uuid != null) { if (s.uuid != null) {
uuidSkins.put(s.uuid, s); uuidSkins.put(s.uuid, s);
} }
if (s.name != null) { if (s.name != null) {
namedSkins.put(s.name, s); namedSkins.put(s.name, s);
} }
@ -58,16 +61,13 @@ public class SkinResourceManager implements IResourceManagerReloadListener {
LiteLoaderLogger.warning(je, "Invalid skins.json in %s", res.getResourcePackName()); LiteLoaderLogger.warning(je, "Invalid skins.json in %s", res.getResourcePackName());
} }
} }
} catch (IOException e) { } catch (IOException ignored) { }
// ignore
}
} }
} }
private SkinData getSkinData(InputStream stream) { private List<Skin> getSkinData(InputStream stream) {
try { try {
return new Gson().fromJson(new InputStreamReader(stream), SkinData.class); return GSON.fromJson(new InputStreamReader(stream), SkinData.class).skins;
} finally { } finally {
IOUtils.closeQuietly(stream); IOUtils.closeQuietly(stream);
} }
@ -75,16 +75,14 @@ public class SkinResourceManager implements IResourceManagerReloadListener {
@Nullable @Nullable
public ResourceLocation getPlayerTexture(GameProfile profile, Type type) { public ResourceLocation getPlayerTexture(GameProfile profile, Type type) {
if (type != Type.SKIN) if (type == Type.SKIN) {
// not supported Skin skin = getSkin(profile);
return null; if (skin != null) {
return getConvertedResource(skin.getTexture());
Skin skin = getSkin(profile); }
if (skin != null) {
final ResourceLocation res = skin.getTexture();
return getConvertedResource(res);
} }
return null;
return null; // not supported
} }
/** /**
@ -99,31 +97,29 @@ public class SkinResourceManager implements IResourceManagerReloadListener {
return converted.get(res); return converted.get(res);
} }
private void loadSkinResource(@Nullable final ResourceLocation res) { /**
* read and convert in a new thread
*/
private void loadSkinResource(@Nullable ResourceLocation res) {
if (res != null) { if (res != null) {
// read and convert in a new thread inProgress.computeIfAbsent(res, r -> CompletableFuture.supplyAsync(new ImageLoader(r), executor).whenComplete((loc, t) -> {
this.inProgress.computeIfAbsent(res, r -> CompletableFuture.supplyAsync(new ImageLoader(r), executor) if (loc != null) {
.whenComplete((loc, t) -> { converted.put(res, loc);
if (loc != null) } else {
converted.put(res, loc); LogManager.getLogger().warn("Errored while processing {}. Using original.", res, t);
else { converted.put(res, res);
LogManager.getLogger().warn("Errored while processing {}. Using original.", res, t); }
converted.put(res, res); }));
}
}));
} }
} }
@Nullable @Nullable
private Skin getSkin(GameProfile profile) { private Skin getSkin(GameProfile profile) {
Skin skin = this.uuidSkins.get(profile.getId()); Skin skin = uuidSkins.get(profile.getId());
if (skin == null) { if (skin != null) {
skin = this.namedSkins.get(profile.getName()); return skin;
} }
return skin;
}
return namedSkins.get(profile.getName());
}
} }

View file

@ -25,7 +25,7 @@ import javax.annotation.Nullable;
public interface SkinServer extends Exposable { public interface SkinServer extends Exposable {
static final Gson gson = new GsonBuilder() public static final Gson gson = new GsonBuilder()
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) .registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
.create(); .create();