MineLittlePony/src/hdskins/java/com/voxelmodpack/hdskins/resources/SkinResourceManager.java
2018-09-06 13:44:41 +02:00

129 lines
4.4 KiB
Java

package com.voxelmodpack.hdskins.resources;
import com.google.common.collect.Maps;
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.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SkinResourceManager implements IResourceManagerReloadListener {
private ExecutorService executor = Executors.newSingleThreadExecutor();
private Map<UUID, Skin> uuidSkins = Maps.newHashMap();
private Map<String, Skin> namedSkins = Maps.newHashMap();
private Map<ResourceLocation, Future<ResourceLocation>> inProgress = Maps.newHashMap();
private Map<ResourceLocation, ResourceLocation> converted = Maps.newHashMap();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
uuidSkins.clear();
namedSkins.clear();
executor.shutdownNow();
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) {
if (s.uuid != null) {
uuidSkins.put(s.uuid, s);
}
if (s.name != null) {
namedSkins.put(s.name, s);
}
}
} catch (JsonParseException je) {
LiteLoaderLogger.warning(je, "Invalid skins.json in %s", res.getResourcePackName());
}
}
} catch (IOException e) {
// ignore
}
}
}
private SkinData getSkinData(InputStream stream) {
try {
return new Gson().fromJson(new InputStreamReader(stream), SkinData.class);
} finally {
IOUtils.closeQuietly(stream);
}
}
@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);
}
return null;
}
/**
* Convert older resources to a newer format.
*
* @param res The skin resource to convert
* @return The converted resource
*/
@Nullable
public ResourceLocation getConvertedResource(@Nullable ResourceLocation res) {
loadSkinResource(res);
return converted.get(res);
}
private void loadSkinResource(@Nullable final 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);
}
}));
}
}
@Nullable
private Skin getSkin(GameProfile profile) {
Skin skin = this.uuidSkins.get(profile.getId());
if (skin == null) {
skin = this.namedSkins.get(profile.getName());
}
return skin;
}
}