mirror of
https://github.com/SKCraft/Launcher.git
synced 2024-11-30 13:13:58 +01:00
Switch to using Minecraft services as skin provider
We do some local processing to draw the head of the skin in 32px resolution.
This commit is contained in:
parent
fd78863697
commit
5d5a462387
@ -11,7 +11,7 @@ import com.skcraft.launcher.auth.microsoft.model.McAuthResponse;
|
|||||||
import com.skcraft.launcher.auth.microsoft.model.McProfileResponse;
|
import com.skcraft.launcher.auth.microsoft.model.McProfileResponse;
|
||||||
import com.skcraft.launcher.auth.microsoft.model.TokenResponse;
|
import com.skcraft.launcher.auth.microsoft.model.TokenResponse;
|
||||||
import com.skcraft.launcher.auth.microsoft.model.XboxAuthorization;
|
import com.skcraft.launcher.auth.microsoft.model.XboxAuthorization;
|
||||||
import com.skcraft.launcher.auth.skin.VisageSkinService;
|
import com.skcraft.launcher.auth.skin.MinecraftSkinService;
|
||||||
import com.skcraft.launcher.util.HttpRequest;
|
import com.skcraft.launcher.util.HttpRequest;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -103,10 +103,9 @@ public class MicrosoftLoginService implements LoginService {
|
|||||||
if (previous != null && previous.getAvatarImage() != null) {
|
if (previous != null && previous.getAvatarImage() != null) {
|
||||||
session.setAvatarImage(previous.getAvatarImage());
|
session.setAvatarImage(previous.getAvatarImage());
|
||||||
} else {
|
} else {
|
||||||
session.setAvatarImage(VisageSkinService.fetchSkinHead(profile.getUuid()));
|
session.setAvatarImage(MinecraftSkinService.fetchSkinHead(profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
package com.skcraft.launcher.auth;
|
package com.skcraft.launcher.auth;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.*;
|
import com.fasterxml.jackson.annotation.*;
|
||||||
import com.skcraft.launcher.auth.skin.VisageSkinService;
|
import com.skcraft.launcher.auth.microsoft.MinecraftServicesAuthorizer;
|
||||||
|
import com.skcraft.launcher.auth.microsoft.model.McProfileResponse;
|
||||||
|
import com.skcraft.launcher.auth.skin.MinecraftSkinService;
|
||||||
import com.skcraft.launcher.util.HttpRequest;
|
import com.skcraft.launcher.util.HttpRequest;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -60,7 +62,10 @@ public class YggdrasilLoginService implements LoginService {
|
|||||||
if (previous != null && previous.getAvatarImage() != null) {
|
if (previous != null && previous.getAvatarImage() != null) {
|
||||||
profile.setAvatarImage(previous.getAvatarImage());
|
profile.setAvatarImage(previous.getAvatarImage());
|
||||||
} else {
|
} else {
|
||||||
profile.setAvatarImage(VisageSkinService.fetchSkinHead(profile.getUuid()));
|
McProfileResponse skinProfile = MinecraftServicesAuthorizer
|
||||||
|
.getUserProfile("Bearer " + response.getAccessToken());
|
||||||
|
|
||||||
|
profile.setAvatarImage(MinecraftSkinService.fetchSkinHead(skinProfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
|
@ -28,8 +28,13 @@ public class MinecraftServicesAuthorizer {
|
|||||||
|
|
||||||
public static McProfileResponse getUserProfile(McAuthResponse auth)
|
public static McProfileResponse getUserProfile(McAuthResponse auth)
|
||||||
throws IOException, InterruptedException, AuthenticationException {
|
throws IOException, InterruptedException, AuthenticationException {
|
||||||
|
return getUserProfile(auth.getAuthorization());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static McProfileResponse getUserProfile(String authorization)
|
||||||
|
throws IOException, InterruptedException, AuthenticationException {
|
||||||
return HttpRequest.get(MC_SERVICES_PROFILE)
|
return HttpRequest.get(MC_SERVICES_PROFILE)
|
||||||
.header("Authorization", auth.getAuthorization())
|
.header("Authorization", authorization)
|
||||||
.execute()
|
.execute()
|
||||||
.expectResponseCodeOr(200, req -> {
|
.expectResponseCodeOr(200, req -> {
|
||||||
McServicesError error = req.returnContent().asJson(McServicesError.class);
|
McServicesError error = req.returnContent().asJson(McServicesError.class);
|
||||||
|
@ -1,12 +1,28 @@
|
|||||||
package com.skcraft.launcher.auth.microsoft.model;
|
package com.skcraft.launcher.auth.microsoft.model;
|
||||||
|
|
||||||
|
import com.beust.jcommander.internal.Lists;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class McProfileResponse {
|
public class McProfileResponse {
|
||||||
@JsonProperty("id") private String uuid;
|
@JsonProperty("id") private String uuid;
|
||||||
private String name;
|
private String name;
|
||||||
|
private List<Skin> skins = Lists.newArrayList();
|
||||||
|
|
||||||
|
public Skin getActiveSkin() {
|
||||||
|
return skins.stream().filter(skin -> skin.getState().equals("ACTIVE")).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public static class Skin {
|
||||||
|
private String state;
|
||||||
|
private String url;
|
||||||
|
private String variant;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.skcraft.launcher.auth.skin;
|
||||||
|
|
||||||
|
import com.skcraft.launcher.auth.microsoft.model.McProfileResponse;
|
||||||
|
import com.skcraft.launcher.util.HttpRequest;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@Log
|
||||||
|
public class MinecraftSkinService {
|
||||||
|
static byte[] downloadSkin(String textureUrl) throws IOException, InterruptedException {
|
||||||
|
return HttpRequest.get(HttpRequest.url(textureUrl))
|
||||||
|
.execute()
|
||||||
|
.expectResponseCode(200)
|
||||||
|
.returnContent()
|
||||||
|
.asBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] fetchSkinHead(McProfileResponse profile) throws InterruptedException {
|
||||||
|
try {
|
||||||
|
byte[] skin = downloadSkin(profile.getActiveSkin().getUrl());
|
||||||
|
|
||||||
|
return SkinProcessor.renderHead(skin);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.log(Level.WARNING, "Failed to download or process skin.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.skcraft.launcher.auth.skin;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SkinProcessor {
|
||||||
|
public static byte[] renderHead(byte[] skinData) throws IOException {
|
||||||
|
BufferedImage skin = ImageIO.read(new ByteArrayInputStream(skinData));
|
||||||
|
|
||||||
|
BufferedImage result = new BufferedImage(32, 32, BufferedImage.TYPE_INT_RGB);
|
||||||
|
Graphics graphics = result.getGraphics();
|
||||||
|
|
||||||
|
// Draw bottom head layer
|
||||||
|
graphics.drawImage(skin, 0, 0, 32, 32, 8, 8, 16, 16, null);
|
||||||
|
// Draw top head layer
|
||||||
|
graphics.drawImage(skin, 0, 0, 32, 32, 40, 8, 48, 16, null);
|
||||||
|
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write(result, "png", outputStream);
|
||||||
|
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
package com.skcraft.launcher.auth.skin;
|
package com.skcraft.launcher.auth.skin;
|
||||||
|
|
||||||
import com.skcraft.launcher.util.HttpRequest;
|
import com.skcraft.launcher.util.HttpRequest;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import static com.skcraft.launcher.util.HttpRequest.url;
|
import static com.skcraft.launcher.util.HttpRequest.url;
|
||||||
|
|
||||||
|
@Log
|
||||||
public class VisageSkinService {
|
public class VisageSkinService {
|
||||||
@Nullable
|
@Nullable
|
||||||
public static byte[] fetchSkinHead(String uuid) throws InterruptedException {
|
public static byte[] fetchSkinHead(String uuid) throws InterruptedException {
|
||||||
@ -19,6 +22,7 @@ public class VisageSkinService {
|
|||||||
.returnContent()
|
.returnContent()
|
||||||
.asBytes();
|
.asBytes();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
log.log(Level.WARNING, "Failed to download or process skin from Visage.", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user