mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2024-12-02 00:37:59 +01:00
Merge branch 'master' into hdskins_rewrites
This commit is contained in:
parent
fa44676aa7
commit
6995776e72
14 changed files with 253 additions and 193 deletions
|
@ -9,8 +9,7 @@ import com.google.common.collect.HashBiMap;
|
|||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
|
@ -58,10 +57,10 @@ import javax.annotation.Nonnull;
|
|||
|
||||
public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||
|
||||
private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
|
||||
public static final ExecutorService skinUploadExecutor = Executors.newSingleThreadExecutor();
|
||||
public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
|
||||
|
||||
private static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
|
||||
public static final ListeningExecutorService skinUploadExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
|
||||
private static final ResourceLocation LOADING = new ResourceLocation("LOADING");
|
||||
|
||||
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.voxelmodpack.hdskins;
|
|||
import com.google.common.collect.Maps;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.skins.CallableFutures;
|
||||
|
||||
import net.minecraft.client.renderer.IImageBuffer;
|
||||
|
@ -23,20 +22,20 @@ public class PreviewTextureManager {
|
|||
|
||||
private final GameProfile profile;
|
||||
|
||||
private Map<Type, MinecraftProfileTexture> textures = null;
|
||||
private Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures = null;
|
||||
|
||||
PreviewTextureManager(GameProfile profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
public CompletableFuture<PreviewTexture> getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
|
||||
public CompletableFuture<PreviewTexture> getPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
|
||||
return CallableFutures.asyncFailableFuture(() ->
|
||||
loadPreviewTexture(location, type, def, callback)
|
||||
, HDSkinManager.skinUploadExecutor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PreviewTexture loadPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
|
||||
private PreviewTexture loadPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) {
|
||||
if (textures == null) {
|
||||
textures = HDSkinManager.INSTANCE.getGatewayServer().getProfileTextures(profile);
|
||||
}
|
||||
|
@ -47,7 +46,7 @@ public class PreviewTextureManager {
|
|||
|
||||
MinecraftProfileTexture texture = textures.get(type);
|
||||
|
||||
IImageBuffer buffer = type != Type.SKIN ? null : new ImageBufferDownloadHD().withCallback(() -> {
|
||||
IImageBuffer buffer = type != MinecraftProfileTexture.Type.SKIN ? null : new ImageBufferDownloadHD().withCallback(() -> {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap()));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ 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;
|
||||
|
@ -12,9 +13,7 @@ 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.methods.CloseableHttpResponse;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
@ -97,9 +96,9 @@ public class ThreadDownloadImageETag extends SimpleTexture {
|
|||
|
||||
private void loadTexture() {
|
||||
try (NetClient client = new NetClient("GET", imageUrl)) {
|
||||
CloseableHttpResponse response = client.getResponse();
|
||||
MoreHttpResponses response = client.getResponse();
|
||||
|
||||
if (client.getResponseCode() == HttpStatus.SC_NOT_FOUND) {
|
||||
if (client.getResponse().getResponseCode() == HttpStatus.SC_NOT_FOUND) {
|
||||
// delete the cache files in case we can't connect in the future
|
||||
clearCache();
|
||||
} else if (checkETag(response)) {
|
||||
|
@ -147,11 +146,11 @@ public class ThreadDownloadImageETag extends SimpleTexture {
|
|||
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());
|
||||
|
@ -163,18 +162,18 @@ public class ThreadDownloadImageETag extends SimpleTexture {
|
|||
return false; // it failed, so re-fetch.
|
||||
}
|
||||
|
||||
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.getResponseCode() / 100 == 2) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.voxelmodpack.hdskins.HDSkinManager;
|
|||
import com.voxelmodpack.hdskins.LocalTexture;
|
||||
import com.voxelmodpack.hdskins.LocalTexture.IBlankSkinSupplier;
|
||||
import com.voxelmodpack.hdskins.PreviewTextureManager;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.SkinManager;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
|
@ -19,6 +20,7 @@ import net.minecraft.util.ResourceLocation;
|
|||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@SuppressWarnings("EntityConstructor")
|
||||
public class EntityPlayerModel extends EntityLivingBase implements IBlankSkinSupplier {
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
|||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.skins.SkinUpload;
|
||||
import com.voxelmodpack.hdskins.skins.SkinUploadResponse;
|
||||
import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFilePNG;
|
||||
|
||||
|
@ -544,7 +545,7 @@ public class GuiSkins extends GameGui {
|
|||
btnUpload.enabled = canUpload();
|
||||
|
||||
HDSkinManager.INSTANCE.getGatewayServer()
|
||||
.uploadSkin(mc.getSession(), path, textureType, getMetadata())
|
||||
.uploadSkin(mc.getSession(), new SkinUpload(textureType, path, getMetadata()))
|
||||
.thenAccept(this::onUploadComplete)
|
||||
.exceptionally(this::onUploadFailure);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
package com.voxelmodpack.hdskins.skins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
|
@ -32,19 +29,23 @@ public abstract class AbstractSkinServer implements SkinServer {
|
|||
|
||||
@Override
|
||||
public Map<Type, MinecraftProfileTexture> getProfileTextures(GameProfile profile) {
|
||||
try {
|
||||
MinecraftTexturesPayload payload = getProfileData(profile);
|
||||
|
||||
if (payload != null && payload.getTextures() != null) {
|
||||
return payload.getTextures();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
|
||||
}
|
||||
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, Type type, Map<String, String> metadata) {
|
||||
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, SkinUpload upload) {
|
||||
return CallableFutures.asyncFailableFuture(() -> {
|
||||
return doUpload(session, image, type, metadata);
|
||||
return doUpload(session, upload);
|
||||
}, HDSkinManager.skinUploadExecutor);
|
||||
}
|
||||
|
||||
|
@ -55,7 +56,9 @@ public abstract class AbstractSkinServer implements SkinServer {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException;
|
||||
protected abstract MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException;
|
||||
|
||||
protected abstract SkinUploadResponse doUpload(Session session, SkinUpload upload) throws AuthenticationException, IOException;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package com.voxelmodpack.hdskins.skins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.apache.http.HttpStatus;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
|
||||
|
@ -26,47 +23,45 @@ public class BethlehemSkinServer extends AbstractSkinServer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MinecraftTexturesPayload getProfileData(GameProfile profile) {
|
||||
public MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException {
|
||||
try (NetClient client = new NetClient("GET", getPath(profile))) {
|
||||
if (client.getResponseCode() == HttpStatus.SC_OK) {
|
||||
return gson.fromJson(client.getResponseText(), MinecraftTexturesPayload.class);
|
||||
if (client.getResponse().ok()) {
|
||||
return client.getResponse().json(MinecraftTexturesPayload.class);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException {
|
||||
protected SkinUploadResponse doUpload(Session session, SkinUpload upload) throws AuthenticationException, IOException {
|
||||
SkinServer.verifyServerConnection(session, SERVER_ID);
|
||||
|
||||
try (NetClient client = new NetClient("POST", address)) {
|
||||
client.putHeaders(createHeaders(session, type, image, metadata));
|
||||
client.putHeaders(createHeaders(session, upload));
|
||||
|
||||
if (image != null) {
|
||||
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
|
||||
if (upload.getImage() != null) {
|
||||
client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage());
|
||||
}
|
||||
|
||||
if (client.getResponseCode() == HttpStatus.SC_OK) {
|
||||
return new SkinUploadResponse(client.getResponseText());
|
||||
if (client.getResponse().ok()) {
|
||||
return new SkinUploadResponse(client.getResponse().text());
|
||||
}
|
||||
|
||||
throw new IOException(client.getResponseText());
|
||||
throw new IOException(client.getResponse().text());
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
|
||||
protected Map<String, ?> createHeaders(Session session, SkinUpload upload) {
|
||||
Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
|
||||
.put("accessToken", session.getToken())
|
||||
.put("user", session.getUsername())
|
||||
.put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId()))
|
||||
.put("type", type.toString().toLowerCase(Locale.US));
|
||||
.put("type", upload.getType().toString().toLowerCase(Locale.US));
|
||||
|
||||
if (image == null) {
|
||||
if (upload.getImage() == null) {
|
||||
builder.put("clear", "1");
|
||||
} else {
|
||||
builder.put("model", metadata.getOrDefault("mode", "default"));
|
||||
builder.put("model", upload.getMetadata().getOrDefault("mode", "default"));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
|
|
@ -11,16 +11,18 @@ import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
|||
import com.mojang.util.UUIDTypeAdapter;
|
||||
|
||||
import net.minecraft.util.Session;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ServerType("legacy")
|
||||
|
@ -49,21 +51,14 @@ public class LegacySkinServer extends AbstractSkinServer {
|
|||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public MinecraftTexturesPayload getProfileData(GameProfile profile) {
|
||||
public MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException {
|
||||
ImmutableMap.Builder<Type, MinecraftProfileTexture> builder = ImmutableMap.builder();
|
||||
|
||||
for (Type type : Type.values()) {
|
||||
|
||||
String url = getPath(address, type, profile);
|
||||
|
||||
try (NetClient client = new NetClient("GET", url)) {
|
||||
if (client.getResponseCode() != HttpStatus.SC_OK) {
|
||||
throw new IOException("Bad response code: " + client.getResponseCode());
|
||||
}
|
||||
|
||||
builder.put(type, new MinecraftProfileTexture(url, null));
|
||||
logger.debug("Found skin for {} at {}", profile.getName(), url);
|
||||
try {
|
||||
builder.put(type, loadProfileTexture(profile, url));
|
||||
} catch (IOException e) {
|
||||
logger.trace("Couldn't find texture for {} at {}. Does it exist?", profile.getName(), url, e);
|
||||
}
|
||||
|
@ -72,25 +67,32 @@ public class LegacySkinServer extends AbstractSkinServer {
|
|||
Map<Type, MinecraftProfileTexture> map = builder.build();
|
||||
|
||||
if (map.isEmpty()) {
|
||||
logger.debug("No textures found for {} at {}", profile, address);
|
||||
return null;
|
||||
throw new IOException(String.format("No textures found for %s at %s", profile, address));
|
||||
}
|
||||
|
||||
return TexturesPayloadBuilder.createTexturesPayload(profile, map);
|
||||
}
|
||||
|
||||
private MinecraftProfileTexture loadProfileTexture(GameProfile profile, String url) throws IOException {
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
if (urlConnection.getResponseCode() / 100 != 2) {
|
||||
throw new IOException("Bad response code: " + urlConnection.getResponseCode() + ". URL: " + url);
|
||||
}
|
||||
logger.debug("Found skin for {} at {}", profile.getName(), url);
|
||||
return new MinecraftProfileTexture(url, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException {
|
||||
protected SkinUploadResponse doUpload(Session session, SkinUpload skin) throws AuthenticationException, IOException {
|
||||
SkinServer.verifyServerConnection(session, SERVER_ID);
|
||||
|
||||
try (NetClient client = new NetClient("POST", address)) {
|
||||
client.putHeaders(createHeaders(session, type, image, metadata));
|
||||
client.putHeaders(createHeaders(session, skin.getType(), skin.getImage(), skin.getMetadata()));
|
||||
|
||||
if (image != null) {
|
||||
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
|
||||
if (skin.getImage() != null) {
|
||||
client.putFile(skin.getType().toString().toLowerCase(Locale.US), "image/png", skin.getImage());
|
||||
}
|
||||
|
||||
String response = client.getResponseText();
|
||||
String response = client.getResponse().text();
|
||||
|
||||
if (response.startsWith("ERROR: ")) { // lol @ "ERROR: OK"
|
||||
response = response.substring(7);
|
||||
|
@ -104,7 +106,6 @@ public class LegacySkinServer extends AbstractSkinServer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
|
||||
Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
|
||||
.put("user", session.getUsername())
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package com.voxelmodpack.hdskins.skins;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Utility class for getting different response types from a http response.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MoreHttpResponses extends AutoCloseable {
|
||||
|
||||
CloseableHttpResponse getResponse();
|
||||
|
||||
default boolean ok() {
|
||||
return getResponseCode() == HttpStatus.SC_OK;
|
||||
}
|
||||
|
||||
default int getResponseCode() {
|
||||
return getResponse().getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
default InputStream getInputStream() throws IOException {
|
||||
return getResponse().getEntity().getContent();
|
||||
}
|
||||
|
||||
default BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
default String text() throws IOException {
|
||||
try (BufferedReader reader = getReader()) {
|
||||
return CharStreams.toString(reader);
|
||||
}
|
||||
}
|
||||
|
||||
default Stream<String> lines() throws IOException {
|
||||
try (BufferedReader reader = getReader()) {
|
||||
return reader.lines();
|
||||
}
|
||||
}
|
||||
|
||||
default <T> T json(Class<T> type) throws IOException {
|
||||
try (Reader reader = new InputStreamReader(getResponse().getEntity().getContent())) {
|
||||
return SkinServer.gson.fromJson(reader, type);
|
||||
}
|
||||
}
|
||||
|
||||
default <T> T json(Type type) throws IOException {
|
||||
try (Reader reader = new InputStreamReader(getResponse().getEntity().getContent())) {
|
||||
return SkinServer.gson.fromJson(reader, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default void close() throws IOException {
|
||||
this.getResponse().close();
|
||||
}
|
||||
|
||||
static MoreHttpResponses execute(CloseableHttpClient client, HttpUriRequest request) throws IOException {
|
||||
CloseableHttpResponse response = client.execute(request);
|
||||
return () -> response;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,19 @@
|
|||
package com.voxelmodpack.hdskins.skins;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
/**
|
||||
* Ew. Why so many builders? >.<
|
||||
|
@ -26,11 +22,19 @@ public class NetClient implements Closeable {
|
|||
|
||||
private static CloseableHttpClient client = null;
|
||||
|
||||
public static CloseableHttpClient nativeClient() {
|
||||
if (client == null) {
|
||||
client = HttpClients.createSystem();
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private RequestBuilder rqBuilder;
|
||||
|
||||
private Map<String, ?> headers;
|
||||
|
||||
private CloseableHttpResponse response = null;
|
||||
private MoreHttpResponses response;
|
||||
|
||||
public NetClient(String method, String uri) {
|
||||
start(method, uri);
|
||||
|
@ -49,7 +53,9 @@ public class NetClient implements Closeable {
|
|||
headers = null;
|
||||
|
||||
if (response != null) {
|
||||
EntityUtils.consumeQuietly(response.getEntity());
|
||||
try {
|
||||
response.close();
|
||||
} catch (IOException ignored) {}
|
||||
response = null;
|
||||
}
|
||||
|
||||
|
@ -97,17 +103,13 @@ public class NetClient implements Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
if (client == null) {
|
||||
client = HttpClients.createSystem();
|
||||
}
|
||||
|
||||
response = client.execute(request);
|
||||
response = MoreHttpResponses.execute(nativeClient(), request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or obtains the http response body.
|
||||
*/
|
||||
public CloseableHttpResponse getResponse() throws IOException {
|
||||
public MoreHttpResponses getResponse() throws IOException {
|
||||
if (response == null) {
|
||||
send();
|
||||
}
|
||||
|
@ -115,33 +117,6 @@ public class NetClient implements Closeable {
|
|||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or obtains a response status code.
|
||||
*/
|
||||
public int getResponseCode() throws IOException {
|
||||
return getResponse().getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes and returns the entire response body.
|
||||
*/
|
||||
public String getResponseText() throws IOException {
|
||||
if (getResponse().getEntity() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(getResponse().getEntity().getContent()))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
int ch;
|
||||
while ((ch = reader.read()) != -1) {
|
||||
builder.append((char)ch);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
|
|
|
@ -8,21 +8,16 @@ import com.mojang.authlib.GameProfile;
|
|||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
import com.mumfrey.liteloader.modconfig.Exposable;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Session;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface SkinServer extends Exposable {
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
|
@ -33,15 +28,13 @@ public interface SkinServer extends Exposable {
|
|||
"http://skins.voxelmodpack.com",
|
||||
"http://skinmanager.voxelmodpack.com"));
|
||||
|
||||
MinecraftTexturesPayload getProfileData(GameProfile profile);
|
||||
|
||||
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getProfileTextures(GameProfile profile);
|
||||
|
||||
CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata);
|
||||
CompletableFuture<SkinUploadResponse> uploadSkin(Session session, SkinUpload upload);
|
||||
|
||||
void validate() throws JsonParseException;
|
||||
|
||||
public static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
||||
static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
||||
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
|
||||
service.joinServer(session.getProfile(), session.getToken(), serverId);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.voxelmodpack.hdskins.skins;
|
||||
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SkinUpload {
|
||||
|
||||
private final URI image;
|
||||
private final Map<String, String> metadata;
|
||||
private final MinecraftProfileTexture.Type type;
|
||||
|
||||
public SkinUpload(MinecraftProfileTexture.Type type, @Nullable URI image, Map<String, String> metadata) {
|
||||
this.image = image;
|
||||
this.metadata = metadata;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public URI getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public MinecraftProfileTexture.Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import com.google.gson.JsonObject;
|
|||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
|
||||
|
@ -14,24 +13,16 @@ import javax.annotation.Nullable;
|
|||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Session;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -46,79 +37,81 @@ public class ValhallaSkinServer extends AbstractSkinServer {
|
|||
super(address);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MinecraftTexturesPayload getProfileData(GameProfile profile) {
|
||||
try (CloseableHttpClient client = HttpClients.createSystem()) {
|
||||
try (CloseableHttpResponse response = client.execute(new HttpGet(getTexturesURI(profile)))) {
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
public MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException {
|
||||
|
||||
try (MoreHttpResponses response = MoreHttpResponses.execute(NetClient.nativeClient(), new HttpGet(getTexturesURI(profile)))) {
|
||||
|
||||
if (response.ok()) {
|
||||
return readJson(response, MinecraftTexturesPayload.class);
|
||||
}
|
||||
throw new IOException("Server sent non-ok response code: " + response.getResponseCode());
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException {
|
||||
try (CloseableHttpClient client = HttpClients.createSystem()) {
|
||||
authorize(client, session);
|
||||
protected SkinUploadResponse doUpload(Session session, SkinUpload skin) throws AuthenticationException, IOException {
|
||||
URI image = skin.getImage();
|
||||
Map<String, String> metadata = skin.getMetadata();
|
||||
MinecraftProfileTexture.Type type = skin.getType();
|
||||
|
||||
authorize(session);
|
||||
|
||||
try {
|
||||
return upload(client, session, image, type, metadata);
|
||||
return upload(session, image, type, metadata);
|
||||
} catch (IOException e) {
|
||||
if (e.getMessage().equals("Authorization failed")) {
|
||||
accessToken = null;
|
||||
authorize(client, session);
|
||||
return upload(client, session, image, type, metadata);
|
||||
authorize(session);
|
||||
return upload(session, image, type, metadata);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SkinUploadResponse upload(CloseableHttpClient client, Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||
private SkinUploadResponse upload(Session session, @Nullable URI image,
|
||||
MinecraftProfileTexture.Type type, Map<String, String> metadata)
|
||||
throws IOException {
|
||||
GameProfile profile = session.getProfile();
|
||||
|
||||
if (image == null) {
|
||||
return resetSkin(client, profile, type);
|
||||
return resetSkin(profile, type);
|
||||
}
|
||||
switch (image.getScheme()) {
|
||||
case "file":
|
||||
return uploadFile(client, new File(image), profile, type, metadata);
|
||||
return uploadFile(new File(image), profile, type, metadata);
|
||||
case "http":
|
||||
case "https":
|
||||
return uploadUrl(client, image, profile, type, metadata);
|
||||
return uploadUrl(image, profile, type, metadata);
|
||||
default:
|
||||
throw new IOException("Unsupported URI scheme: " + image.getScheme());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SkinUploadResponse resetSkin(CloseableHttpClient client, GameProfile profile, MinecraftProfileTexture.Type type) throws IOException {
|
||||
return upload(client, RequestBuilder.delete()
|
||||
private SkinUploadResponse resetSkin(GameProfile profile, MinecraftProfileTexture.Type type) throws IOException {
|
||||
return upload(RequestBuilder.delete()
|
||||
.setUri(buildUserTextureUri(profile, type))
|
||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||
.build());
|
||||
}
|
||||
|
||||
private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||
private SkinUploadResponse uploadFile(File file, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||
MultipartEntityBuilder b = MultipartEntityBuilder.create();
|
||||
b.addBinaryBody("file", file, ContentType.create("image/png"), file.getName());
|
||||
metadata.forEach(b::addTextBody);
|
||||
|
||||
return upload(client, RequestBuilder.put()
|
||||
return upload(RequestBuilder.put()
|
||||
.setUri(buildUserTextureUri(profile, type))
|
||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||
.setEntity(b.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||
return upload(client, RequestBuilder.post()
|
||||
private SkinUploadResponse uploadUrl(URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||
|
||||
return upload(RequestBuilder.post()
|
||||
.setUri(buildUserTextureUri(profile, type))
|
||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||
.addParameter("file", uri.toString())
|
||||
|
@ -128,21 +121,20 @@ public class ValhallaSkinServer extends AbstractSkinServer {
|
|||
.build());
|
||||
}
|
||||
|
||||
private SkinUploadResponse upload(CloseableHttpClient client, HttpUriRequest request) throws IOException {
|
||||
try (CloseableHttpResponse response = client.execute(request)) {
|
||||
private SkinUploadResponse upload(HttpUriRequest request) throws IOException {
|
||||
try (MoreHttpResponses response = MoreHttpResponses.execute(NetClient.nativeClient(), request)) {
|
||||
return readJson(response, SkinUploadResponse.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void authorize(CloseableHttpClient client, Session session) throws IOException, AuthenticationException {
|
||||
if (accessToken != null) {
|
||||
private void authorize(Session session) throws IOException, AuthenticationException {
|
||||
if (this.accessToken != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameProfile profile = session.getProfile();
|
||||
|
||||
AuthHandshake handshake = authHandshake(client, profile.getName());
|
||||
AuthHandshake handshake = authHandshake(profile.getName());
|
||||
|
||||
if (handshake.offline) {
|
||||
return;
|
||||
|
@ -151,7 +143,7 @@ public class ValhallaSkinServer extends AbstractSkinServer {
|
|||
// join the session server
|
||||
Minecraft.getMinecraft().getSessionService().joinServer(profile, session.getToken(), handshake.serverId);
|
||||
|
||||
AuthResponse response = authResponse(client, profile.getName(), handshake.verifyToken);
|
||||
AuthResponse response = authResponse(profile.getName(), handshake.verifyToken);
|
||||
if (!response.userId.equals(profile.getId())) {
|
||||
throw new IOException("UUID mismatch!"); // probably won't ever throw
|
||||
}
|
||||
|
@ -159,29 +151,21 @@ public class ValhallaSkinServer extends AbstractSkinServer {
|
|||
accessToken = response.accessToken;
|
||||
}
|
||||
|
||||
private <T> T readJson(HttpResponse resp, Class<T> cl) throws IOException {
|
||||
String type = resp.getEntity().getContentType().getValue();
|
||||
|
||||
private <T> T readJson(MoreHttpResponses resp, Class<T> cl) throws IOException {
|
||||
String type = resp.getResponse().getEntity().getContentType().getValue();
|
||||
if (!"application/json".equals(type)) {
|
||||
try {
|
||||
throw new IOException("Server returned a non-json response!");
|
||||
} finally {
|
||||
EntityUtils.consumeQuietly(resp.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
try (Reader r = new InputStreamReader(resp.getEntity().getContent())) {
|
||||
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||
// TODO specific error handling
|
||||
throw new IOException(gson.fromJson(r, JsonObject.class).get("message").getAsString());
|
||||
if (resp.ok()) {
|
||||
return resp.json(cl);
|
||||
}
|
||||
throw new IOException(resp.json(JsonObject.class).get("message").getAsString());
|
||||
|
||||
}
|
||||
|
||||
return gson.fromJson(r, cl);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthHandshake authHandshake(CloseableHttpClient client, String name) throws IOException {
|
||||
try (CloseableHttpResponse resp = client.execute(RequestBuilder.post()
|
||||
private AuthHandshake authHandshake(String name) throws IOException {
|
||||
try (MoreHttpResponses resp = MoreHttpResponses.execute(NetClient.nativeClient(), RequestBuilder.post()
|
||||
.setUri(getHandshakeURI())
|
||||
.addParameter("name", name)
|
||||
.build())) {
|
||||
|
@ -189,8 +173,8 @@ public class ValhallaSkinServer extends AbstractSkinServer {
|
|||
}
|
||||
}
|
||||
|
||||
private AuthResponse authResponse(CloseableHttpClient client, String name, long verifyToken) throws IOException {
|
||||
try (CloseableHttpResponse resp = client.execute(RequestBuilder.post()
|
||||
private AuthResponse authResponse(String name, long verifyToken) throws IOException {
|
||||
try (MoreHttpResponses resp = MoreHttpResponses.execute(NetClient.nativeClient(), RequestBuilder.post()
|
||||
.setUri(getResponseURI())
|
||||
.addParameter("name", name)
|
||||
.addParameter("verifyToken", String.valueOf(verifyToken))
|
||||
|
|
|
@ -101,7 +101,7 @@ public class LayerPonyCustomHead<T extends EntityLivingBase> implements LayerRen
|
|||
}
|
||||
|
||||
private ModelWrapper getModel() {
|
||||
return ((IRenderPony) renderer).getModelWrapper();
|
||||
return ((IRenderPony<?>) renderer).getModelWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue