mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2025-02-13 16:24:23 +01:00
Fix freezes for good. This also properly fixes network race issues.
This commit is contained in:
parent
2c592768d3
commit
ae005e3323
7 changed files with 159 additions and 140 deletions
|
@ -1,8 +1,13 @@
|
||||||
package com.voxelmodpack.hdskins;
|
package com.voxelmodpack.hdskins;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
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.MoreExecutors;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
@ -14,7 +19,7 @@ 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.resource.SkinResourceManager;
|
import com.voxelmodpack.hdskins.resource.SkinResourceManager;
|
||||||
import com.voxelmodpack.hdskins.skins.LegacySkinServer;
|
import com.voxelmodpack.hdskins.skins.AsyncCacheLoader;
|
||||||
import com.voxelmodpack.hdskins.skins.SkinServer;
|
import com.voxelmodpack.hdskins.skins.SkinServer;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.IImageBuffer;
|
import net.minecraft.client.renderer.IImageBuffer;
|
||||||
|
@ -32,36 +37,45 @@ import java.awt.Graphics;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumMap;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public final class HDSkinManager implements IResourceManagerReloadListener {
|
public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
|
|
||||||
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
|
||||||
private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
|
private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
|
||||||
private static final Gson GSON = new GsonBuilder()
|
private static final Gson GSON = new GsonBuilder()
|
||||||
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
|
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
private List<SkinServer> skinServers = Lists.newArrayList();
|
private static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
|
||||||
|
public static final ListeningExecutorService skinUploadExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
|
||||||
|
|
||||||
|
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
||||||
|
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
private List<SkinServer> skinServers = Lists.newArrayList();
|
||||||
|
|
||||||
private Map<UUID, Map<Type, ResourceLocation>> skinCache = Maps.newHashMap();
|
private Map<UUID, Map<Type, ResourceLocation>> skinCache = Maps.newHashMap();
|
||||||
|
|
||||||
|
private LoadingCache<GameProfile, Map<Type, MinecraftProfileTexture>> skins = CacheBuilder.newBuilder()
|
||||||
|
.initialCapacity(20)
|
||||||
|
.maximumSize(100)
|
||||||
|
.expireAfterWrite(4, TimeUnit.HOURS)
|
||||||
|
.build(AsyncCacheLoader.create(CacheLoader.from(this::loadProfileData), Collections.emptyMap(), skinDownloadExecutor));
|
||||||
|
|
||||||
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 ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
public HDSkinManager() {
|
|
||||||
addSkinServer(new LegacySkinServer("http://skins.voxelmodpack.com", "http://skinmanager.voxelmodpack.com"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<ResourceLocation> getSkinLocation(GameProfile profile1, final Type type, boolean loadIfAbsent) {
|
public Optional<ResourceLocation> getSkinLocation(GameProfile profile1, final Type type, boolean loadIfAbsent) {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
|
@ -102,14 +116,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
if (skin == null) {
|
if (skin == null) {
|
||||||
if (loadIfAbsent && getProfileData(profile).containsKey(type)) {
|
if (loadIfAbsent && getProfileData(profile).containsKey(type)) {
|
||||||
skinCache.get(profile.getId()).put(type, LOADING);
|
skinCache.get(profile.getId()).put(type, LOADING);
|
||||||
//noinspection Convert2Lambda
|
loadTexture(profile, type, (t, loc, tex) -> skinCache.get(profile.getId()).put(t, loc));
|
||||||
executor.submit(() -> loadTexture(profile, type, new SkinAvailableCallback() {
|
|
||||||
@Override
|
|
||||||
public void skinAvailable(Type type1, ResourceLocation location, MinecraftProfileTexture profileTexture) {
|
|
||||||
skinCache.get(profile.getId()).put(type1, location);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -120,9 +127,6 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
if (profile.getId() != null) {
|
if (profile.getId() != null) {
|
||||||
Map<Type, MinecraftProfileTexture> data = getProfileData(profile);
|
Map<Type, MinecraftProfileTexture> data = getProfileData(profile);
|
||||||
final MinecraftProfileTexture texture = data.get(type);
|
final MinecraftProfileTexture texture = data.get(type);
|
||||||
if (texture == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String skinDir = type.toString().toLowerCase() + "s/";
|
String skinDir = type.toString().toLowerCase() + "s/";
|
||||||
final ResourceLocation skin = new ResourceLocation("hdskins", skinDir + texture.getHash());
|
final ResourceLocation skin = new ResourceLocation("hdskins", skinDir + texture.getHash());
|
||||||
|
@ -136,9 +140,11 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public BufferedImage parseUserSkin(@Nonnull BufferedImage image) {
|
public BufferedImage parseUserSkin(@Nonnull BufferedImage image) {
|
||||||
if (imagebufferdownload != null)
|
BufferedImage image1 = image;
|
||||||
return imagebufferdownload.parseUserSkin(image);
|
if (imagebufferdownload != null) {
|
||||||
return image;
|
image1 = imagebufferdownload.parseUserSkin(image);
|
||||||
|
}
|
||||||
|
return image1 == null ? image : image1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -155,10 +161,10 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Type, MinecraftProfileTexture> getProfileData(GameProfile profile) {
|
private Map<Type, MinecraftProfileTexture> loadProfileData(GameProfile profile) {
|
||||||
EnumMap<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.getProfileData(profile);
|
Optional<MinecraftTexturesPayload> profileData = server.loadProfileData(profile);
|
||||||
profileData.map(MinecraftTexturesPayload::getTextures).ifPresent(it -> it.forEach(textures::putIfAbsent));
|
profileData.map(MinecraftTexturesPayload::getTextures).ifPresent(it -> it.forEach(textures::putIfAbsent));
|
||||||
if (textures.size() == Type.values().length)
|
if (textures.size() == Type.values().length)
|
||||||
break;
|
break;
|
||||||
|
@ -167,6 +173,16 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
return textures;
|
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 addSkinServer(SkinServer skinServer) {
|
public void addSkinServer(SkinServer skinServer) {
|
||||||
this.skinServers.add(0, skinServer);
|
this.skinServers.add(0, skinServer);
|
||||||
}
|
}
|
||||||
|
@ -179,9 +195,13 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public static PreviewTexture getPreviewTexture(ResourceLocation skinResource, GameProfile profile, Type type, ResourceLocation def, @Nullable final SkinAvailableCallback callback) {
|
public static PreviewTexture getPreviewTexture(ResourceLocation skinResource, GameProfile profile, Type type, ResourceLocation def, @Nullable final SkinAvailableCallback callback) {
|
||||||
TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
|
TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
|
||||||
MinecraftProfileTexture url = INSTANCE.getGatewayServer().getPreviewTexture(type, profile);
|
MinecraftProfileTexture url = INSTANCE.getGatewayServer().getPreviewTexture(type, profile).orElse(null);
|
||||||
|
if (url == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
IImageBuffer buffer = new ImageBufferDownloadHD();
|
IImageBuffer buffer = new ImageBufferDownloadHD();
|
||||||
PreviewTexture skinTexture = new PreviewTexture(url.getUrl(), def, type == Type.SKIN ? new IImageBuffer() {
|
PreviewTexture skinTexture = new PreviewTexture(url.getUrl(), def, type == Type.SKIN ? new IImageBuffer() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -213,7 +233,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||||
.flatMap(m -> m.values().stream())
|
.flatMap(m -> m.values().stream())
|
||||||
.forEach(textures::deleteTexture);
|
.forEach(textures::deleteTexture);
|
||||||
INSTANCE.skinCache.clear();
|
INSTANCE.skinCache.clear();
|
||||||
INSTANCE.skinServers.forEach(SkinServer::clearCache);
|
INSTANCE.skins.invalidateAll();
|
||||||
} catch (IOException var1) {
|
} catch (IOException var1) {
|
||||||
var1.printStackTrace();
|
var1.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
package com.voxelmodpack.hdskins.mod;
|
package com.voxelmodpack.hdskins.mod;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
import com.mumfrey.liteloader.core.LiteLoader;
|
import com.mumfrey.liteloader.core.LiteLoader;
|
||||||
import com.mumfrey.liteloader.modconfig.ConfigPanel;
|
import com.mumfrey.liteloader.modconfig.ConfigPanel;
|
||||||
|
import com.mumfrey.liteloader.modconfig.ConfigStrategy;
|
||||||
|
import com.mumfrey.liteloader.modconfig.ExposableOptions;
|
||||||
import com.mumfrey.liteloader.util.ModUtilities;
|
import com.mumfrey.liteloader.util.ModUtilities;
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||||
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
|
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
|
||||||
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
||||||
import com.voxelmodpack.hdskins.gui.HDSkinsConfigPanel;
|
import com.voxelmodpack.hdskins.gui.HDSkinsConfigPanel;
|
||||||
import com.voxelmodpack.hdskins.gui.RenderPlayerModel;
|
import com.voxelmodpack.hdskins.gui.RenderPlayerModel;
|
||||||
|
import com.voxelmodpack.hdskins.skins.SkinServer;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ExposableOptions(strategy = ConfigStrategy.Unversioned, filename = "hdskins")
|
||||||
public class LiteModHDSkinsMod implements HDSkinsMod {
|
public class LiteModHDSkinsMod implements HDSkinsMod {
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
public List<String> skin_servers = SkinServer.defaultServers;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "HD Skins";
|
return "HD Skins";
|
||||||
|
@ -27,6 +37,11 @@ public class LiteModHDSkinsMod implements HDSkinsMod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(File configPath) {
|
public void init(File configPath) {
|
||||||
|
|
||||||
|
// register config
|
||||||
|
LiteLoader.getInstance().registerExposable(this, null);
|
||||||
|
|
||||||
|
// try it initialize voxelmenu button
|
||||||
try {
|
try {
|
||||||
Class<?> ex = Class.forName("com.thevoxelbox.voxelmenu.GuiMainMenuVoxelBox");
|
Class<?> ex = Class.forName("com.thevoxelbox.voxelmenu.GuiMainMenuVoxelBox");
|
||||||
Method mRegisterCustomScreen = ex.getDeclaredMethod("registerCustomScreen", Class.class, String.class);
|
Method mRegisterCustomScreen = ex.getDeclaredMethod("registerCustomScreen", Class.class, String.class);
|
||||||
|
@ -54,5 +69,15 @@ public class LiteModHDSkinsMod implements HDSkinsMod {
|
||||||
@Override
|
@Override
|
||||||
public void onInitCompleted(Minecraft minecraft, LiteLoader loader) {
|
public void onInitCompleted(Minecraft minecraft, LiteLoader loader) {
|
||||||
ModUtilities.addRenderer(EntityPlayerModel.class, new RenderPlayerModel<>(minecraft.getRenderManager()));
|
ModUtilities.addRenderer(EntityPlayerModel.class, new RenderPlayerModel<>(minecraft.getRenderManager()));
|
||||||
|
|
||||||
|
// register skin servers.
|
||||||
|
for (String s : skin_servers) {
|
||||||
|
try {
|
||||||
|
HDSkinManager.INSTANCE.addSkinServer(SkinServer.from(s));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package com.voxelmodpack.hdskins.skins;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
|
||||||
import com.mojang.authlib.GameProfile;
|
|
||||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public abstract class AbstractSkinServer implements SkinServer {
|
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
protected static final ExecutorService skinDownloadExecutor = Executors.newCachedThreadPool();
|
|
||||||
protected static final ListeningExecutorService skinUploadExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
|
|
||||||
|
|
||||||
private LoadingCache<GameProfile, Optional<MinecraftTexturesPayload>> skins = CacheBuilder.newBuilder()
|
|
||||||
.initialCapacity(20)
|
|
||||||
.maximumSize(100)
|
|
||||||
.expireAfterWrite(4, TimeUnit.HOURS)
|
|
||||||
.build(AsyncCacheLoader.create(new CacheLoader<GameProfile, Optional<MinecraftTexturesPayload>>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<MinecraftTexturesPayload> load(GameProfile key) {
|
|
||||||
Preconditions.checkNotNull(key, "profile cannot be null");
|
|
||||||
// prevent race condition where one server responds faster than the previous one
|
|
||||||
synchronized (key) {
|
|
||||||
return loadProfileData(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, Optional.empty(), skinDownloadExecutor));
|
|
||||||
|
|
||||||
protected abstract Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Optional<MinecraftTexturesPayload> getProfileData(GameProfile profile) {
|
|
||||||
boolean was = !skins.asMap().containsKey(profile);
|
|
||||||
Optional<MinecraftTexturesPayload> textures = skins.getUnchecked(profile);
|
|
||||||
// This is the initial value. Refreshing will load it syncronously.
|
|
||||||
if (was) {
|
|
||||||
skins.refresh(profile);
|
|
||||||
}
|
|
||||||
return textures;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearCache() {
|
|
||||||
skins.invalidateAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.voxelmodpack.hdskins.skins;
|
package com.voxelmodpack.hdskins.skins;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||||
|
@ -8,6 +11,7 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||||
import com.mojang.util.UUIDTypeAdapter;
|
import com.mojang.util.UUIDTypeAdapter;
|
||||||
|
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||||
import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload;
|
import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.util.Session;
|
import net.minecraft.util.Session;
|
||||||
|
@ -21,9 +25,11 @@ import java.nio.file.Path;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class LegacySkinServer extends AbstractSkinServer {
|
public class LegacySkinServer implements SkinServer {
|
||||||
|
|
||||||
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
||||||
|
|
||||||
|
@ -32,24 +38,20 @@ public class LegacySkinServer extends AbstractSkinServer {
|
||||||
private final String address;
|
private final String address;
|
||||||
private final String gateway;
|
private final String gateway;
|
||||||
|
|
||||||
public LegacySkinServer(String address, String gateway) {
|
public LegacySkinServer(String address) {
|
||||||
|
this(address, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LegacySkinServer(String address, @Nullable String gateway) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.gateway = gateway;
|
this.gateway = gateway;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddress() {
|
public Optional<MinecraftProfileTexture> getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile) {
|
||||||
return address;
|
if (Strings.isNullOrEmpty(this.gateway))
|
||||||
}
|
return Optional.empty();
|
||||||
|
return Optional.of(new MinecraftProfileTexture(getPath(this.gateway, type, profile), null));
|
||||||
@Override
|
|
||||||
public String getGateway() {
|
|
||||||
return gateway;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MinecraftProfileTexture getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile) {
|
|
||||||
return new MinecraftProfileTexture(getPath(getGateway(), type, profile), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,23 +59,22 @@ public class LegacySkinServer extends AbstractSkinServer {
|
||||||
ImmutableMap.Builder<MinecraftProfileTexture.Type, MinecraftProfileTexture> builder = ImmutableMap.builder();
|
ImmutableMap.Builder<MinecraftProfileTexture.Type, MinecraftProfileTexture> builder = ImmutableMap.builder();
|
||||||
for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) {
|
for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) {
|
||||||
|
|
||||||
String url = getPath(getAddress(), type, profile);
|
String url = getPath(this.address, type, profile);
|
||||||
try {
|
try {
|
||||||
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||||
if (urlConnection.getResponseCode() / 100 != 2) {
|
if (urlConnection.getResponseCode() / 100 != 2) {
|
||||||
throw new IOException("Bad response code: " + urlConnection.getResponseCode());
|
throw new IOException("Bad response code: " + urlConnection.getResponseCode());
|
||||||
}
|
}
|
||||||
builder.put(type, new MinecraftProfileTexture(url, null));
|
builder.put(type, new MinecraftProfileTexture(url, null));
|
||||||
logger.info("Found skin for {} at {}", profile.getName(), url);
|
logger.debug("Found skin for {} at {}", profile.getName(), url);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("Couldn't find texture at {}. Does it exist?", url, e);
|
logger.trace("Couldn't find texture for {} at {}. Does it exist?", profile.getName(), url, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = builder.build();
|
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = builder.build();
|
||||||
if (map.isEmpty()) {
|
if (map.isEmpty()) {
|
||||||
logger.debug("No textures found for {} at {}", profile, this.getAddress());
|
logger.debug("No textures found for {} at {}", profile, this.address);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,17 +90,20 @@ public class LegacySkinServer extends AbstractSkinServer {
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type) {
|
public ListenableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type) {
|
||||||
|
|
||||||
return skinUploadExecutor.submit(() -> {
|
if (Strings.isNullOrEmpty(this.gateway))
|
||||||
|
return Futures.immediateFailedFuture(new NullPointerException("gateway url is blank"));
|
||||||
|
|
||||||
|
return HDSkinManager.skinUploadExecutor.submit(() -> {
|
||||||
verifyServerConnection(session, SERVER_ID);
|
verifyServerConnection(session, SERVER_ID);
|
||||||
|
|
||||||
Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, image);
|
Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, image);
|
||||||
ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(getGateway(), data);
|
ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data);
|
||||||
String response = upload.uploadMultipart();
|
String response = upload.uploadMultipart();
|
||||||
return new SkinUploadResponse(response.equalsIgnoreCase("OK"), response);
|
return new SkinUploadResponse(response.equalsIgnoreCase("OK"), response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, ?> getData(Session session, MinecraftProfileTexture.Type type, String param, Object val) {
|
private static Map<String, ?> getData(Session session, MinecraftProfileTexture.Type type, String param, Object val) {
|
||||||
return ImmutableMap.of(
|
return ImmutableMap.of(
|
||||||
"user", session.getUsername(),
|
"user", session.getUsername(),
|
||||||
"uuid", session.getPlayerID(),
|
"uuid", session.getPlayerID(),
|
||||||
|
@ -107,23 +111,43 @@ public class LegacySkinServer extends AbstractSkinServer {
|
||||||
param, val);
|
param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, ?> getClearData(Session session, MinecraftProfileTexture.Type type) {
|
private static Map<String, ?> getClearData(Session session, MinecraftProfileTexture.Type type) {
|
||||||
return getData(session, type, "clear", "1");
|
return getData(session, type, "clear", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, ?> getUploadData(Session session, MinecraftProfileTexture.Type type, Path skinFile) {
|
private static Map<String, ?> getUploadData(Session session, MinecraftProfileTexture.Type type, Path skinFile) {
|
||||||
return getData(session, type, type.toString().toLowerCase(Locale.US), skinFile);
|
return getData(session, type, type.toString().toLowerCase(Locale.US), skinFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPath(String address, MinecraftProfileTexture.Type type, GameProfile profile) {
|
private static String getPath(String address, MinecraftProfileTexture.Type type, GameProfile profile) {
|
||||||
String uuid = UUIDTypeAdapter.fromUUID(profile.getId());
|
String uuid = UUIDTypeAdapter.fromUUID(profile.getId());
|
||||||
String path = type.toString().toLowerCase() + "s";
|
String path = type.toString().toLowerCase() + "s";
|
||||||
return String.format("%s/%s/%s.png", address, path, uuid);
|
return String.format("%s/%s/%s.png", address, path, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
private static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
||||||
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
|
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
|
||||||
service.joinServer(session.getProfile(), session.getToken(), serverId);
|
service.joinServer(session.getProfile(), session.getToken(), serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be in the format {@code legacy:http://address;http://gateway}. Gateway is optional.
|
||||||
|
*/
|
||||||
|
static LegacySkinServer from(String parsed) {
|
||||||
|
Matcher matcher = Pattern.compile("^legacy:(.+?)(?:;(.*))?$").matcher(parsed);
|
||||||
|
if (matcher.find()) {
|
||||||
|
String addr = matcher.group(1);
|
||||||
|
String gate = matcher.group(2);
|
||||||
|
return new LegacySkinServer(addr, gate);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("server format string was not correct");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("address", address)
|
||||||
|
.add("gateway", gateway)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.voxelmodpack.hdskins.skins;
|
package com.voxelmodpack.hdskins.skins;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
|
@ -7,22 +8,32 @@ import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||||
import net.minecraft.util.Session;
|
import net.minecraft.util.Session;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public interface SkinServer {
|
public interface SkinServer {
|
||||||
|
|
||||||
String getAddress();
|
List<String> defaultServers = Lists.newArrayList("legacy:http://skins.voxelmodpack.com;http://skinmanager.voxelmodpack.com");
|
||||||
|
|
||||||
String getGateway();
|
Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile);
|
||||||
|
|
||||||
Optional<MinecraftTexturesPayload> getProfileData(GameProfile profile);
|
Optional<MinecraftProfileTexture> getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile);
|
||||||
|
|
||||||
MinecraftProfileTexture getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile);
|
|
||||||
|
|
||||||
ListenableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type);
|
ListenableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type);
|
||||||
|
|
||||||
void clearCache();
|
static SkinServer from(String server) {
|
||||||
|
int i = server.indexOf(':');
|
||||||
|
if (i >= 0) {
|
||||||
|
String type = server.substring(0, i);
|
||||||
|
switch (type) {
|
||||||
|
case "legacy":
|
||||||
|
return LegacySkinServer.from(server);
|
||||||
|
case "valhalla": {
|
||||||
|
return ValhallaSkinServer.from(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,33 +8,25 @@ import net.minecraft.util.Session;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class YggSkinServer extends AbstractSkinServer {
|
public class ValhallaSkinServer implements SkinServer {
|
||||||
|
|
||||||
private final String baseURL;
|
private final String baseURL;
|
||||||
|
|
||||||
public YggSkinServer(String baseURL) {
|
public ValhallaSkinServer(String baseURL) {
|
||||||
this.baseURL = baseURL;
|
this.baseURL = baseURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
|
public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddress() {
|
public Optional<MinecraftProfileTexture> getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getGateway() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MinecraftProfileTexture getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,4 +34,11 @@ public class YggSkinServer extends AbstractSkinServer {
|
||||||
public ListenableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type) {
|
public ListenableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ValhallaSkinServer from(String server) {
|
||||||
|
Matcher matcher = Pattern.compile("^valhalla:(.*)$").matcher(server);
|
||||||
|
if (matcher.find())
|
||||||
|
return new ValhallaSkinServer(matcher.group(1));
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@ import com.mumfrey.liteloader.core.LiteLoader;
|
||||||
import com.mumfrey.liteloader.util.ModUtilities;
|
import com.mumfrey.liteloader.util.ModUtilities;
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||||
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
||||||
import com.voxelmodpack.hdskins.skins.LegacySkinServer;
|
import com.voxelmodpack.hdskins.skins.SkinServer;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.entity.Render;
|
import net.minecraft.client.renderer.entity.Render;
|
||||||
import net.minecraft.client.renderer.entity.RenderManager;
|
import net.minecraft.client.renderer.entity.RenderManager;
|
||||||
|
@ -80,6 +80,9 @@ public class MineLittlePony {
|
||||||
|
|
||||||
MetadataSerializer ms = Minecraft.getMinecraft().getResourcePackRepository().rprMetadataSerializer;
|
MetadataSerializer ms = Minecraft.getMinecraft().getResourcePackRepository().rprMetadataSerializer;
|
||||||
ms.registerMetadataSectionType(new PonyDataSerialzier(), IPonyData.class);
|
ms.registerMetadataSectionType(new PonyDataSerialzier(), IPonyData.class);
|
||||||
|
|
||||||
|
// This also makes it the default gateway server.
|
||||||
|
SkinServer.defaultServers.add("legacy:http://minelpskins.voxelmodpack.com;http://minelpskinmanager.voxelmodpack.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
void postInit(Minecraft minecraft) {
|
void postInit(Minecraft minecraft) {
|
||||||
|
@ -90,9 +93,6 @@ public class MineLittlePony {
|
||||||
manager.addSkinModifier(new PonySkinModifier());
|
manager.addSkinModifier(new PonySkinModifier());
|
||||||
// logger.info("Set MineLP skin server URL.");
|
// logger.info("Set MineLP skin server URL.");
|
||||||
|
|
||||||
// This also makes it the default gateway server.
|
|
||||||
manager.addSkinServer(new LegacySkinServer("http://minelpskins.voxelmodpack.com", "http://minelpskinmanager.voxelmodpack.com"));
|
|
||||||
|
|
||||||
RenderManager rm = minecraft.getRenderManager();
|
RenderManager rm = minecraft.getRenderManager();
|
||||||
this.saveCurrentRenderers(rm);
|
this.saveCurrentRenderers(rm);
|
||||||
ModUtilities.addRenderer(EntityPonyModel.class, new RenderPonyModel(rm));
|
ModUtilities.addRenderer(EntityPonyModel.class, new RenderPonyModel(rm));
|
||||||
|
|
Loading…
Reference in a new issue