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

View file

@ -5,18 +5,25 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import com.google.common.collect.Maps; 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.Gson;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
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.mumfrey.liteloader.util.log.LiteLoaderLogger; import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener; import net.minecraft.client.resources.IResourceManagerReloadListener;
@ -24,17 +31,24 @@ import net.minecraft.util.ResourceLocation;
public class SkinResourceManager implements IResourceManagerReloadListener { public class SkinResourceManager implements IResourceManagerReloadListener {
private ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
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();
private Map<ResourceLocation, SkinThread> converted = Maps.newHashMap(); private Map<ResourceLocation, Future<ResourceLocation>> inProgress = Maps.newHashMap();
private Map<ResourceLocation, ResourceLocation> converted = Maps.newHashMap();
@Override @Override
public void onResourceManagerReload(IResourceManager resourceManager) { public void onResourceManagerReload(IResourceManager resourceManager) {
try { try {
uuidSkins.clear(); uuidSkins.clear();
namedSkins.clear(); namedSkins.clear();
for (SkinThread loc : converted.values()) { for (Future<ResourceLocation> loc : inProgress.values()) {
loc.deleteTexture(); loc.cancel(true);
}
inProgress.clear();
for (ResourceLocation res : converted.values()) {
Minecraft.getMinecraft().getTextureManager().deleteTexture(res);
} }
converted.clear(); converted.clear();
for (IResource res : resourceManager.getAllResources(new ResourceLocation("hdskins", "textures/skins/skins.json"))) { 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); Skin skin = getSkin(profile);
if (skin != null) { if (skin != null) {
ResourceLocation res = skin.getTexture(); final ResourceLocation res = skin.getTexture();
if (res != null) { if (res != null) {
SkinThread conv = this.converted.get(res); if (this.inProgress.get(res) == null) {
if (conv == null) {
// read and convert in a new thread // 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; return null;
} }