From d40779c55559fe0ee65887ec37ce01f3ab9b9b7d Mon Sep 17 00:00:00 2001 From: kirillsaint Date: Thu, 8 Feb 2024 17:49:19 +0600 Subject: [PATCH] (ui) new emotes gui --- .../client/emotes/PlayerModelManager.java | 14 +- .../emotes/particles/ParticleEndRod.java | 2 +- .../client/emotes/ui/EmoteMenuGui.java | 167 ++++++++++++++++++ .../client/emotes/ui/ScreenEmoteWheel.java | 11 +- .../mixins/AbstractClientPlayerMixin.java | 2 +- .../mixin/mixins/emotes/MinecraftMixin.java | 6 +- .../client/utils/types/PlayerResponse.java | 1 + src/main/resources/assets/emoticons/icon.png | Bin 3476 -> 0 bytes .../silentclient/emotes}/models/actions.bobj | 0 .../silentclient/emotes}/models/armor.bobj | 0 .../silentclient/emotes}/models/default.bobj | 0 .../silentclient/emotes}/models/default.json | 42 ++--- .../silentclient/emotes}/models/props.bobj | 0 .../emotes}/models/props/basket.png | Bin .../emotes}/models/props/broom.png | Bin .../emotes}/models/props/candy_bag.png | Bin .../emotes}/models/props/chimney.png | Bin .../emotes}/models/props/cloud.png | Bin .../emotes}/models/props/coffin.png | Bin .../emotes}/models/props/egg_bottom.png | Bin .../emotes}/models/props/egg_top.png | Bin .../emotes}/models/props/football.png | Bin .../emotes}/models/props/grave.png | Bin .../emotes}/models/props/heart.png | Bin .../emotes}/models/props/hunt_gun.png | Bin .../silentclient/emotes}/models/props/l.png | Bin .../emotes}/models/props/palette.png | Bin .../emotes}/models/props/party_popper_top.png | Bin .../emotes}/models/props/popcorn.png | Bin .../emotes}/models/props/present.png | Bin .../emotes}/models/props/rose.png | Bin .../emotes}/models/props/skates.png | Bin .../emotes}/models/props/turkey.png | Bin .../silentclient/emotes}/models/slim.bobj | 0 .../silentclient/emotes}/models/slim.json | 42 ++--- .../silentclient/emotes}/models/steve.bobj | 0 .../emotes}/particles/mc-particles.png | Bin 37 files changed, 231 insertions(+), 56 deletions(-) create mode 100644 src/main/java/net/silentclient/client/emotes/ui/EmoteMenuGui.java delete mode 100644 src/main/resources/assets/emoticons/icon.png rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/actions.bobj (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/armor.bobj (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/default.bobj (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/default.json (75%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props.bobj (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/basket.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/broom.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/candy_bag.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/chimney.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/cloud.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/coffin.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/egg_bottom.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/egg_top.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/football.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/grave.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/heart.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/hunt_gun.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/l.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/palette.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/party_popper_top.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/popcorn.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/present.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/rose.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/skates.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/props/turkey.png (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/slim.bobj (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/slim.json (75%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/models/steve.bobj (100%) rename src/main/resources/assets/{emoticons => minecraft/silentclient/emotes}/particles/mc-particles.png (100%) diff --git a/src/main/java/net/silentclient/client/emotes/PlayerModelManager.java b/src/main/java/net/silentclient/client/emotes/PlayerModelManager.java index 70c703b..44bb442 100644 --- a/src/main/java/net/silentclient/client/emotes/PlayerModelManager.java +++ b/src/main/java/net/silentclient/client/emotes/PlayerModelManager.java @@ -59,11 +59,11 @@ public class PlayerModelManager { gsonbuilder.registerTypeAdapter(AnimatorHeldItemConfig.class, new AnimatorHeldItemConfigAdapter()); Gson gson = gsonbuilder.create(); Class oclass = this.getClass(); - BOBJLoader.BOBJData bobjloader$bobjdata1 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/emoticons/models/armor.bobj")); - BOBJLoader.BOBJData bobjloader$bobjdata2 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/emoticons/models/default.bobj")); - BOBJLoader.BOBJData bobjloader$bobjdata3 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/emoticons/models/slim.bobj")); - BOBJLoader.BOBJData bobjloader$bobjdata4 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/emoticons/models/actions.bobj")); - BOBJLoader.BOBJData bobjloader$bobjdata5 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/emoticons/models/props.bobj")); + BOBJLoader.BOBJData bobjloader$bobjdata1 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/armor.bobj")); + BOBJLoader.BOBJData bobjloader$bobjdata2 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/default.bobj")); + BOBJLoader.BOBJData bobjloader$bobjdata3 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/slim.bobj")); + BOBJLoader.BOBJData bobjloader$bobjdata4 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/actions.bobj")); + BOBJLoader.BOBJData bobjloader$bobjdata5 = BOBJLoader.readData(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/props.bobj")); BOBJLoader.merge(bobjloader$bobjdata2, bobjloader$bobjdata1); BOBJLoader.merge(bobjloader$bobjdata3, bobjloader$bobjdata1); BOBJLoader.merge(bobjloader$bobjdata2, bobjloader$bobjdata5); @@ -75,10 +75,10 @@ public class PlayerModelManager { this.steve.init(); this.alex.init(); this.steveConfig = gson.fromJson( - IOUtils.toString(Objects.requireNonNull(oclass.getResourceAsStream("/assets/emoticons/models/default.json"))), AnimatorConfig.class + IOUtils.toString(Objects.requireNonNull(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/default.json"))), AnimatorConfig.class ); this.alexConfig = gson.fromJson( - IOUtils.toString(Objects.requireNonNull(oclass.getResourceAsStream("/assets/emoticons/models/slim.json"))), AnimatorConfig.class + IOUtils.toString(Objects.requireNonNull(oclass.getResourceAsStream("/assets/minecraft/silentclient/emotes/models/slim.json"))), AnimatorConfig.class ); this.steve.data.armatures.get("Armature").enabled = true; this.alex.data.armatures.get("Armature").enabled = true; diff --git a/src/main/java/net/silentclient/client/emotes/particles/ParticleEndRod.java b/src/main/java/net/silentclient/client/emotes/particles/ParticleEndRod.java index ff50119..ea5dd40 100644 --- a/src/main/java/net/silentclient/client/emotes/particles/ParticleEndRod.java +++ b/src/main/java/net/silentclient/client/emotes/particles/ParticleEndRod.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; public class ParticleEndRod extends EntityFX { - public static final ResourceLocation TEXTURE = new ResourceLocation("emoticons:particles/mc-particles.png"); + public static final ResourceLocation TEXTURE = new ResourceLocation("silentclient/emotes/particles/mc-particles.png"); private final int numAgingFrames = 8; public ParticleEndRod(World world, double d0, double d1, double d2, double d3, double d4, double d5) { diff --git a/src/main/java/net/silentclient/client/emotes/ui/EmoteMenuGui.java b/src/main/java/net/silentclient/client/emotes/ui/EmoteMenuGui.java new file mode 100644 index 0000000..5e6ca65 --- /dev/null +++ b/src/main/java/net/silentclient/client/emotes/ui/EmoteMenuGui.java @@ -0,0 +1,167 @@ +package net.silentclient.client.emotes.ui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.util.ResourceLocation; +import net.silentclient.client.Client; +import net.silentclient.client.emotes.EmoteManager; +import net.silentclient.client.gui.SilentScreen; +import net.silentclient.client.gui.elements.IconButton; +import net.silentclient.client.gui.font.SilentFontRenderer; +import net.silentclient.client.gui.lite.clickgui.utils.MouseUtils; +import net.silentclient.client.gui.theme.Theme; +import net.silentclient.client.gui.util.RenderUtil; +import net.silentclient.client.utils.MenuBlurUtils; +import net.silentclient.client.utils.MouseCursorHandler; +import net.silentclient.client.utils.ScrollHelper; +import net.silentclient.client.utils.types.PlayerResponse; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.io.IOException; +import java.util.ArrayList; + +public class EmoteMenuGui extends SilentScreen { + private ScrollHelper scrollHelper = new ScrollHelper(); + + @Override + public void initGui() { + super.initGui(); + defaultCursor = false; + MenuBlurUtils.loadBlur(); + int width = 255; + int height = 200; + int x = this.width / 2 - (width / 2); + int y = this.height / 2 - (height / 2); + this.buttonList.add(new IconButton(0, x + width - 14 - 3, y + 3, 14, 14, 8, 8, new ResourceLocation("silentclient/icons/exit.png"))); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + MouseCursorHandler.CursorType cursorType = getCursor(silentInputs, buttonList); + MenuBlurUtils.renderBackground(this); + int width = 255; + int height = 200; + int x = this.width / 2 - (width / 2); + int y = this.height / 2 - (height / 2); + scrollHelper.setStep(5); + scrollHelper.setElementsHeight((float) Math.ceil((Client.getInstance().getCosmetics().getMyEmotes().size() + 3) / 3) * 85); + scrollHelper.setMaxScroll(height - 20); + scrollHelper.setSpeed(100); + scrollHelper.setFlag(true); + float scrollY = scrollHelper.getScroll(); + RenderUtil.drawRoundedRect(x, y, width, height, 4, Theme.backgroundColor().getRGB()); + Client.getInstance().getSilentFontRenderer().drawString(x + 3, y + 3, "Emotes", 14, SilentFontRenderer.FontType.TITLE); + super.drawScreen(mouseX, mouseY, partialTicks); + GL11.glPushMatrix(); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + ScaledResolution r = new ScaledResolution(Minecraft.getMinecraft()); + int s = r.getScaleFactor(); + int listHeight = height - 20; + int translatedY = r.getScaledHeight() - y - 20 - listHeight; + GL11.glScissor(0 * s, translatedY * s, this.width * s, listHeight * s); + int emoteX = x + 3; + float emoteY = y + 20 + scrollY; + int emoteIndex = 0; + for(PlayerResponse.Account.Cosmetics.CosmeticItem emote : Client.getInstance().getCosmetics().getMyEmotes()) { + boolean isHovered = MouseUtils.isInside(mouseX, mouseY, emoteX, emoteY, 80, 80) && !MouseUtils.isInside(mouseX, mouseY, emoteX + 80 - 3 - 10, emoteY + 3, 10, 10); + if(isHovered) { + cursorType = MouseCursorHandler.CursorType.POINTER; + RenderUtil.drawRoundedRect(emoteX, emoteY, 80, 80, 3, new Color(255, 255, 255, 30).getRGB()); + } + if(MouseUtils.isInside(mouseX, mouseY, emoteX + 80 - 3 - 10, emoteY + 3, 10, 10)) { + cursorType = MouseCursorHandler.CursorType.POINTER; + } + RenderUtil.drawRoundedOutline(emoteX, emoteY, 80, 80, 3, 1, Theme.borderColor().getRGB()); + Client.getInstance().getSilentFontRenderer().drawString(emote.getName(), emoteX + 3, (int) (emoteY + 3), 12, SilentFontRenderer.FontType.TITLE, 64); + + boolean favorite = false; + for(Number i : Client.getInstance().getAccount().getFavoriteCosmetics().emotes == null ? new ArrayList() : Client.getInstance().getAccount().getFavoriteCosmetics().emotes) { + if(i.intValue() == emote.getId()) { + favorite = true; + } + } + + RenderUtil.drawImage(new ResourceLocation(favorite ? "silentclient/icons/star.png" : "silentclient/icons/star_outline.png"), emoteX + 80 - 3 - 10, emoteY + 3, 10, 10); + + emoteIndex += 1; + if(emoteIndex == 3) { + emoteIndex = 0; + emoteX = x + 3; + emoteY += 85; + } else { + emoteX += 83; + } + } + Client.getInstance().getMouseCursorHandler().enableCursor(cursorType); + + GL11.glDisable(GL11.GL_SCISSOR_TEST); + GL11.glPopMatrix(); + } + + @Override + protected void actionPerformed(GuiButton button) throws IOException { + super.actionPerformed(button); + if(button.id == 0) { + mc.displayGuiScreen(null); + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + super.mouseClicked(mouseX, mouseY, mouseButton); + int width = 255; + int height = 200; + int x = this.width / 2 - (width / 2); + int y = this.height / 2 - (height / 2); + int emoteX = x + 3; + float emoteY = (int) (y + 20 + scrollHelper.getScroll()); + int emoteIndex = 0; + for(PlayerResponse.Account.Cosmetics.CosmeticItem emote : Client.getInstance().getCosmetics().getMyEmotes()) { + boolean isHovered = MouseUtils.isInside(mouseX, mouseY, emoteX, emoteY, 80, 80) && !MouseUtils.isInside(mouseX, mouseY, emoteX + 80 - 3 - 10, emoteY + 3, 10, 10); + + if(isHovered) { + EmoteManager.sendEmote(mc.thePlayer.getName(), emote.getId()); + mc.displayGuiScreen(null); + break; + } + + if(MouseUtils.isInside(mouseX, mouseY, emoteX + 80 - 3 - 10, emoteY + 3, 10, 10)) { + Client.getInstance().getAccount().updateFavorite(emote.getId(), "emotes"); + break; + } + + emoteIndex += 1; + if(emoteIndex == 3) { + emoteIndex = 0; + emoteX = x + 3; + emoteY += 85; + } else { + emoteX += 83; + } + } + } + + @Override + public void updateScreen() { + super.updateScreen(); + if(mc.thePlayer == null) { + Client.backgroundPanorama.tickPanorama(); + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + if (keyCode == Keyboard.KEY_ESCAPE) { + mc.displayGuiScreen(null); + } + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + MenuBlurUtils.unloadBlur(); + } +} diff --git a/src/main/java/net/silentclient/client/emotes/ui/ScreenEmoteWheel.java b/src/main/java/net/silentclient/client/emotes/ui/ScreenEmoteWheel.java index e1d934e..5b3f3e6 100644 --- a/src/main/java/net/silentclient/client/emotes/ui/ScreenEmoteWheel.java +++ b/src/main/java/net/silentclient/client/emotes/ui/ScreenEmoteWheel.java @@ -6,6 +6,8 @@ import net.minecraft.util.MathHelper; import net.silentclient.client.Client; import net.silentclient.client.emotes.socket.EmoteSocket; import net.silentclient.client.gui.SilentScreen; +import net.silentclient.client.gui.font.SilentFontRenderer; +import net.silentclient.client.utils.MouseCursorHandler; import net.silentclient.client.utils.types.PlayerResponse; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; @@ -67,6 +69,7 @@ public class ScreenEmoteWheel extends SilentScreen { } currentIndex++; } + this.defaultCursor = false; } @Override @@ -79,7 +82,8 @@ public class ScreenEmoteWheel extends SilentScreen { int count = this.handlers.size(); float radius = (float)resolution.getScaledHeight() * 2.0F / 5.0F; float i = 0.0F; - this.drawString(this.fontRendererObj, "Scroll to view more.", 1, 1, -1); + MouseCursorHandler.CursorType cursorType = getCursor(this.silentInputs, this.buttonList); + Client.getInstance().getSilentFontRenderer().drawString("Scroll to view more.", 1, 1, 14, SilentFontRenderer.FontType.TITLE); for(String s : this.handlers.keySet()) { GL11.glPushMatrix(); @@ -105,6 +109,7 @@ public class ScreenEmoteWheel extends SilentScreen { if (mouseTheta > (double)startTheta && mouseTheta < (double)endTheta) { this.foc = s; hovered = true; + cursorType = MouseCursorHandler.CursorType.POINTER; } } @@ -130,12 +135,14 @@ public class ScreenEmoteWheel extends SilentScreen { for(String string : strings) { textCenterY += 15; - this.drawScaledText(string, textCenterX, textCenterY, Color.WHITE.getRGB()); + this.drawScaledText(string, textCenterX, textCenterY, -1); } GL11.glPopMatrix(); ++i; } + + Client.getInstance().getMouseCursorHandler().enableCursor(cursorType); } protected void drawScaledText(String text, int trueX, int trueY, int color) { diff --git a/src/main/java/net/silentclient/client/mixin/mixins/AbstractClientPlayerMixin.java b/src/main/java/net/silentclient/client/mixin/mixins/AbstractClientPlayerMixin.java index 5358059..d325323 100644 --- a/src/main/java/net/silentclient/client/mixin/mixins/AbstractClientPlayerMixin.java +++ b/src/main/java/net/silentclient/client/mixin/mixins/AbstractClientPlayerMixin.java @@ -112,7 +112,7 @@ public abstract class AbstractClientPlayerMixin implements AbstractClientPlayerE (new Thread("CustomSkinThread") { public void run() { Client.logger.info(String.format("Downloading Custom Skin (%s)", silent$nameClear)); - customSkin.setImage(SCTextureManager.getImage("https://cdn.silentclient.net/skins/" + silent$nameClear.toLowerCase() + ".png")); + customSkin.setImage(SCTextureManager.getImage("https://cdn-test.silentclient.net/file/silentclient/skins/" + silent$nameClear.toLowerCase() + ".png")); CustomSkin.loading = false; customSkin.setLoaded(true); Client.logger.info(String.format("Custom Skin downloaded! (%s)", silent$nameClear)); diff --git a/src/main/java/net/silentclient/client/mixin/mixins/emotes/MinecraftMixin.java b/src/main/java/net/silentclient/client/mixin/mixins/emotes/MinecraftMixin.java index a5c5673..ff14c50 100644 --- a/src/main/java/net/silentclient/client/mixin/mixins/emotes/MinecraftMixin.java +++ b/src/main/java/net/silentclient/client/mixin/mixins/emotes/MinecraftMixin.java @@ -1,10 +1,10 @@ package net.silentclient.client.mixin.mixins.emotes; +import net.minecraft.client.Minecraft; import net.silentclient.client.Client; import net.silentclient.client.emotes.EmotesMod; import net.silentclient.client.emotes.PlayerModelManager; -import net.silentclient.client.emotes.ui.ScreenEmoteWheel; -import net.minecraft.client.Minecraft; +import net.silentclient.client.emotes.ui.EmoteMenuGui; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -21,7 +21,7 @@ public class MinecraftMixin { return; } if(Client.getInstance().getSettingsManager().getSettingByClass(EmotesMod.class, "Emote Wheel Keybind").isKeyDown()) { - Minecraft.getMinecraft().displayGuiScreen(new ScreenEmoteWheel()); + Minecraft.getMinecraft().displayGuiScreen(new EmoteMenuGui()); } } diff --git a/src/main/java/net/silentclient/client/utils/types/PlayerResponse.java b/src/main/java/net/silentclient/client/utils/types/PlayerResponse.java index 6399af0..ba57fa9 100644 --- a/src/main/java/net/silentclient/client/utils/types/PlayerResponse.java +++ b/src/main/java/net/silentclient/client/utils/types/PlayerResponse.java @@ -520,6 +520,7 @@ public class PlayerResponse extends AbstractReply { public ArrayList bandanas = new ArrayList(); public ArrayList hats = new ArrayList(); public ArrayList shields = new ArrayList(); + public ArrayList emotes = new ArrayList(); } public class BanInfo { diff --git a/src/main/resources/assets/emoticons/icon.png b/src/main/resources/assets/emoticons/icon.png deleted file mode 100644 index 2fdb658f2dde647da1611363def4b74f72671599..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3476 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