diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java index 78e61332..cbe2ae64 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java @@ -44,6 +44,7 @@ public final class HDSkinManager { public static final HDSkinManager INSTANCE = new HDSkinManager(); private static final ResourceLocation LOADING = new ResourceLocation("LOADING"); + public static final String METADATA_KEY = "hdskins.metadata"; private String gatewayUrl = "skinmanager.voxelmodpack.com"; private String skinUrl = "skins.voxelmodpack.com"; @@ -141,13 +142,13 @@ public final class HDSkinManager { if (textures == null) { IWebPreferences prefs = this.webprefs.getPreferences(profile); - Map metadata = new Gson().fromJson(prefs.get("hdskins.metadata"), new TypeToken>() {}.getType()); + TypeToken map = new TypeToken>() {}; + Map metadata = new Gson().fromJson(prefs.get(METADATA_KEY), map.getType()); String uuid = UUIDTypeAdapter.fromUUID(profile.getId()); String skinUrl = getCustomTextureURLForId(Type.SKIN, uuid, false); String capeUrl = getCustomTextureURLForId(Type.CAPE, uuid); String elytraUrl = getCustomTextureURLForId(Type.ELYTRA, uuid); - // TODO metadata (needs server support) textures = ImmutableMap.of( Type.SKIN, new MinecraftProfileTexture(skinUrl, metadata), Type.CAPE, new MinecraftProfileTexture(capeUrl, null), diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiColorButton.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiColorButton.java new file mode 100644 index 00000000..cdcf96db --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiColorButton.java @@ -0,0 +1,101 @@ +package com.voxelmodpack.hdskins.gui; + +import static net.minecraft.client.renderer.GlStateManager.color; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.resources.I18n; + +/** + * Color picker button control, spawns a color picker when clicked. Code + * originally by Adam Mummery-Smith. + */ +public class GuiColorButton extends GuiButton { + + private Minecraft mc; + private int color = 0x000000; + private GuiColorPicker picker; + private boolean pickerClicked = false; + + public GuiColorButton(Minecraft minecraft, int id, int xPosition, int yPosition, int controlWidth, int controlHeight, int color, String name) { + super(id, xPosition, yPosition, controlWidth, controlHeight, I18n.format(name)); + this.mc = minecraft; + this.color = color; + } + + public int getColor() { + return this.color; + } + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + boolean mouseOver = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height; + int borderColor = mouseOver || this.picker != null ? 0xFFFFFFFF : 0xFFA0A0A0; + + drawRect(this.xPosition, this.yPosition, this.xPosition + this.width, this.yPosition + this.height, borderColor); + + color(1.0F, 1.0F, 1.0F, 1.0F); + + drawRect(this.xPosition + 1, this.yPosition + 1, this.xPosition + this.width - 1, this.yPosition + this.height - 1, 0xFF000000 | this.color); + + this.mouseDragged(mc, mouseX, mouseY); + + if (this.displayString != null && this.displayString.length() > 0) { + int x = this.xPosition + this.width + 8; + int y = this.yPosition + (this.height - 8) / 2; + this.drawString(mc.fontRendererObj, this.displayString, x, y, this.enabled ? 0xFFFFFFFF : 0xFFA0A0A0); + } + } + + public void drawPicker(Minecraft minecraft, int mouseX, int mouseY) { + if (this.picker != null) { + this.picker.drawButton(minecraft, mouseX, mouseY); + + } + } + + public void closePicker(boolean getColor) { + if (getColor) + this.color = this.picker.getColor(); + this.picker = null; + this.pickerClicked = false; + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + if (this.pickerClicked && this.picker != null) { + this.picker.mouseReleased(mouseX, mouseY); + this.pickerClicked = false; + } + } + + @Override + public boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) { + boolean pressed = super.mousePressed(minecraft, mouseX, mouseY); + + if (this.picker == null) { + if (pressed) { + int xPos = Math.min(this.xPosition + this.width, mc.currentScreen.width - 233); + int yPos = Math.min(this.yPosition, mc.currentScreen.height - 175); + + this.picker = new GuiColorPicker(minecraft, 1, xPos, yPos, 0xFFFFFF & this.color, "Choose color"); + this.pickerClicked = false; + } + + return pressed; + } + + this.pickerClicked = this.picker.mousePressed(minecraft, mouseX, mouseY); + + if (pressed && !this.pickerClicked) { + this.closePicker(true); + } + + return this.pickerClicked; + } + + public boolean keyTyped(char keyChar, int keyCode) { + return (this.picker != null) ? this.picker.textBoxKeyTyped(keyChar, keyCode) : false; + } + +} \ No newline at end of file diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiColorPicker.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiColorPicker.java new file mode 100644 index 00000000..68ab8d1a --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiColorPicker.java @@ -0,0 +1,311 @@ +package com.voxelmodpack.hdskins.gui; + +import static net.minecraft.client.renderer.GlStateManager.*; +import static org.lwjgl.opengl.GL11.*; + +import java.awt.Color; +import java.awt.Rectangle; + +import org.apache.logging.log4j.core.helpers.Integers; +import org.lwjgl.input.Keyboard; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.LogicOp; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +/** + * Color picker flyout control, for use with the designable GUI properties + * window. Code originally by Adam Mummery-Smith. + */ +public class GuiColorPicker extends GuiButton { + + public static final ResourceLocation COLORPICKER_PICKER = new ResourceLocation("hdskins", + "textures/gui/picker.png"); + + /** Indices into the HSB array. */ + private static final int H = 0, S = 1, B = 2; + + /** HSB values from Color.RGBtoHSB. */ + private float[] hsb; + + /** Original and altered RGB values. */ + private int rgb; + + /** Text boxes for manual entry. */ + private GuiTextField txtRed, txtGreen, txtBlue; + + // /** OK and cancel buttons. */ + // private GuiControl btnOk, btnCancel; + + /** Flags to track whether dragging a slider. */ + private boolean draggingHS, draggingB; + + /** Slider rectangles. */ + private Rectangle rectHSArea, rectBArea; + + /** Set when the user clicks ok or cancel. */ + // private DialogResult result = DialogResult.None; + + private FontRenderer fontRenderer; + + private Minecraft mc; + + public GuiColorPicker(Minecraft minecraft, int controlId, int xPos, int yPos, int initialColor, String displayText) { + super(controlId, xPos, yPos, displayText); + this.mc = minecraft; + Color color = new Color(initialColor); + this.hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null); + + this.fontRenderer = minecraft.fontRendererObj; + this.txtRed = new GuiTextField(0, this.fontRenderer, this.xPosition + 163, this.yPosition + 10, 32, 16); + this.txtGreen = new GuiTextField(0, this.fontRenderer, this.xPosition + 163, this.yPosition + 30, 32, 16); + this.txtBlue = new GuiTextField(0, this.fontRenderer, this.xPosition + 163, this.yPosition + 50, 32, 16); + + this.txtRed.setMaxStringLength(3); + this.txtGreen.setMaxStringLength(3); + this.txtBlue.setMaxStringLength(3); + + this.rectHSArea = new Rectangle(this.xPosition + 10, this.yPosition + 10, 128, 128); + this.rectBArea = new Rectangle(this.xPosition + 143, this.yPosition + 10, 15, 128); + + // this.btnOk = + // new GuiControl(minecraft, 0, this.xPosition + 9, this.yPosition + + // 145, 55, 20, + // I18n.format("config.picker.ok")); + // this.btnCancel = + // new GuiControl(minecraft, 1, this.xPosition + 70, this.yPosition + + // 145, 65, 20, + // I18n.format("config.picker.cancel")); + + this.updateColor(); + } + + // public DialogResult getDialogResult() { + // return this.result; + // } + + public int getColor() { + int rgb = (0xFFFFFF & Color.HSBtoRGB(this.hsb[H], this.hsb[S], this.hsb[B])); + return rgb; + } + + protected void drawColorPicker(Minecraft minecraft, int mouseX, int mouseY) { + this.mouseDragged(minecraft, mouseX, mouseY); + + // Calculate coordinates for the selectors + int hPos = this.xPosition + 10 + (int) (128F * this.hsb[H]); + int sPos = this.yPosition + 10 + (128 - (int) (128F * this.hsb[S])); + int bPos = this.yPosition + 10 + (128 - (int) (128F * this.hsb[B])); + + // Calculate B color + int brightness = Color.HSBtoRGB(this.hsb[H], this.hsb[S], 1.0F) | 0xFF000000; + + // Draw backgrounds + // Background + drawRect(this.xPosition, this.yPosition, this.xPosition + this.width, this.yPosition + this.height, 0xAA000000); + // HS background + drawRect(this.xPosition + 9, this.yPosition + 9, this.xPosition + 139, this.yPosition + 139, 0xFFA0A0A0); + // B background + drawRect(this.xPosition + 142, this.yPosition + 9, this.xPosition + 159, this.yPosition + 139, 0xFFA0A0A0); + // Preview background + drawRect(this.xPosition + 162, this.yPosition + 105, this.xPosition + 196, this.yPosition + 139, 0xFFA0A0A0); + + // Draw color picker + this.mc.getTextureManager().bindTexture(GuiColorPicker.COLORPICKER_PICKER); + color(1.0F, 1.0F, 1.0F, 1.0F); + drawScaledCustomSizeModalRect(this.xPosition + 10, this.yPosition + 10, 0, 0, 256, 256, 138, 138, 256, 256); + this.drawCrossHair(hPos, sPos, 5, 1, 0xFF000000); + + // Draw brightness bar + this.drawGradientRect(this.xPosition + 143, this.yPosition + 10, this.xPosition + 158, this.yPosition + 138, brightness, 0xFF000000); + this.drawRotText(this.fontRenderer, "Luminosity", this.xPosition + 150, this.yPosition + 74, 0xFF000000, false); + drawRect(this.xPosition + 142, bPos - 1, this.xPosition + 159, bPos + 1, 0xFFFFFFFF); + + // Draw preview + drawRect(this.xPosition + 163, this.yPosition + 106, this.xPosition + 195, this.yPosition + 138, 0xFF000000 | this.rgb); + + // Draw text boxes + this.txtRed.drawTextBox(); + this.txtGreen.drawTextBox(); + this.txtBlue.drawTextBox(); + + // this.btnOk.drawButton(minecraft, mouseX, mouseY); + // this.btnCancel.drawButton(minecraft, mouseX, mouseY); + } + + private void drawCrossHair(int x, int y, int size, int width, int color) { + float alpha = (color >> 24 & 0xff) / 255F; + float red = (color >> 16 & 0xff) / 255F; + float green = (color >> 8 & 0xff) / 255F; + float blue = (color & 0xff) / 255F; + + GlStateManager.glLineWidth(mc.gameSettings.guiScale * width); + blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + enableBlend(); + disableTexture2D(); + disableLighting(); + color(red, green, blue, alpha); + enableColorLogic(); + colorLogicOp(LogicOp.OR_REVERSE); + + // Draw the frame + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer vb = tessellator.getBuffer(); + + vb.begin(GL_LINES, DefaultVertexFormats.POSITION); + vb.pos(x - size, y, 0).endVertex(); + vb.pos(x + size, y, 0).endVertex(); + tessellator.draw(); + + vb.begin(GL_LINES, DefaultVertexFormats.POSITION); + vb.pos(x, y - size, 0).endVertex(); + vb.pos(x, y + size, 0).endVertex(); + tessellator.draw(); + + disableColorLogic(); + enableTexture2D(); + } + + private void drawRotText(FontRenderer fontRenderer, String text, int xPosition, int yPosition, + int color, boolean colorOrOp) { + if (colorOrOp) { + enableColorLogic(); + colorLogicOp(GL_OR_REVERSE); + } + + int textWidth = fontRenderer.getStringWidth(text) / 2; + + pushMatrix(); + translate(xPosition, yPosition, 0); + rotate(-90, 0, 0, 1); + translate(-textWidth, -4, 0); + + fontRenderer.drawString(text, 0, 0, color); + + popMatrix(); + + if (colorOrOp) { + disableColorLogic(); + enableTexture2D(); + } + } + + public void updateCursorCounter() { + this.txtRed.updateCursorCounter(); + this.txtGreen.updateCursorCounter(); + this.txtBlue.updateCursorCounter(); + } + + protected void updateColor() { + this.rgb = (0xFFFFFF & Color.HSBtoRGB(this.hsb[H], this.hsb[S], this.hsb[B])); + this.txtRed.setText(String.valueOf((this.rgb >> 16) & 0xFF)); + this.txtGreen.setText(String.valueOf((this.rgb >> 8) & 0xFF)); + this.txtBlue.setText(String.valueOf(this.rgb & 0xFF)); + } + + protected void updateColorFromTextEntry() { + int currentRed = (this.rgb >> 16) & 0xFF; + int currentGreen = (this.rgb >> 8) & 0xFF; + int currentBlue = this.rgb & 0xFF; + + currentRed = (int) clamp(tryParseInt(this.txtRed.getText(), currentRed), 0, 255); + currentGreen = (int) clamp(tryParseInt(this.txtGreen.getText(), currentGreen), 0, 255); + currentBlue = (int) clamp(tryParseInt(this.txtBlue.getText(), currentBlue), 0, 255); + + this.hsb = Color.RGBtoHSB(currentRed, currentGreen, currentBlue, null); + this.updateColor(); + } + + @Override + protected void mouseDragged(Minecraft minecraft, int mouseX, int mouseY) { + super.mouseDragged(minecraft, mouseX, mouseY); + + if (this.draggingHS) { + this.hsb[H] = clamp(mouseX - this.xPosition - 10, 0, 128) / 128F; + this.hsb[S] = (128F - clamp(mouseY - this.yPosition - 10, 0, 128)) / 128F; + this.updateColor(); + } + + if (this.draggingB) { + this.hsb[B] = (128F - clamp(mouseY - this.yPosition - 10, 0, 128)) / 128F; + this.updateColor(); + } + + } + + @Override + public boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) { + if (super.mousePressed(minecraft, mouseX, mouseY)) { + + // if (this.btnOk.mousePressed(minecraft, mouseX, mouseY)) + // this.result = DialogResult.OK; + // + // if (this.btnCancel.mousePressed(minecraft, mouseX, mouseY)) + // this.result = DialogResult.Cancel; + + if (this.rectHSArea.contains(mouseX, mouseY)) + this.draggingHS = true; + + if (this.rectBArea.contains(mouseX, mouseY)) + this.draggingB = true; + + this.txtRed.mouseClicked(mouseX, mouseY, 0); + this.txtGreen.mouseClicked(mouseX, mouseY, 0); + this.txtBlue.mouseClicked(mouseX, mouseY, 0); + + return true; + } + + return false; + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + this.draggingHS = false; + this.draggingB = false; + } + + public boolean textBoxKeyTyped(char keyChar, int keyCode) { + this.txtRed.textboxKeyTyped(keyChar, keyCode); + this.txtGreen.textboxKeyTyped(keyChar, keyCode); + this.txtBlue.textboxKeyTyped(keyChar, keyCode); + this.updateColorFromTextEntry(); + + if (keyCode == Keyboard.KEY_TAB) { + if (this.txtRed.isFocused()) { + this.txtRed.setFocused(false); + this.txtGreen.setFocused(true); + this.txtBlue.setFocused(false); + } else if (this.txtGreen.isFocused()) { + this.txtRed.setFocused(false); + this.txtGreen.setFocused(false); + this.txtBlue.setFocused(true); + } else if (this.txtBlue.isFocused()) { + this.txtRed.setFocused(false); + this.txtGreen.setFocused(false); + this.txtBlue.setFocused(false); + } else { + this.txtRed.setFocused(true); + this.txtGreen.setFocused(false); + this.txtBlue.setFocused(false); + } + } + + return true; + } + + private static int tryParseInt(String text, int defaultValue) { + return "".equals(text) ? 0 : Integers.parseInt(text, defaultValue); + } + + private static float clamp(float value, float min, float max) { + return Math.min(Math.max(value, min), max); + } +} \ No newline at end of file diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java index 89771990..b14229c6 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java @@ -77,6 +77,7 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe private GuiButton btnUpload; private GuiButton btnClear; private GuiButton btnBack; + private GuiButton btnMeta; protected EntityPlayerModel localPlayer; protected EntityPlayerModel remotePlayer; protected DoubleBuffer doubleBuffer; @@ -99,6 +100,8 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe private float lastPartialTick; private JFrame fileDrop; + private MetaHandler metadata; + // translations private final String manager = I18n.format("hdskins.manager"); private final String unreadable = I18n.format("hdskins.error.unreadable"); @@ -129,6 +132,9 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe this.reloadRemoteSkin(); this.fetchingSkin = true; this.panoramaRenderer = LiteModHDSkinsMod.getPanoramaRenderer(this); + this.metadata = new MetaHandler(this); + this.setupMetaOverrides(this.metadata); + this.metadata.fetch(); } protected EntityPlayerModel getModel(GameProfile profile) { @@ -210,23 +216,24 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe @Override public void setPanoramaResolution(Minecraft minecraft, int width, int height) {} - protected List getControlList() { - return this.buttonList; - } - @Override public void initGui() { enableDnd(); this.panoramaRenderer.initPanoramaRenderer(); - this.getControlList().clear(); - this.getControlList().add(this.btnBrowse = new GuiButton(0, 30, this.height - 36, 60, 20, "Browse...")); - this.getControlList().add(this.btnUpload = new GuiButton(1, this.width / 2 - 24, this.height / 2 - 10, 48, 20, ">>")); - this.getControlList().add(this.btnClear = new GuiButton(2, this.width - 90, this.height - 36, 60, 20, "Clear")); - this.getControlList().add(this.btnBack = new GuiButton(3, this.width / 2 - 50, this.height - 36, 100, 20, "Close")); + this.buttonList.clear(); + this.buttonList.add(this.btnBrowse = new GuiButton(0, 30, this.height - 36, 60, 20, "Browse...")); + this.buttonList.add(this.btnUpload = new GuiButton(1, this.width / 2 - 24, this.height / 2 - 10, 48, 20, ">>")); + this.buttonList.add(this.btnClear = new GuiButton(2, this.width - 90, this.height - 36, 60, 20, "Clear")); + this.buttonList.add(this.btnBack = new GuiButton(3, this.width / 2 - 50, this.height - 36, 100, 20, "Close")); + this.buttonList.add(this.btnMeta = new GuiButton(4, 2, 2, 20, 20, "...")); this.btnUpload.enabled = false; this.btnBrowse.enabled = !this.mc.isFullScreen(); } + protected void setupMetaOverrides(MetaHandler meta) { + meta.bool("slim"); + } + /** * @wbp.parser.entryPoint */ @@ -365,6 +372,10 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe this.mc.displayGuiScreen(new GuiMainMenu()); } + if (guiButton.id == this.btnMeta.id) { + this.mc.displayGuiScreen(metadata); + } + } } } @@ -455,12 +466,12 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe } this.mc.getTextureManager().bindTexture(cubemapTextures[cubeSide]); -// wr.setColorRGBA_I(0xffffff, 255 / (blendPass + 1)); + // wr.setColorRGBA_I(0xffffff, 255 / (blendPass + 1)); vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); vb.pos(-1.0D, -1.0D, 1.0D).tex(0.0D, 0.0D).endVertex(); vb.pos(1.0D, -1.0D, 1.0D).tex(1.0D, 0.0D).endVertex(); vb.pos(1.0D, 1.0D, 1.0D).tex(1.0D, 1.0D).endVertex(); - vb.pos(-1.0D, 1.0D, 1.0D).tex(0.0D, 1.0D).endVertex(); + vb.pos(-1.0D, 1.0D, 1.0D).tex(0.0D, 1.0D).endVertex(); tessellator.draw(); popMatrix(); } @@ -522,7 +533,7 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe float vSample = this.width * aspect / 256.0F; GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - // wr.setColorRGBA_F(1.0F, 1.0F, 1.0F, 1.0F); + // wr.setColorRGBA_F(1.0F, 1.0F, 1.0F, 1.0F); vb.pos(0.0D, this.height, this.zLevel).tex(0.5F - uSample, 0.5F + vSample).endVertex(); vb.pos(this.width, this.height, this.zLevel).tex(0.5F - uSample, 0.5F - vSample).endVertex(); vb.pos(this.width, 0.0D, this.zLevel).tex(0.5F + uSample, 0.5F - vSample).endVertex(); @@ -720,6 +731,7 @@ public class GuiSkins extends GuiScreen implements IUploadCompleteCallback, IOpe this.skinUploadMessage = upload; this.threadSkinUpload = new ThreadMultipartPostUpload(HDSkinManager.INSTANCE.getGatewayUrl(), sourceData, this); this.threadSkinUpload.start(); + return true; } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/MetaHandler.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/MetaHandler.java new file mode 100644 index 00000000..bc7c1a48 --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/MetaHandler.java @@ -0,0 +1,433 @@ +package com.voxelmodpack.hdskins.gui; + +import java.awt.Color; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.lwjgl.input.Keyboard; + +import com.google.common.base.Converter; +import com.google.common.base.Enums; +import com.google.common.base.Functions; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.primitives.Ints; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.mumfrey.liteloader.client.gui.GuiCheckbox; +import com.mumfrey.webprefs.WebPreferencesManager; +import com.mumfrey.webprefs.interfaces.IWebPreferences; +import com.voxelmodpack.hdskins.HDSkinManager; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiPageButtonList.GuiResponder; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiSlider; +import net.minecraft.client.gui.GuiSlider.FormatHelper; +import net.minecraft.client.resources.I18n; + +public class MetaHandler extends GuiScreen { + + private GuiScreen parent; + private List> options = Lists.newArrayList(); + protected int optionHeight = 5; + protected int optionPosX; + + public MetaHandler(GuiScreen parent) { + this.parent = parent; + } + + public > void selection(String name, Class options) { + this.options.add(new Sel(name, options)); + } + + public void bool(String name) { + this.options.add(new Bol(name)); + } + + public void number(String name, int min, int max) { + this.options.add(new Num(name, min, max)); + } + + public void color(String name) { + this.options.add(new Col(name)); + } + + @Override + public void initGui() { + super.initGui(); + optionHeight = 30; + optionPosX = this.width / 8; + this.buttonList.add(new GuiButton(0, width / 2 - 100, height - 40, 80, 20, "Cancel")); + this.buttonList.add(new GuiButton(1, width / 2 + 20, height - 40, 80, 20, "Apply")); + for (Opt opt : options) { + opt.init(); + } + fetch(); + } + + @Override + protected void actionPerformed(GuiButton button) throws IOException { + switch (button.id) { + case 1: + push(); + case 0: + mc.displayGuiScreen(parent); + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + if (keyCode == Keyboard.KEY_ESCAPE) { + mc.displayGuiScreen(parent); + } else { + super.keyTyped(typedChar, keyCode); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float ticks) { + this.drawDefaultBackground(); + super.drawScreen(mouseX, mouseY, ticks); + for (Opt opt : options) { + opt.drawOption(mouseX, mouseY); + } + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int button) throws IOException { + super.mouseClicked(mouseX, mouseY, button); + for (Opt opt : options) { + if (opt.mouseClicked(mouseX, mouseY)) + break; + + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY, int state) { + super.mouseReleased(mouseX, mouseY, state); + for (Opt opt : options) { + opt.mouseReleased(mouseX, mouseY); + } + } + + public void push() { + String data = new Gson().toJson(toMap()); + + IWebPreferences prefs = WebPreferencesManager.getDefault().getLocalPreferences(false); + prefs.set(HDSkinManager.METADATA_KEY, data); + prefs.commit(false); + } + + public void fetch() { + IWebPreferences prefs = WebPreferencesManager.getDefault().getLocalPreferences(false); + String json = prefs.get(HDSkinManager.METADATA_KEY, "{}"); + Map data = new Gson().fromJson(json, new TypeToken>() {}.getType()); + fromMap(data); + } + + private Map toMap() { + Map map = Maps.newHashMap(); + for (Opt opt : options) { + if (opt.isEnabled()) { + map.put(opt.getName(), opt.toString()); + } + } + return map; + } + + private void fromMap(Map data) { + for (Entry e : data.entrySet()) { + for (Opt opt : options) { + if (opt.name.equals(e.getKey())) { + opt.setEnabled(true); + opt.fromString(e.getValue()); + break; + } + } + } + } + + private abstract class Opt { + + protected Minecraft mc = Minecraft.getMinecraft(); + protected final String name; + protected Optional value = Optional.absent(); + + private GuiCheckbox enabled; + + public Opt(String name) { + this.name = name; + } + + private String getName() { + return name; + } + + public void setEnabled(boolean enabled) { + this.enabled.checked = enabled; + } + + public boolean isEnabled() { + return this.enabled.checked; + } + + protected void init() { + this.enabled = new GuiCheckbox(0, optionPosX + 2, optionHeight, ""); + } + + protected void drawOption(int mouseX, int mouseY) { + this.enabled.drawButton(mc, mouseX, mouseY); + } + + protected boolean mouseClicked(int mouseX, int mouseY) { + if (this.enabled.mousePressed(mc, mouseX, mouseY)) { + this.enabled.checked = !this.enabled.checked; + return true; + } + return false; + } + + protected void mouseReleased(int mouseX, int mouseY) { + + } + + @Override + public abstract String toString(); + + public abstract void fromString(String s); + } + + private class Bol extends Opt { + + private GuiCheckbox chk; + + public Bol(String name) { + super(name); + } + + @Override + public void init() { + super.init(); + this.chk = new GuiCheckbox(0, optionPosX + 20, optionHeight, I18n.format(this.name)); + optionHeight += 14; + } + + @Override + protected void drawOption(int mouseX, int mouseY) { + super.drawOption(mouseX, mouseY); + chk.drawButton(mc, mouseX, mouseY); + + } + + @Override + protected boolean mouseClicked(int mouseX, int mouseY) { + boolean clicked = super.mouseClicked(mouseX, mouseY); + if (!clicked && chk.mousePressed(mc, mouseX, mouseY)) { + chk.checked = !chk.checked; + return true; + } + return clicked; + } + + @Override + public String toString() { + return this.value.transform(Functions.toStringFunction()).orNull(); + } + + @Override + public void fromString(String s) { + value = Optional.of(Boolean.parseBoolean(s)); + } + } + + private class Num extends Opt implements GuiResponder, FormatHelper { + + private final int min; + private final int max; + + private GuiSlider guiSlider; + + public Num(String name, int min, int max) { + super(name); + this.min = min; + this.max = max; + } + + @Override + public void init() { + super.init(); + this.guiSlider = new GuiSlider(this, 0, optionPosX + 20, optionHeight, this.name, min, max, min, this); + optionHeight += 22; + } + + @Override + protected void drawOption(int mouseX, int mouseY) { + super.drawOption(mouseX, mouseY); + this.guiSlider.drawButton(mc, mouseX, mouseY); + } + + @Override + protected boolean mouseClicked(int mouseX, int mouseY) { + boolean clicked = super.mouseClicked(mouseX, mouseY); + return clicked || this.guiSlider.mousePressed(mc, mouseX, mouseY); + } + + @Override + protected void mouseReleased(int mouseX, int mouseY) { + this.guiSlider.mouseReleased(mouseX, mouseY); + } + + @Override + public void setEntryValue(int id, float value) { + this.value = Optional.of((int) value); + } + + @Override + public String getText(int id, String name, float value) { + return name + ": " + (int) value; + } + + @Override + public String toString() { + return this.value.transform(Functions.toStringFunction()).orNull(); + } + + @Override + public void fromString(String s) { + value = Optional.fromNullable(Ints.tryParse(s)); + } + + @Override + public void setEntryValue(int id, boolean value) {} + + @Override + public void setEntryValue(int id, String value) {} + + } + + private class Sel> extends Opt { + + private Class type; + private final List options; + + private int index; + + private GuiButton button; + + public Sel(String name, Class enumType) { + super(name); + this.type = enumType; + this.options = ImmutableList.copyOf(enumType.getEnumConstants()); + } + + @Override + protected void init() { + super.init(); + this.button = new GuiButton(0, optionPosX + 20, optionHeight, 100, 20, name + ": " + I18n.format(this.get().toString())); + optionHeight += 22; + } + + @Override + protected void drawOption(int mouseX, int mouseY) { + super.drawOption(mouseX, mouseY); + this.button.drawButton(mc, mouseX, mouseY); + } + + @Override + protected boolean mouseClicked(int mouseX, int mouseY) { + boolean clicked = super.mouseClicked(mouseX, mouseY); + if (!clicked && this.button.mousePressed(mc, mouseX, mouseY)) { + this.index++; + if (this.index >= this.options.size()) { + this.index = 0; + } + this.value = Optional.of(get()); + this.button.displayString = name + ": " + I18n.format(this.toString()); + return true; + } + return clicked; + } + + private E get() { + return this.options.get(this.index); + } + + @Override + public String toString() { + return this.value.transform(Enums.stringConverter(type).reverse()).orNull(); + } + + @Override + public void fromString(String s) { + value = Enums.getIfPresent(type, s); + this.index = value.isPresent() ? value.get().ordinal() : 0; + this.button.displayString = name + ": " + I18n.format(this.toString()); + } + + } + + private class Col extends Opt { + + private GuiColorButton color; + + private Converter colorConverter = new Converter() { + @Override + protected Color doBackward(Integer b) { + return new Color(b); + } + + @Override + protected Integer doForward(Color a) { + return a.getRGB(); + } + }; + + public Col(String name) { + super(name); + } + + @Override + protected void init() { + super.init(); + this.color = new GuiColorButton(mc, 0, optionPosX + 20, optionHeight, 20, 20, value.transform(colorConverter).or(-1), name); + } + + @Override + protected void drawOption(int mouseX, int mouseY) { + super.drawOption(mouseX, mouseY); + this.color.drawButton(mc, mouseX, mouseY); + } + + @Override + protected boolean mouseClicked(int mouseX, int mouseY) { + boolean clicked = super.mouseClicked(mouseX, mouseY); + if (!clicked && this.color.mousePressed(mc, mouseX, mouseY)) { + this.value = Optional.of(new Color(this.color.getColor())); + return true; + } + return clicked; + } + + @Override + protected void mouseReleased(int mouseX, int mouseY) { + this.color.mouseReleased(mouseX, mouseY); + } + + @Override + public String toString() { + return this.value.transform(Functions.toStringFunction()).orNull(); + } + + @Override + public void fromString(String s) { + this.value = Optional.fromNullable(Ints.tryParse(s)).transform(colorConverter.reverse()); + } + } +} diff --git a/src/hdskins/resources/assets/hdskins/textures/gui/picker.png b/src/hdskins/resources/assets/hdskins/textures/gui/picker.png new file mode 100644 index 00000000..18e1c9dd Binary files /dev/null and b/src/hdskins/resources/assets/hdskins/textures/gui/picker.png differ diff --git a/src/main/java/com/brohoof/minelittlepony/hdskins/gui/GuiSkinsMineLP.java b/src/main/java/com/brohoof/minelittlepony/hdskins/gui/GuiSkinsMineLP.java index 5b1417f9..24461b2a 100644 --- a/src/main/java/com/brohoof/minelittlepony/hdskins/gui/GuiSkinsMineLP.java +++ b/src/main/java/com/brohoof/minelittlepony/hdskins/gui/GuiSkinsMineLP.java @@ -2,20 +2,35 @@ package com.brohoof.minelittlepony.hdskins.gui; import java.awt.image.BufferedImage; +import com.brohoof.minelittlepony.PonyGender; import com.brohoof.minelittlepony.PonyManager; +import com.brohoof.minelittlepony.PonyRace; +import com.brohoof.minelittlepony.PonySize; +import com.brohoof.minelittlepony.TailLengths; import com.brohoof.minelittlepony.util.MineLPLogger; import com.mojang.authlib.GameProfile; import com.voxelmodpack.hdskins.gui.EntityPlayerModel; import com.voxelmodpack.hdskins.gui.GuiSkins; +import com.voxelmodpack.hdskins.gui.MetaHandler; public class GuiSkinsMineLP extends GuiSkins { private PonyManager ponyManager; - + public GuiSkinsMineLP(PonyManager manager) { this.ponyManager = manager; } - + + @Override + protected void setupMetaOverrides(MetaHandler meta) { + super.setupMetaOverrides(meta); + meta.selection("race", PonyRace.class); + meta.selection("tail", TailLengths.class); + meta.selection("gender", PonyGender.class); + meta.selection("size", PonySize.class); + meta.color("magic"); + } + @Override protected EntityPlayerModel getModel(GameProfile profile) { return new EntityPonyModel(profile);