From 1e52830c9107ca4bf6c3f3b7912e8bc885ee5bf3 Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 29 Jun 2018 23:33:05 +0200 Subject: [PATCH] Added proper alex model support to HDSkins. Skin servers should remember what the "model" parameter was when saving a skin and include it in their responses. --- .../voxelmodpack/hdskins/HDSkinManager.java | 2 +- .../voxelmodpack/hdskins/PreviewTexture.java | 14 ++++- .../hdskins/gui/EntityPlayerModel.java | 53 ++++++++++++++----- .../voxelmodpack/hdskins/gui/GuiSkins.java | 39 +++++++++++--- .../hdskins/gui/RenderPlayerModel.java | 4 +- .../hdskins/skins/LegacySkinServer.java | 13 ++--- .../hdskins/skins/SkinServer.java | 2 +- .../hdskins/skins/ValhallaSkinServer.java | 2 +- .../resources/assets/hdskins/lang/en_us.lang | 3 +- .../java/com/minelittlepony/PonyManager.java | 9 +++- .../hdskins/gui/EntityPonyModel.java | 27 ++-------- .../hdskins/gui/RenderPonyModel.java | 5 +- .../com/minelittlepony/pony/data/Pony.java | 4 ++ 13 files changed, 113 insertions(+), 64 deletions(-) diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java index 3faec335..6d90b6f4 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java @@ -231,7 +231,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener { return null; IImageBuffer buffer = new ImageBufferDownloadHD(); - PreviewTexture skinTexture = new PreviewTexture(url.getUrl(), def, type == Type.SKIN ? new IImageBuffer() { + PreviewTexture skinTexture = new PreviewTexture(url.getMetadata("model"), url.getUrl(), def, type == Type.SKIN ? new IImageBuffer() { @Override @Nullable public BufferedImage parseUserSkin(BufferedImage image) { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTexture.java b/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTexture.java index e2359c26..ee6ce18e 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTexture.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTexture.java @@ -10,8 +10,12 @@ public class PreviewTexture extends ThreadDownloadImageData { private boolean uploaded; - public PreviewTexture(String url, ResourceLocation fallbackTexture, @Nullable IImageBuffer imageBuffer) { + private String model; + + public PreviewTexture(String model, String url, ResourceLocation fallbackTexture, @Nullable IImageBuffer imageBuffer) { super(null, url, fallbackTexture, imageBuffer); + + this.model = model; } public boolean isTextureUploaded() { @@ -23,4 +27,12 @@ public class PreviewTexture extends ThreadDownloadImageData { super.deleteGlTexture(); this.uploaded = true; } + + public boolean hasModel() { + return model != null; + } + + public boolean usesThinArms() { + return "thin".equals(model); + } } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java index f793c605..6b2b2f83 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java @@ -16,6 +16,7 @@ import net.minecraft.client.resources.SkinManager; import net.minecraft.entity.EntityLivingBase; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHandSide; import net.minecraft.util.ResourceLocation; @@ -49,9 +50,10 @@ public class EntityPlayerModel extends EntityLivingBase { private DynamicTexture localElytraTexture; private TextureManager textureManager; public final GameProfile profile; - public boolean isSwinging = false; + protected boolean remoteSkin = false; protected boolean hasLocalTexture = false; + protected boolean previewThinArms = false; public EntityPlayerModel(GameProfile profile) { super(null); @@ -59,8 +61,8 @@ public class EntityPlayerModel extends EntityLivingBase { this.textureManager = Minecraft.getMinecraft().getTextureManager(); this.remoteSkinResource = new ResourceLocation("skins/preview_" + this.profile.getName() + ".png"); this.remoteElytraResource = new ResourceLocation("elytras/preview_" + this.profile.getName() + ".png"); - this.localSkinResource = NO_SKIN; - this.localElytraResource = NO_ELYTRA; + this.localSkinResource = getBlankSkin(); + this.localElytraResource = getBlankElytra(); this.textureManager.deleteTexture(this.remoteSkinResource); this.textureManager.deleteTexture(this.remoteElytraResource); } @@ -74,8 +76,8 @@ public class EntityPlayerModel extends EntityLivingBase { this.textureManager.deleteTexture(this.remoteElytraResource); } - this.remoteSkinTexture = HDSkinManager.getPreviewTexture(this.remoteSkinResource, this.profile, Type.SKIN, NO_SKIN, listener); - this.remoteElytraTexture = HDSkinManager.getPreviewTexture(this.remoteElytraResource, this.profile, Type.ELYTRA, NO_ELYTRA, null); + this.remoteSkinTexture = HDSkinManager.getPreviewTexture(this.remoteSkinResource, this.profile, Type.SKIN, getBlankSkin(), listener); + this.remoteElytraTexture = HDSkinManager.getPreviewTexture(this.remoteElytraResource, this.profile, Type.ELYTRA, getBlankElytra(), null); } @@ -94,7 +96,7 @@ public class EntityPlayerModel extends EntityLivingBase { bufferedImage = new ImageBufferDownloadHD().parseUserSkin(image); assert bufferedImage != null; } catch (IOException var4) { - this.localSkinResource = NO_SKIN; + this.localSkinResource = getBlankSkin(); var4.printStackTrace(); return; } @@ -113,7 +115,7 @@ public class EntityPlayerModel extends EntityLivingBase { try { bufferedImage = ImageIO.read(skinTextureFile); } catch (IOException var4) { - this.localElytraResource = NO_ELYTRA; + this.localElytraResource = getBlankElytra(); var4.printStackTrace(); return; } @@ -125,6 +127,14 @@ public class EntityPlayerModel extends EntityLivingBase { } } + protected ResourceLocation getBlankSkin() { + return NO_SKIN; + } + + protected ResourceLocation getBlankElytra() { + return NO_ELYTRA; + } + public boolean isUsingLocalTexture() { return !this.remoteSkin && this.hasLocalTexture; } @@ -137,13 +147,13 @@ public class EntityPlayerModel extends EntityLivingBase { if (this.localSkinTexture != null) { this.textureManager.deleteTexture(this.localSkinResource); this.localSkinTexture = null; - this.localSkinResource = NO_SKIN; + this.localSkinResource = getBlankSkin(); this.hasLocalTexture = false; } if (this.localElytraTexture != null) { this.textureManager.deleteTexture(this.localElytraResource); this.localElytraTexture = null; - this.localElytraResource = NO_ELYTRA; + this.localElytraResource = getBlankElytra(); this.hasLocalTexture = false; } } @@ -157,21 +167,36 @@ public class EntityPlayerModel extends EntityLivingBase { return this.remoteSkin && this.remoteElytraTexture != null ? this.remoteElytraResource : localElytraResource; } - public void swingArm() { - if (!this.isSwinging || this.swingProgressInt >= 4 || this.swingProgressInt < 0) { + public void setPreviewThinArms(boolean thinArms) { + previewThinArms = thinArms; + } + + public boolean usesThinSkin() { + if (isTextureSetupComplete() && remoteSkinTexture.hasModel()) { + return remoteSkinTexture.usesThinArms(); + } + + return previewThinArms; + } + + @Override + public void swingArm(EnumHand hand) { + super.swingArm(hand); + if (!this.isSwingInProgress || this.swingProgressInt >= 4 || this.swingProgressInt < 0) { this.swingProgressInt = -1; - this.isSwinging = true; + this.isSwingInProgress = true; + this.swingingHand = hand; } } public void updateModel() { this.prevSwingProgress = this.swingProgress; - if (this.isSwinging) { + if (this.isSwingInProgress) { ++this.swingProgressInt; if (this.swingProgressInt >= 8) { this.swingProgressInt = 0; - this.isSwinging = false; + this.isSwingInProgress = false; } } else { this.swingProgressInt = 0; diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java index 18f5c277..8dd3757d 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java @@ -27,6 +27,7 @@ import net.minecraft.client.resources.I18n; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Session; import net.minecraft.util.math.MathHelper; @@ -63,6 +64,7 @@ public class GuiSkins extends GuiScreen implements FutureCallback 30 && mouseX < mid - 30 || mouseX > mid + 30 && mouseX < this.width - 30) && mouseY > top && mouseY < bottom) { - this.localPlayer.swingArm(); - this.remotePlayer.swingArm(); + this.localPlayer.swingArm(EnumHand.MAIN_HAND); + this.remotePlayer.swingArm(EnumHand.MAIN_HAND); } } @@ -527,11 +548,13 @@ public class GuiSkins extends GuiScreen implements FutureCallback extends RenderLiving protected final ResourceLocation TEXTURE_ELYTRA = new ResourceLocation("textures/entity/elytra.png"); private static final ModelPlayer FAT = new ModelPlayer(0, false); - //private static final ModelPlayer THIN = new ModelPlayer(0, true); + private static final ModelPlayer THIN = new ModelPlayer(0, true); public RenderPlayerModel(RenderManager renderer) { super(renderer, FAT, 0.0F); @@ -83,7 +83,7 @@ public class RenderPlayerModel extends RenderLiving } public ModelPlayer getEntityModel(M entity) { - return FAT; + return entity.usesThinSkin() ? THIN : FAT; } @Override diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java index 8a7c9d20..8fcb8486 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java @@ -88,7 +88,7 @@ public class LegacySkinServer implements SkinServer { } @Override - public ListenableFuture uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type) { + public ListenableFuture uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type, boolean thinSkinType) { if (Strings.isNullOrEmpty(this.gateway)) return Futures.immediateFailedFuture(new NullPointerException("gateway url is blank")); @@ -96,27 +96,28 @@ public class LegacySkinServer implements SkinServer { return HDSkinManager.skinUploadExecutor.submit(() -> { verifyServerConnection(session, SERVER_ID); - Map data = image == null ? getClearData(session, type) : getUploadData(session, type, image); + Map data = image == null ? getClearData(session, type) : getUploadData(session, type, (thinSkinType ? "thin" : "default"), image); ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data); String response = upload.uploadMultipart(); return new SkinUploadResponse(response.equalsIgnoreCase("OK"), response); }); } - private static Map getData(Session session, MinecraftProfileTexture.Type type, String param, Object val) { + private static Map getData(Session session, MinecraftProfileTexture.Type type, String model, String param, Object val) { return ImmutableMap.of( "user", session.getUsername(), "uuid", session.getPlayerID(), "type", type.toString().toLowerCase(Locale.US), + "model", model, param, val); } private static Map getClearData(Session session, MinecraftProfileTexture.Type type) { - return getData(session, type, "clear", "1"); + return getData(session, type, "default", "clear", "1"); } - private static Map getUploadData(Session session, MinecraftProfileTexture.Type type, Path skinFile) { - return getData(session, type, type.toString().toLowerCase(Locale.US), skinFile); + private static Map getUploadData(Session session, MinecraftProfileTexture.Type type, String model, Path skinFile) { + return getData(session, type, model, type.toString().toLowerCase(Locale.US), skinFile); } private static String getPath(String address, MinecraftProfileTexture.Type type, GameProfile profile) { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java index fb5f89fa..a51ec9c7 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java @@ -20,7 +20,7 @@ public interface SkinServer { Optional getPreviewTexture(MinecraftProfileTexture.Type type, GameProfile profile); - ListenableFuture uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type); + ListenableFuture uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type, boolean thinArmType); static SkinServer from(String server) { int i = server.indexOf(':'); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java index 9a3643b6..edaea83f 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java @@ -32,7 +32,7 @@ public class ValhallaSkinServer implements SkinServer { } @Override - public ListenableFuture uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type) { + public ListenableFuture uploadSkin(Session session, @Nullable Path image, MinecraftProfileTexture.Type type, boolean thinArmType) { return null; } diff --git a/src/hdskins/resources/assets/hdskins/lang/en_us.lang b/src/hdskins/resources/assets/hdskins/lang/en_us.lang index 5e0fd519..623a37cd 100644 --- a/src/hdskins/resources/assets/hdskins/lang/en_us.lang +++ b/src/hdskins/resources/assets/hdskins/lang/en_us.lang @@ -17,6 +17,7 @@ hdskins.upload=Uploading skin please wait... hdskins.local=Local Skin hdskins.server=Server Skin -hdskins.mode.skin=Skin +hdskins.mode.skin=Skin (Steve) +hdskins.mode.skinny=Skin (Alex) hdskins.mode.elytra=Elytra diff --git a/src/main/java/com/minelittlepony/PonyManager.java b/src/main/java/com/minelittlepony/PonyManager.java index d92b2c46..b65a6e9f 100644 --- a/src/main/java/com/minelittlepony/PonyManager.java +++ b/src/main/java/com/minelittlepony/PonyManager.java @@ -65,7 +65,14 @@ public class PonyManager implements IResourceManagerReloadListener, ISkinCacheCl * @param resource A texture resource */ public Pony getPony(ResourceLocation resource, boolean slim) { - return poniesCache.computeIfAbsent(resource, res -> new Pony(res, slim)); + Pony pony = poniesCache.computeIfAbsent(resource, res -> new Pony(res, slim)); + + if (pony.usesThinArms() != slim) { + pony = new Pony(resource, slim); + poniesCache.put(resource, pony); + } + + return pony; } /** diff --git a/src/main/java/com/minelittlepony/hdskins/gui/EntityPonyModel.java b/src/main/java/com/minelittlepony/hdskins/gui/EntityPonyModel.java index 7b35c4a4..ed612190 100644 --- a/src/main/java/com/minelittlepony/hdskins/gui/EntityPonyModel.java +++ b/src/main/java/com/minelittlepony/hdskins/gui/EntityPonyModel.java @@ -1,12 +1,8 @@ package com.minelittlepony.hdskins.gui; -import java.io.File; - import com.mojang.authlib.GameProfile; -import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.voxelmodpack.hdskins.gui.EntityPlayerModel; -import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; /** @@ -20,25 +16,8 @@ public class EntityPonyModel extends EntityPlayerModel { super(profile); } - public void setLocalTexture(File skinTextureFile, Type type) { - super.setLocalTexture(skinTextureFile, type); - } - - public ResourceLocation getSkinTexture() { - ResourceLocation skin = super.getSkinTexture(); - if (skin == NO_SKIN) { - // We're a pony, might as well look like one. - return NO_SKIN_PONY; - } - - return skin; - } - - public void swingArm() { - super.swingArm(); - - // Fixes the preview model swinging the wrong arm. - // Who's maintaining HDSkins anyway? - swingingHand = EnumHand.MAIN_HAND; + @Override + protected ResourceLocation getBlankSkin() { + return NO_SKIN_PONY; } } diff --git a/src/main/java/com/minelittlepony/hdskins/gui/RenderPonyModel.java b/src/main/java/com/minelittlepony/hdskins/gui/RenderPonyModel.java index 07f90a64..24c22ab1 100644 --- a/src/main/java/com/minelittlepony/hdskins/gui/RenderPonyModel.java +++ b/src/main/java/com/minelittlepony/hdskins/gui/RenderPonyModel.java @@ -1,7 +1,6 @@ package com.minelittlepony.hdskins.gui; import com.minelittlepony.MineLittlePony; -import com.minelittlepony.PonyManager; import com.minelittlepony.model.ModelWrapper; import com.minelittlepony.model.components.PonyElytra; import com.minelittlepony.pony.data.Pony; @@ -40,9 +39,7 @@ public class RenderPonyModel extends RenderPlayerModel { return super.getEntityModel(playermodel); } - // TODO: We can't find out whether to use thin arms just by the texture. - // Maybe a trigger pixel for thin arms? #FutureThoughts - Pony thePony = MineLittlePony.getInstance().getManager().getPony(loc, PonyManager.isSlimSkin(playermodel.profile.getId())); + Pony thePony = MineLittlePony.getInstance().getManager().getPony(loc, playermodel.usesThinSkin()); if (thePony.getRace(false).isHuman()) { return super.getEntityModel(playermodel); diff --git a/src/main/java/com/minelittlepony/pony/data/Pony.java b/src/main/java/com/minelittlepony/pony/data/Pony.java index ed89c4df..0d9af777 100644 --- a/src/main/java/com/minelittlepony/pony/data/Pony.java +++ b/src/main/java/com/minelittlepony/pony/data/Pony.java @@ -136,6 +136,10 @@ public class Pony { return metadata.getRace().getEffectiveRace(MineLittlePony.getConfig().getEffectivePonyLevel(ignorePony)); } + public boolean usesThinArms() { + return smallArms; + } + public ResourceLocation getTexture() { return texture; }