Correct more really awkward code formatting decisions (I blame Mumfrey)

This commit is contained in:
Sollace 2018-07-19 22:25:53 +02:00
parent 0d47368bce
commit dfd3c6f2ea
14 changed files with 192 additions and 197 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;
@ -32,7 +29,6 @@ import com.voxelmodpack.hdskins.util.AsyncCacheLoader;
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;
@ -61,12 +57,9 @@ import java.util.stream.Collectors;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public final class HDSkinManager implements IResourceManagerReloadListener { public final class HDSkinManager implements IResourceManagerReloadListener, ISkinModifier {
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());
@ -92,12 +85,18 @@ 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 void clearSkinCache() {
INSTANCE.clearSKinCache();
}
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);
@ -135,7 +134,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();
@ -177,75 +176,77 @@ 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); }
MinecraftProfileTexture texture = getProfileData(profile).get(type);
String skinDir = type.toString().toLowerCase() + "s/"; 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; ResourceLocation skin = new ResourceLocation("hdskins", skinDir + texture.getHash());
ITextureObject texObject = new ThreadDownloadImageETag(file2, bustCache(texture.getUrl()), File etag = new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash());
DefaultPlayerSkin.getDefaultSkinLegacy(),
new IImageBuffer() { IImageBuffer buffer = new ImageBufferDownloadHD() {
@Nonnull @Nonnull
@Override @Override
public BufferedImage parseUserSkin(@Nonnull BufferedImage image) { public BufferedImage parseUserSkin(@Nonnull BufferedImage image) {
BufferedImage image1 = image; if (type != Type.SKIN) {
if (imagebufferdownload != null) { return image;
image1 = imagebufferdownload.parseUserSkin(image);
}
return image1 == null ? image : image1;
} }
@Override BufferedImage converted = super.parseUserSkin(image);
public void skinAvailable() {
if (imagebufferdownload != null) { return converted == null ? image : converted;
imagebufferdownload.skinAvailable();
} }
callback.skinAvailable(type, skin, texture); }.withCallback(() -> callback.skinAvailable(type, skin, texture));
}
});
// schedule texture loading on the main thread. // schedule texture loading on the main thread.
TextureLoader.loadTexture(skin, texObject); 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) { for (SkinServer server : skinServers) {
Optional<MinecraftTexturesPayload> profileData = server.loadProfileData(profile); Optional<MinecraftTexturesPayload> profileData = server.loadProfileData(profile);
profileData.map(MinecraftTexturesPayload::getTextures).ifPresent(it -> it.forEach(textures::putIfAbsent));
if (profileData.isPresent()) {
profileData.get().getTextures().forEach(textures::putIfAbsent);
}
if (textures.size() == Type.values().length) { if (textures.size() == Type.values().length) {
break; return textures;
} }
} }
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) {
@ -265,15 +266,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() { private void clearSKinCache() {
LiteLoaderLogger.info("Clearing local player skin cache"); LiteLoaderLogger.info("Clearing local player skin cache");
try { try {
@ -282,20 +279,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) {
@ -314,6 +308,13 @@ 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();
}
@Override
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

@ -0,0 +1,13 @@
package com.voxelmodpack.hdskins;
/**
* Callback for when a skin is loaded.
*
*/
@FunctionalInterface
public interface ISkinAvailableCallback {
/**
* Called when a skin loads.
*/
void skinAvailable();
}

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 ISkinAvailableCallback callback;
public ImageBufferDownloadHD withCallback(ISkinAvailableCallback 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.skinAvailable();
}
} }
} }

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 @Nullable
public BufferedImage parseUserSkin(BufferedImage image) { public PreviewTexture getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
return buffer.parseUserSkin(image);
}
@Override
public void skinAvailable() {
if (callback != null) {
callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap()));
}
}
};
}
@Nullable
public PreviewTexture getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinManager.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

@ -93,19 +93,22 @@ 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();
@ -125,6 +128,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();
@ -185,7 +189,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,12 +221,6 @@ 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();
@ -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

@ -8,25 +8,18 @@ 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)
public abstract class MixinImageBufferDownload implements IImageBuffer { public abstract class MixinImageBufferDownload implements IImageBuffer {
@Inject( // convert skins from the mojang server
method = "parseUserSkin(Ljava/awt/image/BufferedImage;)Ljava/awt/image/BufferedImage;", @Inject(method = "parseUserSkin(Ljava/awt/image/BufferedImage;)Ljava/awt/image/BufferedImage;",
at = @At("RETURN"), at = @At("RETURN"),
cancellable = true) cancellable = true)
private void update(BufferedImage image, CallbackInfoReturnable<BufferedImage> ci) { private void update(BufferedImage image, CallbackInfoReturnable<BufferedImage> ci) {
// convert skins from mojang server if (image.getHeight() == 32) {
BufferedImage image2 = ci.getReturnValue(); HDSkinManager.INSTANCE.convertSkin(ci.getReturnValue());
boolean isLegacy = image.getHeight() == 32;
if (isLegacy) {
Graphics graphics = image2.getGraphics();
HDSkinManager.INSTANCE.convertSkin(image2, graphics);
graphics.dispose();
} }
} }
} }

View file

@ -12,32 +12,27 @@ 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 {
@Shadow @Shadow
public abstract GameProfile getGameProfile(); public abstract GameProfile getGameProfile();
@Inject( @Inject(method = "getLocationSkin",
method = "getLocationSkin",
cancellable = true, cancellable = true,
at = @At("RETURN")) at = @At("RETURN"))
private void getLocationSkin(CallbackInfoReturnable<ResourceLocation> ci) { private void getLocationSkin(CallbackInfoReturnable<ResourceLocation> ci) {
getTextureLocation(ci, Type.SKIN); getTextureLocation(ci, Type.SKIN);
} }
@Inject( @Inject(method = "getLocationCape",
method = "getLocationCape",
cancellable = true, cancellable = true,
at = @At("RETURN")) at = @At("RETURN"))
private void getLocationCape(CallbackInfoReturnable<ResourceLocation> ci) { private void getLocationCape(CallbackInfoReturnable<ResourceLocation> ci) {
getTextureLocation(ci, Type.CAPE); getTextureLocation(ci, Type.CAPE);
} }
@Inject( @Inject(method = "getLocationElytra",
method = "getLocationElytra",
cancellable = true, cancellable = true,
at = @At("RETURN")) at = @At("RETURN"))
private void getLocationElytra(CallbackInfoReturnable<ResourceLocation> ci) { private void getLocationElytra(CallbackInfoReturnable<ResourceLocation> ci) {
@ -45,24 +40,20 @@ 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( @Inject(method = "getSkinType",
method = "getSkinType",
cancellable = true, cancellable = true,
at = @At("RETURN")) at = @At("RETURN"))
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) {
HDSkinManager.INSTANCE.getSkinLocation(getGameProfile(), Type.SKIN, false).ifPresent(res -> {
String type = skin.getMetadata("model"); String type = skin.getMetadata("model");
if (type == null)
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,8 @@ 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 com.voxelmodpack.hdskins.util.Optionals;
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 +15,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, EnumFacing facing, float rotation, int meta,
@Nullable GameProfile profile, int p_180543_8_, float ticks) { @Nullable GameProfile profile, int a, float ticks) {
if (profile != null) { if (profile != null) {
Optional<ResourceLocation> skin = HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true); bindTexture(Optionals.getOrDefault(HDSkinManager.INSTANCE.getSkinLocation(profile, Type.SKIN, true), 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 List<Skin> getSkinData(InputStream stream) {
private SkinData 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
return null;
Skin skin = getSkin(profile); Skin skin = getSkin(profile);
if (skin != null) { if (skin != null) {
final ResourceLocation res = skin.getTexture(); return getConvertedResource(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) -> {
if (loc != null)
converted.put(res, loc); converted.put(res, loc);
else { } else {
LogManager.getLogger().warn("Errored while processing {}. Using original.", res, t); LogManager.getLogger().warn("Errored while processing {}. Using original.", res, t);
converted.put(res, res); 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();

View file

@ -21,12 +21,9 @@ public abstract class ThreadOpenFile extends Thread {
*/ */
protected final IOpenFileCallback parentScreen; protected final IOpenFileCallback parentScreen;
private JFileChooser fileDialog;
private static String lastChosenFile = null; private static String lastChosenFile = null;
protected ThreadOpenFile(Minecraft minecraft, String dialogTitle, IOpenFileCallback callback) protected ThreadOpenFile(Minecraft minecraft, String dialogTitle, IOpenFileCallback callback) throws IllegalStateException {
throws IllegalStateException {
if (minecraft.isFullScreen()) { if (minecraft.isFullScreen()) {
throw new IllegalStateException("Cannot open an awt window whilst minecraft is in full screen mode!"); throw new IllegalStateException("Cannot open an awt window whilst minecraft is in full screen mode!");
} }
@ -37,13 +34,13 @@ public abstract class ThreadOpenFile extends Thread {
@Override @Override
public void run() { public void run() {
fileDialog = new JFileChooser(); JFileChooser fileDialog = new JFileChooser();
fileDialog.setDialogTitle(this.dialogTitle); fileDialog.setDialogTitle(dialogTitle);
if (lastChosenFile != null) { if (lastChosenFile != null) {
fileDialog.setSelectedFile(new File(lastChosenFile)); fileDialog.setSelectedFile(new File(lastChosenFile));
} }
fileDialog.setFileFilter(this.getFileFilter()); fileDialog.setFileFilter(getFileFilter());
int dialogResult = fileDialog.showOpenDialog(InternalDialog.getAWTContext()); int dialogResult = fileDialog.showOpenDialog(InternalDialog.getAWTContext());
@ -53,7 +50,7 @@ public abstract class ThreadOpenFile extends Thread {
lastChosenFile = f.getAbsolutePath(); lastChosenFile = f.getAbsolutePath();
} }
this.parentScreen.onFileOpenDialogClosed(fileDialog, dialogResult); parentScreen.onFileOpenDialogClosed(fileDialog, dialogResult);
} }
/** /**

View file

@ -0,0 +1,16 @@
package com.voxelmodpack.hdskins.util;
import java.util.Optional;
/**
* Silly optionals
*/
public final class Optionals {
public static <T> T nullableOf(Optional<T> optional) {
return getOrDefault(optional, null);
}
public static <T> T getOrDefault(Optional<T> optional, T def) {
return optional.isPresent() ? optional.get() : def;
}
}