From 861c85b4db280808e912b9afa0a284ebb6024326 Mon Sep 17 00:00:00 2001 From: boomboompower Date: Fri, 6 Mar 2020 21:12:45 +1100 Subject: [PATCH] Begin rewrite #4 --- build.gradle | 27 +- gradlew | 74 +- gradlew.bat | 14 +- .../skinchanger/SkinChangerMod.java | 113 --- .../skinchanger/SkinChangerModOld.java | 91 +++ .../skinchanger/commands/MainCommand.java | 82 -- .../skinchanger/config/ConfigLoader.java | 34 +- .../skinchanger/events/MainEvents.java | 15 +- .../skinchanger/gui/ExperimentalGui.java | 15 +- .../skinchanger/gui/MixinsWarningGui.java | 18 - .../skinchanger/gui/SettingsGui.java | 18 +- .../GuiExperimentalAllPlayers.java | 24 +- .../experimental/GuiExperimentalOptifine.java | 14 +- .../skinchanger/gui/utils/ModernButton.java | 2 +- .../skinchanger/gui/utils/ModernGui.java | 2 +- .../skinchanger/gui/utils/ModernTextBox.java | 2 +- .../tweaks/MixinAbstractClientPlayer.java | 43 +- .../skinchanger/run/JavaMain.java | 2 +- .../boomboompower/skinchanger/run/RunGui.java | 2 +- .../skinchanger/utils/ChatColor.java | 8 +- .../skinchanger/utils/ReflectUtils.java | 2 +- .../skinchanger/utils/fake/FakePlayer.java | 21 +- .../utils/fake/FakePlayerCape.java | 2 +- .../utils/fake/FakePlayerInfo.java | 17 + .../utils/models/capes/CapeManager.java | 7 +- .../utils/models/skins/PlayerSkinType.java | 17 + .../utils/models/skins/SkinManager.java | 11 +- .../mods/skinchanger/SkinChangerMod.java | 95 +++ .../skinchanger/commands/SkinCommand.java | 97 +++ .../configuration/ConfigurationHandler.java | 158 ++++ .../configuration/meta/ConfigurationData.java | 93 +++ .../configuration/meta/SaveableClassData.java | 30 + .../configuration/meta/SaveableField.java | 43 + .../mods/skinchanger/gui/SkinChangerMenu.java | 56 ++ .../skinchanger/installer/InstallerCore.java | 113 +++ .../skinchanger/methods/ChangingMethod.java | 37 + .../methods/ChangingMethodFactory.java | 23 + .../methods/impl/MixinsSkinChangeMethod.java} | 34 +- .../impl/mixins/SkinChangerTweaker.java} | 31 +- .../tweaks/MixinAbstractClientPlayer.java | 98 +++ .../methods/meta/CapeChangeMetadata.java | 63 ++ .../skinchanger/methods/meta/ChangeData.java | 68 ++ .../methods/meta/SkinChangeMetadata.java | 53 ++ .../utils/backend/InternetConnection.java | 45 ++ .../utils/backend}/MojangHooker.java | 184 +++-- .../utils/backend/ReflectionUtils.java | 65 ++ .../utils/backend/ThreadFactory.java | 42 + .../skinchanger/utils/game/ChatColor.java | 108 +++ .../utils/general}/BetterJsonObject.java | 124 +-- .../utils/general/Prerequisites.java | 103 +++ .../utils/general/ReflectUtils.java | 73 ++ .../skinchanger/utils/gui/UISkeleton.java | 45 ++ .../utils/gui/impl/ModernButton.java | 218 ++++++ .../skinchanger/utils/gui/impl/ModernGui.java | 312 ++++++++ .../utils/gui/impl/ModernTextBox.java | 732 ++++++++++++++++++ .../skinchanger/utils/gui/lock/UILock.java | 138 ++++ .../skinchanger/utils/installing/OSType.java | 35 + .../utils/installing/OperatingSystem.java | 84 ++ .../skinchanger/utils/mod/CacheRetriever.java | 290 +++++++ .../skinchanger/utils/mod/ModCommand.java | 105 +++ .../utils/updater}/WebsiteUtils.java | 15 +- src/main/resources/mixins.skinchanger.json | 2 +- 62 files changed, 3972 insertions(+), 517 deletions(-) delete mode 100644 src/main/java/me/boomboompower/skinchanger/SkinChangerMod.java create mode 100644 src/main/java/me/boomboompower/skinchanger/SkinChangerModOld.java delete mode 100644 src/main/java/me/boomboompower/skinchanger/commands/MainCommand.java delete mode 100644 src/main/java/me/boomboompower/skinchanger/gui/MixinsWarningGui.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/SkinChangerMod.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/commands/SkinCommand.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/configuration/ConfigurationHandler.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/ConfigurationData.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableClassData.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableField.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/gui/SkinChangerMenu.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/installer/InstallerCore.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethod.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethodFactory.java rename src/main/java/me/{boomboompower/skinchanger/utils/GlobalUtils.java => do_you_like/mods/skinchanger/methods/impl/MixinsSkinChangeMethod.java} (54%) rename src/main/java/me/{boomboompower/skinchanger/mixins/Tweaker.java => do_you_like/mods/skinchanger/methods/impl/mixins/SkinChangerTweaker.java} (78%) create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/tweaks/MixinAbstractClientPlayer.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/methods/meta/CapeChangeMetadata.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/methods/meta/ChangeData.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/methods/meta/SkinChangeMetadata.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/backend/InternetConnection.java rename src/main/java/me/{boomboompower/skinchanger/utils => do_you_like/mods/skinchanger/utils/backend}/MojangHooker.java (77%) create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ReflectionUtils.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ThreadFactory.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/game/ChatColor.java rename src/main/java/me/{boomboompower/skinchanger/utils => do_you_like/mods/skinchanger/utils/general}/BetterJsonObject.java (74%) create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/general/Prerequisites.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/general/ReflectUtils.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/gui/UISkeleton.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernButton.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernGui.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernTextBox.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/gui/lock/UILock.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OSType.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OperatingSystem.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/mod/CacheRetriever.java create mode 100644 src/main/java/me/do_you_like/mods/skinchanger/utils/mod/ModCommand.java rename src/main/java/me/{boomboompower/skinchanger/utils => do_you_like/mods/skinchanger/utils/updater}/WebsiteUtils.java (98%) diff --git a/build.gradle b/build.gradle index 162e154..b15c6ce 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + buildscript { repositories { jcenter() @@ -57,6 +74,8 @@ repositories { } dependencies { + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.1' + provided('org.spongepowered:mixin:0.7.10-SNAPSHOT') { exclude module: 'launchwrapper' exclude module: 'guava' @@ -64,6 +83,8 @@ dependencies { exclude module: 'commons-io' exclude module: 'log4j-core' } + + provided 'org.projectlombok:lombok:1.16.20' } processResources { @@ -91,11 +112,11 @@ jar { } manifest.attributes( - 'Main-Class' : 'me.boomboompower.skinchanger.run.JavaMain', + 'Main-Class' : 'me.do_you_like.mods.skinchanger.installer.InstallerCore', 'MixinConfigs' : 'mixins.skinchanger.json', 'TweakOrder' : '0', - 'TweakClass' : 'me.boomboompower.skinchanger.mixins.Tweaker', - 'FMLCorePlugin' : 'me.boomboompower.skinchanger.mixins.Tweaker' + 'TweakClass' : 'me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker', + 'FMLCorePlugin' : 'me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker' ) } diff --git a/gradlew b/gradlew index 4453cce..91a7e26 100644 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash ############################################################################## ## @@ -6,30 +6,12 @@ ## ############################################################################## -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -48,7 +30,6 @@ die ( ) { cygwin=false msys=false darwin=false -nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -59,11 +40,31 @@ case "`uname`" in MINGW* ) msys=true ;; - NONSTOP* ) - nonstop=true - ;; esac +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -89,7 +90,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -113,7 +114,6 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,19 +154,11 @@ if $cygwin ; then esac fi -# Escape application args -save ( ) { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") } -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" -exec "$JAVACMD" "$@" +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat index f955316..8a0b282 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,9 +46,10 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windows variants +@rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -59,6 +60,11 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/src/main/java/me/boomboompower/skinchanger/SkinChangerMod.java b/src/main/java/me/boomboompower/skinchanger/SkinChangerMod.java deleted file mode 100644 index 8efe391..0000000 --- a/src/main/java/me/boomboompower/skinchanger/SkinChangerMod.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2017 boomboompower - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package me.boomboompower.skinchanger; - -import me.boomboompower.skinchanger.utils.models.capes.CapeManager; -import me.boomboompower.skinchanger.commands.MainCommand; -import me.boomboompower.skinchanger.config.ConfigLoader; -import me.boomboompower.skinchanger.events.MainEvents; -import me.boomboompower.skinchanger.utils.models.skins.SkinManager; -import me.boomboompower.skinchanger.utils.ChatColor; -import me.boomboompower.skinchanger.utils.MojangHooker; -import me.boomboompower.skinchanger.utils.WebsiteUtils; - -import net.minecraft.client.Minecraft; -import net.minecraftforge.client.ClientCommandHandler; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.ModMetadata; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; - -@Mod(modid = SkinChangerMod.MOD_ID, version = SkinChangerMod.VERSION, acceptedMinecraftVersions = "*") -public class SkinChangerMod { - - public static final String MOD_ID = "skinchanger"; - public static final String VERSION = "2.0.0"; - - private boolean renderingEnabled = true; - - private WebsiteUtils websiteUtils; - private ConfigLoader loader; - - private SkinManager skinManager; - private CapeManager capeManager; - - private MojangHooker mojangHooker; - - @Mod.Instance - private static SkinChangerMod instance; - - public SkinChangerMod() { - - } - - @Mod.EventHandler - public void preInit(FMLPreInitializationEvent event) { - ModMetadata data = event.getModMetadata(); - data.description = ChatColor.AQUA + "A clientside mod that allows you to change your skin instantly!"; - data.authorList.add("boomboompower"); - - this.websiteUtils = new WebsiteUtils("SkinChanger"); - this.loader = new ConfigLoader(event.getSuggestedConfigurationFile()); - - this.skinManager = new SkinManager(this.mojangHooker = new MojangHooker(), Minecraft.getMinecraft().thePlayer, true); - this.capeManager = new CapeManager(Minecraft.getMinecraft().thePlayer, true); - } - - @Mod.EventHandler - public void init(FMLInitializationEvent event) { - MinecraftForge.EVENT_BUS.register(new MainEvents(this)); - ClientCommandHandler.instance.registerCommand(new MainCommand(this)); - - this.websiteUtils.begin(); - this.loader.load(); - } - - public SkinManager getSkinManager() { - return this.skinManager; - } - - public CapeManager getCapeManager() { - return this.capeManager; - } - - public ConfigLoader getLoader() { - return this.loader; - } - - public WebsiteUtils getWebsiteUtils() { - return this.websiteUtils; - } - - public MojangHooker getMojangHooker() { - return this.mojangHooker; - } - - public static SkinChangerMod getInstance() { - return instance; - } - - public void setRenderingEnabled(boolean toggledIn) { - this.renderingEnabled = toggledIn; - } - - public boolean isRenderingEnabled() { - return this.renderingEnabled; - } -} diff --git a/src/main/java/me/boomboompower/skinchanger/SkinChangerModOld.java b/src/main/java/me/boomboompower/skinchanger/SkinChangerModOld.java new file mode 100644 index 0000000..fdb9b71 --- /dev/null +++ b/src/main/java/me/boomboompower/skinchanger/SkinChangerModOld.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.boomboompower.skinchanger; + +import me.boomboompower.skinchanger.utils.models.capes.CapeManager; +import me.boomboompower.skinchanger.config.ConfigLoader; +import me.boomboompower.skinchanger.utils.models.skins.SkinManager; + +//@Mod(modid = SkinChangerMod.MOD_ID, version = SkinChangerMod.VERSION, acceptedMinecraftVersions = "*") +public class SkinChangerModOld { + + public static final String MOD_ID = "skinchanger"; + public static final String VERSION = "2.0.0"; + + //private boolean renderingEnabled = true; + + //private WebsiteUtils websiteUtils; + //private ConfigLoader loader; + + //private SkinManager skinManager; + //private CapeManager capeManager; + + //private MojangHooker mojangHooker; + + //@Mod.Instance + //private static SkinChangerMod instance; + + public SkinChangerModOld() { + + } + + //@Mod.EventHandler + //public void preInit(FMLPreInitializationEvent event) { + //ModMetadata data = event.getModMetadata(); + //data.description = ChatColor.AQUA + "A clientside mod that allows you to change your skin instantly!"; + //data.authorList.add("boomboompower"); + + //this.websiteUtils = new WebsiteUtils("SkinChanger"); + //this.loader = new ConfigLoader(event.getSuggestedConfigurationFile()); + + //this.skinManager = new SkinManager(this.mojangHooker = new MojangHooker(), Minecraft.getMinecraft().thePlayer, true); + //this.capeManager = new CapeManager(Minecraft.getMinecraft().thePlayer, true); + //} + + //@Mod.EventHandler + //public void init(FMLInitializationEvent event) { + //MinecraftForge.EVENT_BUS.register(new MainEvents(this)); + //ClientCommandHandler.instance.registerCommand(new MainCommand(this)); + + //this.websiteUtils.begin(); + //this.loader.load(); + //} + + public SkinManager getSkinManager() { + return null; + } + + public CapeManager getCapeManager() { + return null; + } + + public ConfigLoader getLoader() { + return null; + } + + public static SkinChangerModOld getInstance() { + return null; + } + + public void setRenderingEnabled(boolean toggledIn) { + } + + public boolean isRenderingEnabled() { + return false; + } +} diff --git a/src/main/java/me/boomboompower/skinchanger/commands/MainCommand.java b/src/main/java/me/boomboompower/skinchanger/commands/MainCommand.java deleted file mode 100644 index 4bfa940..0000000 --- a/src/main/java/me/boomboompower/skinchanger/commands/MainCommand.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2017 boomboompower - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package me.boomboompower.skinchanger.commands; - -import me.boomboompower.skinchanger.SkinChangerMod; -import me.boomboompower.skinchanger.gui.SettingsGui; -import me.boomboompower.skinchanger.utils.ChatColor; - -import net.minecraft.client.Minecraft; -import net.minecraft.command.CommandBase; -import net.minecraft.command.ICommandSender; - -import java.util.Arrays; -import java.util.List; -import org.lwjgl.LWJGLException; -import org.lwjgl.opengl.Display; -import org.lwjgl.opengl.DisplayMode; - -public class MainCommand extends CommandBase { - - private SkinChangerMod mod; - - public MainCommand(SkinChangerMod modIn) { - this.mod = modIn; - } - - @Override - public String getCommandName() { - return "skinchanger"; - } - - @Override - public String getCommandUsage(ICommandSender sender) { - return ChatColor.RED + "Usage: /" + getCommandName(); - } - - @Override - public List getCommandAliases() { - return Arrays.asList("changeskin", "changecape"); - } - - @Override - public void processCommand(ICommandSender sender, String[] args) { - if (args.length > 0 && args[0].length() == 1) { - Display.setResizable(false); - Display.setResizable(true); - return; - } - - if (args.length == 0) { - new SettingsGui(this.mod).display(); - } else { - new SettingsGui(this.mod, args[0]).display(); - } - } - - @Override - public boolean canCommandSenderUseCommand(ICommandSender sender) { - return true; - } - - - @Override - public boolean isUsernameIndex(String[] args, int index) { - return index == 0; - } -} diff --git a/src/main/java/me/boomboompower/skinchanger/config/ConfigLoader.java b/src/main/java/me/boomboompower/skinchanger/config/ConfigLoader.java index 34f5915..8bfb97a 100644 --- a/src/main/java/me/boomboompower/skinchanger/config/ConfigLoader.java +++ b/src/main/java/me/boomboompower/skinchanger/config/ConfigLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import java.io.*; import java.nio.file.Files; @@ -53,18 +53,22 @@ public void load() { log("Could not read log properly, saving.", this.configFile.getName()); save(); } - SkinChangerMod.getInstance().getSkinManager().setSkinName(this.configJson.has("skinname") ? this.configJson.get("skinname").getAsString() : null); - SkinChangerMod.getInstance().getCapeManager().setUsingCape(this.configJson.has("usingcape") && this.configJson.get("usingcape").getAsBoolean()); - SkinChangerMod.getInstance().getCapeManager().setExperimental(this.configJson.has("experimental") && this.configJson.get("experimental").getAsBoolean()); - SkinChangerMod.getInstance().setRenderingEnabled(this.configJson.has("rendering") && this.configJson.get("rendering").getAsBoolean()); + SkinChangerModOld + .getInstance().getSkinManager().setSkinName(this.configJson.has("skinname") ? this.configJson.get("skinname").getAsString() : null); + SkinChangerModOld + .getInstance().getCapeManager().setUsingCape(this.configJson.has("usingcape") && this.configJson.get("usingcape").getAsBoolean()); + SkinChangerModOld.getInstance().getCapeManager().setExperimental(this.configJson.has("experimental") && this.configJson.get("experimental").getAsBoolean()); + SkinChangerModOld.getInstance().setRenderingEnabled(this.configJson.has("rendering") && this.configJson.get("rendering").getAsBoolean()); if (this.configJson.has("experimental") && this.configJson.get("experimental").getAsBoolean() && this.configJson.has("ofCapeName")) { - SkinChangerMod.getInstance().getCapeManager().giveOfCape(this.configJson.get("ofCapeName").getAsString()); + SkinChangerModOld + .getInstance().getCapeManager().giveOfCape(this.configJson.get("ofCapeName").getAsString()); } if (this.configJson.has("mixins")) { JsonObject mixinSettings = this.configJson.getAsJsonObject("mixins"); - SkinChangerMod.getInstance().getSkinManager().setSkinType(mixinSettings.has("skinType") ? PlayerSkinType + SkinChangerModOld + .getInstance().getSkinManager().setSkinType(mixinSettings.has("skinType") ? PlayerSkinType .getTypeFromString(mixinSettings.get("skinType").getAsString()) : PlayerSkinType.STEVE); } } else { @@ -78,17 +82,17 @@ public void save() { try { this.configFile.createNewFile(); BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(this.configFile)); - this.configJson.addProperty("skinname", SkinChangerMod.getInstance().getSkinManager().getSkinName()); - this.configJson.addProperty("usingcape", SkinChangerMod.getInstance().getCapeManager().isUsingCape()); - this.configJson.addProperty("experimental", SkinChangerMod.getInstance().getCapeManager().isExperimental()); - this.configJson.addProperty("rendering", SkinChangerMod.getInstance().isRenderingEnabled()); + this.configJson.addProperty("skinname", SkinChangerModOld.getInstance().getSkinManager().getSkinName()); + this.configJson.addProperty("usingcape", SkinChangerModOld.getInstance().getCapeManager().isUsingCape()); + this.configJson.addProperty("experimental", SkinChangerModOld.getInstance().getCapeManager().isExperimental()); + this.configJson.addProperty("rendering", SkinChangerModOld.getInstance().isRenderingEnabled()); - if (SkinChangerMod.getInstance().getCapeManager().isExperimental()) { - this.configJson.addProperty("ofCapeName", SkinChangerMod.getInstance().getCapeManager().getOfCapeName()); + if (SkinChangerModOld.getInstance().getCapeManager().isExperimental()) { + this.configJson.addProperty("ofCapeName", SkinChangerModOld.getInstance().getCapeManager().getOfCapeName()); } JsonObject mixinSettings = new JsonObject(); - mixinSettings.addProperty("skinType", SkinChangerMod.getInstance().getSkinManager().getSkinType().getDisplayName()); + mixinSettings.addProperty("skinType", SkinChangerModOld.getInstance().getSkinManager().getSkinType().getDisplayName()); this.configJson.add("mixins", mixinSettings); diff --git a/src/main/java/me/boomboompower/skinchanger/events/MainEvents.java b/src/main/java/me/boomboompower/skinchanger/events/MainEvents.java index 3057047..bafef7b 100644 --- a/src/main/java/me/boomboompower/skinchanger/events/MainEvents.java +++ b/src/main/java/me/boomboompower/skinchanger/events/MainEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,11 +19,12 @@ import java.util.Iterator; -import me.boomboompower.skinchanger.SkinChangerMod; -import me.boomboompower.skinchanger.mixins.Tweaker; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.utils.fake.FakePlayer; import me.boomboompower.skinchanger.utils.fake.FakePlayerCape; +import me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker; + import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.RendererLivingEntity; import net.minecraft.client.renderer.entity.layers.LayerCape; @@ -38,17 +39,17 @@ public class MainEvents { - private final SkinChangerMod mod; + private final SkinChangerModOld mod; private int currentTick = 100; - public MainEvents(SkinChangerMod modIn) { + public MainEvents(SkinChangerModOld modIn) { this.mod = modIn; } @SubscribeEvent public void onTick(TickEvent.ClientTickEvent event) { - if (Tweaker.MIXINS_ENABLED) { + if (SkinChangerTweaker.MIXINS_ENABLED) { return; } @@ -76,7 +77,7 @@ public void onTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public void onRender(RenderPlayerEvent.Pre event) { - if (Tweaker.MIXINS_ENABLED) { + if (SkinChangerTweaker.MIXINS_ENABLED) { return; } diff --git a/src/main/java/me/boomboompower/skinchanger/gui/ExperimentalGui.java b/src/main/java/me/boomboompower/skinchanger/gui/ExperimentalGui.java index 192e15a..244a587 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/ExperimentalGui.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/ExperimentalGui.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ package me.boomboompower.skinchanger.gui; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.gui.experimental.GuiExperimentalAllPlayers; import me.boomboompower.skinchanger.gui.experimental.GuiExperimentalOptifine; import me.boomboompower.skinchanger.gui.utils.ModernButton; @@ -32,18 +32,18 @@ public class ExperimentalGui extends ModernGui { - private final SkinChangerMod mod; + private final SkinChangerModOld mod; private ModernButton skinCache; - public ExperimentalGui(SkinChangerMod mod) { + public ExperimentalGui(SkinChangerModOld mod) { this.mod = mod; } @Override public void initGui() { this.buttonList.add(new ModernButton(0, this.width / 2 - 75, this.height / 2 - 22, 150, 20, - "Rending: " + (SkinChangerMod.getInstance().isRenderingEnabled() ? ChatColor.GREEN + "On" : ChatColor.GRAY + "Off"))); + "Rending: " + (SkinChangerModOld.getInstance().isRenderingEnabled() ? ChatColor.GREEN + "On" : ChatColor.GRAY + "Off"))); this.buttonList.add(new ModernButton(1, this.width / 2 - 75, this.height / 2 + 2, 150, 20, "All player utils")); this.buttonList.add(new ModernButton(2, this.width / 2 - 75, this.height / 2 + 26, 150, 20, "Optifine utils")); this.buttonList.add(this.skinCache = new ModernButton(3, this.width / 2 - 75, this.height / 2 + 50, 150, 20, "Delete skin cache")); @@ -66,8 +66,9 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { public void buttonPressed(ModernButton button) { switch (button.id) { case 0: - SkinChangerMod.getInstance().setRenderingEnabled(!SkinChangerMod.getInstance().isRenderingEnabled()); - button.setText("Rending: " + (SkinChangerMod.getInstance().isRenderingEnabled() ? ChatColor.GREEN + "On" : ChatColor.GRAY + "Off")); + SkinChangerModOld + .getInstance().setRenderingEnabled(!SkinChangerModOld.getInstance().isRenderingEnabled()); + button.setText("Rending: " + (SkinChangerModOld.getInstance().isRenderingEnabled() ? ChatColor.GREEN + "On" : ChatColor.GRAY + "Off")); break; case 1: this.mc.displayGuiScreen(new GuiExperimentalAllPlayers(this.mod)); diff --git a/src/main/java/me/boomboompower/skinchanger/gui/MixinsWarningGui.java b/src/main/java/me/boomboompower/skinchanger/gui/MixinsWarningGui.java deleted file mode 100644 index e06ecd4..0000000 --- a/src/main/java/me/boomboompower/skinchanger/gui/MixinsWarningGui.java +++ /dev/null @@ -1,18 +0,0 @@ -package me.boomboompower.skinchanger.gui; - -import me.boomboompower.skinchanger.gui.utils.ModernGui; - -public class MixinsWarningGui extends ModernGui { - - @Override - public void initGui() { - super.initGui(); - } - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - drawDefaultBackground(); - - super.drawScreen(mouseX, mouseY, partialTicks); - } -} diff --git a/src/main/java/me/boomboompower/skinchanger/gui/SettingsGui.java b/src/main/java/me/boomboompower/skinchanger/gui/SettingsGui.java index 3121c1c..0a5f707 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/SettingsGui.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/SettingsGui.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,15 +17,14 @@ package me.boomboompower.skinchanger.gui; -import me.boomboompower.skinchanger.SkinChangerMod; -import me.boomboompower.skinchanger.mixins.Tweaker; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.utils.fake.FakePlayer; import me.boomboompower.skinchanger.gui.utils.ModernButton; import me.boomboompower.skinchanger.gui.utils.ModernGui; import me.boomboompower.skinchanger.gui.utils.ModernTextBox; import me.boomboompower.skinchanger.utils.ChatColor; - import me.boomboompower.skinchanger.utils.models.skins.PlayerSkinType; + import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.util.ResourceLocation; import org.lwjgl.input.Keyboard; @@ -34,7 +33,7 @@ public class SettingsGui extends ModernGui { - private final SkinChangerMod mod; + private final SkinChangerModOld mod; private static final FakePlayer fakePlayer = new FakePlayer(); private static final ResourceLocation defaultCape = new ResourceLocation("assets/skinchanger/cape.png"); @@ -45,11 +44,11 @@ public class SettingsGui extends ModernGui { private boolean previewCape = false; - public SettingsGui(SkinChangerMod modIn) { + public SettingsGui(SkinChangerModOld modIn) { this(modIn, ""); } - public SettingsGui(SkinChangerMod modIn, String message) { + public SettingsGui(SkinChangerModOld modIn, String message) { this.mod = modIn; this.message = message; @@ -143,11 +142,8 @@ public void buttonPressed(ModernButton button) { } break; case 2: - if (Tweaker.MIXINS_ENABLED) { + this.mod.getSkinManager().reset(); - } else { - this.mod.getSkinManager().reset(); - } sendChatMessage("Your skin has been reset!"); this.mc.displayGuiScreen(null); break; diff --git a/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalAllPlayers.java b/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalAllPlayers.java index 5274acc..805bd7f 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalAllPlayers.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalAllPlayers.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,19 +17,19 @@ package me.boomboompower.skinchanger.gui.experimental; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.gui.utils.ModernButton; import me.boomboompower.skinchanger.gui.utils.ModernGui; import me.boomboompower.skinchanger.gui.utils.ModernTextBox; -import me.boomboompower.skinchanger.mixins.Tweaker; -import me.boomboompower.skinchanger.utils.models.skins.SkinManager; import me.boomboompower.skinchanger.utils.ChatColor; +import me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker; + import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityOtherPlayerMP; import net.minecraft.entity.Entity; - import net.minecraft.util.ResourceLocation; + import org.lwjgl.input.Keyboard; import java.awt.*; @@ -41,13 +41,13 @@ public class GuiExperimentalAllPlayers extends ModernGui { public static ResourceLocation forcedAllSkins; - private final SkinChangerMod mod; + private final SkinChangerModOld mod; private ModernTextBox textField; private ModernButton resetButton; - public GuiExperimentalAllPlayers(SkinChangerMod theMod) { + public GuiExperimentalAllPlayers(SkinChangerModOld theMod) { this.mod = theMod; } @@ -78,11 +78,11 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { public void buttonPressed(ModernButton button) { switch (button.id) { case 0: - if (Tweaker.MIXINS_ENABLED) { + if (SkinChangerTweaker.MIXINS_ENABLED) { forcedAllSkins = this.mod.getSkinManager().getSkin(this.textField.getText()); } else { for (EntityOtherPlayerMP player : get()) { - new SkinManager(this.mod.getMojangHooker(), player, false).update(this.textField.getText()); + //new SkinManager(this.mod.getMojangHooker(), player, false).update(this.textField.getText()); } } @@ -90,11 +90,11 @@ public void buttonPressed(ModernButton button) { break; case 2: - if (Tweaker.MIXINS_ENABLED) { + if (SkinChangerTweaker.MIXINS_ENABLED) { forcedAllSkins = null; } else { for (EntityOtherPlayerMP player : get()) { - new SkinManager(this.mod.getMojangHooker(), player, false).reset(); + //new SkinManager(this.mod.getMojangHooker(), player, false).reset(); } } @@ -110,7 +110,7 @@ public void buttonPressed(ModernButton button) { @Override public void onGuiClosed() { Keyboard.enableRepeatEvents(false); - SkinChangerMod.getInstance().getLoader().save(); + SkinChangerModOld.getInstance().getLoader().save(); } private List get() { diff --git a/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalOptifine.java b/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalOptifine.java index b3dc0d4..bcc3347 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalOptifine.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/experimental/GuiExperimentalOptifine.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ package me.boomboompower.skinchanger.gui.experimental; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.utils.models.capes.CapeManager; import me.boomboompower.skinchanger.utils.fake.FakePlayer; import me.boomboompower.skinchanger.gui.utils.ModernButton; @@ -37,7 +37,7 @@ public class GuiExperimentalOptifine extends ModernGui { private ModernTextBox textField; public GuiExperimentalOptifine() { - SkinChangerMod.getInstance().getSkinManager().updatePlayer(null); + SkinChangerModOld.getInstance().getSkinManager().updatePlayer(null); } @Override @@ -75,13 +75,13 @@ public void buttonPressed(ModernButton button) { } break; case 1: - SkinChangerMod.getInstance().getCapeManager().setExperimental(false); - SkinChangerMod.getInstance().getCapeManager().removeCape(); + SkinChangerModOld.getInstance().getCapeManager().setExperimental(false); + SkinChangerModOld.getInstance().getCapeManager().removeCape(); this.mc.displayGuiScreen(null); break; case 2: if (!this.textField.getText().isEmpty() && this.textField.getText().length() >= 2) { - SkinChangerMod.getInstance().getCapeManager().giveOfCape(this.textField.getText()); + SkinChangerModOld.getInstance().getCapeManager().giveOfCape(this.textField.getText()); this.mc.displayGuiScreen(null); } break; @@ -93,6 +93,6 @@ public void buttonPressed(ModernButton button) { @Override public void onGuiClosed() { Keyboard.enableRepeatEvents(false); - SkinChangerMod.getInstance().getLoader().save(); + SkinChangerModOld.getInstance().getLoader().save(); } } diff --git a/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernButton.java b/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernButton.java index 3598db8..2a6c296 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernButton.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernGui.java b/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernGui.java index 14f31aa..ca6c8de 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernGui.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernGui.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernTextBox.java b/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernTextBox.java index 8897047..cd474f1 100644 --- a/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernTextBox.java +++ b/src/main/java/me/boomboompower/skinchanger/gui/utils/ModernTextBox.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/mixins/tweaks/MixinAbstractClientPlayer.java b/src/main/java/me/boomboompower/skinchanger/mixins/tweaks/MixinAbstractClientPlayer.java index 93fce7d..0a1bfe3 100644 --- a/src/main/java/me/boomboompower/skinchanger/mixins/tweaks/MixinAbstractClientPlayer.java +++ b/src/main/java/me/boomboompower/skinchanger/mixins/tweaks/MixinAbstractClientPlayer.java @@ -1,10 +1,28 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package me.boomboompower.skinchanger.mixins.tweaks; import com.mojang.authlib.GameProfile; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.gui.experimental.GuiExperimentalAllPlayers; -import me.boomboompower.skinchanger.mixins.Tweaker; + +import me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.AbstractClientPlayer; @@ -40,13 +58,14 @@ public MixinAbstractClientPlayer(World worldIn, GameProfile gameProfileIn) { public ResourceLocation getLocationSkin() { if (getEntityId() == Minecraft.getMinecraft().thePlayer.getEntityId()) { - if (Tweaker.MIXINS_ENABLED && SkinChangerMod.getInstance().isRenderingEnabled() && SkinChangerMod.getInstance().getSkinManager().getShouldUse()) { - if (SkinChangerMod.getInstance().getSkinManager().getSkinName().equals(this.lastSkinName)) { + if (SkinChangerTweaker.MIXINS_ENABLED && SkinChangerModOld.getInstance().isRenderingEnabled() && SkinChangerModOld + .getInstance().getSkinManager().getShouldUse()) { + if (SkinChangerModOld.getInstance().getSkinManager().getSkinName().equals(this.lastSkinName)) { return this.lastSkin; } - this.lastSkinName = SkinChangerMod.getInstance().getSkinManager().getSkinName(); - this.lastSkin = SkinChangerMod.getInstance().getSkinManager().getSkin(this.lastSkinName); + this.lastSkinName = SkinChangerModOld.getInstance().getSkinManager().getSkinName(); + this.lastSkin = SkinChangerModOld.getInstance().getSkinManager().getSkin(this.lastSkinName); return this.lastSkin; } @@ -65,13 +84,13 @@ public ResourceLocation getLocationSkin() public ResourceLocation getLocationCape() { if (getEntityId() == Minecraft.getMinecraft().thePlayer.getEntityId()) { - if (Tweaker.MIXINS_ENABLED && SkinChangerMod.getInstance().getCapeManager().isUsingCape()) { - if (SkinChangerMod.getInstance().getCapeManager().getOfCapeName().equals(this.lastCapeName)) { + if (SkinChangerTweaker.MIXINS_ENABLED && SkinChangerModOld.getInstance().getCapeManager().isUsingCape()) { + if (SkinChangerModOld.getInstance().getCapeManager().getOfCapeName().equals(this.lastCapeName)) { return this.lastSkin; } - this.lastCapeName = SkinChangerMod.getInstance().getCapeManager().getOfCapeName(); - this.lastCape = SkinChangerMod.getInstance().getCapeManager().getOfCape(this.lastCapeName); + this.lastCapeName = SkinChangerModOld.getInstance().getCapeManager().getOfCapeName(); + this.lastCape = SkinChangerModOld.getInstance().getCapeManager().getOfCape(this.lastCapeName); return this.lastCape; } @@ -92,8 +111,8 @@ public ResourceLocation getLocationCape() public String getSkinType() { if (getEntityId() == Minecraft.getMinecraft().thePlayer.getEntityId()) { - if (Tweaker.MIXINS_ENABLED && SkinChangerMod.getInstance().isRenderingEnabled()) { - return SkinChangerMod.getInstance().getSkinManager().getSkinType().getSecretName(); + if (SkinChangerTweaker.MIXINS_ENABLED && SkinChangerModOld.getInstance().isRenderingEnabled()) { + return SkinChangerModOld.getInstance().getSkinManager().getSkinType().getSecretName(); } } diff --git a/src/main/java/me/boomboompower/skinchanger/run/JavaMain.java b/src/main/java/me/boomboompower/skinchanger/run/JavaMain.java index 597ec13..eb0d299 100644 --- a/src/main/java/me/boomboompower/skinchanger/run/JavaMain.java +++ b/src/main/java/me/boomboompower/skinchanger/run/JavaMain.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/run/RunGui.java b/src/main/java/me/boomboompower/skinchanger/run/RunGui.java index d220f21..4e8d48a 100644 --- a/src/main/java/me/boomboompower/skinchanger/run/RunGui.java +++ b/src/main/java/me/boomboompower/skinchanger/run/RunGui.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/utils/ChatColor.java b/src/main/java/me/boomboompower/skinchanger/utils/ChatColor.java index 649524c..3709d3e 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/ChatColor.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/ChatColor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,11 +50,11 @@ public enum ChatColor { private final boolean isFormat; private final String toString; - private ChatColor(char code) { + ChatColor(char code) { this(code, false); } - private ChatColor(char code, boolean isFormat) { + ChatColor(char code, boolean isFormat) { this.code = code; this.isFormat = isFormat; this.toString = new String(new char[] {COLOR_CHAR, code}); @@ -81,7 +81,7 @@ public static String stripColor(final String input) { if (input == null) { return null; } - return Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]").matcher(input).replaceAll(""); + return Pattern.compile("(?i)" + COLOR_CHAR + "[0-9A-FK-OR]").matcher(input).replaceAll(""); } public static String translateAlternateColorCodes(String textToTranslate) { diff --git a/src/main/java/me/boomboompower/skinchanger/utils/ReflectUtils.java b/src/main/java/me/boomboompower/skinchanger/utils/ReflectUtils.java index 1887f96..ed7d765 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/ReflectUtils.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/ReflectUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayer.java b/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayer.java index cc293e4..4c4b252 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayer.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayer.java @@ -1,10 +1,27 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package me.boomboompower.skinchanger.utils.fake; import com.mojang.authlib.GameProfile; import java.util.UUID; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.AbstractClientPlayer; @@ -24,7 +41,7 @@ */ public class FakePlayer extends AbstractClientPlayer { - private static final GameProfile FAKE_GAME_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("skinchanger".getBytes()), "SkinChanger v" + SkinChangerMod.VERSION); + private static final GameProfile FAKE_GAME_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("skinchanger".getBytes()), "SkinChanger v" + SkinChangerModOld.VERSION); private FakePlayerInfo playerInfo; diff --git a/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerCape.java b/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerCape.java index e288f6b..f1981d5 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerCape.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerCape.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerInfo.java b/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerInfo.java index 0dbc7ed..dd95d10 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerInfo.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/fake/FakePlayerInfo.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package me.boomboompower.skinchanger.utils.fake; import com.google.common.base.Objects; diff --git a/src/main/java/me/boomboompower/skinchanger/utils/models/capes/CapeManager.java b/src/main/java/me/boomboompower/skinchanger/utils/models/capes/CapeManager.java index 8a2f38e..22c4ad1 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/models/capes/CapeManager.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/models/capes/CapeManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ package me.boomboompower.skinchanger.utils.models.capes; -import me.boomboompower.skinchanger.SkinChangerMod; +import me.boomboompower.skinchanger.SkinChangerModOld; import me.boomboompower.skinchanger.utils.ReflectUtils; import net.minecraft.client.Minecraft; @@ -54,7 +54,8 @@ public CapeManager(AbstractClientPlayer playerIn, boolean isClientPlayer) { public void addCape() { this.usingCape = true; - Minecraft.getMinecraft().addScheduledTask(() -> setCape(new ResourceLocation(SkinChangerMod.MOD_ID, "cape.png"))); + Minecraft.getMinecraft().addScheduledTask(() -> setCape(new ResourceLocation( + SkinChangerModOld.MOD_ID, "cape.png"))); } public void addCape(ResourceLocation location) { diff --git a/src/main/java/me/boomboompower/skinchanger/utils/models/skins/PlayerSkinType.java b/src/main/java/me/boomboompower/skinchanger/utils/models/skins/PlayerSkinType.java index 63df0de..7017070 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/models/skins/PlayerSkinType.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/models/skins/PlayerSkinType.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package me.boomboompower.skinchanger.utils.models.skins; /** diff --git a/src/main/java/me/boomboompower/skinchanger/utils/models/skins/SkinManager.java b/src/main/java/me/boomboompower/skinchanger/utils/models/skins/SkinManager.java index ce1ad41..3f60863 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/models/skins/SkinManager.java +++ b/src/main/java/me/boomboompower/skinchanger/utils/models/skins/SkinManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,9 +17,6 @@ package me.boomboompower.skinchanger.utils.models.skins; -import me.boomboompower.skinchanger.SkinChangerMod; -import me.boomboompower.skinchanger.mixins.Tweaker; -import me.boomboompower.skinchanger.utils.MojangHooker; import me.boomboompower.skinchanger.utils.ReflectUtils; import net.minecraft.client.Minecraft; @@ -52,7 +49,7 @@ public class SkinManager { private boolean shouldUse = false; - public SkinManager(MojangHooker hooker, AbstractClientPlayer playerIn, boolean normalPlayer) { + public SkinManager(AbstractClientPlayer playerIn, boolean normalPlayer) { this.playerIn = playerIn; this.normalPlayer = normalPlayer; } @@ -100,10 +97,6 @@ private void replaceSkin(String skinName) { } public void replaceSkin(ResourceLocation location) { - if (Tweaker.MIXINS_ENABLED) { - return; - } - if (this.skinName == null || this.skinName.isEmpty() || (this.normalPlayer ? Minecraft.getMinecraft().thePlayer == null : this.playerIn == null)) return; NetworkPlayerInfo playerInfo; diff --git a/src/main/java/me/do_you_like/mods/skinchanger/SkinChangerMod.java b/src/main/java/me/do_you_like/mods/skinchanger/SkinChangerMod.java new file mode 100644 index 0000000..4a282f9 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/SkinChangerMod.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger; + +import java.io.File; + +import me.do_you_like.mods.skinchanger.commands.SkinCommand; +import me.do_you_like.mods.skinchanger.configuration.ConfigurationHandler; +import me.do_you_like.mods.skinchanger.utils.backend.MojangHooker; +import me.do_you_like.mods.skinchanger.utils.game.ChatColor; +import me.do_you_like.mods.skinchanger.utils.mod.CacheRetriever; + +import net.minecraftforge.client.ClientCommandHandler; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ModMetadata; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +@Mod(modid = SkinChangerMod.MOD_ID, version = SkinChangerMod.VERSION, acceptedMinecraftVersions = "*") +public class SkinChangerMod { + + public static final String MOD_ID = "skinchanger"; + public static final String VERSION = "3.0.0"; + + @Mod.Instance + private static SkinChangerMod instance; + + private ConfigurationHandler configurationHandler; + private CacheRetriever cacheRetriever; + private MojangHooker mojangHooker; + + private File modConfigDirectory; + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + ModMetadata data = event.getModMetadata(); + data.description = ChatColor.AQUA + "A client-side mod that allows you to change your skin instantly!"; + data.authorList.add("boomboompower"); + + this.modConfigDirectory = event.getModConfigurationDirectory(); + + this.cacheRetriever = new CacheRetriever(this); + this.configurationHandler = new ConfigurationHandler(this); + } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + //MinecraftForge.EVENT_BUS.register(new MainEvents(this)); + ClientCommandHandler.instance.registerCommand(new SkinCommand(this)); + + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent event) { + this.configurationHandler.load(); + + this.mojangHooker = new MojangHooker(); + } + + public File getModConfigDirectory() { + return this.modConfigDirectory; + } + + public ConfigurationHandler getConfigurationHandler() { + return this.configurationHandler; + } + + public CacheRetriever getCacheRetriever() { + return this.cacheRetriever; + } + + public MojangHooker getMojangHooker() { + return this.mojangHooker; + } + + public static SkinChangerMod getInstance() { + return instance; + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/commands/SkinCommand.java b/src/main/java/me/do_you_like/mods/skinchanger/commands/SkinCommand.java new file mode 100644 index 0000000..3dc55d8 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/commands/SkinCommand.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.commands; + +import java.util.Arrays; +import java.util.List; + +import me.do_you_like.mods.skinchanger.SkinChangerMod; +import me.do_you_like.mods.skinchanger.utils.backend.InternetConnection; +import me.do_you_like.mods.skinchanger.utils.game.ChatColor; +import me.do_you_like.mods.skinchanger.utils.mod.ModCommand; + +import net.minecraft.command.ICommandSender; + +import net.minecraft.util.ResourceLocation; + +public class SkinCommand extends ModCommand { + + public static ResourceLocation VERY_BIG_TEMPORARY_SKIN = null; + public static boolean IS_SLIM_SKIN = false; + + public SkinCommand(SkinChangerMod modIn) { + super(modIn); + } + + @Override + public String getCommandName() { + return "skinchanger"; + } + + @Override + public List getAliases() { + return Arrays.asList("changeskin", "changecape"); + } + + @Override + public void onCommand(ICommandSender sender, String[] args) { + // TODO remove this during production. + if (args.length > 0 && args[0].equalsIgnoreCase("fix")) { + org.lwjgl.opengl.Display.setResizable(false); + org.lwjgl.opengl.Display.setResizable(true); + return; + } + + if (args.length == 0) { + sendMessage(ChatColor.RED + "Incorrect usage, try: /skinchanger "); + } else if (args[0].equalsIgnoreCase("null")) { + VERY_BIG_TEMPORARY_SKIN = null; + IS_SLIM_SKIN = false; + + sendMessage(ChatColor.AQUA + "Your skin has been reset!"); + } else { + if (!InternetConnection.hasInternetConnection()) { + sendMessage(ChatColor.RED + "Could not connect to the internet. " + ChatColor.RED + "Make sure you have a stable internet connection!"); + return; + } + + String id = this.mod.getMojangHooker().getIdFromUsername(args[0]); + + VERY_BIG_TEMPORARY_SKIN = this.mod.getMojangHooker().getSkinFromId(id); + IS_SLIM_SKIN = this.mod.getMojangHooker().hasSlimSkin(id); + + sendMessage(ChatColor.AQUA + "Set skin to " + id + "\'s skin!"); + } + +// if (args.length == 0) { +// new SettingsGui(this.mod).display(); +// } else { +// new SettingsGui(this.mod, args[0]).display(); +// } + } + + @Override + protected boolean shouldMultithreadCommand(String[] args) { + return true; + } + + @Override + public boolean isUsernameIndex(String[] args, int index) { + return index == 0; + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/configuration/ConfigurationHandler.java b/src/main/java/me/do_you_like/mods/skinchanger/configuration/ConfigurationHandler.java new file mode 100644 index 0000000..5f6583f --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/configuration/ConfigurationHandler.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.configuration; + +import com.google.gson.JsonElement; +import java.io.File; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import me.do_you_like.mods.skinchanger.SkinChangerMod; +import me.do_you_like.mods.skinchanger.configuration.meta.ConfigurationData; +import me.do_you_like.mods.skinchanger.configuration.meta.SaveableClassData; +import me.do_you_like.mods.skinchanger.configuration.meta.SaveableField; +import me.do_you_like.mods.skinchanger.utils.general.BetterJsonObject; + + +public class ConfigurationHandler { + + @SaveableField(customName = "SuperSecretValue") + private String specialValue = "HelloWorld"; + + private final SkinChangerMod mod; + private final File configFile; + + private final HashMap, ConfigurationData[]> saveableValues = new HashMap<>(); + + public ConfigurationHandler(SkinChangerMod mod) { + this.mod = mod; + + this.configFile = new File(mod.getModConfigDirectory(), "config.json"); + } + + public void save() { + if (this.saveableValues.isEmpty()) { + return; + } + + BetterJsonObject saveObject = new BetterJsonObject(); + + for (Map.Entry, ConfigurationData[]> o : this.saveableValues.entrySet()) { + Class clazz = o.getKey(); + + // Where all our values will be saved to. + BetterJsonObject classSpecific = new BetterJsonObject(); + + // The list of fields in the class containing data. + ConfigurationData[] dataList = o.getValue(); + + // Loop through each data value. + for (ConfigurationData data : dataList) { + // Retrieves the value from the field. + Object value = data.getValue(); + + // Converts the field value into JSON. + JsonElement serializedData = saveObject.getGsonData().toJsonTree(value); + + // Add the JSON to our JSON config. + saveObject.getData().add(data.getSaveName(), serializedData); + } + + String clazzSaveName = o.getKey().getName(); + + if (clazz.isAnnotationPresent(SaveableClassData.class)) { + clazzSaveName = clazz.getAnnotation(SaveableClassData.class).saveName(); + } + + // Adds that classes config module to the config file. + saveObject.add(clazzSaveName, saveObject); + } + + saveObject.writeToFile(this.configFile); + } + + public void load() { + + } + + public void addAsSaveable(Object clazz) { + if (clazz == null) { + return; + } + + // If the class is already registered, don't add it again. + if (this.saveableValues.containsKey(clazz.getClass())) { + return; + } + + Field[] clazzFields = clazz.getClass().getDeclaredFields(); + + // Don't touch it if it has no fields + if (clazzFields.length <= 0) { + return; + } + + List storedData = new ArrayList<>(); + + // True if a field has been found with a SaveableField attribute. + boolean hasSaveableField = false; + + for (Field f : clazzFields) { + // Check if the field is actually saveable + if (!f.isAnnotationPresent(SaveableField.class)) { + continue; + } + + hasSaveableField = true; + + SaveableField saveable = f.getAnnotation(SaveableField.class); + + String nameToSave = f.getName(); + + if (!saveable.customName().isEmpty()) { + nameToSave = saveable.customName(); + } + + // Create an instance of this field. + ConfigurationData data = new ConfigurationData(f, nameToSave, saveable.shouldOverwriteOnLoad()); + + data.initialize(clazz); + + storedData.add(data); + } + + this.saveableValues.put(clazz.getClass(), storedData.toArray(new ConfigurationData[0])); + + if (!hasSaveableField) { + System.out.println("Class \'%s\' was called through ConfigurationHandler#addAsSaveable however no @SaveableField annotations were present on any fields. It is advised to deregister that class as calling this method for no purpose may degrade performance. "); + + return; + } + } + + public SkinChangerMod getMod() { + return this.mod; + } + + public File getConfigFile() { + return this.configFile; + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/ConfigurationData.java b/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/ConfigurationData.java new file mode 100644 index 0000000..05fe26a --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/ConfigurationData.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.configuration.meta; + +import java.lang.reflect.Field; + +import me.do_you_like.mods.skinchanger.utils.general.Prerequisites; + +/** + * Stores the data for fields. + */ +public class ConfigurationData { + + private final Field field; + private final String saveName; + private final boolean overwriteOnLoad; + + private Object parent; + + public ConfigurationData(Field fieldIn, String saveName) { + this(fieldIn, saveName, true); + } + + public ConfigurationData(Field fieldIn, String saveName, boolean overwriteOnLoad) { + Prerequisites.notNull(fieldIn); + Prerequisites.notNull(saveName); + + this.field = fieldIn; + this.saveName = saveName; + this.overwriteOnLoad = overwriteOnLoad; + } + + public Field getField() { + return this.field; + } + + public String getSaveName() { + return this.saveName; + } + + public boolean isOverwriteOnLoad() { + return this.overwriteOnLoad; + } + + public Object getValue() { + boolean accessible = this.field.isAccessible(); + + try { + boolean modified = false; + + if (!accessible) { + modified = true; + + this.field.setAccessible(true); + } + + Object value = this.field.get(this.parent); + + if (modified) { + this.field.setAccessible(false); + } + + return value; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + return null; + } + + public void initialize(Object parent) { + if (this.parent != null || parent == null) { + return; + } + + this.parent = parent; + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableClassData.java b/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableClassData.java new file mode 100644 index 0000000..7f3bae0 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableClassData.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.configuration.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SaveableClassData { + + String saveName(); +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableField.java b/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableField.java new file mode 100644 index 0000000..f2a2901 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/configuration/meta/SaveableField.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.configuration.meta; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import me.do_you_like.mods.skinchanger.configuration.ConfigurationHandler; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface SaveableField { + + /** + * The custom name to save this value to. + * + * @return the custom name of this value + */ + String customName() default ""; + + /** + * When {@link ConfigurationHandler#load()} is called, should this field be updated? + * + * @return true if the field should be updated + */ + boolean shouldOverwriteOnLoad() default true; +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/gui/SkinChangerMenu.java b/src/main/java/me/do_you_like/mods/skinchanger/gui/SkinChangerMenu.java new file mode 100644 index 0000000..1a2f80f --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/gui/SkinChangerMenu.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.gui; + +import me.do_you_like.mods.skinchanger.utils.gui.impl.ModernButton; +import me.do_you_like.mods.skinchanger.utils.gui.impl.ModernGui; + +public class SkinChangerMenu extends ModernGui { + + @Override + public void onGuiOpen() { + + } + + @Override + public void preRender() { + + } + + @Override + public void onRender(int mouseX, int mouseY, float partialTicks) { + + } + + @Override + public void postRender() { + + } + + @Override + public void buttonPressed(ModernButton button) { + + } + + @Override + public void onKeyTyped(int keyCode, char keyCharacter) { + + } + + +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/installer/InstallerCore.java b/src/main/java/me/do_you_like/mods/skinchanger/installer/InstallerCore.java new file mode 100644 index 0000000..3a7c975 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/installer/InstallerCore.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.installer; + +import java.awt.GraphicsEnvironment; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import javax.swing.JOptionPane; +import javax.swing.UIManager; + +import me.do_you_like.mods.skinchanger.utils.installing.OSType; +import me.do_you_like.mods.skinchanger.utils.installing.OperatingSystem; + +public class InstallerCore { + + private static final String MOD_NAME = "SkinChanger"; + + public static void main(String[] args) { + if (!GraphicsEnvironment.isHeadless()) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception ignored) { + } + + OSType osType = OperatingSystem.getOSType(); + + if (osType == OSType.UNKNOWN) { + onInstallationFailed("Your operating system is not supported by the installer."); + + return; + } + + File mcModDir = new File(OperatingSystem.getMinecraftDirectory(osType), "mods"); + + if (InstallerCore.class.getProtectionDomain() == null || InstallerCore.class.getProtectionDomain().getCodeSource() == null || InstallerCore.class.getProtectionDomain().getCodeSource().getLocation() == null) { + onInstallationFailed("Your mod file may be corrupt."); + + return; + } + + File currentPath = new File(InstallerCore.class.getProtectionDomain().getCodeSource().getLocation().getPath()); + + if (!currentPath.exists()) { + onInstallationFailed("The file you are running doesn't exist??"); + + return; + } + + if (currentPath.isDirectory()) { + onInstallationFailed("You are running the mod in a development environment."); + + return; + } + + try { + + Files.copy(currentPath.toPath(), new File(mcModDir, MOD_NAME + ".jar").toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException ex) { + onInstallationFailed("The mod was unable to be written to the installation directory."); + + ex.printStackTrace(); + + return; + } catch (SecurityException ex) { + onInstallationFailed("The installer did not have permission to copy the mod to the mods directory. \nTry running the jar as an admin."); + + ex.printStackTrace(); + + return; + } + + JOptionPane.showMessageDialog(null, MOD_NAME + " has been installed at: \n " + mcModDir.getAbsolutePath() + "\n\nFrom: \n" + currentPath.getAbsolutePath(), "Installation Successful", JOptionPane.INFORMATION_MESSAGE); + } + } + + private static void onInstallationFailed() { + onInstallationFailed(""); + } + + private static void onInstallationFailed(String additional) { + String message = "Unable to install " + MOD_NAME + ", please place it in your \".minecraft/mods\" directory manually."; + + if (OperatingSystem.getOSType() != OSType.UNKNOWN) { + message += "\n\nIt should be located at: \n" + OperatingSystem.getMinecraftDirectory(OperatingSystem.getOSType()); + } else { + message += "\n\nThe installer was unable to find the minecraft directory for your operating system."; + } + + if (additional.trim().length() > 0) { + message += "\n\n" + additional; + } + + JOptionPane.showMessageDialog(null, message, "Installation Failed", JOptionPane.ERROR_MESSAGE); + } + +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethod.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethod.java new file mode 100644 index 0000000..fb872fd --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethod.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods; + +import me.do_you_like.mods.skinchanger.methods.meta.ChangeData; + +public interface ChangingMethod { + + /** + * Called when the player changes their skin + */ + void onSkinChange(ChangeData data); + + /** + * Called when the player resets their skin + */ + void onSkinReset(ChangeData data); + + void onCapeChange(String oldCape, String newCape); + + void onCapeReset(); +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethodFactory.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethodFactory.java new file mode 100644 index 0000000..c49e1c6 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/ChangingMethodFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods; + +public class ChangingMethodFactory { + + +} diff --git a/src/main/java/me/boomboompower/skinchanger/utils/GlobalUtils.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/MixinsSkinChangeMethod.java similarity index 54% rename from src/main/java/me/boomboompower/skinchanger/utils/GlobalUtils.java rename to src/main/java/me/do_you_like/mods/skinchanger/methods/impl/MixinsSkinChangeMethod.java index f9bd043..4076839 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/GlobalUtils.java +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/MixinsSkinChangeMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,20 +15,34 @@ * along with this program. If not, see . */ -package me.boomboompower.skinchanger.utils; +package me.do_you_like.mods.skinchanger.methods.impl; -import net.minecraft.client.Minecraft; -import net.minecraft.util.ChatComponentText; +import me.do_you_like.mods.skinchanger.methods.ChangingMethod; +import me.do_you_like.mods.skinchanger.methods.meta.ChangeData; -public class GlobalUtils { +/** + * The Mixins implementation of SkinChanger + * + */ +public class MixinsSkinChangeMethod implements ChangingMethod { + + @Override + public void onSkinChange(ChangeData data) { + + } - public static final String PREFIX = ChatColor.AQUA + "SkinChanger" + ChatColor.GOLD + " > " + ChatColor.GRAY; + @Override + public void onSkinReset(ChangeData data) { - public static void sendChatMessage(String msg) { - sendChatMessage(msg, true); } - public static void sendChatMessage(String msg, boolean usePrefix) { - Minecraft.getMinecraft().thePlayer.addChatComponentMessage(new ChatComponentText((usePrefix ? PREFIX : ChatColor.GRAY) + msg)); + @Override + public void onCapeChange(String oldCape, String newCape) { + + } + + @Override + public void onCapeReset() { + } } diff --git a/src/main/java/me/boomboompower/skinchanger/mixins/Tweaker.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/SkinChangerTweaker.java similarity index 78% rename from src/main/java/me/boomboompower/skinchanger/mixins/Tweaker.java rename to src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/SkinChangerTweaker.java index 8e8716e..6f0d33d 100644 --- a/src/main/java/me/boomboompower/skinchanger/mixins/Tweaker.java +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/SkinChangerTweaker.java @@ -1,13 +1,30 @@ -package me.boomboompower.skinchanger.mixins; +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods.impl.mixins; import java.io.BufferedReader; import java.io.BufferedWriter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; +import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStream; +import java.util.List; + import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.LaunchClassLoader; @@ -15,10 +32,8 @@ import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.Mixins; -import java.io.File; -import java.util.List; - -public class Tweaker implements ITweaker { +// --tweakClass me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker +public class SkinChangerTweaker implements ITweaker { public static boolean MIXINS_ENABLED = false; diff --git a/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/tweaks/MixinAbstractClientPlayer.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/tweaks/MixinAbstractClientPlayer.java new file mode 100644 index 0000000..e2cfda1 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/impl/mixins/tweaks/MixinAbstractClientPlayer.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods.impl.mixins.tweaks; + +import com.mojang.authlib.GameProfile; + +import me.do_you_like.mods.skinchanger.commands.SkinCommand; +import me.do_you_like.mods.skinchanger.methods.impl.mixins.SkinChangerTweaker; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.AbstractClientPlayer; +import net.minecraft.client.network.NetworkPlayerInfo; +import net.minecraft.client.resources.DefaultPlayerSkin; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(AbstractClientPlayer.class) +public abstract class MixinAbstractClientPlayer extends EntityPlayer { + + private ResourceLocation lastCape; + private String lastCapeName = null; + + private ResourceLocation lastSkin; + private String lastSkinName = null; + + public MixinAbstractClientPlayer(World worldIn, GameProfile gameProfileIn) { + super(worldIn, gameProfileIn); + } + + /** + * @author boomboompower + * + * @reason Hooking the location of the skin to force set it in the game code + */ + @Overwrite + public ResourceLocation getLocationSkin() { + if (getEntityId() == Minecraft.getMinecraft().thePlayer.getEntityId()) { + if (SkinChangerTweaker.MIXINS_ENABLED && SkinCommand.VERY_BIG_TEMPORARY_SKIN != null) { + return SkinCommand.VERY_BIG_TEMPORARY_SKIN; + } + } + + NetworkPlayerInfo networkplayerinfo = this.getPlayerInfo(); + return networkplayerinfo == null ? DefaultPlayerSkin.getDefaultSkin(this.getUniqueID()) : networkplayerinfo.getLocationSkin(); + } + + /** + * @author boomboompower + * + * @reason Hooking the location of the cape to force set it in the game code + */ + @Overwrite + public ResourceLocation getLocationCape() { + NetworkPlayerInfo networkplayerinfo = this.getPlayerInfo(); + return networkplayerinfo == null ? null : networkplayerinfo.getLocationCape(); + } + + /** + * @author boomboompower + * + * @reason We're adding a hook to the skin type so the player can change the display type of the skin + */ + @Overwrite + public String getSkinType() { + if (getEntityId() == Minecraft.getMinecraft().thePlayer.getEntityId()) { + if (SkinChangerTweaker.MIXINS_ENABLED && SkinCommand.VERY_BIG_TEMPORARY_SKIN != null) { + return SkinCommand.IS_SLIM_SKIN ? "slim" : "default"; + } + } + + NetworkPlayerInfo networkplayerinfo = this.getPlayerInfo(); + return networkplayerinfo == null ? DefaultPlayerSkin.getSkinType(this.getUniqueID()) : networkplayerinfo.getSkinType(); + } + + @Shadow + protected abstract NetworkPlayerInfo getPlayerInfo(); + +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/CapeChangeMetadata.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/CapeChangeMetadata.java new file mode 100644 index 0000000..3d3907b --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/CapeChangeMetadata.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods.meta; + +import net.minecraft.util.ResourceLocation; + +public class CapeChangeMetadata implements ChangeData { + + private String playerName; + private ResourceLocation resource; + private boolean isActive; + + @Override + public String getName() { + return null; + } + + @Override + public ResourceLocation getResource() { + return null; + } + + @Override + public void setResource(String potentialName) { + + } + + @Override + public void setResource(ResourceLocation location) { + + } + + @Override + public boolean isActive() { + return this.resource == null; + } + + @Override + public void setActive(boolean active) { + if (active && this.resource == null && this.playerName != null) { + downloadCape(this.playerName); + } + } + + private void downloadCape(String name) { + + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/ChangeData.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/ChangeData.java new file mode 100644 index 0000000..df2ead4 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/ChangeData.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods.meta; + +import net.minecraft.util.ResourceLocation; + +/** + * Stores all data related to a texture in the game. + */ +public interface ChangeData { + + /** + * The name of the holder of this skin + * + * @return the name of the holder of this resource. + */ + String getName(); + + /** + * The minecraft location of this resource. + * + * @return the location of the resource. + */ + ResourceLocation getResource(); + + /** + * Sets the resource from a given name. + * + * @param potentialName the name to set the resource to. + */ + void setResource(String potentialName); + + /** + * Sets the resource from a location in Minecraft. Doing this will cause {@link #getName()} to be null. + * + * @param location the location of the resource. + */ + void setResource(ResourceLocation location); + + /** + * True if this resource is going to be used in the game code + * + * @return true if this resource is being actively used + */ + boolean isActive(); + + /** + * Sets the resources active state, if this is set to false then the resource should not be used + * + * @param active the active state of the resource / this data + */ + void setActive(boolean active); +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/SkinChangeMetadata.java b/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/SkinChangeMetadata.java new file mode 100644 index 0000000..477e302 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/methods/meta/SkinChangeMetadata.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.methods.meta; + +import net.minecraft.util.ResourceLocation; + +public class SkinChangeMetadata implements ChangeData { + + @Override + public String getName() { + return null; + } + + @Override + public ResourceLocation getResource() { + return null; + } + + @Override + public void setResource(String potentialName) { + + } + + @Override + public void setResource(ResourceLocation location) { + + } + + @Override + public boolean isActive() { + return false; + } + + @Override + public void setActive(boolean active) { + + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/InternetConnection.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/InternetConnection.java new file mode 100644 index 0000000..35440b1 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/InternetConnection.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.backend; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; + +public class InternetConnection { + + private InternetConnection() { + } + + public static boolean hasInternetConnection() { + try { + URL url = new URL("https://google.com"); + + URLConnection connection = url.openConnection(); + + connection.setConnectTimeout(5000); + + connection.connect(); + + return true; + } catch (IOException ex) { + return false; + } + } + +} diff --git a/src/main/java/me/boomboompower/skinchanger/utils/MojangHooker.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/MojangHooker.java similarity index 77% rename from src/main/java/me/boomboompower/skinchanger/utils/MojangHooker.java rename to src/main/java/me/do_you_like/mods/skinchanger/utils/backend/MojangHooker.java index 944021a..c9dfe98 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/MojangHooker.java +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/MojangHooker.java @@ -1,29 +1,40 @@ -package me.boomboompower.skinchanger.utils; +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.backend; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; - import com.google.gson.JsonParseException; import com.google.gson.JsonParser; - -import java.awt.image.BufferedImage; -import java.io.File; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; - +import me.do_you_like.mods.skinchanger.SkinChangerMod; +import me.do_you_like.mods.skinchanger.utils.general.BetterJsonObject; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.IImageBuffer; -import net.minecraft.client.renderer.ImageBufferDownload; -import net.minecraft.client.renderer.ThreadDownloadImageData; import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.util.ResourceLocation; - import org.apache.commons.io.IOUtils; /** @@ -40,7 +51,7 @@ public class MojangHooker { ".mojang.com" }; - private static final HashMap idCaches = new HashMap<>(); // Store the id + private static final HashMap idCaches = new HashMap<>(); // Store the id private static final HashMap responses = new HashMap<>(); // Store responses @@ -64,23 +75,56 @@ public String getIdFromUsername(String nameIn) { if (nameIn == null) { return null; } + + if (idCaches.containsKey(nameIn)) { + return idCaches.get(nameIn)[0]; + } if (nameIn.isEmpty()) { - return idCaches.put(nameIn, ""); + idCaches.put("", new String[] {"", ""}); + + return ""; } BetterJsonObject profile = getProfileFromUsername(nameIn); if (profile.has("success") && !profile.get("success").getAsBoolean()) { - return idCaches.put(nameIn, ""); + idCaches.put(nameIn.toLowerCase(), new String[] {"", ""}); + + return ""; } if (profile.has("id")) { - return idCaches.put(nameIn, profile.get("id").getAsString()); + idCaches.put(nameIn.toLowerCase(), new String[] { profile.get("id").getAsString(), profile.get("name").getAsString() }); + + return profile.get("id").getAsString(); } - return idCaches.put(nameIn, ""); + + idCaches.put(nameIn, new String[] {"", ""}); + + return ""; } - + + /** + * Gets the real name from an input + * + * @param nameIn the name + * @return the real name of the player + */ + public String getRealNameFromName(String nameIn) { + if (nameIn == null) { + return null; + } + + if (idCaches.containsKey(nameIn)) { + return idCaches.get(nameIn)[1]; + } + + getIdFromUsername(nameIn); + + return idCaches.get(nameIn)[1]; + } + /** * Gets the Textures of a player from a username * @@ -157,17 +201,22 @@ private BetterJsonObject getEncryptedTexturesUnsafe(String id) throws Unsupporte if (property.has("name") && property.get("name").getAsString().equals("textures") && property.has("value")) { // We need to decode the Base64 value property byte[] decoded = Base64.getDecoder().decode(property.get("value").getAsString()); - JsonObject decodedObj = new JsonParser().parse(new String(decoded, "UTF-8")).getAsJsonObject(); + JsonObject decodedObj = new JsonParser().parse(new String(decoded, StandardCharsets.UTF_8)).getAsJsonObject(); // We have a match! if (decodedObj.has("textures") && decodedObj.has("profileId") && decodedObj.get("profileId").getAsString().equals(texturesIn.get("id").getAsString())) { - return idEncryptedTextures.put(id, new BetterJsonObject(decodedObj.get("textures").getAsJsonObject())); + idEncryptedTextures.put(id, new BetterJsonObject(decodedObj.get("textures").getAsJsonObject())); + + return idEncryptedTextures.get(id); } } } - return idEncryptedTextures.put(id, new BetterJsonObject()); + + idEncryptedTextures.put(id, new BetterJsonObject()); + + return idEncryptedTextures.get(id); } - + /** * Silent version of {@link #hasSlimSkinUnsafe(String)} * @@ -182,7 +231,7 @@ public boolean hasSlimSkin(String id) { return false; } } - + /** * Is the textures provided a slim skin? * "slim" = ALEX @@ -195,48 +244,54 @@ private boolean hasSlimSkinUnsafe(String id) throws NullPointerException, Unsupp if (id == null) { return false; } - + if (slimSkins.containsKey(id)) { return slimSkins.get(id); } - + JsonObject realTextures = getEncryptedTexturesUnsafe(id).getData(); - + // Should never happen if (!realTextures.has("SKIN")) { - return slimSkins.put(id, false); + slimSkins.put(id, false); + + return false; } - + JsonObject skinData = realTextures.get("SKIN").getAsJsonObject(); - + if (skinData.has("metadata")) { JsonObject metaData = skinData.get("metadata").getAsJsonObject(); - - return slimSkins.put(id, metaData.has("model") && metaData.get("model").getAsString().equals("slim")); + + slimSkins.put(id, metaData.has("model")); + + return metaData.has("model") && metaData.get("model").getAsString().equals("slim"); } - - return slimSkins.put(id, false); + + slimSkins.put(id, false); + + return false; } - + /** * The safe version of skin loading, this will return the Steve model if any issues occur * * @param id the id of the user - * @return the {@link net.minecraft.util.ResourceLocation} of the given id + * @return the {@link ResourceLocation} of the given id */ public ResourceLocation getSkinFromId(String id) { try { return getSkinFromIdUnsafe(id); - } catch (UnsupportedEncodingException ex) { + } catch (UnsupportedEncodingException | IllegalArgumentException ex) { return DefaultPlayerSkin.getDefaultSkinLegacy(); } } - + /** * The unsafe version of skin loading & caching * * @param id the id of the profile, to be used in decryption - * @return the {@link net.minecraft.util.ResourceLocation} of the given id + * @return the {@link ResourceLocation} of the given id * * @throws UnsupportedEncodingException if the encrypted resource cannot be decrypted */ @@ -244,7 +299,7 @@ private ResourceLocation getSkinFromIdUnsafe(String id) throws UnsupportedEncodi if (id != null && !id.isEmpty()) { if (skins.containsKey(id)) { ResourceLocation loc = skins.get(id); - + // Test if the resource is still loaded if (Minecraft.getMinecraft().getTextureManager().getTexture(loc) != null) { return loc; @@ -252,53 +307,41 @@ private ResourceLocation getSkinFromIdUnsafe(String id) throws UnsupportedEncodi skins.remove(id); } } - + JsonObject realTextures = getEncryptedTexturesUnsafe(id).getData(); - + // Should never happen if (!realTextures.has("SKIN")) { - return skins.put(id, DefaultPlayerSkin.getDefaultSkinLegacy()); + skins.put(id, DefaultPlayerSkin.getDefaultSkinLegacy()); + + return DefaultPlayerSkin.getDefaultSkinLegacy(); } - + JsonObject skinData = realTextures.get("SKIN").getAsJsonObject(); - + if (!skinData.has("url")) { - return skins.put(id, DefaultPlayerSkin.getDefaultSkinLegacy()); + skins.put(id, DefaultPlayerSkin.getDefaultSkinLegacy()); + + return DefaultPlayerSkin.getDefaultSkinLegacy(); } - + String url = skinData.get("url").getAsString(); - + + // Ensures minecraft servers are not hacked :) if (!isTrustedDomain(url)) { // Spoofed payload? Does not use an official Mojang network... throw new IllegalArgumentException("Invalid payload, the domain issued was not trusted."); } - + String segment = getLastSegment(url); - - final ResourceLocation location = new ResourceLocation("skinchanger/" + segment); - - File directory = new File(new File("./mods/skinchanger".replace("/", File.separator), "skins"), attemptSubstring(segment, 0, 2)); - File fileLocation = new File(directory, segment + ".png"); - - final IImageBuffer imageBuffer = new ImageBufferDownload(); - ThreadDownloadImageData imageData = new ThreadDownloadImageData(fileLocation, url, DefaultPlayerSkin - .getDefaultSkinLegacy(), new IImageBuffer() { - public BufferedImage parseUserSkin(BufferedImage image) { - if (imageBuffer != null) { - image = imageBuffer.parseUserSkin(image); - } - return image; - } - public void skinAvailable() { - if (imageBuffer != null) { - imageBuffer.skinAvailable(); - } - } - }); - Minecraft.getMinecraft().renderEngine.loadTexture(location, imageData); - return skins.put(id, location); + + ResourceLocation playerSkin = SkinChangerMod.getInstance().getCacheRetriever().loadIntoGame(id, url); + + skins.put(id, playerSkin); + + return playerSkin; } else { - return null; + return DefaultPlayerSkin.getDefaultSkinLegacy(); } } @@ -312,6 +355,7 @@ private String getUrl(String url) { if (org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_L)) { responses.clear(); } + if (responses.containsKey(url)) { return responses.get(url); } diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ReflectionUtils.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ReflectionUtils.java new file mode 100644 index 0000000..e1cbcd7 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ReflectionUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.backend; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.relauncher.ReflectionHelper; + +/** + * A nice reflection class, using a mix of forges ReflectionHandler and some + * of java's internal reflection implementations whilst remaining sun-free! + */ +public class ReflectionUtils { + + private static List logs = new ArrayList<>(); + + public static MethodHandle findMethod(Class clazz, String[] methodNames, Class... methodTypes) { + final Method method = ReflectionHelper.findMethod(clazz, null, methodNames, methodTypes); + + try { + return MethodHandles.lookup().unreflect(method); + } catch (Exception e) { + throw new ReflectionHelper.UnableToFindMethodException(methodNames, e); + } + } + + public static void setPrivateValue(Class classToAccess, T instance, E value, String... fieldNames) { + try { + ReflectionHelper.setPrivateValue(classToAccess, instance, value, + ObfuscationReflectionHelper.remapFieldNames(classToAccess.getName(), fieldNames)); + } catch (Throwable e) { + sendLog("No methods found for arguments: %s !", Arrays.toString(fieldNames)); + } + } + + private static void sendLog(String message, Object... formatting) { + if (logs.contains(message)) { + return; + } + + System.out.println(String.format(message, formatting)); + + logs.add(message); + } +} \ No newline at end of file diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ThreadFactory.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ThreadFactory.java new file mode 100644 index 0000000..3c849e0 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/backend/ThreadFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.backend; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +public class ThreadFactory { + + private AtomicInteger threadNumber = new AtomicInteger(0); // The current ThreadCount + + private ExecutorService POOL; // Async task scheduler + + public ThreadFactory(String factoryName) { + POOL = Executors.newFixedThreadPool(8, r -> new Thread(r, String.format("%s Thread %s", factoryName, this.threadNumber.incrementAndGet()))); + } + + /** + * Runs a task async to the main thread + * + * @param runnable the runnable to run + */ + public void runAsync(Runnable runnable) { + this.POOL.execute(runnable); + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/game/ChatColor.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/game/ChatColor.java new file mode 100644 index 0000000..da37f06 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/game/ChatColor.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.game; + +import java.util.regex.Pattern; + +public enum ChatColor { + + BLACK('0'), + DARK_BLUE('1'), + DARK_GREEN('2'), + DARK_AQUA('3'), + DARK_RED('4'), + DARK_PURPLE('5'), + GOLD('6'), + GRAY('7'), + DARK_GRAY('8'), + BLUE('9'), + GREEN('a'), + AQUA('b'), + RED('c'), + LIGHT_PURPLE('d'), + YELLOW('e'), + WHITE('f'), + MAGIC('k', true), + BOLD('l', true), + STRIKETHROUGH('m', true), + UNDERLINE('n', true), + ITALIC('o', true), + RESET('r'); + + public static final char COLOR_CHAR = '\u00A7'; + + private final char code; + private final boolean isFormat; + private final String toString; + + ChatColor(char code) { + this(code, false); + } + + ChatColor(char code, boolean isFormat) { + this.code = code; + this.isFormat = isFormat; + this.toString = new String(new char[] {COLOR_CHAR, code}); + } + + public char getChar() { + return code; + } + + @Override + public String toString() { + return toString; + } + + public boolean isFormat() { + return isFormat; + } + + public boolean isColor() { + return !isFormat && this != RESET; + } + + public static String stripColor(final String input) { + if (input == null) { + return null; + } + return Pattern.compile("(?i)" + COLOR_CHAR + "[0-9A-FK-OR]").matcher(input).replaceAll(""); + } + + public static String translateAlternateColorCodes(String textToTranslate) { + return translateAlternateColorCodes('&', textToTranslate); + } + + public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) { + char[] b = textToTranslate.toCharArray(); + for (int i = 0; i < b.length - 1; i++) { + if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) { + b[i] = ChatColor.COLOR_CHAR; + b[i+1] = Character.toLowerCase(b[i+1]); + } + } + return new String(b); + } + + /* + * Color then strip the message, useful for removing all colors in the message. + */ + public static String formatUnformat(char altColorChat, String message) { + return stripColor(translateAlternateColorCodes(altColorChat, message)); + } +} \ No newline at end of file diff --git a/src/main/java/me/boomboompower/skinchanger/utils/BetterJsonObject.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/general/BetterJsonObject.java similarity index 74% rename from src/main/java/me/boomboompower/skinchanger/utils/BetterJsonObject.java rename to src/main/java/me/do_you_like/mods/skinchanger/utils/general/BetterJsonObject.java index ec01ea9..3b5527d 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/BetterJsonObject.java +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/general/BetterJsonObject.java @@ -1,31 +1,24 @@ /* - * Hypixel Community Client, Client optimized for Hypixel Network - * Copyright (C) 2018 Hyperium Dev Team + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * GNU General Public License for more details. * - * You should have received a copy of the GNU Affero General Public License + * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package me.boomboompower.skinchanger.utils; +package me.do_you_like.mods.skinchanger.utils.general; + +import com.google.gson.*; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonIOException; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSyntaxException; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -33,20 +26,23 @@ /** * The solution to the missing methods in Google's implementation - * of json, this class contains many useful methods such as pretty - * printing and file writing, as well as optional methods + * of json, this class contains many useful methods such as pretty + * printing and file writing, as well as optional methods * * @author boomboompower * @version 1.0 */ -@SuppressWarnings({"WeakerAccess", "ResultOfMethodCallIgnored", "UnusedReturnValue", - "BooleanMethodIsAlwaysInverted"}) // Don't care +@SuppressWarnings({"WeakerAccess", "ResultOfMethodCallIgnored", "UnusedReturnValue"}) // Don't care public class BetterJsonObject { - /** Our pretty printer */ + /** + * Our pretty printer + */ private final Gson prettyPrinter = new GsonBuilder().setPrettyPrinting().create(); - /** The data holder for our json */ + /** + * The data holder for our json + */ private JsonObject data; /** @@ -58,8 +54,8 @@ public BetterJsonObject() { /** * The default constructor the BetterJsonObject class, uses a json string - * as the parameter and attempts to load it, a new JsonObject will be - * created if the input is null, empty or cannot be loaded into a json format + * as the parameter and attempts to load it, a new JsonObject will be + * created if the input is null, empty or cannot be loaded into a json format * * @param jsonIn the json string to be parsed */ @@ -77,8 +73,8 @@ public BetterJsonObject(String jsonIn) { /** * The alternative constructor for the BetterJsonObject class, this uses - * another JsonObject as the data set. A new JsonObject will be created - * if the input is null + * another JsonObject as the data set. A new JsonObject will be created + * if the input is null * * @param objectIn the object to be used */ @@ -88,9 +84,9 @@ public BetterJsonObject(JsonObject objectIn) { /** * The optional string method, returns an empty string if - * the key is null, empty or the data does not contain - * the key. This will also return an empty string if the data value - * is not a string + * the key is null, empty or the data does not contain + * the key. This will also return an empty string if the data value + * is not a string * * @param key the key the value will be loaded from * @return the value in the json data set or empty if the key cannot be found @@ -101,9 +97,9 @@ public String optString(String key) { /** * The optional string method, returns the default value if - * the key is null, empty or the data does not contain - * the key. This will also return the default value if - * the data value is not a string + * the key is null, empty or the data does not contain + * the key. This will also return the default value if + * the data value is not a string * * @param key the key the value will be loaded from * @return the value in the json data set or the default if the key cannot be found @@ -123,9 +119,9 @@ public String optString(String key, String value) { /** * The optional int method, returns 0 if - * the key is null, empty or the data does not contain - * the key. This will also return 0 if the data value - * is not a string + * the key is null, empty or the data does not contain + * the key. This will also return 0 if the data value + * is not a string * * @param key the key the value will be loaded from * @return the value in the json data set or empty if the key cannot be found @@ -136,9 +132,9 @@ public int optInt(String key) { /** * The optional int method, returns the default value if - * the key is null, empty or the data does not contain - * the key. This will also return the default value if - * the data value is not a number + * the key is null, empty or the data does not contain + * the key. This will also return the default value if + * the data value is not a number * * @param key the key the value will be loaded from * @return the value in the json data set or the default if the key cannot be found @@ -161,9 +157,9 @@ public int optInt(String key, int value) { /** * The optional double method, returns 0.0D if - * the key is null, empty or the data does not contain - * the key. This will also return 0.0D if the data value - * is not a string + * the key is null, empty or the data does not contain + * the key. This will also return 0.0D if the data value + * is not a string * * @param key the key the value will be loaded from * @return the value in the json data set or empty if the key cannot be found @@ -174,9 +170,9 @@ public double optDouble(String key) { /** * The optional double method, returns the default value if - * the key is null, empty or the data does not contain - * the key. This will also return the default value if - * the data value is not a number + * the key is null, empty or the data does not contain + * the key. This will also return the default value if + * the data value is not a number * * @param key the key the value will be loaded from * @return the value in the json data set or the default if the key cannot be found @@ -199,9 +195,9 @@ public double optDouble(String key, double value) { /** * The optional boolean method, returns false if - * the key is null, empty or the data does not contain - * the key. This will also return false if the data value - * is not a string + * the key is null, empty or the data does not contain + * the key. This will also return false if the data value + * is not a string * * @param key the key the value will be loaded from * @return the value in the json data set or empty if the key cannot be found @@ -212,9 +208,9 @@ public boolean optBoolean(String key) { /** * The optional boolean method, returns the default value if - * the key is null, empty or the data does not contain - * the key. This will also return the default value if - * the data value is not a boolean + * the key is null, empty or the data does not contain + * the key. This will also return the default value if + * the data value is not a boolean * * @param key the key the value will be loaded from * @return the value in the json data set or the default if the key cannot be found @@ -251,9 +247,9 @@ public JsonObject getData() { /** * Adds a string to the to the json data file with the - * key that it'll be associated with + * key that it'll be associated with * - * @param key the key + * @param key the key * @param value the value */ public BetterJsonObject addProperty(String key, String value) { @@ -265,9 +261,9 @@ public BetterJsonObject addProperty(String key, String value) { /** * Adds a number to the to the json data file with the - * key that it'll be associated with + * key that it'll be associated with * - * @param key the key + * @param key the key * @param value the value */ public BetterJsonObject addProperty(String key, Number value) { @@ -279,9 +275,9 @@ public BetterJsonObject addProperty(String key, Number value) { /** * Adds a boolean to the to the json data file with the - * key that it'll be associated with + * key that it'll be associated with * - * @param key the key + * @param key the key * @param value the value */ public BetterJsonObject addProperty(String key, Boolean value) { @@ -290,11 +286,11 @@ public BetterJsonObject addProperty(String key, Boolean value) { } return this; } - + /** * Adds another BetterJsonObject into this one * - * @param key the key + * @param key the key * @param object the object to add */ public BetterJsonObject add(String key, BetterJsonObject object) { @@ -306,8 +302,8 @@ public BetterJsonObject add(String key, BetterJsonObject object) { /** * This feature is a HUGE WIP and may not work, it is safer - * to use the toString method with a BufferedWriter instead - * + * to use the toString method with a BufferedWriter instead + *

* We are not responsible for any overwritten files, please use this carefully * * @param file File to write to @@ -340,13 +336,13 @@ public void writeToFile(File file) { /** * Converts the JsonElement to the JsonPrimitive class to allow for better - * functionality + * functionality * * @param element the element to be transferred * @return the JsonPrimitive instance or null if is not an instanceof the JsonPrimitive class */ private JsonPrimitive asPrimitive(JsonElement element) { - return element != null && element instanceof JsonPrimitive ? (JsonPrimitive) element : null; + return element instanceof JsonPrimitive ? (JsonPrimitive) element : null; } /** @@ -361,11 +357,15 @@ public String toString() { /** * Returns the pretty printed data String with - * indents and other things + * indents and other things * * @return pretty printed data */ public String toPrettyString() { return this.prettyPrinter.toJson(this.data); } + + public Gson getGsonData() { + return this.prettyPrinter; + } } diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/general/Prerequisites.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/general/Prerequisites.java new file mode 100644 index 0000000..8973cb9 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/general/Prerequisites.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.general; + +/** + * Simple prerequisites for varies values in the code. + * + * Just used to validate input to ensure things flow smoothly + */ +@SuppressWarnings("ALL") +public class Prerequisites { + + private Prerequisites() { + } + + /** + * Ensures a value is not null. If it is, an error will be thrown. + * + * @param value the value to check + */ + public static void notNull(Object value) { + notNull(value, "Value was null."); + } + + /** + * Ensures a value is not null. If it is, an error will be thrown. + * + * @param value the value to check + * @param errorMessage the message to send + */ + public static void notNull(Object value, String errorMessage) { + if (value != null) { + return; + } + + // Hit em with the fat exception + throw new IllegalArgumentException(errorMessage); + } + + /** + * Ensures a value is not null or empty. If it is, an error will be thrown. + * + * @param value the value to check + */ + public static void notNullOrEmpty(String value) { + notNullOrEmpty(value, "Value was either null or empty."); + } + + /** + * Ensures a value is not null or empty. If it is, an error will be thrown. + * + * @param value the value to check + * @param errorMessage the message to send + */ + public static void notNullOrEmpty(String value, String errorMessage) { + // If the value is not null and its not empty, return. + if (value != null && !value.isEmpty()) { + return; + } + + // Hit em with the fat exception + throw new IllegalArgumentException(errorMessage); + } + + /** + * Ensures a value (string) is not empty. If it is, an error will be thrown. + * + * @param value the value to check + */ + public static void notEmpty(String value) { + notEmpty(value, "Value was empty."); + } + + /** + * Ensures a value (string) is not empty. If it is, an error will be thrown. + * + * @param value the value to check + * @param errorMessage the message to send + */ + public static void notEmpty(String value, String errorMessage) { + if (value == null || !value.isEmpty()) { + return; + } + + // Hit em with the fat exception + throw new IllegalArgumentException(errorMessage); + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/general/ReflectUtils.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/general/ReflectUtils.java new file mode 100644 index 0000000..05c99e3 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/general/ReflectUtils.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.general; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.relauncher.ReflectionHelper; + +/** + * A nice reflection class, using a mix of forges ReflectionHandler and some + * of java's internal reflection implementations whilst remaining sun-free! + */ +public class ReflectUtils { + + private static List logs = new ArrayList<>(); + + public static MethodHandle findMethod(Class clazz, String[] methodNames, Class... methodTypes) { + final Method method = ReflectionHelper.findMethod(clazz, null, methodNames, methodTypes); + + try { + return MethodHandles.lookup().unreflect(method); + } catch (Exception e) { + throw new ReflectionHelper.UnableToFindMethodException(methodNames, e); + } + } + + public static void setPrivateValue(Class classToAccess, T instance, E value, String... fieldNames) { + try { + ReflectionHelper.setPrivateValue(classToAccess, instance, value, + ObfuscationReflectionHelper.remapFieldNames(classToAccess.getName(), fieldNames)); + } catch (Throwable e) { + sendLog("No methods found for arguments: %s !", Arrays.toString(fieldNames)); + } + } + + public static void getPrivateValue(Class classToAccess, T instance, String... fieldNames) { + try { + ReflectionHelper.getPrivateValue(classToAccess, instance, + ObfuscationReflectionHelper.remapFieldNames(classToAccess.getName(), fieldNames)); + } catch (Throwable e) { + sendLog("No methods found for arguments: %s !", Arrays.toString(fieldNames)); + } + } + + private static void sendLog(String message, Object... formatting) { + if (logs.contains(message)) { + return; + } + + System.out.println(String.format(message, formatting)); + logs.add(message); + } +} \ No newline at end of file diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/UISkeleton.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/UISkeleton.java new file mode 100644 index 0000000..f4ba590 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/UISkeleton.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.gui; + +import me.do_you_like.mods.skinchanger.utils.gui.impl.ModernButton; + +public interface UISkeleton { + + void onGuiOpen(); + + default void onGuiClose() { + } + + default void preRender() { + } + + void onRender(int mouseX, int mouseY, float partialTicks); + + default void postRender() { + } + + default void buttonPressed(ModernButton button) { + } + + default void rightClicked(ModernButton button) { + } + + default void onKeyTyped(int keyCode, char keyCharacter) { + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernButton.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernButton.java new file mode 100644 index 0000000..0fe2e2e --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernButton.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.gui.impl; + +import lombok.Getter; +import lombok.Setter; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; + +import java.awt.*; + +/** + * ModernButton, a nicer looking button + * + * @author boomboompower + * @version 2.0 + */ +public class ModernButton extends Gui { + + protected static final ResourceLocation buttonTextures = new ResourceLocation("textures/gui/widgets.png"); + + @Getter + private int id; + + @Setter + @Getter + private int width; + + private int height; + private int xPosition; + private int yPosition; + + @Getter + private boolean enabled; + + @Setter + @Getter + private boolean visible; + + @Getter + @Setter + private boolean favourite; + + @Getter + private boolean hovered; + + @Getter + private String buttonId; + private String displayString; + + private Color enabledColor = null; + private Color disabledColor = null; + + @Getter + private Object buttonData; + + public ModernButton(int buttonId, int x, int y, String buttonText) { + this(buttonId, "", x, y, 200, 20, buttonText); + } + + public ModernButton(int buttonId, String idName, int x, int y, String buttonText) { + this(buttonId, idName, x, y, 200, 20, buttonText); + } + + public ModernButton(int buttonId, int x, int y, int widthIn, int heightIn, String buttonText) { + this(buttonId, "", x, y, widthIn, heightIn, buttonText); + } + + public ModernButton(int buttonId, String idName, int x, int y, int widthIn, int heightIn, String buttonText) { + this.width = 200; + this.height = 20; + this.enabled = true; + this.visible = true; + this.id = buttonId; + this.xPosition = x; + this.yPosition = y; + this.width = widthIn; + this.height = heightIn; + this.buttonId = idName; + this.displayString = buttonText; + } + + /** + * Returns 0 if the button is disabled, 1 if the mouse is NOT hovering over this button and 2 if it IS hovering over + * this button. + */ + protected int getHoverState(boolean mouseOver) { + int i = 1; + + if (!this.enabled) { + i = 0; + } else if (mouseOver) { + i = 2; + } + return i; + } + + /** + * Draws this button to the screen. + */ + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + if (this.visible) { + FontRenderer fontrenderer = mc.fontRendererObj; + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + this.hovered = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height; + int i = this.getHoverState(this.hovered); + + int j = 14737632; + + boolean modern = true; //SkinChangerMod.getInstance().getConfigurationHandler().isModernButton(); + + if (modern) { + mc.getTextureManager().bindTexture(buttonTextures); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.blendFunc(770, 771); + + this.drawTexturedModalRect(this.xPosition, this.yPosition, 0, 46 + i * 20, this.width / 2, this.height); + this.drawTexturedModalRect(this.xPosition + this.width / 2, this.yPosition, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height); + } else { + if (this.enabled) { + drawRect(this.xPosition, this.yPosition, this.xPosition + this.width, this.yPosition + height, getEnabledColor().getRGB()); + } else { + drawRect(this.xPosition, this.yPosition, this.xPosition + this.width, this.yPosition + height, getDisabledColor().getRGB()); + } + } + + if (!this.enabled) { + j = 10526880; + } else if (this.hovered) { + j = 16777120; + } + + if (this.enabled && this.favourite) { + fontrenderer.drawString("\u2726", this.xPosition + this.width - fontrenderer.getStringWidth("\u2726") - 4, this.yPosition + ((fontrenderer.FONT_HEIGHT / 2) + 2), Color.ORANGE.getRGB()); + } + + fontrenderer.drawString(this.displayString, (this.xPosition + this.width / 2 - fontrenderer.getStringWidth(this.displayString) / 2), this.yPosition + (this.height - 8) / 2, j, modern); + } + } + + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + return this.enabled && this.visible && mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height; + } + + public void mouseReleased(int mouseX, int mouseY) { + } + + public void playPressSound(SoundHandler soundHandlerIn) { + soundHandlerIn.playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F)); + } + + public Color getEnabledColor() { + return this.enabledColor == null ? new Color(255, 255, 255, 75) : this.enabledColor; + } + + public ModernButton setEnabledColor(Color colorIn) { + this.enabledColor = colorIn; + + return this; + } + + public Color getDisabledColor() { + return this.disabledColor == null ? new Color(100, 100, 100, 75) : this.disabledColor; + } + + public ModernButton setDisabledColor(Color colorIn) { + this.disabledColor = colorIn; + + return this; + } + + public String getText() { + return this.displayString; + } + + public void setText(String text) { + this.displayString = text != null ? text : ""; + } + + public ModernButton setEnabled(boolean isEnabled) { + this.enabled = isEnabled; + + return this; + } + + public boolean hasButtonData() { + return this.buttonData != null; + } + + public Object setButtonData(Object buttonData) { + this.buttonData = buttonData; + + return this; + } +} \ No newline at end of file diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernGui.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernGui.java new file mode 100644 index 0000000..d73205e --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernGui.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.gui.impl; + +import com.google.common.collect.Lists; +import java.awt.Color; +import java.io.IOException; +import java.util.List; +import me.boomboompower.skinchanger.utils.ChatColor; +import me.do_you_like.mods.skinchanger.SkinChangerMod; +import me.do_you_like.mods.skinchanger.utils.gui.UISkeleton; +import me.do_you_like.mods.skinchanger.utils.gui.lock.UILock; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiLabel; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.ChatComponentText; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +/** + * ModernGui, a better-looking GuiScreen which has more optimizations and features than the normal GuiScreen + * + * @author boomboompower + * @version 4.0 + */ +public abstract class ModernGui extends UILock implements UISkeleton { + + protected final Minecraft mc = Minecraft.getMinecraft(); + protected final FontRenderer fontRendererObj = this.mc.fontRendererObj; + protected final SkinChangerMod mod = SkinChangerMod.getInstance(); + + protected List textList = Lists.newArrayList(); + protected List buttonList = Lists.newArrayList(); + + private ModernButton selectedButton; + + @Override + public final void initGui() { + this.textList.clear(); + this.buttonList.clear(); + + onGuiOpen(); + } + + @Override + public final void onGuiClosed() { + onGuiClose(); + } + + @Override + public final void drawScreen(int mouseX, int mouseY, float partialTicks) { + try { + preRender(); + } catch (Exception ex) { + drawCenteredString(this.fontRendererObj, "An error occurred during preRender();", 0, 0, Color.RED.getRGB()); + + for (int i = 0; i < ex.getStackTrace().length; i++) { + StackTraceElement element = ex.getStackTrace()[i]; + + drawCenteredString(this.fontRendererObj, element.toString(), 5, 12 + (i * 12), Color.RED.getRGB()); + } + + return; + } + + try { + onRender(mouseX, mouseY, partialTicks); + } catch (Exception ex) { + drawCenteredString(this.fontRendererObj, "An error occurred during onRender();", 0, 0, Color.RED.getRGB()); + + for (int i = 0; i < ex.getStackTrace().length; i++) { + StackTraceElement element = ex.getStackTrace()[i]; + + drawCenteredString(this.fontRendererObj, element.toString(), 5, 12 + (i * 12), Color.RED.getRGB()); + } + + return; + } + + for (ModernButton button : this.buttonList) { + button.drawButton(this.mc, mouseX, mouseY); + } + + for (GuiLabel label : this.labelList) { + label.drawLabel(this.mc, mouseX, mouseY); + } + + for (ModernTextBox text : this.textList) { + text.drawTextBox(); + } + + try { + postRender(); + } catch (Exception ex) { + drawCenteredString(this.fontRendererObj, "An error occurred during postRender();", 0, 0, Color.RED.getRGB()); + + for (int i = 0; i < ex.getStackTrace().length; i++) { + StackTraceElement element = ex.getStackTrace()[i]; + + drawCenteredString(this.fontRendererObj, element.toString(), 5, 12 + (i * 12), Color.RED.getRGB()); + } + } + } + + @Override + protected final void keyTyped(char typedChar, int keyCode) { + onKeyTyped(keyCode, typedChar); + + if (keyCode == 1) { + this.mc.displayGuiScreen(null); + + if (this.mc.currentScreen == null) { + this.mc.setIngameFocus(); + } + } else { + for (ModernTextBox text : textList) { + text.textboxKeyTyped(typedChar, keyCode); + } + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + if (mouseButton == 0) { + for (ModernButton button : this.buttonList) { + if (button.mousePressed(this.mc, mouseX, mouseY)) { + this.selectedButton = button; + + button.playPressSound(this.mc.getSoundHandler()); + + this.buttonPressed(button); + } + } + } + + if (mouseButton == 1) { + for (ModernButton button : this.buttonList) { + if (button != null) { + if (button.mousePressed(this.mc, mouseX, mouseY)) { + this.rightClicked(button); + } + } + } + } + + for (ModernTextBox text : this.textList) { + text.mouseClicked(mouseX, mouseY, mouseButton); + } + } + + @Override + public void setWorldAndResolution(Minecraft mc, int width, int height) { + // Required for compatibility + super.mc = mc; + + this.itemRender = mc.getRenderItem(); + this.width = width; + this.height = height; + + this.textList.clear(); + this.buttonList.clear(); + + initGui(); + } + + @Override + public final void updateScreen() { + for (ModernTextBox textBox : this.textList) { + textBox.updateCursorCounter(); + } + } + + @Override + protected final void mouseReleased(int mouseX, int mouseY, int state) { + if (this.selectedButton != null && state == 0) { + this.selectedButton.mouseReleased(mouseX, mouseY); + this.selectedButton = null; + } + } + + /** + * Draws multiple lines on the screen + * + * @param startingX the starting x position of the text + * @param startingY the starting y position of the text + * @param separation the Y valye separatation between each line + * @param lines the lines which will be drawn + */ + public void writeInformation(int startingX, int startingY, int separation, String... lines) { + writeInformation(startingX, startingY, separation, true, lines); + } + + /** + * Draws multiple lines on the screen + * + * @param startingX the starting x position of the text + * @param startingY the starting y position of the text + * @param separation the Y valye separatation between each line + * @param centered true if the text being rendered should be rendered as a centered string + * @param lines the lines which will be drawn + */ + public void writeInformation(int startingX, int startingY, int separation, boolean centered, String... lines) { + if (lines == null || lines.length == 0) { + return; + } + + // Loop through the lines + for (String line : lines) { + // Null components will be treated as an empty string + if (line == null) { + line = ""; + } + + if (centered) { + drawCenteredString(this.fontRendererObj, ChatColor.translateAlternateColorCodes('&', line), startingX, startingY, Color.WHITE.getRGB()); + } else { + drawString(this.fontRendererObj, ChatColor.translateAlternateColorCodes('&', line), startingX, startingY, Color.WHITE.getRGB()); + } + + startingY += separation; + } + } + + public final void display() { + MinecraftForge.EVENT_BUS.register(this); + } + + @SubscribeEvent + public final void onTick(TickEvent.ClientTickEvent event) { + MinecraftForge.EVENT_BUS.unregister(this); + Minecraft.getMinecraft().displayGuiScreen(this); + } + + /** + * Code used to draw an entity on screen, stolen from the Inventory code + * + * @param posX the x position of the entity + * @param posY the y position of the entity + * @param scale the scale the entity should be rendered at + * @param mouseX the x location of the mouse + * @param mouseY the y location of the mouse + * @param entity the entity to render on screen + * @param previewCape true if the entities cape is being previewed + */ + protected final void drawEntityOnScreen(int posX, int posY, int scale, float mouseX, float mouseY, EntityLivingBase entity, boolean previewCape) { + GlStateManager.enableColorMaterial(); + GlStateManager.pushMatrix(); + GlStateManager.translate((float) posX, (float) posY, 50.0F); + GlStateManager.scale((float) (-scale), (float) scale, (float) scale); + GlStateManager.rotate(180.0F, 0.0F, 0.0F , 1.0F); + if (previewCape) { + GlStateManager.rotate(180F, 0F, 360F, 0F); + } + float prevYawOffset = entity.renderYawOffset; + float prevYaw = entity.rotationYaw; + float prevPitch = entity.rotationPitch; + float prevYawRotation = entity.prevRotationYawHead; + float prevHeadRotation = entity.rotationYawHead; + GlStateManager.rotate(135.0F, 0.0F, 1.0F, 0.0F); + RenderHelper.enableStandardItemLighting(); + GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(-((float) Math.atan((double) (mouseY / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F); + entity.renderYawOffset = previewCape ? -(float) Math.atan((double) (mouseX / 40.0F)) * 20.0F : (float) Math.atan((double) (mouseX / 40.0F)) * 20.0F; + entity.rotationYaw = previewCape ? -(float) Math.atan((double) (mouseX / 40.0F)) * 40.0F : (float) Math.atan((double) (mouseX / 40.0F)) * 40.0F; + entity.rotationPitch = -((float) Math.atan((double) (mouseY / 40.0F))) * 20.0F; + entity.rotationYawHead = entity.rotationYaw; + entity.prevRotationYawHead = entity.rotationYaw; + GlStateManager.translate(0.0F, 0.0F, 0.0F); + RenderManager rendermanager = Minecraft.getMinecraft().getRenderManager(); + rendermanager.setPlayerViewY(previewCape ? 180.0F : 0.0F); + rendermanager.setRenderShadow(false); + rendermanager.doRenderEntity(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F, true); + rendermanager.setRenderShadow(true); + entity.renderYawOffset = prevYawOffset; + entity.rotationYaw = prevYaw; + entity.rotationPitch = prevPitch; + entity.prevRotationYawHead = prevYawRotation; + entity.rotationYawHead = prevHeadRotation; + + GlStateManager.popMatrix(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.disableRescaleNormal(); + GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GlStateManager.disableTexture2D(); + GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit); + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernTextBox.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernTextBox.java new file mode 100644 index 0000000..fcb36b0 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/impl/ModernTextBox.java @@ -0,0 +1,732 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.gui.impl; + +import java.awt.Color; +import java.util.Timer; +import java.util.TimerTask; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiPageButtonList; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ChatAllowedCharacters; +import net.minecraft.util.MathHelper; + +public class ModernTextBox extends Gui { + + private String alertMessage = ""; + + private final int id; + private final FontRenderer fontRendererInstance; + public int xPosition; + public int yPosition; + /** The width of this text field. */ + public int width; + public int height; + /** Has the current text being edited on the textbox. */ + private String text = ""; + private int maxStringLength = 16; + private int cursorCounter; + private boolean enableBackgroundDrawing = true; + /** if true the textbox can lose focus by clicking elsewhere on the screen */ + private boolean canLoseFocus = true; + /** If this value is true along with isEnabled, keyTyped will process the keys. */ + private boolean isFocused = false; + /** If this value is true along with isFocused, keyTyped will process the keys. */ + private boolean isEnabled = true; + /** The current character index that should be used as start of the rendered text. */ + private int lineScrollOffset; + private int cursorPosition; + /** other selection position, maybe the same as the cursor */ + private int selectionEnd; + private int enabledColor = 14737632; + private int disabledColor = 7368816; + /** True if this textbox is visible */ + private boolean visible = true; + private GuiPageButtonList.GuiResponder guiResponder; + + private boolean onlyAllowNumbers = false; + private String noTextMessage = "Write here!"; + + private boolean running = false; + + public ModernTextBox(int componentId, int x, int y, int width, int height) { + this(componentId, x, y, width, height, false); + } + + public ModernTextBox(int componentId, int x, int y, int width, int height, boolean onlyAllowNumbers) { + this(componentId, x, y, width, height, "Write Here!", onlyAllowNumbers); + } + + public ModernTextBox(int componentId, int x, int y, int width, int height, String noTextMessage, boolean onlyAllowNumbers) { + this.id = componentId; + this.fontRendererInstance = Minecraft.getMinecraft().fontRendererObj; + this.xPosition = x; + this.yPosition = y; + this.width = width; + this.height = height; + this.noTextMessage = noTextMessage; + this.onlyAllowNumbers = onlyAllowNumbers; + } + + public void setGuiResponder(GuiPageButtonList.GuiResponder guiResponder) { + this.guiResponder = guiResponder; + } + + /** + * Increments the cursor counter + */ + public void updateCursorCounter() { + ++this.cursorCounter; + } + + /** + * Sets the text of the textbox + */ + public void setText(String text) { + if (text == null) { + this.text = ""; + this.setCursorPositionEnd(); + return; + } + + if (format(text).length() > this.maxStringLength) { + this.text = format(text).substring(0, this.maxStringLength); + } else { + this.text = format(text); + } + this.setCursorPositionEnd(); + } + + /** + * Returns the contents of the textbox + */ + public String getText() { + return this.text; + } + + /** + * returns the text between the cursor and selectionEnd + */ + public String getSelectedText() { + int i = this.cursorPosition < this.selectionEnd ? this.cursorPosition: this.selectionEnd; + int j = this.cursorPosition < this.selectionEnd ? this.selectionEnd: this.cursorPosition; + return this.text.substring(i, j); + } + + /** + * replaces selected text, or inserts text at the position on the cursor + */ + public void writeText(String text) { + String s = ""; + String s1 = ChatAllowedCharacters.filterAllowedCharacters(text); + int i = this.cursorPosition < this.selectionEnd ? this.cursorPosition: this.selectionEnd; + int j = this.cursorPosition < this.selectionEnd ? this.selectionEnd: this.cursorPosition; + int k = this.maxStringLength - this.text.length() - (i - j); + int l; + + if (this.text.length() > 0) { + s = s + this.text.substring(0, i); + } + + if (k < s1.length()) { + s = s + s1.substring(0, k); + l = k; + } else { + s = s + s1; + l = s1.length(); + } + + if (this.text.length() > 0 && j < this.text.length()) { + s = s + this.text.substring(j); + } + + this.text = s; + this.moveCursorBy(i - this.selectionEnd + l); + + if (this.guiResponder != null) { + this.guiResponder.func_175319_a(this.id, this.text); + } + } + + /** + * Deletes the specified number of words starting at the cursor position. Negative numbers will delete words left of + * the cursor. + */ + public void deleteWords(int words) { + if (this.text.length() != 0) { + if (this.selectionEnd != this.cursorPosition) { + this.writeText(""); + } else { + this.deleteFromCursor(this.getNthWordFromCursor(words) - this.cursorPosition); + } + } + } + + /** + * delete the selected text, otherwsie deletes characters from either side of the cursor. params: delete num + */ + public void deleteFromCursor(int num) { + if (this.text.length() != 0) { + if (this.selectionEnd != this.cursorPosition) { + this.writeText(""); + } else { + boolean flag = num < 0; + int i = flag ? this.cursorPosition + num: this.cursorPosition; + int j = flag ? this.cursorPosition: this.cursorPosition + num; + String s = ""; + + if (i >= 0) { + s = this.text.substring(0, i); + } + + if (j < this.text.length()) { + s = s + this.text.substring(j); + } + + this.text = s; + + if (flag) { + this.moveCursorBy(num); + } + + if (this.guiResponder != null) { + this.guiResponder.func_175319_a(this.id, this.text); + } + } + } + } + + public int getId() { + return this.id; + } + + /** + * see @getNthNextWordFromPos() params: N, position + */ + public int getNthWordFromCursor(int position) { + return this.getNthWordFromPos(position, this.getCursorPosition()); + } + + /** + * gets the position of the nth word. N may be negative, then it looks backwards. params: N, position + */ + public int getNthWordFromPos(int number, int position) { + return this.getNthWordFromPos(number, position, true); + } + + public int getNthWordFromPos(int number, int position, boolean something) { + int i = position; + boolean flag = number < 0; + int j = Math.abs(number); + + for (int k = 0; k < j; ++k) { + if (!flag) { + int l = this.text.length(); + i = this.text.indexOf(32, i); + + if (i == -1) { + i = l; + } else { + while (something && i < l && this.text.charAt(i) == 32) { + ++i; + } + } + } else { + while (something && i > 0 && this.text.charAt(i -1) == 32) { + --i; + } + + while (i > 0 && this.text.charAt(i -1) != 32) { + --i; + } + } + } + + return i; + } + + /** + * Moves the text cursor by a specified number of characters and clears the selection + */ + public void moveCursorBy(int moveBy) { + this.setCursorPosition(this.selectionEnd + moveBy); + } + + /** + * sets the position of the cursor to the provided index + */ + public void setCursorPosition(int position) { + this.cursorPosition = position; + int i = this.text.length(); + this.cursorPosition = MathHelper.clamp_int(this.cursorPosition, 0, i); + this.setSelectionPos(this.cursorPosition); + } + + /** + * sets the cursors position to the beginning + */ + public void setCursorPositionZero() { + this.setCursorPosition(0); + } + + /** + * sets the cursors position to after the text + */ + public void setCursorPositionEnd() { + this.setCursorPosition(this.text.length()); + } + + /** + * Call this method from your GuiScreen to process the keys into the textbox + */ + public boolean textboxKeyTyped(char c, int keyCode) { + if (!this.isFocused || this.running) { + return false; + } else if (GuiScreen.isKeyComboCtrlA(keyCode)) { + this.setCursorPositionEnd(); + this.setSelectionPos(0); + return true; + } else if (GuiScreen.isKeyComboCtrlC(keyCode)) { + GuiScreen.setClipboardString(this.getSelectedText()); + return true; + } else if (GuiScreen.isKeyComboCtrlV(keyCode)) { + if (this.isEnabled) { + this.writeText(format(GuiScreen.getClipboardString())); + } + + return true; + } else if (GuiScreen.isKeyComboCtrlX(keyCode)) { + GuiScreen.setClipboardString(this.getSelectedText()); + + if (this.isEnabled) { + this.writeText(""); + } + return true; + } else { + switch (keyCode) { + case 14: + if (GuiScreen.isCtrlKeyDown()) { + if (this.isEnabled) { + this.deleteWords( -1); + } + } + else if (this.isEnabled) { + this.deleteFromCursor( -1); + } + + return true; + case 199: + if (GuiScreen.isShiftKeyDown()) { + this.setSelectionPos(0); + } else { + this.setCursorPositionZero(); + } + return true; + case 203: + if (GuiScreen.isShiftKeyDown()) { + if (GuiScreen.isCtrlKeyDown()) { + this.setSelectionPos(this.getNthWordFromPos( -1, this.getSelectionEnd())); + } + else { + this.setSelectionPos(this.getSelectionEnd() -1); + } + } + else if (GuiScreen.isCtrlKeyDown()) { + this.setCursorPosition(this.getNthWordFromCursor( -1)); + } + else { + this.moveCursorBy( -1); + } + + return true; + case 205: + if (GuiScreen.isShiftKeyDown()) { + if (GuiScreen.isCtrlKeyDown()) { + this.setSelectionPos(this.getNthWordFromPos(1, this.getSelectionEnd())); + } else { + this.setSelectionPos(this.getSelectionEnd() + 1); + } + } else if (GuiScreen.isCtrlKeyDown()) { + this.setCursorPosition(this.getNthWordFromCursor(1)); + } else { + this.moveCursorBy(1); + } + return true; + case 207: + if (GuiScreen.isShiftKeyDown()) { + this.setSelectionPos(this.text.length()); + } else { + this.setCursorPositionEnd(); + } + return true; + case 211: + if (GuiScreen.isCtrlKeyDown()) { + if (this.isEnabled) { + this.deleteWords(1); + } + } else if (this.isEnabled) { + this.deleteFromCursor(1); + } + return true; + default: + if (ChatAllowedCharacters.isAllowedCharacter(c)) { + if (onlyAllowNumbers) { + if (Character.isDigit(c)) { + if (this.isEnabled) { + this.writeText(Character.toString(c)); + } + } else if (!running) { + alert("Only numbers can be used!", 1250); + } + } else { + if (this.isEnabled) { + this.writeText(Character.toString(c)); + } + } + return true; + } else { + return false; + } + } + } + } + + /** + * Args: x, y, buttonClicked + */ + public void mouseClicked(int x, int y, int buttonClicked) { + boolean flag = x >= this.xPosition && x < this.xPosition + this.width && y >= this.yPosition && y < this.yPosition + this.height; + + if (this.canLoseFocus && this.isEnabled && !this.running) { + this.setFocused(flag); + } + + if (this.isFocused && flag && buttonClicked == 0) { + int i = x - this.xPosition; + + if (this.enableBackgroundDrawing) { + i -= 4; + } + + String s = this.fontRendererInstance.trimStringToWidth(this.text.substring(this.lineScrollOffset), this.getWidth()); + this.setCursorPosition(this.fontRendererInstance.trimStringToWidth(s, i).length() + this.lineScrollOffset); + } + } + + /** + * Draws the textbox + */ + public void drawTextBox() { + if (this.getVisible()) { + if (this.getEnableBackgroundDrawing()) { + if (this.isEnabled) { + drawRect(this.xPosition, this.yPosition, this.xPosition + width, this.yPosition + height, new Color(0, 148, 255, 75).getRGB()); + } else { + drawRect(this.xPosition, this.yPosition, this.xPosition + width, this.yPosition + height, new Color(0, 125, 215, 75).getRGB()); + } + } + + int i = this.isEnabled ? this.enabledColor : this.disabledColor; + int j = this.cursorPosition - this.lineScrollOffset; + int k = this.selectionEnd - this.lineScrollOffset; + String s = this.fontRendererInstance.trimStringToWidth(this.text.substring(this.lineScrollOffset), this.getWidth()); + boolean flag = j >= 0 && j <= s.length(); + boolean flag1 = this.isFocused && this.cursorCounter / 6 % 2 == 0 && flag; + int l = this.enableBackgroundDrawing ? this.xPosition + 4 : this.xPosition; + int i1 = this.enableBackgroundDrawing ? this.yPosition + (this.height - 8) / 2 : this.yPosition; + int j1 = l; + + if (k > s.length()) { + k = s.length(); + } + + if (!alertMessage.isEmpty()) { + this.fontRendererInstance.drawString(alertMessage, ((this.xPosition + this.width / 2) - fontRendererInstance.getStringWidth(alertMessage) / 2), this.yPosition + this.height / 2 - 4, enabledColor, false); + return; + } + + if (s.isEmpty() && !isFocused && isEnabled) { + this.fontRendererInstance.drawString(noTextMessage, ((this.xPosition + this.width / 2) - fontRendererInstance.getStringWidth(noTextMessage) / 2), this.yPosition + this.height / 2 - 4, i, false); + return; + } + + if (s.length() > 0) { + String s1 = flag ? s.substring(0, j) : s; + j1 = this.fontRendererInstance.drawString(s1, (float) l, (float) i1, i, false); + } + + boolean flag2 = this.cursorPosition < this.text.length() || this.text.length() >= this.getMaxStringLength(); + int k1 = j1; + + if (!flag) { + k1 = j > 0 ? l + this.width: l; + } else if (flag2) { + k1 = j1 -1; --j1; + } + + if (s.length() > 0 && flag && j < s.length()) { + this.fontRendererInstance.drawString(s.substring(j), (float) j1, (float) i1, i, false); + } + + if (flag1) { + if (flag2) { + Gui.drawRect(k1, i1 -1, k1 + 1, i1 + 1 + this.fontRendererInstance.FONT_HEIGHT, -3092272); + } + else { + this.fontRendererInstance.drawString("_", (float) k1, (float) i1, i, false); + } + } + + if (k != j) { + int l1 = l + this.fontRendererInstance.getStringWidth(s.substring(0, k)); + this.drawCursorVertical(k1, i1 -1, l1 -1, i1 + 1 + this.fontRendererInstance.FONT_HEIGHT); + } + } + } + + /** + * draws the vertical line cursor in the textbox + */ + private void drawCursorVertical(int p_146188_1_, int p_146188_2_, int p_146188_3_, int p_146188_4_) { + if (p_146188_1_ < p_146188_3_) { + int i = p_146188_1_; + p_146188_1_ = p_146188_3_; + p_146188_3_ = i; + } + + if (p_146188_2_ < p_146188_4_) { + int j = p_146188_2_; + p_146188_2_ = p_146188_4_; + p_146188_4_ = j; + } + + if (p_146188_3_ > this.xPosition + this.width) { + p_146188_3_ = this.xPosition + this.width; + } + + if (p_146188_1_ > this.xPosition + this.width) { + p_146188_1_ = this.xPosition + this.width; + } + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.color(0.0F, 0.0F, 255.0F, 255.0F); + GlStateManager.disableTexture2D(); + GlStateManager.enableColorLogic(); + GlStateManager.colorLogicOp(5387); + worldrenderer.begin(7, DefaultVertexFormats.POSITION); + worldrenderer.pos((double) p_146188_1_, (double) p_146188_4_, 0.0D).endVertex(); + worldrenderer.pos((double) p_146188_3_, (double) p_146188_4_, 0.0D).endVertex(); + worldrenderer.pos((double) p_146188_3_, (double) p_146188_2_, 0.0D).endVertex(); + worldrenderer.pos((double) p_146188_1_, (double) p_146188_2_, 0.0D).endVertex(); + tessellator.draw(); + GlStateManager.disableColorLogic(); + GlStateManager.enableTexture2D(); + } + + public void setMaxStringLength(int length) { + this.maxStringLength = length; + + if (this.text.length() > length) { + this.text = this.text.substring(0, length); + } + } + + /** + * returns the maximum number of character that can be contained in this textbox + */ + public int getMaxStringLength() { + return this.maxStringLength; + } + + /** + * returns the current position of the cursor + */ + public int getCursorPosition() { + return this.cursorPosition; + } + + /** + * get enable drawing background and outline + */ + public boolean getEnableBackgroundDrawing() { + return this.enableBackgroundDrawing; + } + + /** + * enable drawing background and outline + */ + public void setEnableBackgroundDrawing(boolean enableBackgroundDrawing) { + this.enableBackgroundDrawing = enableBackgroundDrawing; + } + + /** + * Sets the text colour for this textbox (disabled text will not use this colour) + */ + public void setTextColor(int color) { + this.enabledColor = color; + } + + public void setDisabledTextColour(int color) { + this.disabledColor = color; + } + + /** + * Sets focus to this gui element + */ + public void setFocused(boolean isFocused) { + if (isFocused && !this.isFocused) { + this.cursorCounter = 0; + } + this.isFocused = isFocused; + } + + /** + * Getter for the focused field + */ + public boolean isFocused() { + return this.isFocused; + } + + public void setEnabled(boolean enabled) { + this.isEnabled = enabled; + } + + public boolean isEnabled() { + return this.isEnabled; + } + + /** + * the side of the selection that is not the cursor, may be the same as the cursor + */ + public int getSelectionEnd() { + return this.selectionEnd; + } + + /** + * returns the width of the textbox depending on if background drawing is enabled + */ + public int getWidth() { + return this.getEnableBackgroundDrawing() ? this.width - 8 : this.width; + } + + /** + * Sets the position of the selection anchor (i.e. position the selection was started at) + */ + public void setSelectionPos(int pos) { + int i = this.text.length(); + + if (pos > i) { + pos = i; + } + if (pos < 0) { + pos = 0; + } + + this.selectionEnd = pos; + + if (this.fontRendererInstance != null) { + if (this.lineScrollOffset > i) { + this.lineScrollOffset = i; + } + + int j = this.getWidth(); + String s = this.fontRendererInstance.trimStringToWidth(this.text.substring(this.lineScrollOffset), j); + int k = s.length() + this.lineScrollOffset; + + if (pos == this.lineScrollOffset) { + this.lineScrollOffset -= this.fontRendererInstance.trimStringToWidth(this.text, j, true).length(); + } + + if (pos > k) { + this.lineScrollOffset += pos - k; + } else if (pos <= this.lineScrollOffset) { + this.lineScrollOffset -= this.lineScrollOffset - pos; + } + this.lineScrollOffset = MathHelper.clamp_int(this.lineScrollOffset, 0, i); + } + } + + /** + * if true the textbox can lose focus by clicking elsewhere on the screen + */ + public void setCanLoseFocus(boolean canLoseFocus) { + this.canLoseFocus = canLoseFocus; + } + + /** + * returns true if this textbox is visible + */ + public boolean getVisible() { + return this.visible; + } + + /** + * Sets whether or not this textbox is visible + */ + public void setVisible(boolean isVisible) { + this.visible = isVisible; + } + + public boolean isRunning() { + return this.running; + } + + public void alert(String message, int time) { + if (message.isEmpty()) return; + + running = true; + alertMessage = message; + + new Timer().schedule(new TimerTask() { + @Override + public void run() { + alertMessage = ""; + running = false; + } + }, time); + } + + public void setOnlyAllowNumbers(boolean onlyAllowNumbers) { + this.onlyAllowNumbers = onlyAllowNumbers; + } + + public boolean onlyAllowNumbers() { + return this.onlyAllowNumbers; + } + + private String format(String input) { + if (this.onlyAllowNumbers) { + StringBuilder builder = new StringBuilder(); + for (char c : input.toCharArray()) { + if (Character.isDigit(c)) { + builder.append(c); + } + } + return builder.toString(); + } else { + return input; + } + } +} \ No newline at end of file diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/lock/UILock.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/lock/UILock.java new file mode 100644 index 0000000..95060d7 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/gui/lock/UILock.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.gui.lock; + +import java.awt.Color; +import java.io.IOException; + +import me.boomboompower.skinchanger.utils.ChatColor; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.ChatComponentText; + +/** + * Locks the UI methods. Declutters the subclasses method list. + */ +public class UILock extends GuiScreen { + + @Override + public final void drawDefaultBackground() { + Gui.drawRect(0, 0, this.width, this.height, new Color(2, 2, 2, 120).getRGB()); + } + + @Override + public final void drawCenteredString(FontRenderer fontRendererIn, String text, int x, int y, int color) { + fontRendererIn.drawString(text, (float) (x - fontRendererIn.getStringWidth(text) / 2), (float) y, color, false); + } + + public final void drawCenteredString(FontRenderer fontRendererIn, String text, int x, int y, int color, boolean shadow) { + fontRendererIn.drawString(text, (float) (x - fontRendererIn.getStringWidth(text) / 2), (float) y, color, shadow); + } + + @Override + public final void drawString(FontRenderer fontRendererIn, String text, int x, int y, int color) { + fontRendererIn.drawString(text, (float) x, (float) y, color, false); + } + + @Override + public final boolean doesGuiPauseGame() { + return false; + } + + @Override + public final void sendChatMessage(String msg) { + this.mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText( + ChatColor.AQUA + "SkinChanger" + ChatColor.GOLD + " > " + ChatColor.GRAY + msg)); + } + + @Override + public final void confirmClicked(boolean result, int id) { + } + + @Override + public final void sendChatMessage(String msg, boolean addToChat) { + sendChatMessage(msg); + } + + @Override + public final void drawBackground(int tint) { + super.drawBackground(tint); + } + + @Override + public final void drawTexturedModalRect(int x, int y, int textureX, int textureY, int width, int height) { + super.drawTexturedModalRect(x, y, textureX, textureY, width, height); + } + + @Override + public final void drawTexturedModalRect(float xCoord, float yCoord, int minU, int minV, int maxU, int maxV) { + super.drawTexturedModalRect(xCoord, yCoord, minU, minV, maxU, maxV); + } + + @Override + public final void drawTexturedModalRect(int xCoord, int yCoord, TextureAtlasSprite textureSprite, int widthIn, int heightIn) { + super.drawTexturedModalRect(xCoord, yCoord, textureSprite, widthIn, heightIn); + } + + @Override + public final void drawWorldBackground(int tint) { + super.drawWorldBackground(tint); + } + + @Override + public final void handleInput() throws IOException { + super.handleInput(); + } + + @Override + public final void handleKeyboardInput() throws IOException { + super.handleKeyboardInput(); + } + + @Override + public final void handleMouseInput() throws IOException { + super.handleMouseInput(); + } + + @Override + public final void onResize(Minecraft mcIn, int w, int h) { + super.onResize(mcIn, w, h); + } + + @Override + protected final void actionPerformed(GuiButton button) { + } + + @Override + protected final void setText(String newChatText, boolean shouldOverwrite) { + } + + @Override + protected final void drawCreativeTabHoveringText(String tabName, int mouseX, int mouseY) { + } + + @Override + protected final void drawGradientRect(int left, int top, int right, int bottom, int startColor, int endColor) { + super.drawGradientRect(left, top, right, bottom, startColor, endColor); + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OSType.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OSType.java new file mode 100644 index 0000000..9949082 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OSType.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.installing; + +public enum OSType { + WINDOWS("C:\\Users\\USERNAME\\AppData\\Roaming\\.minecraft"), + MAC("~/Library/Application Support/minecraft"), + LINUX("~/.minecraft"), + UNKNOWN("?"); + + private String normalDirectory; + + OSType(String directory) { + this.normalDirectory = directory; + } + + public String getNormalDirectory() { + return this.normalDirectory; + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OperatingSystem.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OperatingSystem.java new file mode 100644 index 0000000..91ef89f --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/installing/OperatingSystem.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.installing; + +import java.io.File; + +public class OperatingSystem { + + private static OSType osType; + + static { + String osName = System.getProperty("os.name"); + + if (osName.startsWith("Windows")) { + osType = OSType.WINDOWS; + } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) { + osType = OSType.MAC; + } else if (osName.startsWith("Linux")) { + osType = OSType.LINUX; + } else { + osType = OSType.UNKNOWN; + } + } + + private OperatingSystem() { + } + + public static OSType getOSType() { + if (osType != null) { + return osType; + } + + String osName = System.getProperty("os.name"); + + if (osName.startsWith("Windows")) { + osType = OSType.WINDOWS; + } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) { + osType = OSType.MAC; + } else if (osName.startsWith("Linux")) { + osType = OSType.LINUX; + } else { + osType = OSType.UNKNOWN; + } + + return osType; + } + + public static File getMinecraftDirectory(OSType system) { + String path; + + switch (system) { + case WINDOWS: + path = "C:\\Users\\" + System.getProperty("user.name") + "\\AppData\\Roaming\\.minecraft\\"; + break; + case LINUX: + case MAC: + path = system.getNormalDirectory(); + break; + default: + path = null; + } + + if (path == null) { + return null; + } + + return new File(path); + } +} \ No newline at end of file diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/mod/CacheRetriever.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/mod/CacheRetriever.java new file mode 100644 index 0000000..465d039 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/mod/CacheRetriever.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.mod; + +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.UUID; + +import me.do_you_like.mods.skinchanger.SkinChangerMod; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IImageBuffer; +import net.minecraft.client.renderer.ImageBufferDownload; +import net.minecraft.client.renderer.ThreadDownloadImageData; +import net.minecraft.client.resources.DefaultPlayerSkin; +import net.minecraft.util.ResourceLocation; + +public class CacheRetriever { + + private HashMap cachedValues = new HashMap<>(); + + private final SkinChangerMod mod; + private final File cacheDirectory; + + public CacheRetriever(SkinChangerMod mod) { + this.mod = mod; + this.cacheDirectory = new File(mod.getModConfigDirectory(), "cache"); + + genCacheDirectory(); + } + + // String.format("https://minotar.net/skin/%s", name) + public ResourceLocation loadIntoGame(String name, String url) { + File cacheDirectory = getCacheDirForName(name); + + boolean cacheFileExists = doesCacheExist(name); + + if (isCacheExpired(name)) { + cacheFileExists = false; + + cacheDirectory.delete(); + } + + ResourceLocation location = new ResourceLocation("skins/" + getCacheName(name)); + + File dataFile = new File(cacheDirectory, cacheDirectory.getName() + ".png"); + + IImageBuffer imageBuffer = new ImageBufferDownload(); + + ThreadDownloadImageData imageData = new ThreadDownloadImageData(dataFile, url, DefaultPlayerSkin.getDefaultSkinLegacy(), new IImageBuffer() { + @Override + public BufferedImage parseUserSkin(BufferedImage image) { + return imageBuffer.parseUserSkin(image); + } + + @Override + public void skinAvailable() { + imageBuffer.skinAvailable(); + } + }); + + Minecraft.getMinecraft().renderEngine.loadTexture(location, imageData); + + if (!cacheFileExists) { + generateCacheFiles(name); + } + + return location; + } + + public void generateCacheFiles(String name) { + File cacheDirectory = getCacheDirForName(name); + + if (isCacheExpired(name)) { + cacheDirectory.delete(); + } + + if (!cacheDirectory.exists()) { + if (!cacheDirectory.mkdir()) { + System.err.println("Failed to create a cache directory."); + return; + } + } + + File dataFile = new File(cacheDirectory, cacheDirectory.getName() + ".png"); + File cacheFile = new File(cacheDirectory, cacheDirectory.getName() + ".lock"); + + try { + if (!dataFile.exists()) { + if (!dataFile.createNewFile()) { + System.err.println("Failed to create a cache file."); + } + } + + if (!cacheFile.exists()) { + if (!cacheFile.createNewFile()) { + System.err.println("Failed to create a cache file."); + } + } + + // Write the cache information + if (cacheFile.exists()) { + FileWriter writer = new FileWriter(cacheFile); + BufferedWriter bufferedWriter = new BufferedWriter(writer); + + long expirationTime = System.currentTimeMillis(); + + // Current time + 1 day + expirationTime += 24 * 60 * 60 * 1000; + + // Write the one line. + bufferedWriter.write(expirationTime + System.lineSeparator()); + bufferedWriter.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Returns true if the value inside the cache file is either missing + * + * @param name the name of the file to check the cache from. + * @return true if the cached file should have expired. + */ + public boolean isCacheExpired(String name) { + if (name == null) { + return true; + } + + File fileCache = getCacheDirForName(name); + + if (!fileCache.exists()) { + return true; + } + + File cacheLock = new File(fileCache, fileCache.getName() + ".lock"); + + if (!cacheLock.exists()) { + return true; + } + + try { + FileReader fileReader = new FileReader(cacheLock); + BufferedReader bufferedReader = new BufferedReader(fileReader); + + // First line contains the expiration time. + String line = bufferedReader.readLine(); + + bufferedReader.close(); + + long time = Long.valueOf(line); + + return System.currentTimeMillis() > time; + } catch (IOException ex) { + System.err.println("Unable to read cache file for " + name); + + ex.printStackTrace(); + + return true; + } catch (NumberFormatException ex) { + System.err.println("Cache file had an invalid number"); + + ex.printStackTrace(); + + return true; + } + } + + /** + * Returns true if the cache file for a name exists. + * + * @param name the name to check for a cache file. + * @return true if the cache file exists + */ + public boolean doesCacheExist(String name) { + File cacheDirectory = getCacheDirForName(name); + + if (!cacheDirectory.exists()) { + return false; + } + + File dataFile = new File(cacheDirectory, cacheDirectory.getName() + ".png"); + File cacheFile = new File(cacheDirectory, cacheDirectory.getName() + ".lock"); + + return dataFile.exists() && cacheFile.exists(); + } + + /** + * Generates a unique ID from a string which can be used as a cache name. + * + * @param name the name to retrieve a cache name from + * + * @return a unique ID for the entered name which corresponds to the name's cache directory. + */ + private String getCacheName(String name) { + name = name.toLowerCase(); + + // If the cache file exists in memory, just return the name of it. + if (this.cachedValues.containsKey(name)) { + return this.cachedValues.get(name); + } + + UUID id = UUID.nameUUIDFromBytes(name.getBytes()); + + // Take up to the first 5 characters of the name + String subStrName = name.substring(0, Math.min(5, name.length())); + + // Split the UUID into its four segments 0-1-2-3 + String[] uuidSplit = id.toString().split("-"); + + // Take the first and second component of the UUID. + String idFirstComponent = uuidSplit[0] + uuidSplit[1]; + + // Creates the final name of the cache file. + String finalCacheName = subStrName + "_" + idFirstComponent; + + // Cache the name so this code doesn't run on it again. + this.cachedValues.put(name, finalCacheName); + + return finalCacheName; + } + + /** + * Retrieves the cache directory from a name/input. + * + * @param nameOfFile the input which will be cached + * @return a directory which corresponds to a names cache file. + */ + private File getCacheDirForName(String nameOfFile) { + String cacheName = getCacheName(nameOfFile); + + return new File(this.cacheDirectory, cacheName); + } + + /** + * Attempts to generate a cache directory. + * + * @return true if the cache directory already existed. + */ + private boolean genCacheDirectory() { + boolean existed = true; + + if (!this.cacheDirectory.getParentFile().exists()) { + existed = false; + + if (this.cacheDirectory.getParentFile().mkdirs()) { + System.out.println("Suggested mod directory created."); + } else { + System.err.println("Unable to create the mod directory"); + + return false; + } + } + + if (!this.cacheDirectory.exists()) { + existed = false; + + if (this.cacheDirectory.mkdir()) { + System.out.println("Cache directory created."); + } else { + System.err.println("Unable to create cache directory."); + + return false; + } + } + + return existed; + } +} diff --git a/src/main/java/me/do_you_like/mods/skinchanger/utils/mod/ModCommand.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/mod/ModCommand.java new file mode 100644 index 0000000..d0cf962 --- /dev/null +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/mod/ModCommand.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2020 boomboompower + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.do_you_like.mods.skinchanger.utils.mod; + +import java.util.List; +import me.do_you_like.mods.skinchanger.SkinChangerMod; +import me.do_you_like.mods.skinchanger.utils.backend.ThreadFactory; +import me.do_you_like.mods.skinchanger.utils.game.ChatColor; + +import net.minecraft.client.Minecraft; +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; + +/** + * An enhanced CommandBase implementation which provides a few extra features. + * + * @since SkinChanger v3.0 + * @author boomboompower + */ +public abstract class ModCommand extends CommandBase { + + // Async thread handler. + private final ThreadFactory threadFactory = new ThreadFactory("ModCommand"); + + protected SkinChangerMod mod; + + public ModCommand(SkinChangerMod skinChangerMod) { + this.mod = skinChangerMod; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return ChatColor.RED + "Usage: /" + getCommandName(); + } + + @Override + public final List getCommandAliases() { + return getAliases(); + } + + @Override + public final void processCommand(ICommandSender sender, String[] args) { + try { + if (shouldMultithreadCommand(args)) { + this.threadFactory.runAsync(() -> onCommand(sender, args)); + } else { + onCommand(sender, args); + } + } catch (Exception ex) { + sendMessage(ChatColor.RED + "An error occurred whilst running this command."); + + ex.printStackTrace(); + } + } + + /** + * A safer way to execute a command. Errors which occur here will not cause the game to crash. + * + * @param sender the sender of the command + * @param args the arguments of the command + */ + public abstract void onCommand(ICommandSender sender, String[] args); + + public abstract List getAliases(); + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + return true; + } + + /** + * Return true if the command should be run on its own thread. + * + * @param args the arguments of the command + * @return true if the command should be async + */ + protected boolean shouldMultithreadCommand(String[] args) { + return false; + } + + /** + * Sends a raw message to the client. + * + * @param message the message to send + */ + protected void sendMessage(String message) { + Minecraft.getMinecraft().thePlayer.addChatComponentMessage(new ChatComponentText(message)); + } +} diff --git a/src/main/java/me/boomboompower/skinchanger/utils/WebsiteUtils.java b/src/main/java/me/do_you_like/mods/skinchanger/utils/updater/WebsiteUtils.java similarity index 98% rename from src/main/java/me/boomboompower/skinchanger/utils/WebsiteUtils.java rename to src/main/java/me/do_you_like/mods/skinchanger/utils/updater/WebsiteUtils.java index 520ebf5..1fd4e88 100644 --- a/src/main/java/me/boomboompower/skinchanger/utils/WebsiteUtils.java +++ b/src/main/java/me/do_you_like/mods/skinchanger/utils/updater/WebsiteUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 boomboompower + * Copyright (C) 2020 boomboompower * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,13 +15,12 @@ * along with this program. If not, see . */ -package me.boomboompower.skinchanger.utils; +package me.do_you_like.mods.skinchanger.utils.updater; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; - import java.net.HttpURLConnection; import java.net.URL; import java.util.LinkedList; @@ -31,9 +30,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - -import me.boomboompower.skinchanger.SkinChangerMod; - +import me.boomboompower.skinchanger.SkinChangerModOld; +import me.boomboompower.skinchanger.utils.ChatColor; import net.minecraft.client.Minecraft; import net.minecraft.event.ClickEvent; import net.minecraft.event.HoverEvent; @@ -43,7 +41,6 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent; - import org.apache.commons.io.IOUtils; /** @@ -159,7 +156,7 @@ public void begin() { this.showUpdateHeader = object.get("updateheader").getAsBoolean(); } - int currentVersion = formatVersion(SkinChangerMod.VERSION); + int currentVersion = formatVersion(SkinChangerModOld.VERSION); int latestVersion = object.has("latest-version") ? formatVersion(object.get("latest-version").getAsString()) : -1; if (currentVersion < latestVersion && latestVersion > 0) { @@ -339,7 +336,7 @@ private int formatVersion(String input) { @SubscribeEvent(priority = EventPriority.LOW) public void onJoin(FMLNetworkEvent.ClientConnectedToServerEvent event) { - WebsiteUtils utils = SkinChangerMod.getInstance().getWebsiteUtils(); + WebsiteUtils utils = this; if (utils.isDisabled()) return; diff --git a/src/main/resources/mixins.skinchanger.json b/src/main/resources/mixins.skinchanger.json index 12fbe7a..769ea22 100644 --- a/src/main/resources/mixins.skinchanger.json +++ b/src/main/resources/mixins.skinchanger.json @@ -1,5 +1,5 @@ { - "package": "me.boomboompower.skinchanger.mixins", + "package": "me.do_you_like.mods.skinchanger.methods.impl.mixins", "refmap": "mixins.skinchanger.refmap.json", "compatibilityLevel": "JAVA_8", "verbose": true,