diff --git a/src/main/java/me/braydon/mc/common/PlayerUtils.java b/src/main/java/me/braydon/mc/common/PlayerUtils.java index 98ed819..4b47312 100644 --- a/src/main/java/me/braydon/mc/common/PlayerUtils.java +++ b/src/main/java/me/braydon/mc/common/PlayerUtils.java @@ -17,18 +17,19 @@ import java.net.URL; */ @UtilityClass public final class PlayerUtils { - private static final int SKIN_TEXTURE_SIZE = 64; // The skin of a skin texture + public static final int SKIN_TEXTURE_SIZE = 64; // The skin of a skin texture /** * Get the head texture of a skin. * * @param skin the skin to get the head texture from + * @param part the part of the skin to get * @param size the size to scale the head texture to * @return the head texture of the skin */ @SneakyThrows - public static byte[] getHeadTexture(@NonNull Skin skin, int size) { - return getSkinPartTexture(skin, 8, 8, SKIN_TEXTURE_SIZE / 8, SKIN_TEXTURE_SIZE / 8, size); + public static byte[] getSkinPart(@NonNull Skin skin, @NonNull Skin.Part part, int size) { + return getSkinPartTexture(skin, part.getX(), part.getY(), part.getWidth(), part.getHeight(), size); } /** diff --git a/src/main/java/me/braydon/mc/config/AppConfig.java b/src/main/java/me/braydon/mc/config/AppConfig.java new file mode 100644 index 0000000..b1604c7 --- /dev/null +++ b/src/main/java/me/braydon/mc/config/AppConfig.java @@ -0,0 +1,24 @@ +package me.braydon.mc.config; + +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * The configuration for the app. + * + * @author Braydon + */ +@Configuration @Getter +public class AppConfig { + public static AppConfig INSTANCE; + + @Value("${server.publicUrl}") + private String serverPublicUrl; + + @PostConstruct + public void onInitialize() { + INSTANCE = this; + } +} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/controller/PlayerController.java b/src/main/java/me/braydon/mc/controller/PlayerController.java index e24dd08..056487a 100644 --- a/src/main/java/me/braydon/mc/controller/PlayerController.java +++ b/src/main/java/me/braydon/mc/controller/PlayerController.java @@ -92,6 +92,6 @@ public final class PlayerController { // Return the head texture return ResponseEntity.ok() .contentType(extension.equalsIgnoreCase("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_JPEG) - .body(PlayerUtils.getHeadTexture(target, size)); + .body(PlayerUtils.getSkinPart(target, Skin.Part.HEAD, size)); } } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/Skin.java b/src/main/java/me/braydon/mc/model/Skin.java index 26eaa0f..1b33bf4 100644 --- a/src/main/java/me/braydon/mc/model/Skin.java +++ b/src/main/java/me/braydon/mc/model/Skin.java @@ -1,14 +1,20 @@ package me.braydon.mc.model; import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; import lombok.*; +import me.braydon.mc.common.PlayerUtils; +import me.braydon.mc.config.AppConfig; + +import java.util.HashMap; +import java.util.Map; /** * A skin for a {@link Player}. * * @author Braydon */ -@AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter @ToString +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @Setter @Getter @ToString public final class Skin { public static final Skin DEFAULT_STEVE = new Skin("http://textures.minecraft.net/texture/60a5bd016b3c9a1b9272e4929e30827a67be4ebb219017adbbc4a4d22ebd5b1", Model.DEFAULT); @@ -22,6 +28,25 @@ public final class Skin { */ @NonNull private final Model model; + /** + * URLs to the parts of this skin. + */ + @NonNull @SerializedName("parts") private Map partUrls = new HashMap<>(); + + /** + * Populate the part URLs for this skin. + * + * @param playerUuid the UUID of the player + * @return the skin + */ + @NonNull + public Skin populatePartUrls(@NonNull String playerUuid) { + for (Part part : Part.values()) { + partUrls.put(part.name(), AppConfig.INSTANCE.getServerPublicUrl() + "/player/" + part.name().toLowerCase() + "/" + playerUuid + ".png"); + } + return this; + } + /** * Build a skin from the given Json object. * @@ -47,4 +72,22 @@ public final class Skin { public enum Model { SLIM, DEFAULT } + + /** + * The part of a skin. + */ + @AllArgsConstructor @Getter @ToString + public enum Part { + HEAD(8, 8, PlayerUtils.SKIN_TEXTURE_SIZE / 8, PlayerUtils.SKIN_TEXTURE_SIZE / 8); + + /** + * The coordinates of this part. + */ + private final int x, y; + + /** + * The size of this part. + */ + private final int width, height; + } } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java b/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java index 096abd3..8e87cf7 100644 --- a/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java +++ b/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java @@ -38,6 +38,11 @@ public final class MojangProfileToken { */ @NonNull private final ProfileAction[] profileActions; + /** + * Get the skin and cape of this profile. + * + * @return the skin and cape of this profile + */ public Tuple getSkinAndCape() { ProfileProperty textures = getPropertyByName("textures"); // Get the profile textures if (textures == null) { // No profile textures @@ -48,7 +53,7 @@ public final class MojangProfileToken { // Return the tuple containing the skin and cape return new Tuple<>( - Skin.fromJsonObject(texturesJsonObject.getAsJsonObject("SKIN")), + Skin.fromJsonObject(texturesJsonObject.getAsJsonObject("SKIN")).populatePartUrls(id), Cape.fromJsonObject(texturesJsonObject.getAsJsonObject("CAPE")) ); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 27e80e9..f66e79b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,6 +2,7 @@ server: address: 0.0.0.0 port: 7500 + publicUrl: "http://localhost:7500" # The publicly accessible URL for this app # Log Configuration logging: