From 55c1ca4139bbb3f9965bdbc276a949f2fb2d0e83 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 12 Apr 2024 19:50:36 +0100 Subject: [PATCH] add skin overlays to all images if it's enabled --- .../common/renderer/SkinRenderer.java | 19 ++++++++++++-- .../common/renderer/impl/BodyRenderer.java | 12 ++++----- .../renderer/impl/IsometricHeadRenderer.java | 6 ++--- .../common/renderer/impl/SquareRenderer.java | 9 +------ .../controller/PlayerController.java | 4 +-- .../cc/fascinated/model/skin/ISkinPart.java | 6 +++-- .../java/cc/fascinated/model/skin/Skin.java | 25 +++++-------------- .../cc/fascinated/service/PlayerService.java | 2 +- 8 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/main/java/cc/fascinated/common/renderer/SkinRenderer.java b/src/main/java/cc/fascinated/common/renderer/SkinRenderer.java index f93de80..3e31a41 100644 --- a/src/main/java/cc/fascinated/common/renderer/SkinRenderer.java +++ b/src/main/java/cc/fascinated/common/renderer/SkinRenderer.java @@ -4,24 +4,29 @@ import cc.fascinated.common.ImageUtils; import cc.fascinated.model.skin.ISkinPart; import cc.fascinated.model.skin.Skin; import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; +@Log4j2 public abstract class SkinRenderer { /** - * Get the texture of a part of a skin. + * Get the texture of a part of the skin. * * @param skin the skin to get the part texture from * @param part the part of the skin to get * @param size the size to scale the texture to + * @param renderOverlays should the overlays be rendered * @return the texture of the skin part */ @SneakyThrows - public BufferedImage getVanillaSkinPart(Skin skin, ISkinPart.Vanilla part, double size) { + public BufferedImage getVanillaSkinPart(Skin skin, ISkinPart.Vanilla part, double size, boolean renderOverlays) { ISkinPart.Vanilla.Coordinates coordinates = part.getCoordinates(); // The coordinates of the part // The skin texture is legacy, use legacy coordinates @@ -37,6 +42,16 @@ public abstract class SkinRenderer { if (coordinates instanceof ISkinPart.Vanilla.LegacyCoordinates legacyCoordinates && legacyCoordinates.isFlipped()) { partTexture = ImageUtils.flip(partTexture); } + + // Draw part overlays + ISkinPart.Vanilla[] overlayParts = part.getOverlays(); + if (overlayParts != null && renderOverlays) { + log.info("Applying overlays to part: {}", part.name()); + for (ISkinPart.Vanilla overlay : overlayParts) { + applyOverlay(partTexture.createGraphics(), getVanillaSkinPart(skin, overlay, size, false)); + } + } + return partTexture; } diff --git a/src/main/java/cc/fascinated/common/renderer/impl/BodyRenderer.java b/src/main/java/cc/fascinated/common/renderer/impl/BodyRenderer.java index 513a89b..e8de081 100644 --- a/src/main/java/cc/fascinated/common/renderer/impl/BodyRenderer.java +++ b/src/main/java/cc/fascinated/common/renderer/impl/BodyRenderer.java @@ -21,12 +21,12 @@ public class BodyRenderer extends SkinRenderer { Graphics2D graphics = texture.createGraphics(); // Create the graphics for drawing // Get the Vanilla skin parts to draw - BufferedImage face = getVanillaSkinPart(skin, ISkinPart.Vanilla.FACE, -1); - BufferedImage body = getVanillaSkinPart(skin, ISkinPart.Vanilla.BODY_FRONT, -1); - BufferedImage leftArm = getVanillaSkinPart(skin, ISkinPart.Vanilla.LEFT_ARM_FRONT, -1); - BufferedImage rightArm = getVanillaSkinPart(skin, ISkinPart.Vanilla.RIGHT_ARM_FRONT, -1); - BufferedImage leftLeg = getVanillaSkinPart(skin, ISkinPart.Vanilla.LEFT_LEG_FRONT, -1); - BufferedImage rightLeg = getVanillaSkinPart(skin, ISkinPart.Vanilla.RIGHT_LEG_FRONT, -1); + BufferedImage face = getVanillaSkinPart(skin, ISkinPart.Vanilla.FACE, -1, renderOverlays); + BufferedImage body = getVanillaSkinPart(skin, ISkinPart.Vanilla.BODY_FRONT, -1, renderOverlays); + BufferedImage leftArm = getVanillaSkinPart(skin, ISkinPart.Vanilla.LEFT_ARM_FRONT, -1, renderOverlays); + BufferedImage rightArm = getVanillaSkinPart(skin, ISkinPart.Vanilla.RIGHT_ARM_FRONT, -1, renderOverlays); + BufferedImage leftLeg = getVanillaSkinPart(skin, ISkinPart.Vanilla.LEFT_LEG_FRONT, -1, renderOverlays); + BufferedImage rightLeg = getVanillaSkinPart(skin, ISkinPart.Vanilla.RIGHT_LEG_FRONT, -1, renderOverlays); // Draw the body parts graphics.drawImage(face, 4, 0, null); diff --git a/src/main/java/cc/fascinated/common/renderer/impl/IsometricHeadRenderer.java b/src/main/java/cc/fascinated/common/renderer/impl/IsometricHeadRenderer.java index ab23179..e4a9e02 100644 --- a/src/main/java/cc/fascinated/common/renderer/impl/IsometricHeadRenderer.java +++ b/src/main/java/cc/fascinated/common/renderer/impl/IsometricHeadRenderer.java @@ -28,9 +28,9 @@ public class IsometricHeadRenderer extends IsometricSkinRenderer { @Override public BufferedImage render(Skin skin, ISkinPart.Vanilla part, boolean renderOverlays, int size) { double scale = size / 8D; - BufferedImage partImage = getVanillaSkinPart(skin, part, scale); // Get the part image + BufferedImage partImage = getVanillaSkinPart(skin, part, scale, renderOverlays); // Get the part image if (!renderOverlays) { // Not rendering overlays return partImage; } @@ -26,13 +26,6 @@ public class SquareRenderer extends SkinRenderer { Graphics2D graphics = texture.createGraphics(); // Create the graphics for drawing graphics.drawImage(partImage, 0, 0, null); - // Draw part overlays - ISkinPart.Vanilla[] overlayParts = part.getOverlays(); - if (overlayParts != null) { - for (ISkinPart.Vanilla overlay : overlayParts) { - applyOverlay(graphics, getVanillaSkinPart(skin, overlay, scale)); - } - } graphics.dispose(); return texture; } diff --git a/src/main/java/cc/fascinated/controller/PlayerController.java b/src/main/java/cc/fascinated/controller/PlayerController.java index e806978..0c0b0ae 100644 --- a/src/main/java/cc/fascinated/controller/PlayerController.java +++ b/src/main/java/cc/fascinated/controller/PlayerController.java @@ -48,7 +48,7 @@ public class PlayerController { @Parameter(description = "The part of the skin", example = "head") @PathVariable String part, @Parameter(description = "The UUID or Username of the player", example = "ImFascinated") @PathVariable String id, @Parameter(description = "The size of the image", example = "256") @RequestParam(required = false, defaultValue = "256") int size, - @Parameter(description = "Whether to render the skin overlay (skin layers)", example = "false") @RequestParam(required = false, defaultValue = "false") boolean overlay, + @Parameter(description = "Whether to render the skin overlay (skin layers)", example = "false") @RequestParam(required = false, defaultValue = "false") boolean overlays, @Parameter(description = "Whether to download the image") @RequestParam(required = false, defaultValue = "false") boolean download) { CachedPlayer player = playerService.getPlayer(id); String dispositionHeader = download ? "attachment; filename=%s.png" : "inline; filename=%s.png"; @@ -58,6 +58,6 @@ public class PlayerController { .cacheControl(cacheControl) .contentType(MediaType.IMAGE_PNG) .header(HttpHeaders.CONTENT_DISPOSITION, dispositionHeader.formatted(player.getUsername())) - .body(playerService.getSkinPart(player, part, overlay, size).getBytes()); + .body(playerService.getSkinPart(player, part, overlays, size).getBytes()); } } diff --git a/src/main/java/cc/fascinated/model/skin/ISkinPart.java b/src/main/java/cc/fascinated/model/skin/ISkinPart.java index 10b042d..7349589 100644 --- a/src/main/java/cc/fascinated/model/skin/ISkinPart.java +++ b/src/main/java/cc/fascinated/model/skin/ISkinPart.java @@ -59,12 +59,14 @@ public interface ISkinPart { @Getter enum Vanilla implements ISkinPart { // Overlays + HEAD_OVERLAY_TOP(true, new Coordinates(40, 0), 8, 8), HEAD_OVERLAY_FACE(true, new Coordinates(40, 8), 8, 8), + HEAD_OVERLAY_LEFT(true, new Coordinates(48, 8), 8, 8), // Head - HEAD_TOP(true, new Coordinates(8, 0), 8, 8), + HEAD_TOP(true, new Coordinates(8, 0), 8, 8, HEAD_OVERLAY_TOP), FACE(false, new Coordinates(8, 8), 8, 8, HEAD_OVERLAY_FACE), - HEAD_LEFT(true, new Coordinates(0, 8), 8, 8), + HEAD_LEFT(true, new Coordinates(0, 8), 8, 8, HEAD_OVERLAY_LEFT), HEAD_RIGHT(true, new Coordinates(16, 8), 8, 8), HEAD_BOTTOM(true, new Coordinates(16, 0), 8, 8), HEAD_BACK(true, new Coordinates(24, 8), 8, 8), diff --git a/src/main/java/cc/fascinated/model/skin/Skin.java b/src/main/java/cc/fascinated/model/skin/Skin.java index 0bf93a8..2931bfd 100644 --- a/src/main/java/cc/fascinated/model/skin/Skin.java +++ b/src/main/java/cc/fascinated/model/skin/Skin.java @@ -1,5 +1,6 @@ package cc.fascinated.model.skin; +import cc.fascinated.common.EnumUtils; import cc.fascinated.common.PlayerUtils; import cc.fascinated.config.Config; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -77,9 +78,10 @@ public class Skin { } String url = json.get("url").getAsString(); JsonObject metadata = json.getAsJsonObject("metadata"); - Model model = Model.fromName(metadata == null ? "default" : // Fall back to slim if the model is not found - metadata.get("model").getAsString()); - return new Skin(url, model); + return new Skin( + url, + EnumUtils.getEnumConstant(Model.class, metadata != null ? metadata.get("model").getAsString() : "DEFAULT") + ); } /** @@ -106,21 +108,6 @@ public class Skin { */ public enum Model { DEFAULT, - SLIM; - - /** - * Gets the model from its name. - * - * @param name the name of the model - * @return the model - */ - public static Model fromName(String name) { - for (Model model : values()) { - if (model.name().equalsIgnoreCase(name)) { - return model; - } - } - return null; - } + SLIM } } diff --git a/src/main/java/cc/fascinated/service/PlayerService.java b/src/main/java/cc/fascinated/service/PlayerService.java index aecbfc7..5d52115 100644 --- a/src/main/java/cc/fascinated/service/PlayerService.java +++ b/src/main/java/cc/fascinated/service/PlayerService.java @@ -138,7 +138,7 @@ public class PlayerService { } String name = part.name(); - log.info("Getting skin part {} for player: {}", name, player.getUniqueId()); + log.info("Getting skin part {} for player: {} (size: {}, renderOverlays: {})", name, player.getUniqueId(), size, renderOverlay); String key = "%s-%s-%s-%s".formatted(player.getUniqueId(), name, size, renderOverlay); Optional cache = playerSkinPartCacheRepository.findById(key);