Show skin part URLs in the Skin model

This commit is contained in:
Braydon 2024-04-07 00:07:08 -04:00
parent 193974dda9
commit 50a6af9ed8
6 changed files with 80 additions and 6 deletions

@ -17,18 +17,19 @@ import java.net.URL;
*/ */
@UtilityClass @UtilityClass
public final class PlayerUtils { 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. * Get the head texture of a skin.
* *
* @param skin the skin to get the head texture from * @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 * @param size the size to scale the head texture to
* @return the head texture of the skin * @return the head texture of the skin
*/ */
@SneakyThrows @SneakyThrows
public static byte[] getHeadTexture(@NonNull Skin skin, int size) { public static byte[] getSkinPart(@NonNull Skin skin, @NonNull Skin.Part part, int size) {
return getSkinPartTexture(skin, 8, 8, SKIN_TEXTURE_SIZE / 8, SKIN_TEXTURE_SIZE / 8, size); return getSkinPartTexture(skin, part.getX(), part.getY(), part.getWidth(), part.getHeight(), size);
} }
/** /**

@ -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;
}
}

@ -92,6 +92,6 @@ public final class PlayerController {
// Return the head texture // Return the head texture
return ResponseEntity.ok() return ResponseEntity.ok()
.contentType(extension.equalsIgnoreCase("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_JPEG) .contentType(extension.equalsIgnoreCase("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_JPEG)
.body(PlayerUtils.getHeadTexture(target, size)); .body(PlayerUtils.getSkinPart(target, Skin.Part.HEAD, size));
} }
} }

@ -1,14 +1,20 @@
package me.braydon.mc.model; package me.braydon.mc.model;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
import lombok.*; 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}. * A skin for a {@link Player}.
* *
* @author Braydon * @author Braydon
*/ */
@AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter @ToString @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @Setter @Getter @ToString
public final class Skin { public final class Skin {
public static final Skin DEFAULT_STEVE = new Skin("http://textures.minecraft.net/texture/60a5bd016b3c9a1b9272e4929e30827a67be4ebb219017adbbc4a4d22ebd5b1", Model.DEFAULT); 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; @NonNull private final Model model;
/**
* URLs to the parts of this skin.
*/
@NonNull @SerializedName("parts") private Map<String, String> 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. * Build a skin from the given Json object.
* *
@ -47,4 +72,22 @@ public final class Skin {
public enum Model { public enum Model {
SLIM, DEFAULT 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;
}
} }

@ -38,6 +38,11 @@ public final class MojangProfileToken {
*/ */
@NonNull private final ProfileAction[] profileActions; @NonNull private final ProfileAction[] profileActions;
/**
* Get the skin and cape of this profile.
*
* @return the skin and cape of this profile
*/
public Tuple<Skin, Cape> getSkinAndCape() { public Tuple<Skin, Cape> getSkinAndCape() {
ProfileProperty textures = getPropertyByName("textures"); // Get the profile textures ProfileProperty textures = getPropertyByName("textures"); // Get the profile textures
if (textures == null) { // No 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 the tuple containing the skin and cape
return new Tuple<>( return new Tuple<>(
Skin.fromJsonObject(texturesJsonObject.getAsJsonObject("SKIN")), Skin.fromJsonObject(texturesJsonObject.getAsJsonObject("SKIN")).populatePartUrls(id),
Cape.fromJsonObject(texturesJsonObject.getAsJsonObject("CAPE")) Cape.fromJsonObject(texturesJsonObject.getAsJsonObject("CAPE"))
); );
} }

@ -2,6 +2,7 @@
server: server:
address: 0.0.0.0 address: 0.0.0.0
port: 7500 port: 7500
publicUrl: "http://localhost:7500" # The publicly accessible URL for this app
# Log Configuration # Log Configuration
logging: logging: