Format this to better convery what it's _trying_ to do. Killjoy pls

This commit is contained in:
Sollace 2018-08-10 12:28:18 +02:00
parent 0e530d9572
commit cddca0e1ea
6 changed files with 170 additions and 158 deletions

View file

@ -26,7 +26,6 @@ import com.voxelmodpack.hdskins.skins.SkinServer;
import com.voxelmodpack.hdskins.skins.ValhallaSkinServer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IImageBuffer;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.client.resources.IResourceManager;
@ -88,12 +87,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
private List<ISkinModifier> skinModifiers = Lists.newArrayList();
private SkinResourceManager resources = new SkinResourceManager();
// private ExecutorService executor = Executors.newCachedThreadPool();
private Class<? extends GuiSkins> skinsClass = null;
private HDSkinManager() {
// register default skin server types
addSkinServerType(LegacySkinServer.class);
addSkinServerType(ValhallaSkinServer.class);
@ -173,46 +170,40 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
return url + (url.indexOf('?') > -1 ? '&' : '?') + Long.toString(new Date().getTime() / 1000);
}
private void loadTexture(GameProfile profile, final Type type, final SkinAvailableCallback callback) {
if (profile.getId() != null) {
Map<Type, MinecraftProfileTexture> data = getProfileData(profile);
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);
private void loadTexture(GameProfile profile, Type type, SkinAvailableCallback callback) {
if (profile.getId() == null) {
return;
}
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) {
Map<Type, MinecraftProfileTexture> textures = Maps.newEnumMap(Type.class);
for (SkinServer server : skinServers) {
try {
server.loadProfileData(profile).getTextures().forEach(textures::putIfAbsent);
@ -222,43 +213,47 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
} catch (IOException e) {
LogManager.getLogger().trace(e);
}
}
return textures;
}
public Map<Type, MinecraftProfileTexture> getProfileData(GameProfile profile) {
boolean was = !skins.asMap().containsKey(profile);
Map<Type, MinecraftProfileTexture> textures = skins.getUnchecked(profile);
// This is the initial value. Refreshing will load it asynchronously.
if (was) {
skins.refresh(profile);
}
return textures;
}
public void addSkinServerType(Class<? extends SkinServer> type) {
Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface");
Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract");
ServerType st = type.getAnnotation(ServerType.class);
if (st == null) {
throw new IllegalArgumentException("class is not annotated with @ServerType");
}
this.skinServerTypes.put(st.value(), type);
Preconditions.checkArgument(st != null, "class is not annotated with @ServerType");
skinServerTypes.put(st.value(), type);
}
public Class<? extends SkinServer> getSkinServerClass(String type) {
return this.skinServerTypes.get(type);
return skinServerTypes.get(type);
}
public void addSkinServer(SkinServer skinServer) {
this.skinServers.add(skinServer);
skinServers.add(skinServer);
}
// TODO: Why is this deprecated?
@Deprecated
public SkinServer getGatewayServer() {
return this.skinServers.get(0);
return skinServers.get(0);
}
public void setEnabled(boolean enabled) {
@ -266,7 +261,9 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
}
public static CompletableFuture<PreviewTextureManager> getPreviewTextureManager(GameProfile profile) {
return INSTANCE.getGatewayServer().getPreviewTextures(profile).thenApply(PreviewTextureManager::new);
return INSTANCE.getGatewayServer().getPreviewTextures(profile).thenApply(mcu -> {
return new PreviewTextureManager(mcu.getTextures());
});
}
public void addClearListener(ISkinCacheClearListener listener) {
@ -279,6 +276,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
try {
FileUtils.deleteDirectory(new File(LiteLoader.getAssetsDirectory(), "skins"));
FileUtils.deleteDirectory(new File(LiteLoader.getAssetsDirectory(), "hd"));
TextureManager textures = Minecraft.getMinecraft().getTextureManager();
skinCache.values().stream()
.flatMap(m -> m.values().stream())
@ -313,14 +311,18 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
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) {
for (ISkinModifier skin : skinModifiers) {
skin.convertSkin(image, dest);
}
skinModifiers.forEach(a -> a.convertSkin(image, dest));
}
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
this.resources.onResourceManagerReload(resourceManager);
resources.onResourceManagerReload(resourceManager);
}
}

View file

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

View file

@ -6,26 +6,31 @@ import net.minecraft.util.ResourceLocation;
import javax.annotation.Nullable;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
public class PreviewTexture extends ThreadDownloadImageData {
private boolean uploaded;
private String model;
public PreviewTexture(@Nullable String model, String url, ResourceLocation fallbackTexture, @Nullable IImageBuffer imageBuffer) {
super(null, url, fallbackTexture, imageBuffer);
public PreviewTexture(MinecraftProfileTexture texture, ResourceLocation fallbackTexture, @Nullable IImageBuffer imageBuffer) {
super(null, texture.getUrl(), fallbackTexture, imageBuffer);
this.model = model == null ? "default" : model;
model = texture.getMetadata("model");
if (model == null) {
model = "default";
}
}
public boolean isTextureUploaded() {
return uploaded && this.getGlTextureId() > -1;
return uploaded && getGlTextureId() > -1;
}
@Override
public void deleteGlTexture() {
super.deleteGlTexture();
this.uploaded = true;
uploaded = true;
}
public boolean hasModel() {
@ -35,4 +40,8 @@ public class PreviewTexture extends ThreadDownloadImageData {
public boolean usesThinArms() {
return "thin".equals(model);
}
public String getModel() {
return model;
}
}

View file

@ -2,12 +2,13 @@ package com.voxelmodpack.hdskins;
import com.google.common.collect.Maps;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import net.minecraft.client.Minecraft;
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 java.awt.image.BufferedImage;
import java.util.Map;
import javax.annotation.Nullable;
@ -18,37 +19,29 @@ import javax.annotation.Nullable;
*/
public class PreviewTextureManager {
private final Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures;
private final Map<Type, MinecraftProfileTexture> textures;
PreviewTextureManager(MinecraftTexturesPayload payload) {
this.textures = payload.getTextures();
PreviewTextureManager(Map<Type, MinecraftProfileTexture> textures) {
this.textures = textures;
}
@Nullable
public PreviewTexture getPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def,
@Nullable SkinManager.SkinAvailableCallback callback) {
public PreviewTexture getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
if (!textures.containsKey(type)) {
return null;
}
MinecraftProfileTexture texture = textures.get(type);
IImageBuffer buffer = new ImageBufferDownloadHD();
PreviewTexture skinTexture = new PreviewTexture(texture.getMetadata("model"), texture.getUrl(), def,
type == MinecraftProfileTexture.Type.SKIN ? 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()));
}
}
} : null);
IImageBuffer buffer = type != Type.SKIN ? null : new ImageBufferDownloadHD().withCallback(() -> {
if (callback != null) {
callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap()));
}
});
TextureLoader.loadTexture(location, skinTexture);
PreviewTexture skinTexture = new PreviewTexture(texture, def, buffer);
Minecraft.getMinecraft().getTextureManager().loadTexture(location, skinTexture);
return skinTexture;
}

View file

@ -2,6 +2,9 @@ package com.voxelmodpack.hdskins;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.voxelmodpack.hdskins.skins.MoreHttpResponses;
import com.voxelmodpack.hdskins.skins.NetClient;
import net.minecraft.client.renderer.IImageBuffer;
import net.minecraft.client.renderer.texture.SimpleTexture;
import net.minecraft.client.renderer.texture.TextureUtil;
@ -10,12 +13,8 @@ import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.FileUtils;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -36,46 +35,48 @@ public class ThreadDownloadImageETag extends SimpleTexture {
private final File cacheFile;
private final File eTagFile;
private final String imageUrl;
@Nullable
private final IImageBuffer imageBuffer;
@Nullable
private BufferedImage bufferedImage;
@Nullable
private Thread imageThread;
private boolean textureUploaded;
public ThreadDownloadImageETag(@Nonnull File cacheFileIn, String imageUrlIn, ResourceLocation defLocation, @Nullable IImageBuffer imageBufferIn) {
super(defLocation);
this.cacheFile = cacheFileIn;
this.eTagFile = new File(cacheFile.getParentFile(), cacheFile.getName() + ".etag");
this.imageUrl = imageUrlIn;
this.imageBuffer = imageBufferIn;
public ThreadDownloadImageETag(@Nonnull File cacheLocation, String url, ResourceLocation def, @Nullable IImageBuffer buffer) {
super(def);
cacheFile = cacheLocation;
eTagFile = new File(cacheFile.getParentFile(), cacheFile.getName() + ".etag");
imageUrl = url;
imageBuffer = buffer;
}
private void checkTextureUploaded() {
if (!this.textureUploaded) {
if (this.bufferedImage != null) {
if (this.textureLocation != null) {
this.deleteGlTexture();
if (!textureUploaded) {
if (bufferedImage != null) {
if (textureLocation != null) {
deleteGlTexture();
}
TextureUtil.uploadTextureImage(super.getGlTextureId(), this.bufferedImage);
this.textureUploaded = true;
TextureUtil.uploadTextureImage(super.getGlTextureId(), bufferedImage);
textureUploaded = true;
}
}
}
public int getGlTextureId() {
this.checkTextureUploaded();
checkTextureUploaded();
return super.getGlTextureId();
}
private void setBufferedImage(@Nonnull BufferedImage bufferedImageIn) {
this.bufferedImage = bufferedImageIn;
bufferedImage = bufferedImageIn;
if (this.imageBuffer != null) {
this.imageBuffer.skinAvailable();
if (imageBuffer != null) {
imageBuffer.skinAvailable();
}
}
@ -85,24 +86,20 @@ public class ThreadDownloadImageETag extends SimpleTexture {
}
public void loadTexture(IResourceManager resourceManager) throws IOException {
if (this.bufferedImage == null && this.textureLocation != null) {
if (bufferedImage == null && textureLocation != null) {
super.loadTexture(resourceManager);
}
if (this.imageThread == null) {
this.imageThread = new Thread(this::loadTexture, "Texture Downloader #" + THREAD_ID.incrementAndGet());
this.imageThread.setDaemon(true);
this.imageThread.start();
if (imageThread == null) {
imageThread = new Thread(this::loadTexture, "Texture Downloader #" + THREAD_ID.incrementAndGet());
imageThread.setDaemon(true);
imageThread.start();
}
}
private void loadTexture() {
HttpResponse response = null;
try {
HttpClient client = HttpClientBuilder.create().build();
response = client.execute(new HttpGet(imageUrl));
int status = response.getStatusLine().getStatusCode();
if (status == HttpStatus.SC_NOT_FOUND) {
try (MoreHttpResponses response = new NetClient("GET", imageUrl).send()) {
if (response.getResponseCode() == HttpStatus.SC_NOT_FOUND) {
// delete the cache files in case we can't connect in the future
clearCache();
} else if (checkETag(response)) {
@ -132,9 +129,6 @@ public class ThreadDownloadImageETag extends SimpleTexture {
}
}
LOGGER.error("Couldn't load skin {} ", imageUrl, e);
} finally {
if (response != null)
EntityUtils.consumeQuietly(response.getEntity());
}
}
@ -149,15 +143,15 @@ public class ThreadDownloadImageETag extends SimpleTexture {
}
private void clearCache() {
FileUtils.deleteQuietly(this.cacheFile);
FileUtils.deleteQuietly(this.eTagFile);
FileUtils.deleteQuietly(cacheFile);
FileUtils.deleteQuietly(eTagFile);
}
private boolean checkETag(HttpResponse response) {
private boolean checkETag(MoreHttpResponses response) {
try {
if (cacheFile.isFile()) {
String localETag = Files.readFirstLine(eTagFile, Charsets.UTF_8);
Header remoteETag = response.getFirstHeader(HttpHeaders.ETAG);
Header remoteETag = response.getResponse().getFirstHeader(HttpHeaders.ETAG);
// true if no remote etag or does match
return remoteETag == null || localETag.equals(remoteETag.getValue());
}
@ -168,18 +162,18 @@ public class ThreadDownloadImageETag extends SimpleTexture {
}
}
private void loadTextureFromServer(HttpResponse response) {
private void loadTextureFromServer(MoreHttpResponses response) {
LOGGER.debug("Downloading http texture from {} to {}", imageUrl, cacheFile);
try {
if (response.getStatusLine().getStatusCode() / 100 == 2) {
if (response.ok()) {
BufferedImage bufferedimage;
// write the image to disk
FileUtils.copyInputStreamToFile(response.getEntity().getContent(), cacheFile);
FileUtils.copyInputStreamToFile(response.getInputStream(), cacheFile);
bufferedimage = ImageIO.read(cacheFile);
// maybe write the etag to disk
Header eTag = response.getFirstHeader(HttpHeaders.ETAG);
Header eTag = response.getResponse().getFirstHeader(HttpHeaders.ETAG);
if (eTag != null) {
FileUtils.write(eTagFile, eTag.getValue(), Charsets.UTF_8);
}

View file

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