Switch custom skins to use futures

This commit is contained in:
Matthew Messinger 2016-08-27 23:16:31 -04:00
parent 4f74761163
commit b4fd26f181
2 changed files with 55 additions and 37 deletions

View file

@ -3,6 +3,7 @@ package com.voxelmodpack.hdskins.resource;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
@ -15,20 +16,28 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.util.ResourceLocation;
public class SkinThread implements Runnable {
public class ImageLoader implements Callable<ResourceLocation> {
private ResourceLocation original;
private ResourceLocation updated;
private BufferedImage image;
private Minecraft mc = Minecraft.getMinecraft();
public SkinThread(ResourceLocation loc) {
private final ResourceLocation original;
public ImageLoader(ResourceLocation loc) {
this.original = loc;
new Thread(this).start();
}
@Override
public void run() {
image = new ImageBufferDownloadHD().parseUserSkin(getImage(original));
public ResourceLocation call() throws Exception {
BufferedImage image = getImage(original);
final BufferedImage updated = new ImageBufferDownloadHD().parseUserSkin(image);
return this.mc.addScheduledTask(new Callable<ResourceLocation>() {
@Override
public ResourceLocation call() throws Exception {
return loadSkin(updated);
}
}).get();
}
@Nullable
@ -46,24 +55,11 @@ public class SkinThread implements Runnable {
return null;
}
public ResourceLocation getResource() {
return this.updated;
}
public void deleteTexture() {
Minecraft.getMinecraft().getTextureManager().deleteTexture(updated);
}
public boolean isReady() {
return image != null;
}
public void uploadSkin() {
private ResourceLocation loadSkin(BufferedImage image) {
ResourceLocation conv = new ResourceLocation("hdskins-converted", original.getResourcePath());
Minecraft.getMinecraft().getTextureManager().loadTexture(conv, new DynamicTextureImage(image));
updated = conv;
image = null;
this.mc.getTextureManager().loadTexture(conv, new DynamicTextureImage(image));
return conv;
}
}

View file

@ -5,18 +5,25 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
@ -24,17 +31,24 @@ import net.minecraft.util.ResourceLocation;
public class SkinResourceManager implements IResourceManagerReloadListener {
private ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
private Map<UUID, Skin> uuidSkins = Maps.newHashMap();
private Map<String, Skin> namedSkins = Maps.newHashMap();
private Map<ResourceLocation, SkinThread> converted = Maps.newHashMap();
private Map<ResourceLocation, Future<ResourceLocation>> inProgress = Maps.newHashMap();
private Map<ResourceLocation, ResourceLocation> converted = Maps.newHashMap();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
try {
uuidSkins.clear();
namedSkins.clear();
for (SkinThread loc : converted.values()) {
loc.deleteTexture();
for (Future<ResourceLocation> loc : inProgress.values()) {
loc.cancel(true);
}
inProgress.clear();
for (ResourceLocation res : converted.values()) {
Minecraft.getMinecraft().getTextureManager().deleteTexture(res);
}
converted.clear();
for (IResource res : resourceManager.getAllResources(new ResourceLocation("hdskins", "textures/skins/skins.json"))) {
@ -74,19 +88,27 @@ public class SkinResourceManager implements IResourceManagerReloadListener {
Skin skin = getSkin(profile);
if (skin != null) {
ResourceLocation res = skin.getTexture();
final ResourceLocation res = skin.getTexture();
if (res != null) {
SkinThread conv = this.converted.get(res);
if (conv == null) {
if (this.inProgress.get(res) == null) {
// read and convert in a new thread
this.converted.put(res, conv = new SkinThread(res));
final ListenableFuture<ResourceLocation> conv = executor.submit(new ImageLoader(res));
conv.addListener(new Runnable() {
@Override
public void run() {
try {
converted.put(res, conv.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}, executor);
this.inProgress.put(res, conv);
}
// gotta stay in this thread to load it
if (conv.isReady()) {
conv.uploadSkin();
}
return conv.getResource();
}
return converted.get(res);
}
return null;
}