├── .github └── workflows │ └── build.yml ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src └── main ├── java └── com │ └── luna │ └── synthesis │ ├── Synthesis.java │ ├── commands │ ├── CopyToClipboardCommand.java │ └── SynthesisCommand.java │ ├── core │ ├── Config.java │ └── CustomSortingBehavior.java │ ├── events │ ├── MessageSentEvent.java │ └── packet │ │ ├── CustomChannelDuplexHandler.java │ │ ├── PacketEvent.java │ │ ├── PacketReceivedEvent.java │ │ └── PacketSentEvent.java │ ├── features │ ├── cleanup │ │ ├── CoopCleanup.java │ │ ├── DungeonCleanup.java │ │ └── LoreCleanup.java │ ├── future │ │ └── ChunkBorders.java │ └── utilities │ │ ├── AncestralSpade.java │ │ ├── BestiaryDropRate.java │ │ ├── BetterWitherImpactPerspective.java │ │ ├── ChatBridge.java │ │ ├── ContainerChat.java │ │ ├── SearchMode.java │ │ ├── Share.java │ │ ├── VisibleLinks.java │ │ └── WishingCompass.java │ ├── managers │ ├── BackpackManager.java │ └── MathManager.java │ ├── mixins │ ├── BlockStainedGlassPaneMixin.java │ ├── ContainerMixin.java │ ├── EntityPlayerMixin.java │ ├── EntityPlayerSPMixin.java │ ├── GuiContainerMixin.java │ ├── GuiNewChatMixin.java │ ├── GuiPlayerTabOverlayMixin.java │ ├── GuiScreenMixin.java │ ├── RenderItemMixin.java │ ├── accessors │ │ ├── GuiChatAccessor.java │ │ ├── GuiContainerAccessor.java │ │ ├── GuiNewChatAccessor.java │ │ ├── GuiRepairAccessor.java │ │ ├── ItemModelMesherAccessor.java │ │ └── S2FPacketSetSlotAccessor.java │ ├── neu │ │ └── NEUEventListenerMixin.java │ ├── optifine │ │ ├── CapeUtilsMixin.java │ │ └── PlayerItemsLayerMixin.java │ ├── patcher │ │ ├── ChatHandlerMixin.java │ │ └── ImagePreviewerMixin.java │ └── skytils │ │ └── ChatTabsMixin.java │ └── utils │ ├── ChatLib.java │ ├── MixinUtils.java │ ├── ReflectionUtils.java │ └── Utils.java └── resources ├── mcmod.info └── synthesis.mixins.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [ pull_request, push ] 3 | 4 | jobs: 5 | build: 6 | strategy: 7 | matrix: 8 | java: [ 8 ] 9 | os: [ ubuntu-20.04 ] 10 | runs-on: ${{ matrix.os }} 11 | steps: 12 | - name: checkout repository 13 | uses: actions/checkout@v2 14 | - name: validate gradle wrapper 15 | uses: gradle/wrapper-validation-action@v1 16 | - name: setup jdk ${{ matrix.java }} 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: ${{ matrix.java }} 20 | - name: make gradle wrapper executable 21 | run: chmod +x ./gradlew 22 | - name: build 23 | run: ./gradlew build 24 | - name: capture build artifacts 25 | uses: actions/upload-artifact@v2 26 | with: 27 | name: Artifacts 28 | path: build/libs/ 29 | - name: send jar to webhook 30 | env: 31 | commits: ${{ toJSON(github.event.commits)}} 32 | run: | 33 | curl -H "secret:${{ secrets.BUILD_SECRET }}" \ 34 | -F commits="$commits" \ 35 | -F filename=Synthesis.jar \ 36 | -F upload=@build/libs/Synthesis.jar \ 37 | ${{ secrets.BUILD_URL }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea 15 | 16 | # gradle 17 | build 18 | .gradle 19 | 20 | # other 21 | eclipse 22 | run 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Synthesis 2 | Hypixel SkyBlock QoL Mod. A collection of random mod features that I couldn't find anywhere else. 3 | 4 | Releases and announcements at the official [discord](https://discord.gg/vAUuKSwbp6). 5 | Feedback such as suggestions, new features, bugs, etc. will also be collected there. 6 | 7 | *** 8 | 9 | ## Features 10 |
11 | Cleanup 12 | 13 | ### Cleanup 14 | Features that help the game feel more clean. 15 | - Coop cleanup, fully customizable 16 | - Auction creation messages 17 | - Auction cancellation messages 18 | - Auction collection messages 19 | - Collection tooltips 20 | - Beacon stat change messages 21 | - Co-op member traveled to island messages 22 | - Dungeon cleanup, fully customizable 23 | - Potion effects message 24 | - Solo dungeon class message 25 | - Ultimate ability message 26 | - Blessing stats messages 27 | - Silverfish messages 28 | - Wither/Blood key usage messages 29 | - Watcher messages 30 | - Doesn't remove the final message 31 | - Lore cleanup, still customizable (0.2.0+) 32 | - Gear score line 33 | - HPB stat bonuses 34 | - Reforge stat bonuses 35 | - Gemstone stat bonuses 36 | - Gemstone icons 37 | - Enchantment descriptions 38 | - And an option to remove enchantment names 39 | - Item abilities 40 | - Full armor set bonuses 41 | - Soulbound text 42 | - Obfuscated text from recombobulator 43 | - Option to not cleanup lore when in the auction house 44 | - Tablist cleanup (0.2.0+) 45 | - Option to remove tablist header 46 | - Option to remove the last 2 lines from the tablist footer 47 | - Chat cleanup (0.3.0+) 48 | - Option to remove old reforge messages when a new one is received 49 | - 50 | 51 |
52 | 53 |
54 | Future features 55 | 56 | ### Future features 57 | Features from future versions of the game. Yes, I don't know to name this one. 58 | - Chunk borders (F3 + G) 59 | - Chat clear (F3 + D) not clearing sent messages, so up and down arrows still work. 60 |
61 | 62 |
63 | Utilities 64 | 65 | ### Utilities 66 | The actual collection of QoL features that doesn't fit any other category. 67 | - Container Chat 68 | - Allows you to type and chat while inside gui inventories 69 | - Search Mode 70 | - Allows you to toggle search mode by pressing Ctrl + F with chat open, 71 | which will only display chat messages that contain what you type. 72 | - Mode to scroll back to a message when you right click on it while on search mode. 73 | - Backpack Retexturing 74 | - HOTM Perk Level Display 75 | - Displays perk level as stack size in the HOTM menu. 76 | - Drop chance to drop rate 77 | - Converts item drop chance to drop rate in the bestiary menu. 78 | - Bestiary glance 79 | - Displays bestiary level and progress in the bestiary menu. 80 | - Armadillo fix 81 | - Prevents your screen being blocked when you are inside a block while riding an armadillo pet. 82 | - Wishing compass triangulation 83 | - Locates where a wishing compass points to. Use one, wait for the particle trail to disappear, move away and use it again. 84 | - Option to add a waypoint at the location while using [Skytils](https://github.com/Skytils/SkytilsMod/). 85 | - Ancestral Spade triangulation 86 | - Quite literally the same thing as wishing compass, but with a few changes. 87 | - Wishing compass uses left display 88 | - Displays a wishing compass' left uses as stack size. 89 | - Visible links 90 | - Makes clickable links in chat blue and underlined. 91 | - Colorless panes 92 | - Turns glass panes gray so glass blocks are more visible. Just used for some gemstone mining, really. 93 | - Chat in portal 94 | - Allows you to type and use chat while inside a nether portal, like the one in dungeon blood room. 95 | - **Note**: It's possible to make portals not close containers such as player inventory, ender chest and others, 96 | but won't for now since I don't know if Hypixel would like that. 97 | - Better wither impact perspective (im good with names, 0.2.0+) 98 | - Toggling perspective while holding a wither impact weapon will skip the front camera. 99 | - Option to make it global instead of wither impact only (0.3.0+) 100 | - Superpairs IDs (0.2.0+) 101 | - Gives skyblock item IDs to items inside superpairs, so NEU and SBE can read them for price displays. 102 | - Additionally, resource packs can also modify those items. 103 | - This was made 1 minute before realizing [Skytils](https://github.com/Skytils/SkytilsMod/) has a working price display inside superpairs, so no need to use this if you use Skytils. 104 | - Shares 105 | - Shares are a way to showcase your items to other users using the mod. 106 | - To show an item, hold it and type "[item]" (configurable) in chat. 107 | - Option to be able to scroll through the share tooltip while using [ScrollableTooltips](https://github.com/Sk1erLLC/ScrollableTooltips) 108 | - Option to click a share to copy an embed for discord. Simply copy it and paste it in a channel on discord. 109 | - Bridge messages 110 | - Formats guild messages sent by a bridge bot. 111 | - Detects username and message based on message format. 112 | - Currently, only works with the formats "ign > msg" and "ign: msg". 113 | - If your bridge bot has another format, let me know. 114 | - If you don't have a bridge bot, [get one](https://neppy.antonio32a.com/). 115 | - Customizable bot name. 116 | - Customizable message format. 117 | - Working links sent from discord while using the format. 118 | - Compatible with [Skytils](https://github.com/Skytils/SkytilsMod/)' guild chat tab regardless of format. 119 | - Optifine 120 | - Allows you to have any optifine user's cape. Only you see this cape! 121 | - Options to bring back from early SkyBlock: 122 | - Yeti with trans cape. 123 | - Terracotta with trans cape. 124 | - Bonzo with non binary cape. 125 | - Grinch with candy cane cape. 126 | - Option to disable all of them, but come on, why would you. 127 | - Option to disable optifine's santa/witch hat. 128 | - [Patcher](https://github.com/Sk1erLLC/Patcher) 129 | - Option to fix an issue that would make compact chat not work under very specific circumstance. 130 | Also when using search mode/container chat in some instances. 131 | - Option to add custom trusted domains to Patcher's Image Preview. 132 | - Some image hosts, like [boob.li](https://boob.li/), won't work with [Patcher](https://github.com/Sk1erLLC/Patcher) 's Image Preview, but will when trusted with this feature. 133 |
134 |
135 | Commands 136 | 137 | ### Commands 138 | 139 | The mod only really has one command, /synth, which hosts all other subcommands. 140 | - /synth 141 | - Aliases: /synthesis, /syn 142 | - When used without an argument, it opens the config menu. 143 | - Subcommands: 144 | - bp 145 | - Arguments: backpack number, texture name, texture meta. 146 | - Re textures the backpack in the *backpack number* slot, with the texture *texture name* and *texture meta* 147 | - For example, if you wanted the first backpack to be a fish, you would just use /synth bp fish. If you wanted a pufferfish instead, you would do /synth bp fish 3. 148 | - To remove a backpack's texture, don't add any texture name or meta to the command. 149 | - domains 150 | - Arguments: "add/remove/list", domain 151 | - Adds or removes a domain to or from the trusted domain list for [Patcher](https://github.com/Sk1erLLC/Patcher)'s Image Preview. 152 | - Can also list all the current trusted domains. 153 |
-------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | maven { 5 | name = "forge" 6 | url = "https://maven.minecraftforge.net/" 7 | } 8 | maven { 9 | name = "sponge" 10 | url = "https://repo.spongepowered.org/repository/maven-public" 11 | } 12 | maven { 13 | name = "jitpack" 14 | url = "https://jitpack.io/" 15 | } 16 | } 17 | dependencies { 18 | classpath "com.github.asbyth:ForgeGradle:6f53277" 19 | classpath "com.github.jengelman.gradle.plugins:shadow:6.1.0" 20 | classpath "com.github.xcfrg:MixinGradle:0.6-SNAPSHOT" 21 | } 22 | } 23 | 24 | apply plugin: "java" 25 | apply plugin: "net.minecraftforge.gradle.forge" 26 | apply plugin: "com.github.johnrengelman.shadow" 27 | apply plugin: "org.spongepowered.mixin" 28 | 29 | version = "0.3.1" 30 | group = "com.luna" 31 | archivesBaseName = "Synthesis" 32 | 33 | sourceCompatibility = JavaVersion.VERSION_1_8 34 | targetCompatibility = JavaVersion.VERSION_1_8 35 | compileJava.options.encoding = "UTF-8" 36 | 37 | sourceSets { 38 | main { 39 | output.resourcesDir = java.outputDir 40 | } 41 | } 42 | 43 | minecraft { 44 | version = "1.8.9-11.15.1.2318-1.8.9" 45 | runDir = "run" 46 | mappings = "stable_22" 47 | makeObfSourceJar = false 48 | 49 | clientJvmArgs += "-Delementa.dev=true" 50 | clientRunArgs += "--tweakClass gg.essential.loader.stage0.EssentialSetupTweaker" 51 | clientRunArgs += "--mixin synthesis.mixins.json" 52 | } 53 | 54 | mixin { 55 | add sourceSets.main, "synthesis.mixins.refmap.json" 56 | defaultObfuscationEnv searge 57 | } 58 | 59 | configurations { 60 | embed 61 | implementation.extendsFrom(embed) 62 | } 63 | 64 | repositories { 65 | mavenCentral() 66 | maven { url = "https://repo.sk1er.club/repository/maven-public/" } 67 | maven { url = "https://jitpack.io/" } 68 | maven { url = "https://repo.spongepowered.org/repository/maven-public/" } 69 | } 70 | 71 | dependencies { 72 | embed "gg.essential:loader-launchwrapper:1.1.3" 73 | compileOnly "gg.essential:essential-1.8.9-forge:1759" 74 | 75 | annotationProcessor "org.spongepowered:mixin:0.8.4" 76 | compileOnly "org.spongepowered:mixin:0.8.4" 77 | 78 | annotationProcessor "com.google.code.gson:gson:2.2.4" 79 | annotationProcessor "com.google.guava:guava:21.0" 80 | annotationProcessor "org.ow2.asm:asm-tree:6.2" 81 | annotationProcessor "org.ow2.asm:asm-util:6.2" 82 | annotationProcessor "org.apache.logging.log4j:log4j-core:2.0-beta9" 83 | 84 | compileOnly "org.projectlombok:lombok:1.18.12" 85 | annotationProcessor "org.projectlombok:lombok:1.18.12" 86 | } 87 | 88 | shadowJar { 89 | archiveName = "Synthesis.jar" 90 | classifier = "" 91 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 92 | 93 | manifest.attributes( 94 | "ForceLoadAsMod": true, 95 | "ModSide": "CLIENT", 96 | "TweakClass": "gg.essential.loader.stage0.EssentialSetupTweaker", 97 | "MixinConfigs": "synthesis.mixins.json" 98 | ) 99 | 100 | exclude("dummyThing") 101 | exclude("META-INF/maven/") 102 | exclude("META-INF/nar/") 103 | exclude("module-info.class") 104 | exclude("META-INF/versions/") 105 | exclude("LICENSE.txt") 106 | 107 | configurations = [project.configurations.embed] 108 | } 109 | 110 | reobfJar.dependsOn tasks.shadowJar 111 | 112 | reobf { 113 | shadowJar { 114 | mappingType = "SEARGE" 115 | } 116 | } 117 | 118 | processResources { 119 | inputs.property "version", project.version 120 | inputs.property "mcversion", project.minecraft.version 121 | 122 | from(sourceSets.main.resources.srcDirs) { 123 | include "mcmod.info" 124 | 125 | expand "version": project.version, "mcversion": project.minecraft.version 126 | } 127 | 128 | from(sourceSets.main.resources.srcDirs) { 129 | exclude "mcmod.info" 130 | } 131 | 132 | from(file("LICENSE")) 133 | } 134 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SynthesisMod/Synthesis/574824a82a0833ce2a3b41ee345e33e68cb27cc2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/Synthesis.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis; 2 | 3 | import com.luna.synthesis.commands.CopyToClipboardCommand; 4 | import com.luna.synthesis.commands.SynthesisCommand; 5 | import com.luna.synthesis.core.Config; 6 | import com.luna.synthesis.events.packet.PacketEvent; 7 | import com.luna.synthesis.features.cleanup.CoopCleanup; 8 | import com.luna.synthesis.features.cleanup.DungeonCleanup; 9 | import com.luna.synthesis.features.cleanup.LoreCleanup; 10 | import com.luna.synthesis.features.future.ChunkBorders; 11 | import com.luna.synthesis.features.utilities.*; 12 | import com.luna.synthesis.managers.BackpackManager; 13 | import com.luna.synthesis.utils.ReflectionUtils; 14 | import lombok.Getter; 15 | import net.minecraftforge.common.MinecraftForge; 16 | import net.minecraftforge.fml.common.Mod; 17 | import net.minecraftforge.fml.common.Mod.EventHandler; 18 | import net.minecraftforge.fml.common.event.FMLInitializationEvent; 19 | 20 | import java.io.File; 21 | 22 | @Mod( 23 | modid = Synthesis.MODID, 24 | version = Synthesis.VERSION, 25 | name = Synthesis.NAME, 26 | clientSideOnly = true 27 | ) 28 | public class Synthesis { 29 | public static final String NAME = "Synthesis"; 30 | public static final String MODID = "synthesis"; 31 | public static final String VERSION = "0.3.1"; 32 | public static final String configLocation = "./config/synthesis.toml"; 33 | 34 | @Getter private static Synthesis instance; 35 | @Getter private final Config config; 36 | @Getter private final BackpackManager backpackManager; 37 | 38 | public Synthesis() { 39 | instance = this; 40 | config = new Config(); 41 | backpackManager = new BackpackManager(new File("./config/synthesisbackpacks.json")); 42 | } 43 | 44 | @EventHandler 45 | public void init(FMLInitializationEvent event) { 46 | MinecraftForge.EVENT_BUS.register(new PacketEvent()); 47 | MinecraftForge.EVENT_BUS.register(this); 48 | MinecraftForge.EVENT_BUS.register(new CoopCleanup()); 49 | MinecraftForge.EVENT_BUS.register(new ChunkBorders()); 50 | MinecraftForge.EVENT_BUS.register(new SearchMode()); 51 | MinecraftForge.EVENT_BUS.register(new BestiaryDropRate()); 52 | MinecraftForge.EVENT_BUS.register(new ContainerChat()); 53 | MinecraftForge.EVENT_BUS.register(new WishingCompass()); 54 | MinecraftForge.EVENT_BUS.register(new ChatBridge()); 55 | MinecraftForge.EVENT_BUS.register(new VisibleLinks()); 56 | MinecraftForge.EVENT_BUS.register(new Share()); 57 | MinecraftForge.EVENT_BUS.register(new DungeonCleanup()); 58 | MinecraftForge.EVENT_BUS.register(new BetterWitherImpactPerspective()); 59 | MinecraftForge.EVENT_BUS.register(new LoreCleanup()); 60 | MinecraftForge.EVENT_BUS.register(new AncestralSpade()); 61 | config.preload(); 62 | new SynthesisCommand().register(); 63 | new CopyToClipboardCommand().register(); 64 | ReflectionUtils.onInit(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/commands/CopyToClipboardCommand.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.commands; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.utils.ChatLib; 6 | import gg.essential.api.commands.Command; 7 | import gg.essential.api.commands.DefaultHandler; 8 | 9 | import java.awt.*; 10 | import java.awt.datatransfer.StringSelection; 11 | 12 | public class CopyToClipboardCommand extends Command { 13 | 14 | public CopyToClipboardCommand() { 15 | super("ctcc"); 16 | } 17 | 18 | private final Config config = Synthesis.getInstance().getConfig(); 19 | 20 | // I will let you know that I despise having to create commands to run code on chat click. 21 | // I'll end up rewriting clicks eventually. JUST YOU WAIT. 22 | @DefaultHandler 23 | public void handle(String toCopy) { 24 | if (!config.utilitiesShareCopyEmbed) return; 25 | ChatLib.chat("Copied &a" + toCopy + "&r to clipboard."); 26 | Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(toCopy), null); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/commands/SynthesisCommand.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.commands; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.managers.BackpackManager; 6 | import com.luna.synthesis.utils.ChatLib; 7 | import gg.essential.api.EssentialAPI; 8 | import gg.essential.api.commands.*; 9 | import net.minecraft.item.Item; 10 | import net.minecraft.item.ItemStack; 11 | import net.minecraftforge.fml.common.Loader; 12 | 13 | import java.util.*; 14 | 15 | public class SynthesisCommand extends Command { 16 | public SynthesisCommand() { 17 | super("synthesis"); 18 | } 19 | 20 | private final Config config = Synthesis.getInstance().getConfig(); 21 | 22 | @Override 23 | public Set getCommandAliases() { 24 | return new HashSet<>(Arrays.asList(new Alias("syn"), new Alias("synth"))); 25 | } 26 | 27 | @DefaultHandler 28 | public void handle() { 29 | EssentialAPI.getGuiUtil().openScreen(Synthesis.getInstance().getConfig().gui()); 30 | } 31 | 32 | @SubCommand("bp") 33 | public void bp(@DisplayName("backpack number") int number, @DisplayName("texture name") Optional name, @DisplayName("texture meta") Optional meta) { 34 | BackpackManager bpm = Synthesis.getInstance().getBackpackManager(); 35 | if (number < 1 || number > 18) { 36 | ChatLib.chat("That's not a valid backpack number."); 37 | return; 38 | } 39 | if (!name.isPresent()) { 40 | bpm.modifyData(String.valueOf(number), "", 0); 41 | ChatLib.chat("Removed custom texture from backpack " + number); 42 | } else { 43 | String itemName = name.get().toLowerCase(); 44 | if (!itemName.startsWith("minecraft:")) { 45 | itemName = "minecraft:" + itemName; 46 | } 47 | Item item = Item.getByNameOrId(itemName); 48 | if (item == null) { 49 | ChatLib.chat("Item \"" + itemName + "\" does not exist."); 50 | return; 51 | } 52 | if (meta.isPresent()) { 53 | List items = new ArrayList<>(); 54 | item.getSubItems(item, item.getCreativeTab(), items); 55 | if (items.size() - 1 < meta.get()) { 56 | ChatLib.chat("Meta can't be that high for this item."); 57 | return; 58 | } 59 | bpm.modifyData(String.valueOf(number), itemName, meta.get()); 60 | ChatLib.chat("Added " + itemName + " texture to backpack " + number + " with meta " + meta.get()); 61 | } else { 62 | bpm.modifyData(String.valueOf(number), itemName, 0); 63 | ChatLib.chat("Added " + itemName + " texture to backpack " + number); 64 | } 65 | } 66 | } 67 | 68 | @SubCommand("domains") 69 | public void domains(@Options({"add", "remove", "list"}) String options, @DisplayName("domain") Optional domain) { 70 | if (!Loader.isModLoaded("patcher")) { 71 | ChatLib.chat("You can only use this feature if you use patcher."); 72 | return; 73 | } 74 | switch (options) { 75 | case "add": 76 | if (!domain.isPresent()) { 77 | ChatLib.chat("You need to specify a domain. Example: bigraccoon.monster"); 78 | return; 79 | } 80 | if (config.patcherCustomDomains.contains(domain.get().toLowerCase())) { 81 | ChatLib.chat("That's already a trusted domain."); 82 | return; 83 | } 84 | config.patcherCustomDomains += domain.get().toLowerCase() + ","; 85 | ChatLib.chat("Added &a" + domain.get() + "&r to the trusted domain list."); 86 | config.markDirty(); 87 | config.writeData(); 88 | break; 89 | case "remove": 90 | if (!domain.isPresent()) { 91 | ChatLib.chat("You need to specify a domain. Example: bigraccoon.monster"); 92 | return; 93 | } 94 | if (!config.patcherCustomDomains.contains(domain.get().toLowerCase())) { 95 | ChatLib.chat("That was not a trusted domain."); 96 | return; 97 | } 98 | config.patcherCustomDomains = config.patcherCustomDomains.replace(domain.get().toLowerCase() + ",", ""); 99 | ChatLib.chat("Removed &c" + domain.get() + "&r from the trusted domain list."); 100 | config.markDirty(); 101 | config.writeData(); 102 | break; 103 | case "list": 104 | if (config.patcherCustomDomains.equals("")) { 105 | ChatLib.chat("There aren't any trusted domains."); 106 | return; 107 | } 108 | ChatLib.chat("&aList of domains: "); 109 | for (String s : config.patcherCustomDomains.split(",")) { 110 | ChatLib.chat(" &7- &a" + s); 111 | } 112 | if (domain.isPresent()) { 113 | ChatLib.chat("&dYou don't need to specify another argument, btw."); 114 | } 115 | break; 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/core/Config.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.core; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import gg.essential.vigilance.Vigilant; 5 | import gg.essential.vigilance.data.JVMAnnotationPropertyCollector; 6 | import gg.essential.vigilance.data.Property; 7 | import gg.essential.vigilance.data.PropertyType; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.util.ChatComponentText; 10 | import net.minecraft.util.EnumChatFormatting; 11 | import net.minecraftforge.fml.common.Loader; 12 | 13 | import java.awt.*; 14 | import java.io.File; 15 | 16 | public class Config extends Vigilant { 17 | 18 | // Me englando is no bueno. 19 | // If you find something that could be rewritten to be more concise and clear, let me know 20 | 21 | @Property( 22 | type = PropertyType.SELECTOR, 23 | name = "Collection tooltips", 24 | description = "Cleans some lines on the co-op collection display.", 25 | category = "Cleanup", 26 | subcategory = "Co-op", 27 | options = { 28 | "Unchanged", 29 | "Empty contributions", 30 | "Other people's contributions", 31 | "All contributions" 32 | } 33 | ) 34 | public int cleanupCoopCollections = 0; 35 | 36 | @Property( 37 | type = PropertyType.SELECTOR, 38 | name = "Auction creation", 39 | description = "Removes co-op auction creation messages.", 40 | category = "Cleanup", 41 | subcategory = "Co-op", 42 | options = { 43 | "None", 44 | "Own auctions", 45 | "Own auctions and show price", 46 | "Other people's auctions", 47 | "All auctions", 48 | "All auctions and show price for own" 49 | } 50 | ) 51 | public int cleanupCoopAuctionCreation = 0; 52 | 53 | @Property( 54 | type = PropertyType.SELECTOR, 55 | name = "Auction cancellations", 56 | description = "Removes co-op auction cancellation messages.", 57 | category = "Cleanup", 58 | subcategory = "Co-op", 59 | options = { 60 | "None", 61 | "Own auctions", 62 | "Other people's auctions", 63 | "All auctions" 64 | } 65 | ) 66 | public int cleanupCoopAuctionCancellation = 0; 67 | 68 | @Property( 69 | type = PropertyType.SELECTOR, 70 | name = "Auction collections", 71 | description = "Removes co-op auction collection messages.", 72 | category = "Cleanup", 73 | subcategory = "Co-op", 74 | options = { 75 | "None", 76 | "Own auctions", 77 | "Other people's auctions", 78 | "All auctions" 79 | } 80 | ) 81 | public int cleanupCoopAuctionCollection = 0; 82 | 83 | @Property( 84 | type = PropertyType.SELECTOR, 85 | name = "Beacon stat changes", 86 | description = "Removes co-op beacon stat changes messages.", 87 | category = "Cleanup", 88 | subcategory = "Co-op", 89 | options = { 90 | "None", 91 | "Own changes", 92 | "Other people's changes", 93 | "All changes" 94 | } 95 | ) 96 | public int cleanupCoopBeaconStatChanges = 0; 97 | 98 | @Property( 99 | type = PropertyType.SWITCH, 100 | name = "Co-op travel messages", 101 | description = "Removes the chat message when your coop members travel to another island.", 102 | category = "Cleanup", 103 | subcategory = "Co-op" 104 | ) 105 | public boolean cleanupCoopTravel = false; 106 | 107 | @Property( 108 | type = PropertyType.SWITCH, 109 | name = "Remove dungeon potion effects message", 110 | description = "Removes the chat message when you join a dungeon with active potion effects outside.", 111 | category = "Cleanup", 112 | subcategory = "Dungeon" 113 | ) 114 | public boolean cleanupDungeonPotionEffects = false; 115 | 116 | @Property( 117 | type = PropertyType.SWITCH, 118 | name = "Remove dungeon class message", 119 | description = "Removes the chat message when you're the only player using a class.", 120 | category = "Cleanup", 121 | subcategory = "Dungeon" 122 | ) 123 | public boolean cleanupDungeonSoloClassMessage = false; 124 | 125 | @Property( 126 | type = PropertyType.SWITCH, 127 | name = "Remove dungeon ultimate message", 128 | description = "Removes the dungeon reminder that your ultimate is ready to use.", 129 | category = "Cleanup", 130 | subcategory = "Dungeon" 131 | ) 132 | public boolean cleanupDungeonUltimateMessage = false; 133 | 134 | @Property( 135 | type = PropertyType.SWITCH, 136 | name = "Remove dungeon blessing stats messages", 137 | description = "Removes the chat message that shows the stats of the collected blessing.", 138 | category = "Cleanup", 139 | subcategory = "Dungeon" 140 | ) 141 | public boolean cleanupDungeonBlessingStatMessages = false; 142 | 143 | @Property( 144 | type = PropertyType.SWITCH, 145 | name = "Remove dungeon blessing messages", 146 | description = "Also removes the message that a blessing has been obtained, not only stats.", 147 | category = "Cleanup", 148 | subcategory = "Dungeon" 149 | ) 150 | public boolean cleanupDungeonBlessingMessages = false; 151 | 152 | @Property( 153 | type = PropertyType.SWITCH, 154 | name = "Remove dungeon silverfish messages", 155 | description = "Removes the chat message when you hit the silverfish while it's moving.", 156 | category = "Cleanup", 157 | subcategory = "Dungeon" 158 | ) 159 | public boolean cleanupDungeonSilverfishMessages = false; 160 | 161 | @Property( 162 | type = PropertyType.SWITCH, 163 | name = "Remove dungeon key usage messages", 164 | description = "Removes the chat message that explains how to use blood and wither keys.", 165 | category = "Cleanup", 166 | subcategory = "Dungeon" 167 | ) 168 | public boolean cleanupDungeonKeyUsageMessages = false; 169 | 170 | @Property( 171 | type = PropertyType.SWITCH, 172 | name = "Remove dungeon watcher messages", 173 | description = "Removes all watcher messages except for the last one.", 174 | category = "Cleanup", 175 | subcategory = "Dungeon" 176 | ) 177 | public boolean cleanupDungeonWatcherMessages = false; 178 | 179 | @Property( 180 | type = PropertyType.SWITCH, 181 | name = "Remove gear score", 182 | description = "Removes the gear score line.", 183 | category = "Cleanup", 184 | subcategory = "Lore" 185 | ) 186 | public boolean cleanupLoreGearScore = false; 187 | 188 | @Property( 189 | type = PropertyType.SWITCH, 190 | name = "Remove HPB stat bonuses", 191 | description = "Removes the text of bonus stats from hot/fuming potato books.", 192 | category = "Cleanup", 193 | subcategory = "Lore" 194 | ) 195 | public boolean cleanupLoreHPB = false; 196 | 197 | @Property( 198 | type = PropertyType.SWITCH, 199 | name = "Remove reforge stat bonuses", 200 | description = "Removes the text of bonus stats from reforge.", 201 | category = "Cleanup", 202 | subcategory = "Lore" 203 | ) 204 | public boolean cleanupLoreReforge = false; 205 | 206 | @Property( 207 | type = PropertyType.SWITCH, 208 | name = "Remove gemstone stat bonuses", 209 | description = "Removes the text of bonus stats from gemstones.", 210 | category = "Cleanup", 211 | subcategory = "Lore" 212 | ) 213 | public boolean cleanupLoreGemstones = false; 214 | 215 | @Property( 216 | type = PropertyType.SWITCH, 217 | name = "Remove dungeon stat bonuses", 218 | description = "Removes the text of the weapon's dungeon stats.", 219 | category = "Cleanup", 220 | subcategory = "Lore" 221 | ) 222 | public boolean cleanupLoreDungeon = false; 223 | 224 | @Property( 225 | type = PropertyType.SWITCH, 226 | name = "Remove gemstone icons", 227 | description = "Removes the line that indicates applied gemstones.", 228 | category = "Cleanup", 229 | subcategory = "Lore" 230 | ) 231 | public boolean cleanupLoreGemstoneSlots = false; 232 | 233 | @Property( 234 | type = PropertyType.SWITCH, 235 | name = "Remove enchantment descriptions", 236 | description = "Removes the explanation of what each enchantment does when the item has a low amount of enchantments.", 237 | category = "Cleanup", 238 | subcategory = "Lore" 239 | ) 240 | public boolean cleanupLoreEnchantmentDescriptions = false; 241 | 242 | @Property( 243 | type = PropertyType.SWITCH, 244 | name = "Remove enchantments and reforge abilities", 245 | description = "Removes both the paragraph of enchantments and any mention of reforge abilities.", 246 | category = "Cleanup", 247 | subcategory = "Lore" 248 | ) 249 | public boolean cleanupLoreEnchantments = false; 250 | 251 | @Property( 252 | type = PropertyType.SWITCH, 253 | name = "Remove reforge abilities", 254 | description = "Removes only the reforge ability text and leaves the paragraph of enchantments alone.", 255 | category = "Cleanup", 256 | subcategory = "Lore" 257 | ) 258 | public boolean cleanupLoreReforgeAbility = false; 259 | 260 | @Property( 261 | type = PropertyType.SWITCH, 262 | name = "Remove item abilities", 263 | description = "Removes the item ability text.", 264 | category = "Cleanup", 265 | subcategory = "Lore" 266 | ) 267 | public boolean cleanupLoreAbilities = false; 268 | 269 | @Property( 270 | type = PropertyType.SWITCH, 271 | name = "Remove armor piece bonuses", 272 | description = "Removes the armor piece bonus text.", 273 | category = "Cleanup", 274 | subcategory = "Lore" 275 | ) 276 | public boolean cleanupLorePieceBonus = false; 277 | 278 | @Property( 279 | type = PropertyType.SWITCH, 280 | name = "Remove armor full set bonuses", 281 | description = "Removes the armor full set bonus text.", 282 | category = "Cleanup", 283 | subcategory = "Lore" 284 | ) 285 | public boolean cleanupLoreFullSetBonus = false; 286 | 287 | @Property( 288 | type = PropertyType.SWITCH, 289 | name = "Remove co-op soulbound text", 290 | description = "Removes the \"§8* Co-op Soulbound *§r\" text.", 291 | category = "Cleanup", 292 | subcategory = "Lore" 293 | ) 294 | public boolean cleanupLoreCoopSoulbound = false; 295 | 296 | @Property( 297 | type = PropertyType.SWITCH, 298 | name = "Remove solo soulbound text", 299 | description = "Removes the \"§8* Soulbound *§r\" text.", 300 | category = "Cleanup", 301 | subcategory = "Lore" 302 | ) 303 | public boolean cleanupLoreSoloSoulbound = false; 304 | 305 | @Property( 306 | type = PropertyType.SWITCH, 307 | name = "Remove recombobulated obfuscated text", 308 | description = "Removes the obfuscated text (§ka§r) on the rarity of a recombobulated item.", 309 | category = "Cleanup", 310 | subcategory = "Lore" 311 | ) 312 | public boolean cleanupLoreRecombobulatedObfuscated = false; 313 | 314 | @Property( 315 | type = PropertyType.SWITCH, 316 | name = "Remove \"§7Lvl§r\" from pet names in the pet menu", 317 | description = "Shows only the pet's level number in the pet menu.\n\n" + 318 | "§c§lWARNING§r§c: This WILL conflict with Skytils' item rarity feature at this time\n§cdue to their pet name regex detection, and consequently almost any other mod features that depends on the pet's display name.\n" + 319 | "§e§lCAUTION§r§e: This will also affect the output of the pet's display name\n§eif you use Developer Mode to copy item NBT data using the §7/sba nbt§e command from SkyblockAddons.", 320 | category = "Cleanup", 321 | subcategory = "Lore" 322 | ) 323 | public boolean cleanupPetDisplayName = false; 324 | 325 | @Property( 326 | type = PropertyType.SELECTOR, 327 | name = "Remove pet type text in the pet menu", 328 | description = "Removes the pet's type (type and/or skill, your choice) from its lore in the pet menu.\n" + 329 | "Example (show skill only): §8Mining Pet§r -> §8Mining\n" + 330 | "Example (show type only): §8Combat Morph§r -> §8Morph\n", 331 | category = "Cleanup", 332 | subcategory = "Lore", 333 | options = { 334 | "Off", 335 | "Show skill only and remove pet type", 336 | "Show type only and remove pet's skill", 337 | "Remove both skill and type" 338 | } 339 | ) 340 | public int cleanupLorePetType = 0; 341 | 342 | @Property( 343 | type = PropertyType.SWITCH, 344 | name = "Remove pet perk names in the pet menu", 345 | description = "Examples: §6Hive§r, §6Ridable§r, §6Run§r, §6Odyssey§r, §6Mining Exp Boost§r.", 346 | category = "Cleanup", 347 | subcategory = "Lore" 348 | ) 349 | public boolean cleanupLorePetPerkName = false; 350 | 351 | @Property( 352 | type = PropertyType.SWITCH, 353 | name = "Remove pet \"§6Held Item: §r\" prefix in the pet menu", 354 | description = "Example: §6Held Item: §aGold Claws\nThis will §lNOT§r remove the ability text\n§rof the held pet item in question.", 355 | category = "Cleanup", 356 | subcategory = "Lore" 357 | ) 358 | public boolean cleanupLorePetHeldItemPrefix = false; 359 | 360 | @Property( 361 | type = PropertyType.SWITCH, 362 | name = "Remove pet lore's empty lines in the pet menu", 363 | description = "This is a rather self-explanatory feature, but Essential's config menu renderer throws a hissy fit if you leave the description line empty, so now you're forced to read this.", 364 | category = "Cleanup", 365 | subcategory = "Lore" 366 | ) 367 | public boolean cleanupLorePetEmptyLines = false; 368 | 369 | @Property( 370 | type = PropertyType.SWITCH, 371 | name = "Remove pet lore's \"§b§lMAX LEVEL§r\" line in the pet menu", 372 | description = "This is a rather self-explanatory feature, but Essential's config menu renderer throws a hissy fit if you leave the description line empty, so now you're forced to read this.", 373 | category = "Cleanup", 374 | subcategory = "Lore" 375 | ) 376 | public boolean cleanupLorePetMaxLevel = false; 377 | 378 | @Property( 379 | type = PropertyType.SWITCH, 380 | name = "Remove pet lore's \"§eClick to summon!§r\" line in the pet menu", 381 | description = "This is a rather self-explanatory feature, but Essential's config menu renderer throws a hissy fit if you leave the description line empty, so now you're forced to read this.", 382 | category = "Cleanup", 383 | subcategory = "Lore" 384 | ) 385 | public boolean cleanupLorePetClickToSummon = false; 386 | 387 | @Property( 388 | type = PropertyType.SWITCH, 389 | name = "Remove pet lore's \"§cClick to despawn!§r\" line in the pet menu", 390 | description = "This is a rather self-explanatory feature, but Essential's config menu renderer throws a hissy fit if you leave the description line empty, so now you're forced to read this.", 391 | category = "Cleanup", 392 | subcategory = "Lore" 393 | ) 394 | public boolean cleanupLorePetClickToDespawn = false; 395 | 396 | @Property( 397 | type = PropertyType.SWITCH, 398 | name = "Compact pet lore's \"§a(X/10) Pet Candy Used§r\" line in the pet menu", 399 | description = "Example: §a(X/10) Pet Candy Used§r -> §aX Cand[y/ies]", 400 | category = "Cleanup", 401 | subcategory = "Lore" 402 | ) 403 | public boolean cleanupLorePetCandiesUsed = false; 404 | 405 | @Property( 406 | type = PropertyType.SWITCH, 407 | name = "Auction house exception", 408 | description = "Stops the lore being cleaned up when the auction house menu is opened.", 409 | category = "Cleanup", 410 | subcategory = "Lore" 411 | ) 412 | public boolean cleanupLoreAuctionException = false; 413 | 414 | @Property( 415 | type = PropertyType.SWITCH, 416 | name = "Remove old reforge messages", 417 | description = "Removes past reforge messages from chat when a new one is received.", 418 | category = "Cleanup", 419 | subcategory = "Chat" 420 | ) 421 | public boolean cleanupChatOldReforgeMessages = false; 422 | 423 | @Property( 424 | type = PropertyType.SWITCH, 425 | name = "Remove tablist header", 426 | description = "Removes the message at the top of the tablist.", 427 | category = "Cleanup", 428 | subcategory = "Tablist" 429 | ) 430 | public boolean cleanupTablistHeader = false; 431 | 432 | @Property( 433 | type = PropertyType.SWITCH, 434 | name = "Remove tablist footer", 435 | description = "Removes the last 2 lines at the bottom of the tablist.", 436 | category = "Cleanup", 437 | subcategory = "Tablist" 438 | ) 439 | public boolean cleanupTablistFooter = false; 440 | 441 | //FUTURE 442 | 443 | @Property( 444 | type = PropertyType.SWITCH, 445 | name = "Keep sent messages", 446 | description = "Clearing the chat with F3 + D won't clear sent messages from the up and down arrows.", 447 | category = "Future features" 448 | ) 449 | public boolean futureKeepSentMessages = false; 450 | 451 | @Property( 452 | type = PropertyType.SWITCH, 453 | name = "Chunk borders", 454 | description = "Pressing F3 + G toggles chunk borders.", 455 | category = "Future features" 456 | ) 457 | public boolean futureChunkBorders = false; 458 | 459 | @Property( 460 | type = PropertyType.SWITCH, 461 | name = "Container chat", 462 | description = "Opens the chat when having a container open.", 463 | category = "Utilities" 464 | ) 465 | public boolean utilitiesContainerChat = false; 466 | 467 | @Property( 468 | type = PropertyType.SWITCH, 469 | name = "Container control", 470 | description = "Requires to have the control key held down to be able to open chat inside a container.\nIf not toggled, holding control key down will not open container chat.", 471 | category = "Utilities" 472 | ) 473 | public boolean utilitiesContainerControl = false; 474 | 475 | @Property( 476 | type = PropertyType.SWITCH, 477 | name = "Resize chat", 478 | description = "Resizes chat when inside a container for it to fit on the screen.", 479 | category = "Utilities" 480 | ) 481 | public boolean utilitiesResizeContainerChat = false; 482 | 483 | @Property( 484 | type = PropertyType.SWITCH, 485 | name = "Reopen chat", 486 | description = "When a container is closed while typing, reopen chat with what you were typing.", 487 | category = "Utilities" 488 | ) 489 | public boolean utilitiesReopenContainerChat = false; 490 | 491 | @Property( 492 | type = PropertyType.SWITCH, 493 | name = "Transfer chat", 494 | description = "When a container is opened while typing from chat or another container, carry over what you were typing.", 495 | category = "Utilities" 496 | ) 497 | public boolean utilitiesTransferContainerChat = false; 498 | 499 | @Property( 500 | type = PropertyType.SWITCH, 501 | name = "Chat search mode", 502 | description = "Pressing Ctrl + F when chat is open will toggle search mode.", 503 | category = "Utilities" 504 | ) 505 | public boolean utilitiesChatSearchMode = false; 506 | 507 | @Property( 508 | type = PropertyType.SWITCH, 509 | name = "Chat search instant refresh", 510 | description = "Chat will look for chat messages every key typed instead of only after pressing enter.", 511 | category = "Utilities" 512 | ) 513 | public boolean utilitiesChatSearchKeyRefresh = false; 514 | 515 | @Property( 516 | type = PropertyType.SWITCH, 517 | name = "Search scroll", 518 | description = "Scrolls to a message when right clicked on while on search mode.", 519 | category = "Utilities" 520 | ) 521 | public boolean utilitiesChatScrollClick = false; 522 | 523 | @Property( 524 | type = PropertyType.SWITCH, 525 | name = "Backpack retexturing", 526 | description = "Allows you to retexture storage backpacks.", 527 | category = "Utilities" 528 | ) 529 | public boolean utilitiesBackpackRetexturing = false; 530 | 531 | @Property( 532 | type = PropertyType.SWITCH, 533 | name = "HOTM Perk Level Display", 534 | description = "Shows perk level as stack size.", 535 | category = "Utilities" 536 | ) 537 | public boolean utilitiesPerkLevelDisplay = false; 538 | 539 | @Property( 540 | type = PropertyType.SWITCH, 541 | name = "HOTM Max Perk Display", 542 | description = "Shows perk level as stack size also on maxed perks.", 543 | category = "Utilities" 544 | ) 545 | public boolean utilitiesMaxPerkLevelDisplay = false; 546 | 547 | @Property( 548 | type = PropertyType.SELECTOR, 549 | name = "Drop chance to drop rate", 550 | description = "Displays drop chances as drop rates in bestiary.", 551 | category = "Utilities", 552 | options = { 553 | "None", 554 | "Hold shift", 555 | "Permanent" 556 | } 557 | ) 558 | public int utilitiesDropChanceToDropRate = 0; 559 | 560 | @Property( 561 | type = PropertyType.SWITCH, 562 | name = "Bestiary glance", 563 | description = "Displays bestiary level and progress in the bestiary menu.", 564 | category = "Utilities" 565 | ) 566 | public boolean utilitiesBestiaryGlance = false; 567 | 568 | @Property( 569 | type = PropertyType.SWITCH, 570 | name = "Armadillo fix", 571 | description = "Stops armadillo blocking the screen when trying to mine blocks.", 572 | category = "Utilities" 573 | ) 574 | public boolean utilitiesArmadilloFix = false; 575 | 576 | @Property( 577 | type = PropertyType.SWITCH, 578 | name = "WishingCompass helper", 579 | description = "Triangulates the location wishing compass points to. Use the item once, wait until the particle trail has disappeared, move away a bit and use it again. Make sure /pq is NOT \"off\".", 580 | category = "Utilities" 581 | ) 582 | public boolean utilitiesWishingCompass = false; 583 | 584 | @Property( 585 | type = PropertyType.SWITCH, 586 | name = "Block triangulation item", 587 | description = "Blocks using wishing compass if the last trail hasn't disappeared.", 588 | category = "Utilities" 589 | ) 590 | public boolean utilitiesBlockWishingCompass = false; 591 | 592 | @Property( 593 | type = PropertyType.SWITCH, 594 | name = "WishingCompass waypoints", 595 | description = "Sets a waypoint at the location calculated by triangulation. Uses Skytils' waypoints.", 596 | category = "Utilities" 597 | ) 598 | public boolean utilitiesWishingCompassWaypoint = false; 599 | 600 | @Property( 601 | type = PropertyType.SWITCH, 602 | name = "AncestralSpade helper", 603 | description = "Triangulates the location ancestral spade points to. §cLook straight up or down§r, se the item once, wait until the particle trail has disappeared, move away a bit and use it again. Make sure /pq is NOT \"off\".", 604 | category = "Utilities" 605 | ) 606 | public boolean utilitiesAncestralSpade = false; 607 | 608 | @Property( 609 | type = PropertyType.SWITCH, 610 | name = "Burrow waypoints", 611 | description = "Sets a waypoint at the location calculated by ancestral spade triangulation.", 612 | category = "Utilities" 613 | ) 614 | public boolean utilitiesAncestralSpadeWaypoint = false; 615 | 616 | @Property( 617 | type = PropertyType.COLOR, 618 | name = "Burrow waypoint color", 619 | description = "The color of the waypoint beacon.", 620 | category = "Utilities", 621 | allowAlpha = false 622 | ) 623 | public Color utilitiesAncestralSpadeWaypointColor = Color.RED; 624 | 625 | @Property( 626 | type = PropertyType.SWITCH, 627 | name = "Parse burrow arrow", 628 | description = "Saves the direction arrow from a burrow, making it only require an extra use of Ancestral Spade. If waypoints are in the opposite direction, lower /pq values are recommended.", 629 | category = "Utilities" 630 | ) 631 | public boolean utilitiesAncestralSpadeArrow = false; 632 | 633 | @Property( 634 | type = PropertyType.SWITCH, 635 | name = "Display wishing compass uses left", 636 | description = "Displays the uses left on wishing compasses.", 637 | category = "Utilities" 638 | ) 639 | public boolean utilitiesWishingCompassUsesLeft = false; 640 | 641 | @Property( 642 | type = PropertyType.SWITCH, 643 | name = "Always display wishing compass uses left", 644 | description = "Also displays uses left on wishing compasses when they have 3 uses left.", 645 | category = "Utilities" 646 | ) 647 | public boolean utilitiesWishingCompassAlwaysUsesLeft = false; 648 | 649 | @Property( 650 | type = PropertyType.SWITCH, 651 | name = "Visible links", 652 | description = "Makes clickable links blue and underlined.", 653 | category = "Utilities" 654 | ) 655 | public boolean utilitiesVisibleLinks = false; 656 | 657 | @Property( 658 | type = PropertyType.SWITCH, 659 | name = "Colorless panes", 660 | description = "Removes the color from glass panes so glass blocks are more visible.", 661 | category = "Utilities" 662 | ) 663 | public boolean utilitiesColorlessPanes = false; 664 | 665 | @Property( 666 | type = PropertyType.SWITCH, 667 | name = "Chat in portal", 668 | description = "Lets you open and use chat inside a nether portal.", 669 | category = "Utilities" 670 | ) 671 | public boolean utilitiesPortalChat = false; 672 | 673 | @Property( 674 | type = PropertyType.SWITCH, 675 | name = "Better wither impact perspective", 676 | description = "Toggling third person view will skip the front camera if holding a wither impact weapon.", 677 | category = "Utilities" 678 | ) 679 | public boolean utilitiesWitherImpactPerspective = false; 680 | 681 | @Property( 682 | type = PropertyType.SWITCH, 683 | name = "Better perspective", 684 | description = "Makes Better wither impact perspective skip the wither impact test and will always skip the front camera.", 685 | category = "Utilities" 686 | ) 687 | public boolean utilitiesWitherImpactPerspectiveGlobal = false; 688 | 689 | @Property( 690 | type = PropertyType.SWITCH, 691 | name = "Superpairs IDs", 692 | description = "Gives superpairs item rewards SkyBlock IDs so mods like NEU and SBE can display price and resource packs can display custom textures.", 693 | category = "Utilities" 694 | ) 695 | public boolean utilitiesSuperpairsIDs = false; 696 | 697 | @Property( 698 | type = PropertyType.TEXT, 699 | name = "Share text", 700 | description = "Hold an item and type the text to show the item to other Synthesis users.", 701 | category = "Utilities", 702 | subcategory = "Share" 703 | ) 704 | public String utilitiesShareText = "[item]"; 705 | 706 | @Property( 707 | type = PropertyType.SWITCH, 708 | name = "Share scroll", 709 | description = "Scrolling while hovering a share and holding control will not scroll the chat.", 710 | category = "Utilities", 711 | subcategory = "Share" 712 | ) 713 | public boolean utilitiesShareScroll = false; 714 | 715 | @Property( 716 | type = PropertyType.SWITCH, 717 | name = "Share copy embed", 718 | description = "Clicking on shares copies a link to clipboard, that embeds an item preview on discord.", 719 | category = "Utilities", 720 | subcategory = "Share" 721 | ) 722 | public boolean utilitiesShareCopyEmbed = false; 723 | 724 | @Property( 725 | type = PropertyType.SWITCH, 726 | name = "Better bridge message", 727 | description = "Reformats guild bridge messages.", 728 | category = "Utilities", 729 | subcategory = "Bridge" 730 | ) 731 | public boolean utilitiesBridge = false; 732 | 733 | @Property( 734 | type = PropertyType.TEXT, 735 | name = "Bridge bot name", 736 | description = "The IGN of the minecraft account acting as a bridge. Case sensitive.", 737 | category = "Utilities", 738 | subcategory = "Bridge", 739 | min = 1, 740 | max = 16 741 | ) 742 | public String utilitiesBridgeBotName = "mmmmBeepBeepBeep"; 743 | 744 | @Property( 745 | type = PropertyType.TEXT, 746 | name = "Bridge message format", 747 | description = "The message that will be sent when a message is sent from discord. Use and for message sender and message. Use & for color codes.", 748 | category = "Utilities", 749 | subcategory = "Bridge" 750 | ) 751 | public String utilitiesBridgeMessageFormat = "&9[Discord] &6&r: "; 752 | 753 | @Property( 754 | type = PropertyType.BUTTON, 755 | name = "Test bridge message", 756 | description = "Send in chat a message formatted like the above format. Useful for testing that format.", 757 | category = "Utilities", 758 | subcategory = "Bridge", 759 | placeholder = "Test" 760 | ) 761 | public void utilitiesBridgeTestFormat() { 762 | Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(utilitiesBridgeMessageFormat.replaceAll("&", "§").replace("", "Luna").replace("", "This is an example message. Thank you for using Synthesis!"))); 763 | } 764 | 765 | @Property( 766 | type = PropertyType.BUTTON, 767 | name = "Color code guide", 768 | description = "Sends a chat message with all formatting codes.", 769 | category = "Utilities", 770 | subcategory = "Bridge", 771 | placeholder = "Show" 772 | ) 773 | public void utilitiesBridgeColorCodeGuide() { 774 | for (EnumChatFormatting value : EnumChatFormatting.values()) { 775 | if (value.getFriendlyName().equals("obfuscated")) { 776 | Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( "&" + value.toString().replace("§", "") + " - " + value + value.getFriendlyName())); 777 | } else { 778 | Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(value + "&" + value.toString().replace("§", "") + " - " + value.getFriendlyName())); 779 | } 780 | } 781 | } 782 | 783 | @Property( 784 | type = PropertyType.SWITCH, 785 | name = "Bridge guild chat tab", 786 | description = "If using skytils' chattabs, moves formatted bridge messages to the guild tab.", 787 | category = "Utilities", 788 | subcategory = "Bridge" 789 | ) 790 | public boolean utilitiesBridgeGuildChatTab = true; 791 | 792 | @Property( 793 | type = PropertyType.TEXT, 794 | name = "Custom cape", 795 | description = "Use someone else's optifine cape. Only you will see this! Leave empty to not use someone else's cape.", 796 | category = "Utilities", 797 | subcategory = "Optifine", 798 | min = 1, 799 | max = 16 800 | ) 801 | public String utilitiesOptifineCustomCape = ""; 802 | 803 | @Property( 804 | type = PropertyType.SWITCH, 805 | name = "Trans yeti", 806 | description = "Gives the yeti a trans cape.", 807 | category = "Utilities", 808 | subcategory = "Optifine" 809 | ) 810 | public boolean utilitiesOptifineTransYeti = true; 811 | 812 | @Property( 813 | type = PropertyType.SWITCH, 814 | name = "Trans terracotta", 815 | description = "Gives the terracotta a trans cape.", 816 | category = "Utilities", 817 | subcategory = "Optifine" 818 | ) 819 | public boolean utilitiesOptifineTransTerracotta = true; 820 | 821 | @Property( 822 | type = PropertyType.SWITCH, 823 | name = "Non binary bonzo", 824 | description = "Gives bonzo a non binary cape.", 825 | category = "Utilities", 826 | subcategory = "Optifine" 827 | ) 828 | public boolean utilitiesOptifineNonBinaryBonzo = true; 829 | 830 | @Property( 831 | type = PropertyType.SWITCH, 832 | name = "Candy cane grinch", 833 | description = "Gives the grinch a candy cane cape.", 834 | category = "Utilities", 835 | subcategory = "Optifine" 836 | ) 837 | public boolean utilitiesOptifineCandyCaneGrinch = true; 838 | 839 | @Property( 840 | type = PropertyType.SWITCH, 841 | name = "Hide santa/witch hat", 842 | description = "Hides the witch/santa hat given to players with capes on halloween/christmas.", 843 | category = "Utilities", 844 | subcategory = "Optifine" 845 | ) 846 | public boolean utilitiesOptifineHideHats = false; 847 | 848 | //PATCHER 849 | 850 | @Property( 851 | type = PropertyType.SWITCH, 852 | name = "Compact chat fix", 853 | description = "Fixes chat messages not being removed with compact chat when the chat is refreshed.", 854 | category = "Patcher" 855 | ) 856 | public boolean patcherCompactChatFix = true; 857 | 858 | @Property( 859 | type = PropertyType.SWITCH, 860 | name = "Custom image preview domains", 861 | description = "Lets you set and use custom domains for Patcher's ImagePreview. Do not add sites you do not trust. Use at own risk.", 862 | category = "Patcher" 863 | ) 864 | public boolean patcherCustomImagePreviewer = false; 865 | 866 | @Property( 867 | type = PropertyType.TEXT, 868 | name = "Custom domains", 869 | description = "Look, I'm way too lazy to store this in a json as an array or whatever. It's literally just text why would I care.", 870 | category = "Patcher", 871 | hidden = true 872 | ) 873 | public String patcherCustomDomains = ""; 874 | 875 | public Config() { 876 | super(new File(Synthesis.configLocation), "§dSynthesis", new JVMAnnotationPropertyCollector(), new CustomSortingBehavior()); 877 | initialize(); 878 | setSubcategoryDescription("Utilities", "Share", "A simple way to show your items to other people using the mod. Hold the item, type whatever \"Share text\" is and a preview for your item will be sent."); 879 | hidePropertyIf("patcherCompactChatFix", () -> !Loader.isModLoaded("patcher")); 880 | hidePropertyIf("patcherCustomImagePreviewer", () -> !Loader.isModLoaded("patcher")); 881 | hidePropertyIf("utilitiesShareScroll", () -> !Loader.isModLoaded("text_overflow_scroll")); 882 | hidePropertyIf("utilitiesWishingCompassWaypoint", () -> !Loader.isModLoaded("skytils")); 883 | addDependency("utilitiesWishingCompassWaypoint", "utilitiesWishingCompass"); 884 | addDependency("utilitiesBlockWishingCompass", "utilitiesWishingCompass"); 885 | addDependency("utilitiesContainerControl", "utilitiesContainerChat"); 886 | addDependency("cleanupDungeonBlessingMessages", "cleanupDungeonBlessingStatMessages"); 887 | addDependency("utilitiesWitherImpactPerspectiveGlobal", "utilitiesWitherImpactPerspective"); 888 | registerListener("utilitiesColorlessPanes", (z) -> Minecraft.getMinecraft().renderGlobal.loadRenderers()); 889 | } 890 | } 891 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/core/CustomSortingBehavior.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.core; 2 | 3 | import gg.essential.vigilance.data.Category; 4 | import gg.essential.vigilance.data.PropertyData; 5 | import gg.essential.vigilance.data.SortingBehavior; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.Comparator; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class CustomSortingBehavior extends SortingBehavior { 13 | 14 | @NotNull 15 | @Override 16 | public Comparator getCategoryComparator() { 17 | return (o1, o2) -> 0; 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public Comparator getPropertyComparator() { 23 | return (o1, o2) -> 0; 24 | } 25 | 26 | @NotNull 27 | @Override 28 | public Comparator>> getSubcategoryComparator() { 29 | return (o1, o2) -> 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/events/MessageSentEvent.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.events; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.Cancelable; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | @Cancelable 7 | public class MessageSentEvent extends Event { 8 | public String message; 9 | 10 | public MessageSentEvent(String message) { 11 | this.message = message; 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/events/packet/CustomChannelDuplexHandler.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.events.packet; 2 | 3 | import io.netty.channel.ChannelDuplexHandler; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelPromise; 6 | import net.minecraft.network.Packet; 7 | import net.minecraftforge.common.MinecraftForge; 8 | 9 | // https://github.com/ChatTriggers/ChatTriggers/pull/232 10 | public class CustomChannelDuplexHandler extends ChannelDuplexHandler { 11 | @Override 12 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 13 | if (msg instanceof Packet) { 14 | PacketReceivedEvent event = new PacketReceivedEvent((Packet) msg); 15 | MinecraftForge.EVENT_BUS.post(event); 16 | 17 | if (!event.isCanceled()) 18 | ctx.fireChannelRead(event.getPacket()); 19 | } 20 | } 21 | 22 | @Override 23 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { 24 | if (msg instanceof Packet) { 25 | PacketSentEvent event = new PacketSentEvent((Packet) msg); 26 | MinecraftForge.EVENT_BUS.post(event); 27 | 28 | if (!event.isCanceled()) 29 | ctx.write(event.getPacket(), promise); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/events/packet/PacketEvent.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.events.packet; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 4 | import net.minecraftforge.fml.common.network.FMLNetworkEvent; 5 | 6 | public class PacketEvent { 7 | @SubscribeEvent 8 | public void onNetworkEvent(FMLNetworkEvent.ClientConnectedToServerEvent event) { 9 | event.manager.channel().pipeline().addAfter( 10 | "fml:packet_handler", 11 | "synthesis_packet_handler", 12 | new CustomChannelDuplexHandler() 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/events/packet/PacketReceivedEvent.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.events.packet; 2 | 3 | import lombok.Getter; 4 | import net.minecraft.network.Packet; 5 | import net.minecraftforge.fml.common.eventhandler.Event; 6 | 7 | public class PacketReceivedEvent extends Event { 8 | @Getter private final Packet packet; 9 | private Boolean cancelled = false; 10 | 11 | public PacketReceivedEvent(Packet packet) { 12 | this.packet = packet; 13 | } 14 | 15 | @Override 16 | public boolean isCancelable() { 17 | return true; 18 | } 19 | 20 | @Override 21 | public boolean isCanceled() { 22 | return cancelled; 23 | } 24 | 25 | @Override 26 | public void setCanceled(boolean cancel) { 27 | cancelled = cancel; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/events/packet/PacketSentEvent.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.events.packet; 2 | 3 | import lombok.Getter; 4 | import net.minecraft.network.Packet; 5 | import net.minecraftforge.fml.common.eventhandler.Event; 6 | 7 | public class PacketSentEvent extends Event { 8 | @Getter private final Packet packet; 9 | private Boolean cancelled = false; 10 | 11 | public PacketSentEvent(Packet packet) { 12 | this.packet = packet; 13 | } 14 | 15 | @Override 16 | public boolean isCancelable() { 17 | return true; 18 | } 19 | 20 | @Override 21 | public boolean isCanceled() { 22 | return cancelled; 23 | } 24 | 25 | @Override 26 | public void setCanceled(boolean cancel) { 27 | cancelled = cancel; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/cleanup/CoopCleanup.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.cleanup; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.events.packet.PacketReceivedEvent; 6 | import com.luna.synthesis.utils.ChatLib; 7 | import com.luna.synthesis.utils.Utils; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.event.HoverEvent; 10 | import net.minecraft.network.play.server.S02PacketChat; 11 | import net.minecraft.util.ChatComponentText; 12 | import net.minecraft.util.EnumChatFormatting; 13 | import net.minecraft.util.IChatComponent; 14 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 15 | import net.minecraftforge.event.entity.player.ItemTooltipEvent; 16 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Iterator; 20 | import java.util.List; 21 | import java.util.concurrent.atomic.AtomicReference; 22 | import java.util.stream.Collectors; 23 | 24 | public class CoopCleanup { 25 | 26 | private final Config config = Synthesis.getInstance().getConfig(); 27 | private boolean onContributions = false; 28 | private boolean shouldRemove = false; 29 | 30 | private List messageQueue = new ArrayList<>(); 31 | private boolean isDividerBlock = false; 32 | private IChatComponent theMessage = null; 33 | private final AtomicReference price = new AtomicReference<>(""); 34 | 35 | // I'm deeply terrified of regexes being called way too many times, as long as the message cannot be faked or give false positives, this will have to work. 36 | @SubscribeEvent 37 | public void onTooltip(ItemTooltipEvent event) { 38 | if (config.cleanupCoopCollections == 0) return; 39 | if (config.cleanupCoopCollections == 1) { 40 | event.toolTip.removeIf(s -> EnumChatFormatting.getTextWithoutFormattingCodes(s).endsWith(": 0")); 41 | } else if (config.cleanupCoopCollections == 2) { 42 | Iterator iterator = event.toolTip.iterator(); 43 | while (iterator.hasNext()) { 44 | String actualLine = EnumChatFormatting.getTextWithoutFormattingCodes(iterator.next()); 45 | if (actualLine.equals("")) { 46 | onContributions = false; 47 | } 48 | if (onContributions) { 49 | String player = Minecraft.getMinecraft().getSession().getUsername(); 50 | if (!actualLine.contains(player)) { 51 | iterator.remove(); 52 | } 53 | } 54 | if (actualLine.startsWith("Co-op Contributions:")) { 55 | onContributions = true; 56 | } 57 | } 58 | onContributions = false; 59 | } else if (config.cleanupCoopCollections == 3) { 60 | Iterator iterator = event.toolTip.iterator(); 61 | while (iterator.hasNext()) { 62 | String actualLine = EnumChatFormatting.getTextWithoutFormattingCodes(iterator.next()); 63 | if (actualLine.startsWith("Co-op Contributions:")) { 64 | shouldRemove = true; 65 | } 66 | if (shouldRemove) { 67 | iterator.remove(); 68 | } 69 | if (actualLine.startsWith("Total Collected: ")) { 70 | shouldRemove = true; 71 | } 72 | if (actualLine.equals("")) { 73 | shouldRemove = false; 74 | } 75 | } 76 | shouldRemove = false; 77 | } 78 | } 79 | 80 | // It is not necessary to check hover action because the " » " changes color depending on party/coop member, but I realised that when this was already done so whatever 81 | @SubscribeEvent 82 | public void onChatMessage(ClientChatReceivedEvent event) { 83 | if (!config.cleanupCoopTravel) return; 84 | if (event.type != 0) return; 85 | String message = EnumChatFormatting.getTextWithoutFormattingCodes(event.message.getUnformattedText()); 86 | if (message.startsWith(" » ") && message.contains(" is traveling to ") && message.endsWith(" FOLLOW")) { 87 | if (event.message.getChatStyle() != null) { 88 | HoverEvent hover = event.message.getChatStyle().getChatHoverEvent(); 89 | if (hover == null) return; 90 | if (hover.getAction() == HoverEvent.Action.SHOW_TEXT) { 91 | String text = EnumChatFormatting.getTextWithoutFormattingCodes(hover.getValue().getUnformattedText()); 92 | if (!text.startsWith("SkyBlock Travel")) return; 93 | if (text.split("\n").length >= 2) { 94 | text = text.split("\n")[1]; 95 | } 96 | if (!text.equals("Party member")) { 97 | event.setCanceled(true); 98 | } 99 | } 100 | } 101 | } 102 | if (!messageQueue.isEmpty() && !isDividerBlock) { 103 | if (event.message.getUnformattedText().equals(messageQueue.get(0))) { 104 | messageQueue.remove(0); 105 | event.setCanceled(true); 106 | } 107 | } 108 | if (event.message.getUnformattedText().startsWith("BIN Auction started for ")) { 109 | if (!price.get().equals("")) { 110 | event.message = new ChatComponentText(event.message.getFormattedText().replace("!", "") + EnumChatFormatting.YELLOW + " at " + EnumChatFormatting.GOLD + price.get() + " coins" + EnumChatFormatting.YELLOW + "!"); 111 | price.set(""); 112 | } else { 113 | theMessage = event.message; 114 | event.setCanceled(true); 115 | } 116 | } 117 | } 118 | 119 | // Used as a way to detect bulk messages (the ones between dividers) and filter out potential messages that got caught between them. 120 | @SubscribeEvent 121 | public void onPacketReceived(PacketReceivedEvent event) { 122 | if (event.getPacket() instanceof S02PacketChat) { 123 | S02PacketChat packet = (S02PacketChat) event.getPacket(); 124 | if (packet.getType() != 2) { 125 | if (isDividerBlock) { 126 | messageQueue.add(packet.getChatComponent().getUnformattedText()); 127 | } 128 | if (Utils.isDivider(packet.getChatComponent().getUnformattedText())) { 129 | if (isDividerBlock) { 130 | isDividerBlock = false; 131 | String player = Minecraft.getMinecraft().getSession().getUsername(); 132 | messageQueue = messageQueue.stream().filter(s -> { 133 | if (Utils.isDivider(s)) return true; 134 | if (s.contains(" created a BIN auction for ") || s.contains(" created an auction for ")) { 135 | switch (config.cleanupCoopAuctionCreation) { 136 | case 0: 137 | return false; 138 | case 1: 139 | return s.contains(player); 140 | case 2: 141 | if (s.contains(player) && s.endsWith(" coins!")) { 142 | price.set(s.split(" at ")[1].replace(" coins!", "")); 143 | return true; 144 | } 145 | return false; 146 | case 3: 147 | return !s.contains(player); 148 | case 4: 149 | return true; 150 | case 5: 151 | if (s.contains(player) && s.endsWith(" coins!")) { 152 | price.set(s.split(" at ")[1].replace(" coins!", "")); 153 | } 154 | return true; 155 | } 156 | } else if (s.contains(" cancelled an auction ")) { 157 | switch (config.cleanupCoopAuctionCancellation) { 158 | case 0: 159 | return false; 160 | case 1: 161 | return s.contains(player); 162 | case 2: 163 | return !s.contains(player); 164 | case 3: 165 | return true; 166 | } 167 | } else if (s.contains(" collected an auction for ")) { 168 | switch (config.cleanupCoopAuctionCollection) { 169 | case 0: 170 | return false; 171 | case 1: 172 | return s.contains(player); 173 | case 2: 174 | return !s.contains(player); 175 | case 3: 176 | return true; 177 | } 178 | } else if (s.contains(" has set the beacon profile stat to ")) { 179 | switch (config.cleanupCoopBeaconStatChanges) { 180 | case 0: 181 | return false; 182 | case 1: 183 | return s.contains(player); 184 | case 2: 185 | return !s.contains(player); 186 | case 3: 187 | return true; 188 | } 189 | } 190 | return false; 191 | }).collect(Collectors.toList()); 192 | if (messageQueue.size() <= 2) messageQueue.clear(); 193 | if (theMessage != null && !price.get().equals("")) { 194 | Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(theMessage.getFormattedText().replace("!", "") + EnumChatFormatting.YELLOW + " at " + EnumChatFormatting.GOLD + price.get() + " coins" + EnumChatFormatting.YELLOW + "!")); 195 | theMessage = null; 196 | price.set(""); 197 | } 198 | } else { 199 | isDividerBlock = true; 200 | messageQueue.add(packet.getChatComponent().getUnformattedText()); 201 | } 202 | } 203 | } 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/cleanup/DungeonCleanup.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.cleanup; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.util.StringUtils; 6 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 7 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 8 | 9 | public class DungeonCleanup { 10 | 11 | private final Config config = Synthesis.getInstance().getConfig(); 12 | 13 | @SubscribeEvent 14 | public void onChatMessage(ClientChatReceivedEvent event) { 15 | if (event.type != 0) return; 16 | String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); 17 | if (!msg.contains(":")) { 18 | if (config.cleanupDungeonPotionEffects && msg.equals("Your active Potion Effects have been paused and stored. They will be restored when you leave Dungeons! You are not allowed to use existing Potion Effects while in Dungeons.")) { 19 | event.setCanceled(true); 20 | } 21 | if (config.cleanupDungeonSoloClassMessage) { 22 | if (msg.startsWith("Your ") && msg.endsWith(" stats are doubled because you are the only player using this class!")) { 23 | event.setCanceled(true); 24 | } else if (msg.startsWith("[Healer] ") || msg.startsWith("[Berserk] ") || msg.startsWith("[Mage] ") || msg.startsWith("[Archer] ") || msg.startsWith("[Tank] ")) { 25 | event.setCanceled(true); 26 | } 27 | } 28 | if (config.cleanupDungeonUltimateMessage && msg.endsWith(" is ready to use! Press DROP to activate it!")) { 29 | event.setCanceled(true); 30 | } 31 | if (config.cleanupDungeonBlessingStatMessages) { 32 | if ((config.cleanupDungeonBlessingMessages && (msg.startsWith("A Blessing of ") || (msg.contains(" has obtained Blessing of ") && msg.endsWith("!")))) || msg.startsWith("DUNGEON BUFF! A Blessing of ") || msg.startsWith("DUNGEON BUFF! You found a Blessing of ") || msg.startsWith(" Grants you ") || msg.startsWith(" Granted you ")) { 33 | event.setCanceled(true); 34 | } 35 | } 36 | if (config.cleanupDungeonSilverfishMessages && msg.equals("You cannot hit the silverfish while it's moving!")) { 37 | event.setCanceled(true); 38 | } 39 | if (config.cleanupDungeonKeyUsageMessages && (msg.equals("RIGHT CLICK on the BLOOD DOOR to open it. This key can only be used to open 1 door!") || msg.equals("RIGHT CLICK on a WITHER door to open it. This key can only be used to open 1 door!"))) { 40 | event.setCanceled(true); 41 | } 42 | } 43 | if (config.cleanupDungeonWatcherMessages && msg.startsWith("[BOSS] The Watcher: ") && !msg.equals("[BOSS] The Watcher: You have proven yourself. You may pass.")) { 44 | event.setCanceled(true); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/cleanup/LoreCleanup.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.cleanup; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.inventory.ContainerChest; 7 | import net.minecraft.item.ItemStack; 8 | import net.minecraft.util.StringUtils; 9 | import net.minecraftforge.event.entity.player.ItemTooltipEvent; 10 | import net.minecraftforge.fml.common.eventhandler.EventPriority; 11 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 12 | 13 | import net.minecraft.item.ItemSkull; 14 | 15 | import java.util.Iterator; 16 | 17 | public class LoreCleanup { 18 | 19 | private final Config config = Synthesis.getInstance().getConfig(); 20 | // Some fucking tasty spaghetti 21 | 22 | @SubscribeEvent(priority = EventPriority.LOW) 23 | public void onItemTooltip(ItemTooltipEvent event) { 24 | if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { 25 | ContainerChest containerChest = (ContainerChest)Minecraft.getMinecraft().thePlayer.openContainer; 26 | String title = StringUtils.stripControlCodes(containerChest.getLowerChestInventory().getDisplayName().getUnformattedText()); 27 | if (config.cleanupLoreAuctionException && (title.startsWith("Auctions") || title.endsWith("Auction View") || title.endsWith("'s Auctions"))) return; 28 | } 29 | ItemStack item = event.itemStack; 30 | if (!item.hasTagCompound() || !item.getTagCompound().hasKey("ExtraAttributes") || !item.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("id")) return; 31 | Iterator iterator = event.toolTip.iterator(); 32 | int index = 0; 33 | boolean inEnchantments = false; 34 | boolean inAbility = false; 35 | boolean petHoldingItem = false; 36 | boolean inPetsMenuAndIsAPet = ((item.getItem() instanceof ItemSkull && Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest && StringUtils.stripControlCodes(((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)).getLowerChestInventory().getDisplayName().getUnformattedText()).endsWith("Pets")) && (item.getDisplayName().matches(".+\\[Lvl \\d+\\] (?§[0-9a-fk-or]).+") || item.getDisplayName().matches(".+\\[\\d+\\] (?§[0-9a-fk-or]).+"))); 37 | String previousLine = ""; 38 | while (iterator.hasNext()) { 39 | // Thank you vanilla, very cool 40 | String line = iterator.next().replace("§5§o", ""); 41 | // GEAR SCORE, GEMSTONE SLOTS, SOULBOUND, PET STUFF 42 | if (config.cleanupPetDisplayName && inPetsMenuAndIsAPet && StringUtils.stripControlCodes(item.getDisplayName()).startsWith("[Lvl ") && StringUtils.stripControlCodes(item.getDisplayName()).contains("] ")){ 43 | item.setStackDisplayName(item.getDisplayName().replace("Lvl ", "")); 44 | } 45 | /* CONDITIONAL TO SKIP BASE CASE LINES, EDIT WITH CAUTION! -ERY */ 46 | else if (inPetsMenuAndIsAPet && (previousLine.startsWith("§6") && previousLine.contains("Held Item"))) { 47 | //(inPetsMenuAndIsAPet && (previousLine.startsWith("§6") && previousLine.contains("Held Item")) || line.matches(".*§7[a-z].*") || line.matches(".*§[abcde569].*")) //PLAN: THERE IS NONE. HYPIXEL IS SO INCONSISTENT WITH THEIR LINE SPACING I'M SURPRISED ANY OF THE UNCOMMENTED CODE I WROTE EVEN WORKS. -ERY 48 | previousLine = line; 49 | } else if (config.cleanupLorePetType > 0 && config.cleanupLorePetType < 4 && inPetsMenuAndIsAPet && line.startsWith("§8") && (line.endsWith(" Pet") || line.endsWith(" Mount") || line.endsWith(" Morph") || line.endsWith(" gain XP") || line.contains("All Skills"))) { 50 | previousLine = line; 51 | if (config.cleanupLorePetType == 3 || line.contains("All Skills")) 52 | iterator.remove(); 53 | else if (config.cleanupLorePetType == 2 && !line.contains("All Skills")) 54 | event.toolTip.set(index, line.replace("Mining ", "").replace("Combat ", "").replace("Fishing ", "").replace("Farming ", "").replace("Foraging ", "").replace("Enchanting ", "").replace("Alchemy ", "").replace("Gabagool ", "")); 55 | else if (config.cleanupLorePetType == 1) 56 | event.toolTip.set(index, line.replace(" Pet", "").replace(" Mount", "").replace(" Morph", "").replace(", feed to gain XP", "")); 57 | } else if (config.cleanupLorePetPerkName && inPetsMenuAndIsAPet && line.startsWith("§6") && !line.contains("Held Item")) { 58 | previousLine = line; 59 | iterator.remove(); 60 | } 61 | /* PLAN: SOMEHOW DETECT THE BEGINNING OF A NEW PERK DESCRIPTION AND ADD A HYPHEN TO THE BEGINNING OF IT. 62 | I ALREADY TRIED THE "inXYZ" CONDITIONAL STRATEGY AND IT WENT TERRIBLY WRONG BECAUSE, AGAIN, HYPIXEL 63 | PET MENU LORE HAS NO STANDARD CONVENTION WHATSOEVER. -ERY 64 | 65 | else if (config.cleanupLorePetPerkHyphens && inPetsMenuAndIsAPet && line.contains("§7§7") && !line.contains(":") && line.matches(".*§7§7[A-Z].*") && !previousLine.contains("Held Item")) { 66 | event.toolTip.set(index, ("§e§r§7- " + line)); 67 | previousLine = line; 68 | continue; 69 | */ 70 | else if (config.cleanupLorePetHeldItemPrefix && inPetsMenuAndIsAPet && line.contains("Held Item")) { 71 | previousLine = line; 72 | event.toolTip.set(index, line.replace("Held Item: ", "")); 73 | petHoldingItem = true; 74 | } else if (config.cleanupLorePetMaxLevel && inPetsMenuAndIsAPet && line.contains("MAX LEVEL")) { 75 | previousLine = line; 76 | iterator.remove(); 77 | } else if (config.cleanupLorePetClickToSummon && inPetsMenuAndIsAPet && line.contains("Click to summon!")) { 78 | previousLine = line; 79 | iterator.remove(); 80 | } else if (config.cleanupLorePetClickToDespawn && inPetsMenuAndIsAPet && line.contains("Click to despawn!")) { 81 | previousLine = line; 82 | iterator.remove(); 83 | } else if (config.cleanupLorePetCandiesUsed && inPetsMenuAndIsAPet && line.contains("Pet Candy Used")) { 84 | previousLine = line; 85 | // begin the very hacky solution i wrote but it works on the pets that i own so im rolling with this unless anyone has better ideas -ery 86 | int ifPetHeldItemEnabledOffset = 2; 87 | if (!config.cleanupLorePetHeldItemPrefix) 88 | if (!petHoldingItem) 89 | ifPetHeldItemEnabledOffset = 0; 90 | else 91 | ifPetHeldItemEnabledOffset = 1; 92 | else if (!petHoldingItem) 93 | ifPetHeldItemEnabledOffset = 0; 94 | // end hacky solution -ery 95 | String pluralOrSingular = "Candies"; 96 | if (line.contains("1/") && !line.contains("10/")) 97 | pluralOrSingular = "Candy"; 98 | event.toolTip.set(index + ifPetHeldItemEnabledOffset, line.replace("/10", "").replace("Pet Candy Used", pluralOrSingular).replace("(", "").replace(")", "")); 99 | } else if (config.cleanupLorePetEmptyLines && inPetsMenuAndIsAPet && line.equals("")) { 100 | previousLine = line; 101 | iterator.remove(); 102 | } 103 | /* PLAN: SOMEHOW REMOVE PROGRESS BAR WITHOUT EDGE CASES OF PROGRESS COUNT DUPLICATING ITSELF. 104 | ATTEMPTED AND FAILED BECAUSE AAAAAAAAAAAAAAAAAA -ERY 105 | 106 | else if (config.cleanupLorePetLevelProgressBar && inPetsMenuAndIsAPet && line.contains("--") && (line.contains("f-") || line.contains("2-"))) { 107 | event.toolTip.set(index, line.replaceAll("-", "")); 108 | previousLine = line; 109 | // iterator.remove(); 110 | continue; 111 | } 112 | */ 113 | /* PLAN: SOMEHOW REMOVE TEXT PRECEDING PERCENTAGE PROGRESS. 114 | ATTEMPTED AND FAILED BECAUSE AAAAAAAAAAAAAAAAAA -ERY 115 | 116 | else if (config.cleanupLorePetLevelPercent && inPetsMenuAndIsAPet && line.contains("Progress to Level")) { 117 | event.toolTip.set(index, line.replaceAll(".*Progress to Level [0-9]{1,3}.*", "% of next Lvl")); 118 | // previousLine = line; 119 | continue; 120 | } 121 | */ 122 | else if (StringUtils.stripControlCodes(line).startsWith("Gear Score: ") && config.cleanupLoreGearScore) { 123 | iterator.remove(); 124 | } else if (StringUtils.stripControlCodes(line).startsWith(" [") && config.cleanupLoreGemstoneSlots) { 125 | iterator.remove(); 126 | } else if ((line.contains("§8§l") && line.contains("*") && line.contains("8Co-op Soulbound")) && config.cleanupLoreCoopSoulbound) { 127 | iterator.remove(); 128 | } else if ((line.contains("§8§l") && line.contains("*") && line.contains("8Soulbound")) && config.cleanupLoreSoloSoulbound) { 129 | iterator.remove(); 130 | } else { 131 | // STAT BONUSES, RECOMBOBULATED TEXT 132 | if (line.contains(" ")) { 133 | for (String s : line.split(" ")) { 134 | String replacement = line.replace(s + " ", "").replace(s, ""); 135 | if (s.startsWith("§8(+") && config.cleanupLoreDungeon) { 136 | event.toolTip.set(index, replacement); 137 | line = replacement; 138 | } else if (s.startsWith("§d(+") && config.cleanupLoreGemstones) { 139 | event.toolTip.set(index, replacement); 140 | line = replacement; 141 | } else if (s.startsWith("§9(+") && config.cleanupLoreReforge) { 142 | event.toolTip.set(index, replacement); 143 | line = replacement; 144 | } else if (s.startsWith("§e(+") && config.cleanupLoreHPB) { 145 | event.toolTip.set(index, replacement); 146 | line = replacement; 147 | } else if (s.contains("§l§ka") && config.cleanupLoreRecombobulatedObfuscated) { 148 | event.toolTip.set(index, replacement); 149 | line = replacement; 150 | } 151 | } 152 | } 153 | 154 | // ENCHANTMENTS 155 | if (!StringUtils.stripControlCodes(item.getDisplayName()).equals("Enchanted Book")) { 156 | if (((line.startsWith("§9") || line.startsWith("§d§l")) && config.cleanupLoreEnchantmentDescriptions && !(inPetsMenuAndIsAPet && item.getItem() instanceof ItemSkull))) inEnchantments = true; 157 | if (inEnchantments) { 158 | if (!config.cleanupLoreEnchantments && (line.startsWith("§9") || line.startsWith("§d§l"))) { 159 | index++; 160 | continue; 161 | } 162 | if (StringUtils.stripControlCodes(line).equals("")) { 163 | iterator.remove(); 164 | continue; 165 | } 166 | inEnchantments = false; 167 | if (config.cleanupLoreEnchantments) { 168 | iterator.remove(); 169 | continue; 170 | } 171 | } 172 | } 173 | 174 | // ABILITIES 175 | if (!line.endsWith("RIGHT CLICK") && !line.endsWith("LEFT CLICK") && !line.equals("§aScroll Abilities:")) { 176 | if (config.cleanupLoreReforgeAbility && line.startsWith("§9") && line.endsWith(" Bonus")) inAbility = true; 177 | else if (config.cleanupLoreFullSetBonus && line.startsWith("§6Full Set Bonus: ")) inAbility = true; 178 | else if (config.cleanupLorePieceBonus && line.startsWith("§6Piece Bonus: ")) inAbility = true; 179 | } else if (config.cleanupLoreAbilities) { 180 | inAbility = true; 181 | } 182 | if (inAbility) { 183 | iterator.remove(); 184 | if (line.equals("")) inAbility = false; 185 | } else { 186 | index++; 187 | } 188 | } 189 | } 190 | 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/future/ChunkBorders.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.future; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.renderer.GlStateManager; 7 | import net.minecraft.client.renderer.Tessellator; 8 | import net.minecraft.client.renderer.WorldRenderer; 9 | import net.minecraft.client.renderer.vertex.DefaultVertexFormats; 10 | import net.minecraft.entity.player.EntityPlayer; 11 | import net.minecraftforge.client.event.RenderWorldLastEvent; 12 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 13 | import net.minecraftforge.fml.common.gameevent.InputEvent; 14 | import org.lwjgl.input.Keyboard; 15 | import org.lwjgl.opengl.GL11; 16 | 17 | public class ChunkBorders { 18 | 19 | private final Config config = Synthesis.getInstance().getConfig(); 20 | private boolean isToggled = false; 21 | 22 | // Directly taken from 1.12.2, translated and adapted a bit. 23 | @SubscribeEvent 24 | public void onRenderWorld(RenderWorldLastEvent event) { 25 | if (!config.futureChunkBorders) return; 26 | if (!isToggled) return; 27 | if (Minecraft.getMinecraft().thePlayer == null) return; 28 | 29 | EntityPlayer entityplayer = Minecraft.getMinecraft().thePlayer; 30 | Tessellator tessellator = Tessellator.getInstance(); 31 | WorldRenderer worldRenderer = tessellator.getWorldRenderer(); 32 | double d0 = entityplayer.lastTickPosX + (entityplayer.posX - entityplayer.lastTickPosX) * event.partialTicks; 33 | double d1 = entityplayer.lastTickPosY + (entityplayer.posY - entityplayer.lastTickPosY) * event.partialTicks; 34 | double d2 = entityplayer.lastTickPosZ + (entityplayer.posZ - entityplayer.lastTickPosZ) * event.partialTicks; 35 | double d3 = 0.0D - d1; 36 | double d4 = 256.0D - d1; 37 | GlStateManager.disableTexture2D(); 38 | GlStateManager.disableBlend(); 39 | double d5 = (entityplayer.chunkCoordX << 4) - d0; 40 | double d6 = (entityplayer.chunkCoordZ << 4) - d2; 41 | GL11.glLineWidth(1.0F); 42 | worldRenderer.begin(3, DefaultVertexFormats.POSITION_COLOR); 43 | 44 | for (int i = -16; i <= 32; i += 16) { 45 | for (int j = -16; j <= 32; j += 16) { 46 | worldRenderer.pos(d5 + i, d3, d6 + j).color(1.0F, 0.0F, 0.0F, 0.0F).endVertex(); 47 | worldRenderer.pos(d5 + i, d3, d6 + j).color(1.0F, 0.0F, 0.0F, 0.5F).endVertex(); 48 | worldRenderer.pos(d5 + i, d4, d6 + j).color(1.0F, 0.0F, 0.0F, 0.5F).endVertex(); 49 | worldRenderer.pos(d5 + i, d4, d6 + j).color(1.0F, 0.0F, 0.0F, 0.0F).endVertex(); 50 | } 51 | } 52 | 53 | for (int k = 2; k < 16; k += 2) { 54 | worldRenderer.pos(d5 + k, d3, d6).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 55 | worldRenderer.pos(d5 + k, d3, d6).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 56 | worldRenderer.pos(d5 + k, d4, d6).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 57 | worldRenderer.pos(d5 + k, d4, d6).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 58 | worldRenderer.pos(d5 + k, d3, d6 + 16.0D).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 59 | worldRenderer.pos(d5 + k, d3, d6 + 16.0D).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 60 | worldRenderer.pos(d5 + k, d4, d6 + 16.0D).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 61 | worldRenderer.pos(d5 + k, d4, d6 + 16.0D).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 62 | } 63 | 64 | for (int l = 2; l < 16; l += 2) { 65 | worldRenderer.pos(d5, d3, d6 + l).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 66 | worldRenderer.pos(d5, d3, d6 + l).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 67 | worldRenderer.pos(d5, d4, d6 + l).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 68 | worldRenderer.pos(d5, d4, d6 + l).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 69 | worldRenderer.pos(d5 + 16.0D, d3, d6 + l).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 70 | worldRenderer.pos(d5 + 16.0D, d3, d6 + l).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 71 | worldRenderer.pos(d5 + 16.0D, d4, d6 + l).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 72 | worldRenderer.pos(d5 + 16.0D, d4, d6 + l).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 73 | } 74 | 75 | for (int i1 = 0; i1 <= 256; i1 += 2) { 76 | double d7 = i1 - d1; 77 | worldRenderer.pos(d5, d7, d6).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 78 | worldRenderer.pos(d5, d7, d6).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 79 | worldRenderer.pos(d5, d7, d6 + 16.0D).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 80 | worldRenderer.pos(d5 + 16.0D, d7, d6 + 16.0D).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 81 | worldRenderer.pos(d5 + 16.0D, d7, d6).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 82 | worldRenderer.pos(d5, d7, d6).color(1.0F, 1.0F, 0.0F, 1.0F).endVertex(); 83 | worldRenderer.pos(d5, d7, d6).color(1.0F, 1.0F, 0.0F, 0.0F).endVertex(); 84 | } 85 | 86 | tessellator.draw(); 87 | GL11.glLineWidth(2.0F); 88 | worldRenderer.begin(3, DefaultVertexFormats.POSITION_COLOR); 89 | 90 | for (int j1 = 0; j1 <= 16; j1 += 16) { 91 | for (int l1 = 0; l1 <= 16; l1 += 16) { 92 | worldRenderer.pos(d5 + j1, d3, d6 + l1).color(0.25F, 0.25F, 1.0F, 0.0F).endVertex(); 93 | worldRenderer.pos(d5 + j1, d3, d6 + l1).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 94 | worldRenderer.pos(d5 + j1, d4, d6 + l1).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 95 | worldRenderer.pos(d5 + j1, d4, d6 + l1).color(0.25F, 0.25F, 1.0F, 0.0F).endVertex(); 96 | } 97 | } 98 | 99 | for (int k1 = 0; k1 <= 256; k1 += 16) { 100 | double d8 = k1 - d1; 101 | worldRenderer.pos(d5, d8, d6).color(0.25F, 0.25F, 1.0F, 0.0F).endVertex(); 102 | worldRenderer.pos(d5, d8, d6).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 103 | worldRenderer.pos(d5, d8, d6 + 16.0D).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 104 | worldRenderer.pos(d5 + 16.0D, d8, d6 + 16.0D).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 105 | worldRenderer.pos(d5 + 16.0D, d8, d6).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 106 | worldRenderer.pos(d5, d8, d6).color(0.25F, 0.25F, 1.0F, 1.0F).endVertex(); 107 | worldRenderer.pos(d5, d8, d6).color(0.25F, 0.25F, 1.0F, 0.0F).endVertex(); 108 | } 109 | 110 | tessellator.draw(); 111 | GL11.glLineWidth(1.0F); 112 | GlStateManager.enableBlend(); 113 | GlStateManager.enableTexture2D(); 114 | } 115 | 116 | // F3 + G, like in future versions of the game. Should this be configurable? Eh.. 117 | @SubscribeEvent 118 | public void onKeyPress(InputEvent.KeyInputEvent event) { 119 | if (!Keyboard.getEventKeyState()) return; 120 | if (!config.futureChunkBorders) return; 121 | if (Keyboard.isKeyDown(61) && Keyboard.getEventKey() == 34) { 122 | isToggled = !isToggled; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/AncestralSpade.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.events.packet.PacketReceivedEvent; 6 | import com.luna.synthesis.utils.ChatLib; 7 | import com.luna.synthesis.utils.Utils; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.renderer.GlStateManager; 10 | import net.minecraft.item.ItemStack; 11 | import net.minecraft.network.play.server.S2APacketParticles; 12 | import net.minecraft.util.*; 13 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 14 | import net.minecraftforge.client.event.RenderWorldLastEvent; 15 | import net.minecraftforge.event.entity.player.PlayerInteractEvent; 16 | import net.minecraftforge.event.world.WorldEvent; 17 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 18 | import net.minecraftforge.fml.common.gameevent.TickEvent; 19 | 20 | import java.awt.*; 21 | 22 | public class AncestralSpade { 23 | 24 | private final Config config = Synthesis.getInstance().getConfig(); 25 | private final ResourceLocation beaconBeam = new ResourceLocation("textures/entity/beacon_beam.png"); 26 | private boolean awaiting = false; 27 | private boolean awaitingForArrow = false; 28 | private long lastSpoon = -1L; 29 | private Vec3 pos1 = null; 30 | private Vec3 pos2 = null; 31 | private Vec3 vec1 = null; 32 | private Vec3 vec2 = null; 33 | private BlockPos solution = null; 34 | 35 | @SubscribeEvent 36 | public void onPacketReceived(PacketReceivedEvent event) { 37 | if (!config.utilitiesAncestralSpade) return; 38 | if (event.getPacket() instanceof S2APacketParticles) { 39 | S2APacketParticles packet = (S2APacketParticles) event.getPacket(); 40 | if (packet.getParticleType() == EnumParticleTypes.FIREWORKS_SPARK && packet.getXOffset() == 0 && packet.getYOffset() == 0 && packet.getZOffset() == 0) { 41 | if (packet.getParticleSpeed() == 0 && packet.getParticleCount() == 1) { 42 | if (awaiting) { 43 | if (pos1 == null) { 44 | pos1 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); 45 | awaiting = false; 46 | } else if (pos2 == null) { 47 | pos2 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); 48 | awaiting = false; 49 | } 50 | } else { 51 | if (vec1 == null && pos1 != null) { 52 | vec1 = new Vec3(packet.getXCoordinate() - pos1.xCoord, packet.getYCoordinate() - pos1.yCoord, packet.getZCoordinate() - pos1.zCoord).normalize(); 53 | } else if (vec2 == null && pos2 != null) { 54 | vec2 = new Vec3(packet.getXCoordinate() - pos2.xCoord, packet.getYCoordinate() - pos2.yCoord, packet.getZCoordinate() - pos2.zCoord).normalize(); 55 | calculateIntercept(); 56 | } 57 | } 58 | } 59 | } else if (packet.getParticleType() == EnumParticleTypes.REDSTONE && packet.getParticleSpeed() == 1 && packet.getParticleCount() == 0) { 60 | if (awaitingForArrow) { 61 | if (pos1 == null) { 62 | pos1 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); 63 | } else if (vec1 == null) { 64 | if (packet.getXCoordinate() - pos1.xCoord == 0 && packet.getZCoordinate() - pos1.zCoord == 0) return; 65 | vec1 = new Vec3(packet.getXCoordinate() - pos1.xCoord, packet.getYCoordinate() - pos1.yCoord, packet.getZCoordinate() - pos1.zCoord).normalize(); 66 | awaitingForArrow = false; 67 | } 68 | } 69 | } 70 | } 71 | } 72 | 73 | @SubscribeEvent 74 | public void onRightClick(PlayerInteractEvent event) { 75 | if (!config.utilitiesAncestralSpade) return; 76 | if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR || event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { 77 | ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); 78 | if (item == null) return; 79 | if (StringUtils.stripControlCodes(item.getDisplayName()).contains("Ancestral Spade")) { 80 | if (System.currentTimeMillis() >= lastSpoon + 3000) { 81 | if (Minecraft.getMinecraft().thePlayer.rotationPitch == 90 || Minecraft.getMinecraft().thePlayer.rotationPitch == -90) { 82 | awaiting = true; 83 | lastSpoon = System.currentTimeMillis(); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | @SubscribeEvent 91 | public void onClientTick(TickEvent.ClientTickEvent event) { 92 | if (solution != null && Minecraft.getMinecraft().thePlayer != null) { 93 | if (Math.pow(Minecraft.getMinecraft().thePlayer.posX - solution.getX(), 2) + Math.pow(Minecraft.getMinecraft().thePlayer.posZ - solution.getZ(), 2) <= 9) { 94 | solution = null; 95 | } 96 | } 97 | } 98 | 99 | @SubscribeEvent 100 | public void onChatMessage(ClientChatReceivedEvent event) { 101 | if (event.type == 2) return; 102 | if (!config.utilitiesAncestralSpade || !config.utilitiesAncestralSpadeArrow) return; 103 | String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); 104 | if (msg.startsWith("You dug out a Griffin Burrow!")) { 105 | awaitingForArrow = true; 106 | } 107 | } 108 | 109 | @SubscribeEvent 110 | public void onRenderWorld(RenderWorldLastEvent event) { 111 | if (config.utilitiesAncestralSpadeWaypoint && solution != null) { 112 | double renderPosX = Minecraft.getMinecraft().getRenderManager().viewerPosX; 113 | double renderPosY = Minecraft.getMinecraft().getRenderManager().viewerPosY; 114 | double renderPosZ = Minecraft.getMinecraft().getRenderManager().viewerPosZ; 115 | GlStateManager.pushMatrix(); 116 | GlStateManager.translate(-renderPosX, -renderPosY, -renderPosZ); 117 | Minecraft.getMinecraft().getTextureManager().bindTexture(beaconBeam); 118 | Utils.renderBeamSegment(solution.getX(), 0, solution.getZ(), event.partialTicks, 1.0, Minecraft.getMinecraft().theWorld.getTotalWorldTime(), 0, 256, config.utilitiesAncestralSpadeWaypointColor.getColorComponents(null)); 119 | GlStateManager.translate(renderPosX, renderPosY, renderPosZ); 120 | GlStateManager.popMatrix(); 121 | } 122 | } 123 | 124 | @SubscribeEvent 125 | public void onWorldLoad(WorldEvent.Load event) { 126 | pos1 = null; 127 | pos2 = null; 128 | vec1 = null; 129 | vec2 = null; 130 | awaiting = false; 131 | solution = null; 132 | } 133 | 134 | // All math in the mod is thanks to Lucy, this included, thank you, Lucy! 135 | // If you don't understand something don't blame me, I just copied her notes. 136 | // And no, you cannot expect me to do very simple math, I will simply ask the math genius when possible. 137 | private void calculateIntercept() { 138 | double p1x = pos1.xCoord; 139 | double p1z = pos1.zCoord; 140 | double v1x = vec1.xCoord; 141 | double v1z = vec1.zCoord; 142 | // 143 | double p2x = pos2.xCoord; 144 | double p2z = pos2.zCoord; 145 | double v2x = vec2.xCoord; 146 | double v2z = vec2.zCoord; 147 | double a = v1z / v1x * p1x - p1z; 148 | double b = v2z / v2x * p2x - p2z; 149 | double x = (a - b) / (v1z / v1x - v2z / v2x); 150 | double z = v1z / v1x * x - a; 151 | 152 | BlockPos solution = new BlockPos(x, 0, z); 153 | ChatLib.chat("Solution: (" + solution.getX() + ", " + solution.getZ() + ")"); 154 | this.solution = solution; 155 | pos1 = pos2 = vec1 = vec2 = null; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/BestiaryDropRate.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.GuiScreen; 7 | import net.minecraft.client.gui.inventory.GuiChest; 8 | import net.minecraft.inventory.ContainerChest; 9 | import net.minecraft.util.EnumChatFormatting; 10 | import net.minecraft.util.StringUtils; 11 | import net.minecraftforge.event.entity.player.ItemTooltipEvent; 12 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 13 | 14 | import java.util.Iterator; 15 | import java.util.concurrent.atomic.AtomicInteger; 16 | 17 | public class BestiaryDropRate { 18 | 19 | private final Config config = Synthesis.getInstance().getConfig(); 20 | 21 | @SubscribeEvent 22 | public void onItemTooltip(ItemTooltipEvent event) { 23 | if (config.utilitiesDropChanceToDropRate == 0) return; 24 | if (config.utilitiesDropChanceToDropRate == 1 && !GuiScreen.isShiftKeyDown()) return; 25 | if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) { 26 | ContainerChest chest = (ContainerChest) ((GuiChest) Minecraft.getMinecraft().currentScreen).inventorySlots; 27 | if (chest.getLowerChestInventory().getDisplayName().getUnformattedText().contains(" ➜ ")) { 28 | Iterator it = event.toolTip.iterator(); 29 | AtomicInteger i = new AtomicInteger(0); 30 | it.forEachRemaining(s -> { 31 | String line = StringUtils.stripControlCodes(s); 32 | if (line.endsWith("%)")) { 33 | try { 34 | double number = Double.parseDouble(line.split("\\(")[1].replace("%)", "")); 35 | if (number < 100) { 36 | event.toolTip.set(i.get(), s.replaceAll("\\(§a[\\d.]+%§8\\)", 37 | EnumChatFormatting.DARK_GRAY + "(" + EnumChatFormatting.GREEN + "1/" + Math.floor(10000 / number + 0.5) / 100 + EnumChatFormatting.DARK_GRAY + ")")); 38 | } 39 | } catch (NumberFormatException ignored) {} 40 | } 41 | i.getAndIncrement(); 42 | }); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/BetterWitherImpactPerspective.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 8 | import net.minecraftforge.fml.common.gameevent.InputEvent; 9 | import org.lwjgl.input.Keyboard; 10 | 11 | public class BetterWitherImpactPerspective { 12 | 13 | private final Config config = Synthesis.getInstance().getConfig(); 14 | 15 | // InputEvent has to be the absolute worst event in forge 16 | @SubscribeEvent 17 | public void onKey(InputEvent.KeyInputEvent event) { 18 | if (!config.utilitiesWitherImpactPerspective) return; 19 | if (!Keyboard.getEventKeyState()) return; 20 | if (Keyboard.getEventKey() == Minecraft.getMinecraft().gameSettings.keyBindTogglePerspective.getKeyCode()) { 21 | if (Minecraft.getMinecraft().gameSettings.thirdPersonView == 2) { 22 | if (config.utilitiesWitherImpactPerspectiveGlobal) { 23 | Minecraft.getMinecraft().gameSettings.thirdPersonView = 0; 24 | } else { 25 | ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); 26 | if (item == null) return; 27 | if (item.hasTagCompound()) { 28 | if (item.getTagCompound().hasKey("ExtraAttributes")) { 29 | if (item.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("ability_scroll")) { 30 | if (item.getTagCompound().getCompoundTag("ExtraAttributes").getTagList("ability_scroll", 8).tagCount() == 3) { 31 | Minecraft.getMinecraft().gameSettings.thirdPersonView = 0; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/ChatBridge.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.utils.Utils; 6 | import net.minecraft.event.ClickEvent; 7 | import net.minecraft.util.ChatComponentText; 8 | import net.minecraft.util.IChatComponent; 9 | import net.minecraft.util.StringUtils; 10 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 11 | import net.minecraftforge.fml.common.eventhandler.EventPriority; 12 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 13 | 14 | import java.net.URI; 15 | import java.net.URISyntaxException; 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | public class ChatBridge { 20 | 21 | private final Config config = Synthesis.getInstance().getConfig(); 22 | private final Pattern msgPattern = Pattern.compile("^Guild > (?\\[[A-Z+]+] )?(?[a-zA-Z0-9_]{3,16})(? \\[.+])?: (?.*)(?( >|:))(? .*)"); 23 | 24 | @SubscribeEvent(priority = EventPriority.HIGHEST) 25 | public void onClientChatMessage(ClientChatReceivedEvent event) { 26 | if (!config.utilitiesBridge) return; 27 | String message = StringUtils.stripControlCodes(event.message.getUnformattedText()); 28 | if (!message.startsWith("Guild > ") || !message.contains(config.utilitiesBridgeBotName)) return; 29 | Matcher matcher = msgPattern.matcher(message); 30 | if (matcher.matches() && matcher.groupCount() == 7) { 31 | String msgSender = matcher.group(2); 32 | if (msgSender.equals(config.utilitiesBridgeBotName)) { 33 | String ign = matcher.group(4); 34 | String msg = matcher.group(7); 35 | event.message = Utils.newChatWithLinks(config.utilitiesBridgeMessageFormat.replaceAll("&", "§").replace("", ign).replace("", msg)); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/ContainerChat.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.mixins.accessors.GuiRepairAccessor; 6 | import com.luna.synthesis.utils.MixinUtils; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.GuiChat; 9 | import net.minecraft.client.gui.GuiRepair; 10 | import net.minecraft.client.gui.GuiScreen; 11 | import net.minecraft.client.gui.inventory.GuiContainer; 12 | import net.minecraft.client.gui.inventory.GuiContainerCreative; 13 | import net.minecraft.util.MathHelper; 14 | import net.minecraftforge.client.event.GuiOpenEvent; 15 | import net.minecraftforge.client.event.GuiScreenEvent; 16 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 17 | import org.lwjgl.input.Keyboard; 18 | import org.lwjgl.input.Mouse; 19 | 20 | public class ContainerChat { 21 | 22 | private final Config config = Synthesis.getInstance().getConfig(); 23 | 24 | private String historyBuffer = ""; 25 | private int sentHistoryCursor = -1; 26 | 27 | // For chat transfer magic 28 | @SubscribeEvent 29 | public void onGuiOpen(GuiOpenEvent event) { 30 | if (!config.utilitiesContainerChat) return; 31 | sentHistoryCursor = Minecraft.getMinecraft().ingameGUI.getChatGUI().getSentMessages().size(); 32 | if (config.utilitiesReopenContainerChat && MixinUtils.inputField != null) { 33 | if (event.gui == null) { 34 | if (Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { 35 | if (MixinUtils.inputField.isFocused()) { 36 | event.gui = new GuiChat(MixinUtils.inputField.getText()); 37 | } 38 | } else { 39 | MixinUtils.inputField = null; 40 | } 41 | } 42 | } 43 | } 44 | 45 | // Originally in mixin, had to rewrite because SBE and Cowlection would have bad compatibility issues. 46 | // I also need to fix this working when SBE's search bar is focused, but I don't think I'll be able to do that. 47 | @SubscribeEvent 48 | public void onKeyTyped(GuiScreenEvent.KeyboardInputEvent event) { 49 | if (!(event.gui instanceof GuiContainer)) return; 50 | if (event.gui instanceof GuiContainerCreative) return; 51 | if (!config.utilitiesContainerChat) return; 52 | if (!Keyboard.getEventKeyState()) return; 53 | int keyCode = Keyboard.getEventKey(); 54 | if (MixinUtils.inputField == null) return; 55 | if (event.gui instanceof GuiRepair && ((GuiRepairAccessor) event.gui).getNameField().isFocused()) return; 56 | if (event instanceof GuiScreenEvent.KeyboardInputEvent.Pre) { 57 | if (MixinUtils.inputField.isFocused()) { 58 | if (keyCode == 1) { 59 | MixinUtils.inputField.setFocused(false); 60 | MixinUtils.inputField.setText(""); 61 | Keyboard.enableRepeatEvents(false); 62 | Minecraft.getMinecraft().ingameGUI.getChatGUI().resetScroll(); 63 | } 64 | if (keyCode != Minecraft.getMinecraft().gameSettings.keyBindScreenshot.getKeyCode()) { 65 | event.setCanceled(true); 66 | } 67 | } else { 68 | if (keyCode == Minecraft.getMinecraft().gameSettings.keyBindChat.getKeyCode()) { 69 | if (config.utilitiesContainerControl && !GuiScreen.isCtrlKeyDown()) return; 70 | if (!config.utilitiesContainerControl && GuiScreen.isCtrlKeyDown()) return; 71 | MixinUtils.inputField.setFocused(true); 72 | Keyboard.enableRepeatEvents(true); 73 | return; 74 | } else if (keyCode == Minecraft.getMinecraft().gameSettings.keyBindCommand.getKeyCode()) { 75 | MixinUtils.inputField.setText("/"); 76 | MixinUtils.inputField.setFocused(true); 77 | Keyboard.enableRepeatEvents(true); 78 | return; 79 | } 80 | } 81 | 82 | if (keyCode != 28 && keyCode != 156) { 83 | if (keyCode == 200) { 84 | getSentHistory(-1); 85 | } else if (keyCode == 208) { 86 | getSentHistory(1); 87 | } else { 88 | MixinUtils.inputField.textboxKeyTyped(Keyboard.getEventCharacter(), keyCode); 89 | } 90 | } else { 91 | if (!MixinUtils.inputField.isFocused()) return; 92 | String text = MixinUtils.inputField.getText().trim(); 93 | 94 | if (!text.isEmpty()) { 95 | event.gui.sendChatMessage(text); 96 | } 97 | sentHistoryCursor = Minecraft.getMinecraft().ingameGUI.getChatGUI().getSentMessages().size(); 98 | MixinUtils.inputField.setText(""); 99 | MixinUtils.inputField.setFocused(false); 100 | Minecraft.getMinecraft().ingameGUI.getChatGUI().resetScroll(); 101 | } 102 | } 103 | } 104 | 105 | @SubscribeEvent 106 | public void onScroll(GuiScreenEvent.MouseInputEvent.Pre event) { 107 | if (!config.utilitiesContainerChat) return; 108 | if (!(event.gui instanceof GuiContainer)) return; 109 | if (MixinUtils.inputField == null) return; 110 | if (!MixinUtils.inputField.isFocused()) return; 111 | int i = Mouse.getEventDWheel(); 112 | if (i != 0) { 113 | if (i > 1) { 114 | i = 1; 115 | } 116 | 117 | if (i < -1) { 118 | i = -1; 119 | } 120 | 121 | if (!GuiScreen.isShiftKeyDown()) { 122 | i *= 7; 123 | } 124 | 125 | Minecraft.getMinecraft().ingameGUI.getChatGUI().scroll(i); 126 | } 127 | } 128 | 129 | private void getSentHistory(int msgPos) { 130 | int i = this.sentHistoryCursor + msgPos; 131 | int j = Minecraft.getMinecraft().ingameGUI.getChatGUI().getSentMessages().size(); 132 | i = MathHelper.clamp_int(i, 0, j); 133 | 134 | if (i != this.sentHistoryCursor) { 135 | if (i == j) { 136 | this.sentHistoryCursor = j; 137 | MixinUtils.inputField.setText(this.historyBuffer); 138 | } else { 139 | if (this.sentHistoryCursor == j) { 140 | this.historyBuffer = MixinUtils.inputField.getText(); 141 | } 142 | MixinUtils.inputField.setText(Minecraft.getMinecraft().ingameGUI.getChatGUI().getSentMessages().get(i)); 143 | this.sentHistoryCursor = i; 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/SearchMode.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.mixins.accessors.GuiNewChatAccessor; 6 | import com.luna.synthesis.utils.MixinUtils; 7 | import com.luna.synthesis.utils.Utils; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.gui.ChatLine; 10 | import net.minecraft.client.gui.GuiChat; 11 | import net.minecraft.client.gui.ScaledResolution; 12 | import net.minecraft.client.gui.inventory.GuiContainer; 13 | import net.minecraft.util.ChatComponentText; 14 | import net.minecraft.util.EnumChatFormatting; 15 | import net.minecraft.util.MathHelper; 16 | import net.minecraftforge.client.event.GuiScreenEvent; 17 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 18 | import org.lwjgl.input.Keyboard; 19 | import org.lwjgl.input.Mouse; 20 | 21 | import java.util.Iterator; 22 | import java.util.List; 23 | import java.util.stream.Collectors; 24 | 25 | public class SearchMode { 26 | 27 | public static boolean isSearchMode = false; 28 | private final Config config = Synthesis.getInstance().getConfig(); 29 | 30 | @SubscribeEvent 31 | public void onKeyTyped(GuiScreenEvent.KeyboardInputEvent.Pre event) { 32 | if (!(event.gui instanceof GuiChat || (event.gui instanceof GuiContainer && config.utilitiesContainerChat && MixinUtils.inputField != null && MixinUtils.inputField.isFocused()))) return; 33 | if (!config.utilitiesChatSearchMode) return; 34 | if (!Keyboard.getEventKeyState()) return; 35 | if (Keyboard.isRepeatEvent()) return; 36 | if (Keyboard.getEventKey() == 33 && Keyboard.isKeyDown(29)) { 37 | isSearchMode = !isSearchMode; 38 | if (isSearchMode) { 39 | ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).invokeSetChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); 40 | } else { 41 | Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesissearchmode".hashCode()); 42 | } 43 | event.setCanceled(true); 44 | if (!isSearchMode) { 45 | Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); 46 | } 47 | } else if (Keyboard.getEventKey() == 1) { 48 | if (isSearchMode) { 49 | isSearchMode = false; 50 | Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesissearchmode".hashCode()); 51 | Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); 52 | } 53 | } else if (Keyboard.getEventKey() == 28 && isSearchMode) { 54 | if (!config.utilitiesChatSearchKeyRefresh) { 55 | Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); 56 | if (((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().size() == 0) { 57 | ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).invokeSetChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); 58 | } 59 | } 60 | event.setCanceled(true); 61 | } 62 | } 63 | 64 | @SubscribeEvent 65 | public void onKeyTypedPost(GuiScreenEvent.KeyboardInputEvent.Post event) { 66 | if (!(event.gui instanceof GuiChat || (event.gui instanceof GuiContainer && config.utilitiesContainerChat && MixinUtils.inputField != null && MixinUtils.inputField.isFocused()))) return; 67 | if (!Keyboard.getEventKeyState() && event.gui instanceof GuiChat) return; 68 | if (config.utilitiesChatSearchKeyRefresh && isSearchMode) { 69 | Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); 70 | if (((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().size() == 0) { 71 | ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).invokeSetChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); 72 | } 73 | } 74 | } 75 | 76 | @SubscribeEvent 77 | public void onMouseClicked(GuiScreenEvent.MouseInputEvent.Pre event) { 78 | if (!isSearchMode) return; 79 | if (!config.utilitiesChatScrollClick) return; 80 | if (Mouse.getEventButton() != 1) return; 81 | if (!Mouse.getEventButtonState()) return; 82 | int index = getChatLineIndex(Mouse.getX(), Mouse.getY()); 83 | if (index == -1) return; 84 | List chatLines = ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines(); 85 | ChatLine cl = ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().get(index); 86 | int newIndex = 0; 87 | if (chatLines.stream().map(chatLine -> chatLine.getChatComponent().equals(cl.getChatComponent())).count() > 1) { 88 | for (int i = 0; i < index; i++) { 89 | if (chatLines.get(i).getChatComponent().equals(cl.getChatComponent())) { 90 | newIndex++; 91 | } 92 | } 93 | } 94 | isSearchMode = false; 95 | Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesissearchmode".hashCode()); 96 | Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); 97 | Minecraft.getMinecraft().ingameGUI.getChatGUI().resetScroll(); 98 | chatLines = ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines(); 99 | int scrollAmount = -1; 100 | if (newIndex == 0) { 101 | scrollAmount = chatLines.stream().map(ChatLine::getChatComponent).collect(Collectors.toList()).indexOf(cl.getChatComponent()); 102 | } 103 | if (chatLines.stream().filter(chatLine -> chatLine.getChatComponent().equals(cl.getChatComponent())).count() > 1) { 104 | for (int i = 0; i < chatLines.size(); i++) { 105 | if (chatLines.get(i).getChatComponent().equals(cl.getChatComponent())) { 106 | if (newIndex == 0) { 107 | scrollAmount = i; 108 | break; 109 | } else { 110 | newIndex--; 111 | } 112 | } 113 | } 114 | } 115 | Minecraft.getMinecraft().ingameGUI.getChatGUI().scroll(scrollAmount); 116 | } 117 | 118 | private int getChatLineIndex(int mouseX, int mouseY) { 119 | if (!Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatOpen()) { 120 | return -1; 121 | } else { 122 | ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); 123 | int i = scaledresolution.getScaleFactor(); 124 | float f = Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatScale(); 125 | int j = mouseX / i - 3; 126 | int k = mouseY / i - 27; 127 | j = MathHelper.floor_float(j / f); 128 | k = MathHelper.floor_float(k / f); 129 | 130 | if (j >= 0 && k >= 0) { 131 | //int l = Minecraft.getMinecraft().ingameGUI.getChatGUI().getLineCount(); 132 | int l = Math.min(Minecraft.getMinecraft().ingameGUI.getChatGUI().getLineCount(), ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().size()); 133 | 134 | if (j <= MathHelper.floor_float(Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatWidth() / Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatScale()) && k < Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT * l + l) { 135 | int i1 = k / Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT + ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getScrollPos(); 136 | 137 | if (i1 >= 0 && i1 < ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().size()) { 138 | return i1; 139 | //return ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().get(i1); 140 | } 141 | 142 | return -1; 143 | } else { 144 | return -1; 145 | } 146 | } else { 147 | return -1; 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/Share.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.google.gson.*; 4 | import com.luna.synthesis.Synthesis; 5 | import com.luna.synthesis.core.Config; 6 | import com.luna.synthesis.events.MessageSentEvent; 7 | import com.luna.synthesis.utils.ChatLib; 8 | import com.luna.synthesis.utils.MixinUtils; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.client.gui.GuiChat; 11 | import net.minecraft.client.gui.GuiScreen; 12 | import net.minecraft.client.gui.inventory.GuiContainer; 13 | import net.minecraft.event.ClickEvent; 14 | import net.minecraft.event.HoverEvent; 15 | import net.minecraft.item.ItemStack; 16 | import net.minecraft.nbt.NBTTagCompound; 17 | import net.minecraft.nbt.NBTTagList; 18 | import net.minecraft.util.ChatComponentText; 19 | import net.minecraft.util.EnumChatFormatting; 20 | import net.minecraft.util.IChatComponent; 21 | import net.minecraft.util.StringUtils; 22 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 23 | import net.minecraftforge.client.event.GuiScreenEvent; 24 | import net.minecraftforge.fml.common.Loader; 25 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 26 | import org.apache.commons.io.IOUtils; 27 | import org.apache.http.HttpEntity; 28 | import org.apache.http.HttpResponse; 29 | import org.apache.http.client.HttpClient; 30 | import org.apache.http.client.methods.HttpGet; 31 | import org.apache.http.client.methods.HttpPost; 32 | import org.apache.http.entity.ContentType; 33 | import org.apache.http.entity.StringEntity; 34 | import org.apache.http.impl.client.HttpClients; 35 | import org.lwjgl.input.Mouse; 36 | 37 | import java.io.IOException; 38 | import java.io.InputStream; 39 | import java.io.OutputStream; 40 | import java.net.HttpURLConnection; 41 | import java.net.URL; 42 | import java.nio.charset.StandardCharsets; 43 | import java.util.*; 44 | import java.util.concurrent.atomic.AtomicReference; 45 | import java.util.regex.Matcher; 46 | import java.util.regex.Pattern; 47 | 48 | public class Share { 49 | 50 | private final Pattern shareRegexPattern = Pattern.compile("\\{SynthesisShare:([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})}", Pattern.CASE_INSENSITIVE); 51 | private final Config config = Synthesis.getInstance().getConfig(); 52 | 53 | @SubscribeEvent 54 | public void onMessageSent(MessageSentEvent event) { 55 | String message = event.message; 56 | if (message.contains(config.utilitiesShareText)) { 57 | ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); 58 | if (item == null) return; 59 | event.setCanceled(true); 60 | 61 | NBTTagCompound extraAttributes = item.getSubCompound("ExtraAttributes", false); 62 | JsonArray loreArray = new JsonArray(); 63 | NBTTagList lore = item.getSubCompound("display", false).getTagList("Lore", 8); 64 | for (int i = 0; i < lore.tagCount(); i++) { 65 | loreArray.add(new JsonPrimitive(lore.getStringTagAt(i))); 66 | } 67 | 68 | JsonObject itemJson = new JsonObject(); 69 | itemJson.add("name", new JsonPrimitive(item.getSubCompound("display", false).getString("Name"))); 70 | itemJson.add("lore", loreArray); 71 | JsonObject extraObject = new JsonObject(); 72 | if (item.hasTagCompound()) { 73 | if (item.getTagCompound().hasKey("display")) { 74 | if (item.getTagCompound().getCompoundTag("display").hasKey("color")) { 75 | extraObject.add("color", new JsonPrimitive(item.getTagCompound().getCompoundTag("display").getInteger("color"))); 76 | } 77 | } 78 | } 79 | if (extraAttributes != null && extraAttributes.hasKey("uuid")) { 80 | itemJson.add("uuid", new JsonPrimitive(extraAttributes.getString("uuid"))); 81 | } 82 | 83 | itemJson.add("extra", extraObject); 84 | 85 | JsonObject body = new JsonObject(); 86 | body.add("owner", new JsonPrimitive(Minecraft.getMinecraft().getSession().getPlayerID())); 87 | body.add("item", itemJson); 88 | 89 | (new Thread(() -> { 90 | try { 91 | URL url = new URL("https://synthesis-share.antonio32a.com/share"); 92 | HttpURLConnection http = (HttpURLConnection) url.openConnection(); 93 | http.setDoOutput(true); 94 | http.setDoInput(true); 95 | http.setRequestProperty("Content-Type", "application/json"); 96 | http.setRequestProperty("User-Agent", "SynthesisMod"); 97 | http.setRequestProperty("Accept", "application/json"); 98 | http.setRequestProperty("Method", "POST"); 99 | http.connect(); 100 | try (OutputStream os = http.getOutputStream()) { 101 | os.write(body.toString().getBytes(StandardCharsets.UTF_8)); 102 | os.close(); 103 | if (http.getResponseCode() != 200) { 104 | ChatLib.chat("Something went wrong trying to upload share. Check logs maybe?"); 105 | return; 106 | } 107 | JsonParser parser = new JsonParser(); 108 | JsonObject shareJson = parser.parse(IOUtils.toString(http.getInputStream())).getAsJsonObject(); 109 | if (!shareJson.get("success").getAsBoolean()) { 110 | ChatLib.chat("Share was not successful. Reason: " + shareJson.get("error").getAsString()); 111 | return; 112 | } 113 | 114 | String shareId = shareJson.get("share").getAsJsonObject().get("id").getAsString(); 115 | String share = "{SynthesisShare:" + shareId + "}"; 116 | //Can't write event.message because this is a thread 117 | Minecraft.getMinecraft().thePlayer.sendChatMessage(message.replace("[item]", share).replace("[share]", share)); 118 | } 119 | } catch (IOException e) { 120 | ChatLib.chat("Something went wrong trying to upload share. Check logs maybe?"); 121 | e.printStackTrace(); 122 | } 123 | })).start(); 124 | } 125 | } 126 | 127 | @SubscribeEvent 128 | public void onChatReceived(ClientChatReceivedEvent event) { 129 | if (event.type == 0 || event.type == 1) { 130 | String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); 131 | if (!msg.contains("{SynthesisShare:") || !msg.contains("}")) return; 132 | 133 | Matcher matcher = shareRegexPattern.matcher(msg); 134 | event.setCanceled(true); 135 | 136 | (new Thread(() -> { 137 | ArrayList shares = new ArrayList<>(); 138 | while (matcher.find()) { 139 | String shareId = matcher.group(1); 140 | 141 | try { 142 | URL url = new URL("https://synthesis-share.antonio32a.com/share/" + shareId); 143 | HttpURLConnection http = (HttpURLConnection) url.openConnection(); 144 | http.setDoOutput(true); 145 | http.setDoInput(true); 146 | http.setRequestProperty("User-Agent", "SynthesisMod"); 147 | http.setRequestProperty("Accept", "application/json"); 148 | http.setRequestProperty("Method", "GET"); 149 | http.connect(); 150 | try (InputStream instream = http.getInputStream()) { 151 | if (http.getResponseCode() != 200) { 152 | Minecraft.getMinecraft().thePlayer.addChatMessage(event.message); 153 | return; 154 | } 155 | JsonParser parser = new JsonParser(); 156 | JsonObject shareJson = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); 157 | if (!shareJson.get("success").getAsBoolean()) { 158 | Minecraft.getMinecraft().thePlayer.addChatMessage(event.message); 159 | return; 160 | } 161 | 162 | JsonObject shareItem = shareJson.get("share").getAsJsonObject().get("item").getAsJsonObject(); 163 | String itemName = shareItem.get("name").getAsString(); 164 | JsonArray itemLore = shareItem.get("lore").getAsJsonArray(); 165 | boolean isItemVerified = shareJson.get("share").getAsJsonObject().get("verified").getAsBoolean(); 166 | 167 | IChatComponent verifiedComponent = new ChatComponentText((isItemVerified ? EnumChatFormatting.GREEN + "✔ " : EnumChatFormatting.RED + "✖ ")); 168 | verifiedComponent.getChatStyle().setChatHoverEvent(new HoverEvent( 169 | HoverEvent.Action.SHOW_TEXT, 170 | new ChatComponentText((isItemVerified ? EnumChatFormatting.GREEN + "This item is verified!\nIt exists in the API." : EnumChatFormatting.RED + "This item is not verified!\nAPI is off or the item may not exist.")) 171 | )); 172 | 173 | AtomicReference s = new AtomicReference<>(""); 174 | if (shareItem.has("extra")) { 175 | if (shareItem.get("extra").getAsJsonObject().has("color")) { 176 | s.set(EnumChatFormatting.GRAY + "Color: #" + Integer.toHexString(shareItem.get("extra").getAsJsonObject().get("color").getAsInt()).toUpperCase() + "\n"); 177 | } 178 | } 179 | itemLore.iterator().forEachRemaining(jsonElement -> s.set(s.get() + jsonElement.getAsString() + "\n")); 180 | String shareLore = itemName + "\n" + s.get(); 181 | 182 | IChatComponent shareComponent = new ChatComponentText(EnumChatFormatting.LIGHT_PURPLE 183 | + "[Synthesis " + itemName + EnumChatFormatting.LIGHT_PURPLE + "]"); 184 | shareComponent.getChatStyle().setChatHoverEvent(new HoverEvent( 185 | HoverEvent.Action.SHOW_TEXT, 186 | new ChatComponentText(shareLore.substring(0, shareLore.length() - 1)) 187 | )).setChatClickEvent(new ClickEvent( 188 | ClickEvent.Action.RUN_COMMAND, 189 | "/ctcc https://synthesis-share.antonio32a.com/share/" + shareId + "?embed" 190 | )); 191 | verifiedComponent.appendSibling(shareComponent); 192 | shares.add(verifiedComponent); 193 | } 194 | } catch (IOException | JsonParseException e) { 195 | Minecraft.getMinecraft().thePlayer.addChatMessage(event.message); 196 | e.printStackTrace(); 197 | } 198 | } 199 | 200 | IChatComponent toSend = new ChatComponentText(""); 201 | ListIterator it = Arrays.asList(event.message.getFormattedText().split(shareRegexPattern.pattern())).listIterator(); 202 | while (it.hasNext()) { 203 | String s = it.next(); 204 | toSend.appendSibling(new ChatComponentText(s)); 205 | if (it.hasNext()) { 206 | toSend.appendSibling(shares.get(it.nextIndex() - 1)); 207 | } 208 | } 209 | 210 | Minecraft.getMinecraft().thePlayer.addChatMessage(toSend); 211 | })).start(); 212 | 213 | } 214 | } 215 | 216 | @SubscribeEvent 217 | public void onScroll(GuiScreenEvent.MouseInputEvent.Pre event) { 218 | if (!config.utilitiesShareScroll) return; 219 | if (!GuiScreen.isCtrlKeyDown()) return; 220 | if (!(event.gui instanceof GuiChat)) return; 221 | int i = Mouse.getEventDWheel(); 222 | if (i != 0) { 223 | IChatComponent comp = Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatComponent(Mouse.getX(), Mouse.getY()); 224 | if (comp != null && comp.getChatStyle().getChatHoverEvent() != null && comp.getChatStyle().getChatHoverEvent().getAction() == HoverEvent.Action.SHOW_TEXT) { 225 | event.setCanceled(true); 226 | } 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/VisibleLinks.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.event.ClickEvent; 6 | import net.minecraft.util.EnumChatFormatting; 7 | import net.minecraft.util.IChatComponent; 8 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 9 | import net.minecraftforge.fml.common.eventhandler.EventPriority; 10 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 11 | 12 | public class VisibleLinks { 13 | 14 | private final Config config = Synthesis.getInstance().getConfig(); 15 | 16 | // Low priority so it's compatible with bridge 17 | @SubscribeEvent(priority = EventPriority.LOW) 18 | public void onChatMessage(ClientChatReceivedEvent event) { 19 | if (!config.utilitiesVisibleLinks) return; 20 | if (event.type == 0 || event.type == 1) { 21 | for (IChatComponent iChatComponent : event.message.getSiblings()) { 22 | if (iChatComponent.getChatStyle().getChatClickEvent() != null) { 23 | if (iChatComponent.getChatStyle().getChatClickEvent().getAction().equals(ClickEvent.Action.OPEN_URL)) { 24 | iChatComponent.getChatStyle().setColor(EnumChatFormatting.AQUA).setUnderlined(true); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/features/utilities/WishingCompass.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.features.utilities; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.events.packet.PacketReceivedEvent; 6 | import com.luna.synthesis.utils.ChatLib; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.item.ItemStack; 9 | import net.minecraft.network.play.server.S2APacketParticles; 10 | import net.minecraft.util.BlockPos; 11 | import net.minecraft.util.EnumParticleTypes; 12 | import net.minecraft.util.StringUtils; 13 | import net.minecraft.util.Vec3; 14 | import net.minecraftforge.client.ClientCommandHandler; 15 | import net.minecraftforge.event.entity.player.PlayerInteractEvent; 16 | import net.minecraftforge.event.world.WorldEvent; 17 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 18 | 19 | public class WishingCompass { 20 | 21 | private final Config config = Synthesis.getInstance().getConfig(); 22 | private boolean awaiting = false; 23 | private long lastItem = -1L; 24 | private Vec3 pos1 = null; 25 | private Vec3 pos2 = null; 26 | private Vec3 vec1 = null; 27 | private Vec3 vec2 = null; 28 | 29 | @SubscribeEvent 30 | public void onPacketReceived(PacketReceivedEvent event) { 31 | if (!config.utilitiesWishingCompass) return; 32 | if (event.getPacket() instanceof S2APacketParticles) { 33 | S2APacketParticles packet = (S2APacketParticles) event.getPacket(); 34 | if (packet.getParticleType() == EnumParticleTypes.VILLAGER_HAPPY && packet.getParticleSpeed() == 0.0 && packet.getParticleCount() == 1.0) { 35 | if (awaiting) { 36 | if (pos1 == null) { 37 | pos1 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); 38 | awaiting = false; 39 | } else if (pos2 == null) { 40 | pos2 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); 41 | awaiting = false; 42 | } 43 | } else { 44 | if (vec1 == null && pos1 != null) { 45 | vec1 = new Vec3(packet.getXCoordinate() - pos1.xCoord, packet.getYCoordinate() - pos1.yCoord, packet.getZCoordinate() - pos1.zCoord).normalize(); 46 | } else if (vec2 == null && pos2 != null) { 47 | vec2 = new Vec3(packet.getXCoordinate() - pos2.xCoord, packet.getYCoordinate() - pos2.yCoord, packet.getZCoordinate() - pos2.zCoord).normalize(); 48 | calculateIntercept(); 49 | } 50 | } 51 | } 52 | } 53 | } 54 | 55 | @SubscribeEvent 56 | public void onRightClick(PlayerInteractEvent event) { 57 | if (!config.utilitiesWishingCompass) return; 58 | if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR || event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { 59 | ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); 60 | if (item == null) return; 61 | if (StringUtils.stripControlCodes(item.getDisplayName()).contains("Wishing Compass")) { 62 | if (config.utilitiesBlockWishingCompass && System.currentTimeMillis() - lastItem < 4000) { 63 | ChatLib.chat("Last trail hasn't disappeared yet, chill."); 64 | event.setCanceled(true); 65 | return; 66 | } 67 | awaiting = true; 68 | lastItem = System.currentTimeMillis(); 69 | } 70 | } 71 | } 72 | 73 | @SubscribeEvent 74 | public void onWorldLoad(WorldEvent.Load event) { 75 | pos1 = null; 76 | pos2 = null; 77 | vec1 = null; 78 | vec2 = null; 79 | awaiting = false; 80 | } 81 | 82 | // All math in the mod is thanks to Lucy, this included, thank you, Lucy! 83 | // If you don't understand something don't blame me, I just copied her notes. 84 | // And no, you cannot expect me to do very simple math, I will simply ask the math genius when possible. 85 | private void calculateIntercept() { 86 | double a = pos1.xCoord; 87 | double b = pos1.yCoord; 88 | double c = pos1.zCoord; 89 | double i = vec1.xCoord; 90 | double j = vec1.yCoord; 91 | double k = vec1.zCoord; 92 | // 93 | double h = pos2.xCoord; 94 | double v = pos2.yCoord; 95 | double w = pos2.zCoord; 96 | double l = vec2.xCoord; 97 | double m = vec2.yCoord; 98 | double n = vec2.zCoord; 99 | 100 | double t = ((b - v) / m - (a - h) / l) / ((i / l) - (j / m)); 101 | double s = (j * (c - w) + k * (v - b)) / (j * n - k * m); 102 | 103 | if (t < 0 || s < 0) { 104 | ChatLib.chat("Something went wrong. Did you wait until the first particle trail disappeared? Did you move from one quadrant to another?"); 105 | } else { 106 | BlockPos solution = new BlockPos((a + t * i + h + s * l) / 2, (b + t * j + v + s * m) / 2, (c + t * k + w + s * n) / 2); 107 | if (Math.abs(solution.getX() - 513) < 65 && Math.abs(solution.getZ() - 513) < 65) { 108 | ChatLib.chat("This compass points to the nucleus! You need to place crystals so the compass points somewhere else. It's also possible that the structure hasn't spawned."); 109 | } else { 110 | ChatLib.chat("Solution: (" + solution.getX() + ", " + solution.getY() + ", " + solution.getZ() + ")"); 111 | if (config.utilitiesWishingCompassWaypoint) { 112 | ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/sthw set " + solution.getX() + " " + solution.getY() + " " + solution.getZ() + " WishingCompass"); 113 | } 114 | } 115 | } 116 | 117 | pos1 = pos2 = vec1 = vec2 = null; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/managers/BackpackManager.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.managers; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonPrimitive; 7 | 8 | import java.io.*; 9 | 10 | public class BackpackManager { 11 | 12 | private JsonObject jsonObject; 13 | private File file; 14 | 15 | // Damn this is old and garbage lmao 16 | public BackpackManager(File file) { 17 | if (!file.exists()) { 18 | try { 19 | file.createNewFile(); 20 | this.file = file; 21 | createData(); 22 | } catch (IOException e) { 23 | e.printStackTrace(); 24 | } 25 | } else { 26 | try { 27 | FileReader reader = new FileReader(file); 28 | this.jsonObject = new Gson().fromJson(reader, JsonObject.class); 29 | this.file = file; 30 | reader.close(); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | } 36 | 37 | 38 | private void createData() throws IOException { 39 | JsonObject emptyData = new JsonObject(); 40 | for (int i = 1; i <= 18; i++) { 41 | JsonArray array = new JsonArray(); 42 | array.add(new JsonPrimitive("")); 43 | array.add(new JsonPrimitive(0)); 44 | emptyData.add(String.valueOf(i), array); 45 | } 46 | this.jsonObject = emptyData; 47 | saveData(); 48 | } 49 | 50 | private void saveData() { 51 | try { 52 | FileWriter writer = new FileWriter(this.file); 53 | new Gson().toJson(this.jsonObject, writer); 54 | writer.close(); 55 | } catch (IOException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | 60 | public void modifyData(String key, String name, int meta) { 61 | JsonArray array = new JsonArray(); 62 | array.add(new JsonPrimitive(name)); 63 | array.add(new JsonPrimitive(meta)); 64 | this.jsonObject.add(key, array); 65 | saveData(); 66 | } 67 | 68 | public String getName(String key) { 69 | if (this.jsonObject.has(key)) { 70 | return this.jsonObject.get(key).getAsJsonArray().get(0).getAsString(); 71 | } else { 72 | return ""; 73 | } 74 | } 75 | 76 | public int getMeta(String key) { 77 | if (this.jsonObject.has(key)) { 78 | return this.jsonObject.get(key).getAsJsonArray().get(1).getAsInt(); 79 | } else { 80 | return 0; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/managers/MathManager.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.managers; 2 | 3 | public class MathManager { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/BlockStainedGlassPaneMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import net.minecraft.block.BlockPane; 5 | import net.minecraft.block.BlockStainedGlassPane; 6 | import net.minecraft.block.material.Material; 7 | import net.minecraft.block.properties.PropertyEnum; 8 | import net.minecraft.block.state.IBlockState; 9 | import net.minecraft.item.EnumDyeColor; 10 | import net.minecraft.util.BlockPos; 11 | import net.minecraft.util.EnumFacing; 12 | import net.minecraft.world.IBlockAccess; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | 16 | @Mixin(BlockStainedGlassPane.class) 17 | public class BlockStainedGlassPaneMixin extends BlockPane { 18 | 19 | protected BlockStainedGlassPaneMixin(Material materialIn, boolean canDrop) { 20 | super(materialIn, canDrop); 21 | } 22 | 23 | @Shadow 24 | public static final PropertyEnum COLOR = PropertyEnum.create("color", EnumDyeColor.class); 25 | 26 | @Override 27 | public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) { 28 | if (Synthesis.getInstance() != null && Synthesis.getInstance().getConfig() != null) { 29 | if (Synthesis.getInstance().getConfig().utilitiesColorlessPanes) { 30 | return state.withProperty(NORTH, canPaneConnectTo(worldIn, pos, EnumFacing.NORTH)) 31 | .withProperty(SOUTH, canPaneConnectTo(worldIn, pos, EnumFacing.SOUTH)) 32 | .withProperty(WEST, canPaneConnectTo(worldIn, pos, EnumFacing.WEST)) 33 | .withProperty(EAST, canPaneConnectTo(worldIn, pos, EnumFacing.EAST)) 34 | .withProperty(COLOR, EnumDyeColor.SILVER); 35 | } 36 | } 37 | return super.getActualState(state, worldIn, pos); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/ContainerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.inventory.Container; 7 | import net.minecraft.inventory.ContainerChest; 8 | import net.minecraft.item.ItemStack; 9 | import net.minecraft.nbt.NBTTagCompound; 10 | import net.minecraft.nbt.NBTTagInt; 11 | import net.minecraft.nbt.NBTTagString; 12 | import net.minecraft.util.StringUtils; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.ModifyArg; 16 | 17 | @Mixin(Container.class) 18 | public class ContainerMixin { 19 | 20 | private final Config config = Synthesis.getInstance().getConfig(); 21 | 22 | @ModifyArg(method = {"putStackInSlot", "putStacksInSlots"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/Slot;putStack(Lnet/minecraft/item/ItemStack;)V")) 23 | public ItemStack overridePutStack(ItemStack in) { 24 | if (!config.utilitiesSuperpairsIDs) return in; 25 | if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { 26 | ContainerChest containerChest = (ContainerChest) Minecraft.getMinecraft().thePlayer.openContainer; 27 | String title = StringUtils.stripControlCodes(containerChest.getLowerChestInventory().getDisplayName().getUnformattedText()); 28 | if (!title.startsWith("Superpairs (")) return in; 29 | if (in == null) return in; 30 | String itemName = StringUtils.stripControlCodes(in.getDisplayName()); 31 | if (itemName.equals("Experiment the Fish")) return in; 32 | 33 | if (!in.getTagCompound().hasKey("ExtraAttributes")) { 34 | in.getTagCompound().setTag("ExtraAttributes", new NBTTagCompound()); 35 | } 36 | NBTTagCompound ea = in.getTagCompound().getCompoundTag("ExtraAttributes"); 37 | 38 | if (itemName.startsWith("+")) { 39 | if (itemName.endsWith(" Enchanting Exp")) { 40 | ea.setTag("id", new NBTTagString("ENCHANTING_EXPERIENCE")); 41 | } else if (itemName.endsWith(" XP")) { 42 | ea.setTag("id", new NBTTagString("POWER_UP_EXPERIENCE")); 43 | } 44 | } 45 | 46 | switch (itemName) { 47 | case "Gained +3 Clicks": 48 | ea.setTag("id", new NBTTagString("POWER_UP_EXTRA_CLICKS")); 49 | break; 50 | case "Instant Find": 51 | ea.setTag("id", new NBTTagString("POWER_UP_INSTANT_FIND")); 52 | break; 53 | case "Titanic Experience Bottle": 54 | ea.setTag("id", new NBTTagString("TITANIC_EXP_BOTTLE")); 55 | break; 56 | case "Grand Experience Bottle": 57 | ea.setTag("id", new NBTTagString("GRAND_EXP_BOTTLE")); 58 | break; 59 | case "Experience Bottle": 60 | ea.setTag("id", new NBTTagString("EXP_BOTTLE")); 61 | break; 62 | case "Enchanted Book": 63 | ea.setTag("id", new NBTTagString("ENCHANTED_BOOK")); 64 | ea.setTag("enchantments", new NBTTagCompound()); 65 | String enchant = StringUtils.stripControlCodes(in.getSubCompound("display", false).getTagList("Lore", 8).getStringTagAt(2)); 66 | String enchantName = ""; 67 | for (int i = 0; i < enchant.split(" ").length - 1; i++) { 68 | enchantName += enchant.split(" ")[i]; 69 | if (i != enchant.split(" ").length - 2) { 70 | enchantName += "_"; 71 | } 72 | } 73 | enchantName = enchantName.toLowerCase(); 74 | ea.getCompoundTag("enchantments").setTag(enchantName, new NBTTagInt(in.stackSize)); 75 | break; 76 | } 77 | } 78 | return in; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/EntityPlayerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.entity.EntityLivingBase; 6 | import net.minecraft.entity.monster.EntityZombie; 7 | import net.minecraft.entity.player.EntityPlayer; 8 | import net.minecraft.world.World; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Mixin(EntityPlayer.class) 15 | public abstract class EntityPlayerMixin extends EntityLivingBase { 16 | 17 | private final Config config = Synthesis.getInstance().getConfig(); 18 | 19 | public EntityPlayerMixin(World worldIn) { 20 | super(worldIn); 21 | } 22 | 23 | @Inject(method = "isEntityInsideOpaqueBlock", at = @At("HEAD"), cancellable = true) 24 | public void isEntityInsideOpaqueBlock(CallbackInfoReturnable cir) { 25 | if (config.utilitiesArmadilloFix && this.isRiding() && this.ridingEntity instanceof EntityZombie) { 26 | cir.setReturnValue(false); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/EntityPlayerSPMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.entity.EntityPlayerSP; 6 | import net.minecraft.client.gui.GuiChat; 7 | import net.minecraft.client.gui.GuiScreen; 8 | import net.minecraft.client.gui.inventory.GuiContainer; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | @Mixin(EntityPlayerSP.class) 14 | public class EntityPlayerSPMixin { 15 | 16 | private final Config config = Synthesis.getInstance().getConfig(); 17 | 18 | // It's possible (and very easy) to make portals never close any gui (since it closes it only clientside, server would not care) 19 | // BUT I'm not sure if Hypixel would like that/there's any potential false bans SO only chat for now. 20 | @Redirect(method = "onLivingUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiScreen;doesGuiPauseGame()Z")) 21 | public boolean overrideDoesGuiPauseGame(GuiScreen gui) { 22 | if (config.utilitiesPortalChat) { 23 | return gui.doesGuiPauseGame() || gui instanceof GuiChat; //|| gui instanceof GuiContainer; 24 | } 25 | return gui.doesGuiPauseGame(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/GuiContainerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.utils.MixinUtils; 6 | import com.luna.synthesis.utils.ReflectionUtils; 7 | import net.minecraft.client.gui.*; 8 | import net.minecraft.client.gui.inventory.GuiContainer; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | @Mixin(GuiContainer.class) 18 | public class GuiContainerMixin extends GuiScreen { 19 | 20 | private final Config config = Synthesis.getInstance().getConfig(); 21 | private final boolean patcherClearField = ReflectionUtils.getPatcherChatField(); 22 | 23 | private GuiTextField inputField; 24 | 25 | @Inject(method = "initGui", at = @At("RETURN")) 26 | public void initGui(CallbackInfo ci) { 27 | if (config.utilitiesContainerChat) { 28 | this.inputField = new GuiTextField(0, this.fontRendererObj, 4, this.height - 12, this.width - 4, 12); 29 | this.inputField.setMaxStringLength(256); 30 | this.inputField.setEnableBackgroundDrawing(false); 31 | this.inputField.setText(config.utilitiesTransferContainerChat && MixinUtils.inputField != null && MixinUtils.inputField.isFocused() && !MixinUtils.inputField.getText().equals("") ? MixinUtils.inputField.getText() : ""); 32 | this.inputField.setFocused(MixinUtils.inputField != null && MixinUtils.inputField.isFocused()); 33 | this.inputField.setCanLoseFocus(false); 34 | MixinUtils.inputField = this.inputField; 35 | if (config.utilitiesResizeContainerChat) { 36 | mc.ingameGUI.getChatGUI().refreshChat(); 37 | } 38 | } 39 | } 40 | 41 | @Inject(method = "updateScreen", at = @At("RETURN")) 42 | public void updateScreen(CallbackInfo ci) { 43 | if (config.utilitiesContainerChat) { 44 | this.inputField.updateCursorCounter(); 45 | } 46 | } 47 | 48 | @Inject(method = "drawScreen", at = @At(value = "INVOKE", target = "net/minecraft/client/gui/GuiScreen.drawScreen(IIF)V")) 49 | public void drawScreen(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) { 50 | if (config.utilitiesContainerChat && this.inputField.isFocused()) { 51 | if (!patcherClearField) { 52 | Gui.drawRect(2, this.height - 14, this.width - 2, this.height - 2, Integer.MIN_VALUE); 53 | } 54 | this.inputField.drawTextBox(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/GuiNewChatMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.luna.synthesis.Synthesis; 5 | import com.luna.synthesis.core.Config; 6 | import com.luna.synthesis.features.utilities.SearchMode; 7 | import com.luna.synthesis.mixins.accessors.GuiChatAccessor; 8 | import com.luna.synthesis.mixins.accessors.GuiContainerAccessor; 9 | import com.luna.synthesis.utils.MixinUtils; 10 | import com.luna.synthesis.utils.Utils; 11 | import net.minecraft.client.Minecraft; 12 | import net.minecraft.client.gui.*; 13 | import net.minecraft.client.gui.inventory.GuiContainer; 14 | import net.minecraft.util.ChatComponentText; 15 | import net.minecraft.util.EnumChatFormatting; 16 | import net.minecraft.util.IChatComponent; 17 | import net.minecraft.util.StringUtils; 18 | import org.spongepowered.asm.mixin.Final; 19 | import org.spongepowered.asm.mixin.Mixin; 20 | import org.spongepowered.asm.mixin.Shadow; 21 | import org.spongepowered.asm.mixin.injection.*; 22 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 23 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 24 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 25 | 26 | import java.util.List; 27 | 28 | @Mixin(GuiNewChat.class) 29 | public abstract class GuiNewChatMixin { 30 | 31 | private boolean needsRefresh = false; 32 | @Final @Shadow private final List chatLines = Lists.newArrayList(); 33 | @Final @Shadow private final List drawnChatLines = Lists.newArrayList(); 34 | @Shadow public abstract void deleteChatLine(int id); 35 | @Shadow protected abstract void setChatLine(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly); 36 | private final Config config = Synthesis.getInstance().getConfig(); 37 | 38 | @Inject(method = "clearChatMessages", at = @At(value = "INVOKE", target = "Ljava/util/List;clear()V", ordinal = 2), cancellable = true) 39 | public void clearChatMessages(CallbackInfo ci) { 40 | if (Synthesis.getInstance() != null && Synthesis.getInstance().getConfig() != null && Synthesis.getInstance().getConfig().futureKeepSentMessages) { 41 | ci.cancel(); 42 | } 43 | } 44 | 45 | @Inject(method = "getChatWidth", at = @At("HEAD"), cancellable = true) 46 | public void getChatWidth(CallbackInfoReturnable cir) { 47 | if (Synthesis.getInstance() != null && Synthesis.getInstance().getConfig() != null && Synthesis.getInstance().getConfig().utilitiesContainerChat && Minecraft.getMinecraft().currentScreen instanceof GuiContainer && Synthesis.getInstance().getConfig().utilitiesResizeContainerChat) { 48 | cir.setReturnValue(((GuiContainerAccessor) Minecraft.getMinecraft().currentScreen).getGuiLeft()); 49 | needsRefresh = true; 50 | } else { 51 | if (needsRefresh) { 52 | needsRefresh = false; 53 | Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); 54 | } 55 | } 56 | } 57 | 58 | @Inject(method = "getChatOpen", at = @At("HEAD"), cancellable = true) 59 | public void getChatOpen(CallbackInfoReturnable cir) { 60 | if (Synthesis.getInstance() != null && Synthesis.getInstance().getConfig() != null && Synthesis.getInstance().getConfig().utilitiesContainerChat && Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { 61 | if (MixinUtils.inputField != null && MixinUtils.inputField.isFocused()) { 62 | cir.setReturnValue(true); 63 | } 64 | } 65 | } 66 | 67 | // A way to "continue" in loops from inside a mixin. Kinda proud of this one ngl, fixes lag when searching for a lot of lines, mostly with Patcher's void chat. 68 | @ModifyVariable(method = "refreshChat", at = @At(value = "INVOKE", target = "Ljava/util/List;get(I)Ljava/lang/Object;", shift = At.Shift.BEFORE), index = 1) 69 | public int i(int in) { 70 | GuiScreen gui = Minecraft.getMinecraft().currentScreen; 71 | if (SearchMode.isSearchMode && ((gui instanceof GuiChat) || (gui instanceof GuiContainer && config.utilitiesContainerChat && MixinUtils.inputField != null && MixinUtils.inputField.isFocused()))) { 72 | GuiTextField input = gui instanceof GuiChat ? ((GuiChatAccessor) gui).getInputField() : MixinUtils.inputField; 73 | if (!input.getText().equals("")) { 74 | String line = StringUtils.stripControlCodes(this.chatLines.get(in).getChatComponent().getUnformattedText()).toLowerCase(); 75 | if (!line.contains(input.getText().toLowerCase()) || !line.equals("search mode on")) { 76 | for (int i = in; i >= 0; i--) { 77 | String line2 = StringUtils.stripControlCodes(this.chatLines.get(i).getChatComponent().getUnformattedText()).toLowerCase(); 78 | if (line2.contains(input.getText().toLowerCase()) || line2.equals("search mode on")) { 79 | return i; 80 | } 81 | } 82 | return -1; 83 | } 84 | return in; 85 | } 86 | } 87 | return in; 88 | } 89 | 90 | // This just here so it's possible to "continue" in the last iteration of the loop 91 | @Inject(method = "refreshChat", at = @At(value = "INVOKE", target = "Ljava/util/List;get(I)Ljava/lang/Object;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) 92 | public void refreshChat(CallbackInfo ci, int i) { 93 | if (i == -1) { 94 | ci.cancel(); 95 | } 96 | } 97 | 98 | @Inject(method = "setChatLine", at = @At("HEAD"), cancellable = true) 99 | public void setChatLine(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly, CallbackInfo ci) { 100 | if (SearchMode.isSearchMode && Minecraft.getMinecraft().currentScreen instanceof GuiChat) { 101 | GuiTextField input = ((GuiChatAccessor) Minecraft.getMinecraft().currentScreen).getInputField(); 102 | String text = chatComponent.getUnformattedText().toLowerCase(); 103 | if (!input.getText().equals("") && !text.contains(input.getText().toLowerCase()) && !displayOnly) { 104 | this.chatLines.add(0, new ChatLine(updateCounter, chatComponent, chatLineId)); 105 | ci.cancel(); 106 | } 107 | } 108 | } 109 | 110 | // The section below is used so the SEARCH MODE ON message always stays at the bottom of the chat 111 | 112 | // Fix for refreshChat deleting messages with same id? For no reason either?? 113 | // If you're not using the mod, go to a hub and tab player's names so the message of potential players shows up 114 | // Then, go to chat options and modify any setting, like opacity, doesn't matter if end value is the same, it just has to be changed 115 | // THE MESSAGE WILL DISAPPEAR, FOR NO REASON EITHER, WHAT THE FWICK 116 | @Redirect(method = "setChatLine", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;deleteChatLine(I)V")) 117 | public void deleteChatLine(GuiNewChat chat, int id, IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly) { 118 | if (!displayOnly) { 119 | this.deleteChatLine(id); 120 | } 121 | } 122 | 123 | @ModifyArg(method = "setChatLine", at = @At(value = "INVOKE", target = "Ljava/util/List;add(ILjava/lang/Object;)V", ordinal = 0)) 124 | public int modifyIndex(int in, Object line) { 125 | ChatLine cl = (ChatLine) line; 126 | if (SearchMode.isSearchMode && !cl.getChatComponent().getFormattedText().contains(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON")) { 127 | if (this.drawnChatLines.size() == 0) { 128 | this.deleteChatLine("synthesissearchmode".hashCode()); 129 | this.setChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); 130 | } 131 | return 1; 132 | } 133 | return in; 134 | } 135 | 136 | // For reforge message cleanup - There's probably a better way to do this, but I'm blind 137 | // Also regexes wack, you know how it goes with me and regexes 138 | @ModifyArg(method = "printChatMessage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;printChatMessageWithOptionalDeletion(Lnet/minecraft/util/IChatComponent;I)V"), index = 1) 139 | public int overrideChatId(IChatComponent chatComponent, int in) { 140 | if (config.cleanupChatOldReforgeMessages) { 141 | String msg = StringUtils.stripControlCodes(chatComponent.getUnformattedText()); 142 | // Why must I be punished like this. 143 | // What have I done to deserve this. 144 | // Luna from the future (10 minutes after starting to code this): I should have done this with like 5 regexes holy shit this is annoying 145 | // I have no clue what I did here, but I indeed regret it now, months after the fact, now that I have to change this. 146 | if ((msg.startsWith("You reforged your ") && msg.contains(" into a ") && msg.endsWith("!")) || 147 | (msg.startsWith("You applied the ") && msg.contains(" reforge to your ") && msg.endsWith("!")) || 148 | (msg.startsWith("You selected the ") && msg.endsWith(" power for your Accessory Bag!"))) { 149 | return "synthesisreforgemessagecleanup".hashCode(); 150 | } 151 | } 152 | return in; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/GuiPlayerTabOverlayMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.gui.GuiPlayerTabOverlay; 6 | import net.minecraft.util.ChatComponentText; 7 | import net.minecraft.util.IChatComponent; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 11 | 12 | @Mixin(GuiPlayerTabOverlay.class) 13 | public class GuiPlayerTabOverlayMixin { 14 | 15 | private final Config config = Synthesis.getInstance().getConfig(); 16 | 17 | // mhm tasty spaghetti 18 | 19 | @ModifyVariable(method = "setFooter", at = @At("HEAD"), argsOnly = true) 20 | public IChatComponent overrideFooter(IChatComponent in) { 21 | if (config.cleanupTablistFooter) { 22 | String s = in.getFormattedText() 23 | .replace("\n§r§r§r§r§s§r\n§r§r§aRanks, Boosters & MORE! §r§c§lSTORE.HYPIXEL.NET§r", "") 24 | .replace("§r§aRanks, Boosters & MORE! §r§c§lSTORE.HYPIXEL.NET§r", ""); 25 | return s.length() == 0 ? null : new ChatComponentText(s); 26 | } 27 | return in; 28 | } 29 | 30 | @ModifyVariable(method = "setHeader", at = @At("HEAD"), argsOnly = true) 31 | public IChatComponent overrideHeader(IChatComponent in) { 32 | if (config.cleanupTablistHeader) { 33 | return null; 34 | } 35 | return in; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/GuiScreenMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.events.MessageSentEvent; 4 | import net.minecraft.client.gui.GuiScreen; 5 | import net.minecraftforge.common.MinecraftForge; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(GuiScreen.class) 13 | public class GuiScreenMixin { 14 | 15 | private String newMessage = ""; 16 | 17 | @Inject(method = "sendChatMessage(Ljava/lang/String;)V", at = @At("HEAD"), cancellable = true) 18 | public void onMessageSent(String message, CallbackInfo ci) { 19 | MessageSentEvent event = new MessageSentEvent(message); 20 | MinecraftForge.EVENT_BUS.post(event); 21 | 22 | if (event.isCanceled()) { 23 | ci.cancel(); 24 | } else if (!event.message.equals(message)) { 25 | newMessage = event.message; 26 | } 27 | } 28 | 29 | @ModifyVariable(method = "sendChatMessage(Ljava/lang/String;)V", at = @At("HEAD")) 30 | public String overrideMessageSent(String msg) { 31 | if (!newMessage.equals("")) { 32 | msg = newMessage; 33 | newMessage = ""; 34 | } 35 | return msg; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/RenderItemMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.managers.BackpackManager; 6 | import com.luna.synthesis.utils.MixinUtils; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.FontRenderer; 9 | import net.minecraft.client.renderer.GlStateManager; 10 | import net.minecraft.client.renderer.ItemModelMesher; 11 | import net.minecraft.client.renderer.entity.RenderItem; 12 | import net.minecraft.client.resources.model.IBakedModel; 13 | import net.minecraft.init.Items; 14 | import net.minecraft.inventory.ContainerChest; 15 | import net.minecraft.item.Item; 16 | import net.minecraft.item.ItemStack; 17 | import net.minecraft.nbt.NBTTagCompound; 18 | import net.minecraft.util.StringUtils; 19 | import org.spongepowered.asm.mixin.Mixin; 20 | import org.spongepowered.asm.mixin.injection.*; 21 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 22 | 23 | import java.util.Iterator; 24 | import java.util.concurrent.atomic.AtomicReference; 25 | 26 | @Mixin(RenderItem.class) 27 | public class RenderItemMixin { 28 | 29 | private final Config config = Synthesis.getInstance().getConfig(); 30 | 31 | // Might make these two onto a forge event because they're very cool 32 | @Redirect(method = "renderItemIntoGUI", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemModelMesher;getItemModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/resources/model/IBakedModel;")) 33 | public IBakedModel iBakedModel(ItemModelMesher imm, ItemStack stack) { 34 | String name = StringUtils.stripControlCodes(stack.getDisplayName()); 35 | if (config.utilitiesBackpackRetexturing && name.startsWith("Backpack Slot ")) { 36 | String number = name.replaceAll("Backpack Slot ", ""); 37 | BackpackManager bpm = Synthesis.getInstance().getBackpackManager(); 38 | if (!bpm.getName(number).equals("")) { 39 | return MixinUtils.getItemModel(imm, Item.getByNameOrId(bpm.getName(number)), bpm.getMeta(number)); 40 | } 41 | } 42 | return imm.getItemModel(stack); 43 | } 44 | 45 | @Inject(method = "renderItemOverlayIntoGUI", at = @At(value = "JUMP", ordinal = 1, shift = At.Shift.BEFORE), cancellable = true) 46 | public void renderItemOverlayIntoGUI(FontRenderer fr, ItemStack stack, int xPosition, int yPosition, String text, CallbackInfo ci) { 47 | if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { 48 | ContainerChest containerChest = (ContainerChest) Minecraft.getMinecraft().thePlayer.openContainer; 49 | String title = StringUtils.stripControlCodes(containerChest.getLowerChestInventory().getDisplayName().getUnformattedText()); 50 | if (config.utilitiesPerkLevelDisplay && title.equals("Heart of the Mountain")) { 51 | if (stack.getItem() == Items.emerald || (config.utilitiesMaxPerkLevelDisplay && stack.getItem() == Items.diamond)) { 52 | String level = StringUtils.stripControlCodes(stack.getTooltip(Minecraft.getMinecraft().thePlayer, true).get(1)); 53 | if (level.startsWith("Level ")) { 54 | level = level.replaceAll("Level ", ""); 55 | } else { 56 | return; 57 | } 58 | if (level.contains("/")) { 59 | level = level.split("/")[0]; 60 | } 61 | if (level.equals("1")) return; 62 | drawStringAsStackSize(level, xPosition, yPosition); 63 | ci.cancel(); 64 | } 65 | } else if (config.utilitiesBestiaryGlance && (title.equals("Bestiary") || title.contains(" ➜ "))) { 66 | if (StringUtils.stripControlCodes(stack.getDisplayName()).startsWith("Bestiary Milestone ")) { 67 | String level = StringUtils.stripControlCodes(stack.getDisplayName()).replace("Bestiary Milestone ", ""); 68 | drawStringAsStackSize(level, xPosition, yPosition); 69 | ci.cancel(); 70 | } else if (stack == containerChest.getInventory().get(52)) { 71 | ItemStack bestiary = containerChest.getInventory().get(51); 72 | if (bestiary == null || !bestiary.getDisplayName().contains("Bestiary Milestone ")) return; 73 | AtomicReference progress = new AtomicReference<>(""); 74 | Iterator it = bestiary.getTooltip(Minecraft.getMinecraft().thePlayer, false).iterator(); 75 | it.forEachRemaining(s -> { 76 | String line = StringUtils.stripControlCodes(s); 77 | if (line.endsWith("/10")) { 78 | progress.set(line.split(" ")[line.split(" ").length - 1].replace("/10", "")); 79 | } 80 | }); 81 | if (progress.get().equals("")) return; 82 | drawStringAsStackSize(progress.get(), xPosition, yPosition); 83 | ci.cancel(); 84 | } 85 | } 86 | } 87 | if (config.utilitiesWishingCompassUsesLeft) { 88 | if (stack != null && stack.getDisplayName().contains("Wishing Compass")) { 89 | NBTTagCompound tag = stack.getTagCompound(); 90 | if (tag.hasKey("ExtraAttributes")) { 91 | if (tag.getCompoundTag("ExtraAttributes").hasKey("wishing_compass_uses")) { 92 | drawStringAsStackSize(String.valueOf(3 - tag.getCompoundTag("ExtraAttributes").getInteger("wishing_compass_uses")), xPosition, yPosition); 93 | } else { 94 | if (config.utilitiesWishingCompassAlwaysUsesLeft) { 95 | drawStringAsStackSize("3", xPosition, yPosition); 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | private void drawStringAsStackSize(String text, int xPosition, int yPosition) { 104 | GlStateManager.disableLighting(); 105 | GlStateManager.disableDepth(); 106 | GlStateManager.disableBlend(); 107 | Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(text, (float)(xPosition + 19 - 2 - Minecraft.getMinecraft().fontRendererObj.getStringWidth(text)), (float)(yPosition + 6 + 3), 16777215); 108 | GlStateManager.enableLighting(); 109 | GlStateManager.enableDepth(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/accessors/GuiChatAccessor.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.accessors; 2 | 3 | import net.minecraft.client.gui.GuiChat; 4 | import net.minecraft.client.gui.GuiTextField; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(GuiChat.class) 9 | public interface GuiChatAccessor { 10 | 11 | @Accessor GuiTextField getInputField(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/accessors/GuiContainerAccessor.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.accessors; 2 | 3 | import net.minecraft.client.gui.inventory.GuiContainer; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(GuiContainer.class) 8 | public interface GuiContainerAccessor { 9 | 10 | @Accessor int getGuiLeft(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/accessors/GuiNewChatAccessor.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.accessors; 2 | 3 | import net.minecraft.client.gui.ChatLine; 4 | import net.minecraft.client.gui.GuiNewChat; 5 | import net.minecraft.util.IChatComponent; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | import org.spongepowered.asm.mixin.gen.Invoker; 10 | 11 | import java.util.List; 12 | 13 | @Mixin(GuiNewChat.class) 14 | public interface GuiNewChatAccessor { 15 | 16 | @Accessor List getChatLines(); 17 | @Accessor List getDrawnChatLines(); 18 | @Accessor int getScrollPos(); 19 | @Invoker void invokeSetChatLine(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/accessors/GuiRepairAccessor.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.accessors; 2 | 3 | import net.minecraft.client.gui.GuiRepair; 4 | import net.minecraft.client.gui.GuiTextField; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(GuiRepair.class) 9 | public interface GuiRepairAccessor { 10 | 11 | @Accessor GuiTextField getNameField(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/accessors/ItemModelMesherAccessor.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.accessors; 2 | 3 | import net.minecraft.client.renderer.ItemModelMesher; 4 | import net.minecraft.client.resources.model.IBakedModel; 5 | import net.minecraft.item.Item; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(ItemModelMesher.class) 10 | public interface ItemModelMesherAccessor { 11 | 12 | @Invoker IBakedModel invokeGetItemModel(Item item, int meta); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/accessors/S2FPacketSetSlotAccessor.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.accessors; 2 | 3 | import net.minecraft.item.ItemStack; 4 | import net.minecraft.network.play.server.S2FPacketSetSlot; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(S2FPacketSetSlot.class) 9 | public interface S2FPacketSetSlotAccessor { 10 | 11 | @Accessor int getWindowId(); 12 | @Accessor int getSlot(); 13 | @Accessor(value = "item") ItemStack getItemStack(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/neu/NEUEventListenerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.neu; 2 | 3 | import com.luna.synthesis.utils.MixinUtils; 4 | import org.spongepowered.asm.mixin.Dynamic; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Pseudo; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.ModifyArg; 9 | 10 | @Pseudo 11 | @Mixin(targets = "io.github.moulberry.notenoughupdates.NEUEventListener", remap = false) 12 | public class NEUEventListenerMixin { 13 | 14 | @Dynamic 15 | @ModifyArg(method = "onTick", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Keyboard;enableRepeatEvents(Z)V")) 16 | public boolean overrideKeyEvents(boolean in) { 17 | if (MixinUtils.inputField != null && MixinUtils.inputField.isFocused()) { 18 | return true; 19 | } 20 | return in; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/optifine/CapeUtilsMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.optifine; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.utils.ChatLib; 6 | import net.minecraft.client.Minecraft; 7 | import org.spongepowered.asm.mixin.Dynamic; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Pseudo; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 12 | 13 | @Pseudo 14 | @Mixin(targets = "net.optifine.player.CapeUtils") 15 | public class CapeUtilsMixin { 16 | 17 | private static final Config config = Synthesis.getInstance().getConfig(); 18 | 19 | // I want to give people the ability to toggle anything in the mod they don't want. 20 | // I don't know what would cause people to toggle them off. 21 | // I wouldn't be mad, just disappointed. 22 | @Dynamic 23 | @ModifyVariable(method = "downloadCape(Lnet/minecraft/client/entity/AbstractClientPlayer;)V", at = @At("STORE"), name = "username") 24 | private static String downloadCape(String in) { 25 | if (!config.utilitiesOptifineCustomCape.equals("") && in.equals(Minecraft.getMinecraft().getSession().getUsername())) { 26 | return config.utilitiesOptifineCustomCape; 27 | } 28 | if (config.utilitiesOptifineTransYeti && in.equals("Yeti ")) { 29 | return "Yeti"; 30 | } 31 | if (config.utilitiesOptifineTransTerracotta && in.equals("Terracotta ")) { 32 | return "Terracotta"; 33 | } 34 | if (config.utilitiesOptifineNonBinaryBonzo && in.equals("Bonzo ")) { 35 | return "Bonzo"; 36 | } 37 | if (config.utilitiesOptifineCandyCaneGrinch && in.equals("Grinch ")) { 38 | return "Grinch"; 39 | } 40 | return in; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/optifine/PlayerItemsLayerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.optifine; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.entity.EntityLivingBase; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Pseudo; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Pseudo 13 | @Mixin(targets = "net.optifine.player.PlayerItemsLayer") 14 | public class PlayerItemsLayerMixin { 15 | 16 | private final Config config = Synthesis.getInstance().getConfig(); 17 | 18 | // It's so great that I just made this almost after the santa hat is gone, but hey, here's to 2022 halloween if humanity hasn't collapsed by then. 19 | @Inject(method = "renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;FF)V", at = @At("HEAD"), cancellable = true) 20 | public void renderEquippedItems(EntityLivingBase entityLiving, float scale, float partialTicks, CallbackInfo ci) { 21 | if (config.utilitiesOptifineHideHats) { 22 | ci.cancel(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/patcher/ChatHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.patcher; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import net.minecraft.client.gui.ChatLine; 6 | import org.spongepowered.asm.mixin.Dynamic; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Pseudo; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Redirect; 11 | 12 | import java.util.Set; 13 | 14 | @Pseudo 15 | @Mixin(targets = "club.sk1er.patcher.util.chat.ChatHandler", remap = false) 16 | public class ChatHandlerMixin { 17 | 18 | private static final Config config = Synthesis.getInstance().getConfig(); 19 | 20 | // GuiNewChat::setChatLine breaks equals since ChatLine's is not overridden + the method creates a new chat line, this fixes that 21 | @Dynamic 22 | @Redirect(method = "deleteMessageByHash(I)Z", at = @At(value = "INVOKE", target = "Ljava/util/Set;contains(Ljava/lang/Object;)Z"), remap = false) 23 | private static boolean contains(Set toRemove, Object obj) { 24 | if (!config.patcherCompactChatFix) return toRemove.contains(obj); 25 | ChatLine cl2 = (ChatLine) obj; 26 | for (ChatLine cl : toRemove) { 27 | if (cl.getChatLineID() == cl2.getChatLineID() && cl.getUpdatedCounter() == cl2.getUpdatedCounter() && cl.getChatComponent().equals(cl2.getChatComponent())) { 28 | return true; 29 | } 30 | } 31 | return false; 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/patcher/ImagePreviewerMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.patcher; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import gg.essential.api.utils.TrustedHostsUtil; 6 | import org.spongepowered.asm.mixin.Dynamic; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Pseudo; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Redirect; 11 | 12 | import java.util.Collections; 13 | import java.util.HashSet; 14 | import java.util.Set; 15 | 16 | @Pseudo 17 | @Mixin(targets = "club.sk1er.patcher.screen.render.overlay.ImagePreview", remap = false) 18 | public class ImagePreviewerMixin { 19 | 20 | private final Config config = Synthesis.getInstance().getConfig(); 21 | 22 | // Probably not the way to do this since TrustedHostUtil::addTrustedHost exists BUT don't care. 23 | @Dynamic 24 | @Redirect(method = "handle(Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Lgg/essential/api/utils/TrustedHostsUtil;getTrustedHosts()Ljava/util/Set;")) 25 | public Set equalsIgnoreCase(TrustedHostsUtil util) { 26 | if (config.patcherCustomImagePreviewer && !config.patcherCustomDomains.equals("")) { 27 | Set newHosts = new HashSet<>(util.getTrustedHosts()); 28 | for (String s : config.patcherCustomDomains.split(",")) { 29 | newHosts.add(new TrustedHostsUtil.TrustedHost(s, s, Collections.singleton(s))); 30 | } 31 | return newHosts; 32 | } else { 33 | return util.getTrustedHosts(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/mixins/skytils/ChatTabsMixin.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.mixins.skytils; 2 | 3 | import com.luna.synthesis.Synthesis; 4 | import com.luna.synthesis.core.Config; 5 | import com.luna.synthesis.utils.Utils; 6 | import net.minecraft.network.play.server.S02PacketChat; 7 | import net.minecraft.util.ChatComponentText; 8 | import net.minecraft.util.IChatComponent; 9 | import net.minecraft.util.StringUtils; 10 | import org.spongepowered.asm.mixin.Dynamic; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Pseudo; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 15 | import org.spongepowered.asm.mixin.injection.Redirect; 16 | 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | @Pseudo 21 | @Mixin(targets = "skytils.skytilsmod.features.impl.handlers.ChatTabs", remap = false) 22 | public class ChatTabsMixin { 23 | 24 | private final Config config = Synthesis.getInstance().getConfig(); 25 | 26 | // Hacky way to add bridge messages to guild, shrug 27 | @Dynamic 28 | @ModifyVariable(method = "shouldAllow", at = @At("HEAD")) 29 | public IChatComponent overrideShouldAllow(IChatComponent in) { 30 | if (config.utilitiesBridgeGuildChatTab) { 31 | if (in.getFormattedText().startsWith(config.utilitiesBridgeMessageFormat.replaceAll("&", "§").split("<")[0])) { 32 | return new ChatComponentText("§r§2Guild > " + in.getFormattedText()); 33 | } 34 | } 35 | return in; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/utils/ChatLib.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.utils; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.util.ChatComponentText; 5 | 6 | public class ChatLib { 7 | 8 | public static void chat(Object message) { 9 | if (message instanceof String) { 10 | for (String s : ((String) message).split("\n")) { 11 | s = "&d[Synthesis]&r " + s; 12 | Minecraft.getMinecraft().thePlayer.addChatMessage( 13 | new ChatComponentText(s.replaceAll("&", "§")) 14 | ); 15 | } 16 | } else { 17 | message = ("&d[Synthesis]&r " + message).replaceAll("&", "§"); 18 | Minecraft.getMinecraft().thePlayer.addChatMessage( 19 | new ChatComponentText(message.toString())); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/utils/MixinUtils.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.utils; 2 | 3 | import com.luna.synthesis.mixins.accessors.ItemModelMesherAccessor; 4 | import net.minecraft.client.gui.GuiTextField; 5 | import net.minecraft.client.renderer.ItemModelMesher; 6 | import net.minecraft.client.resources.model.IBakedModel; 7 | import net.minecraft.item.Item; 8 | 9 | // This is the absolute wrong way to do this BUT until I figure out something better, shrug 10 | public class MixinUtils { 11 | 12 | public static GuiTextField inputField; 13 | 14 | public static IBakedModel getItemModel(ItemModelMesher imm, Item item, int meta) { 15 | ItemModelMesherAccessor imma = (ItemModelMesherAccessor) imm; 16 | return imma.invokeGetItemModel(item, meta); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/utils/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.utils; 2 | 3 | import net.minecraftforge.fml.common.Loader; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | public class ReflectionUtils { 8 | 9 | private static final String PATCHER_CONFIG_NAME = "club.sk1er.patcher.config.PatcherConfig"; 10 | private static Field patcherChatField = null; 11 | 12 | public static void onInit() { 13 | if (Loader.isModLoaded("patcher")) { 14 | handlePatcherReflection(); 15 | } 16 | } 17 | 18 | private static void handlePatcherReflection() { 19 | try { 20 | Class cls = Class.forName(PATCHER_CONFIG_NAME); 21 | Field f = cls.getField("transparentChatInputField"); 22 | if (f.getType() == boolean.class) { 23 | patcherChatField = f; 24 | } 25 | } catch (ReflectiveOperationException e) { 26 | // Why is there not a logger 27 | System.out.println("Unable to execute Patcher Reflection"); 28 | } 29 | } 30 | 31 | public static boolean getPatcherChatField(){ 32 | if (patcherChatField == null) return false; 33 | try { 34 | return patcherChatField.getBoolean(null); 35 | } catch (ReflectiveOperationException ignored) {} 36 | return false; 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/luna/synthesis/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.luna.synthesis.utils; 2 | 3 | import net.minecraft.client.renderer.GlStateManager; 4 | import net.minecraft.client.renderer.Tessellator; 5 | import net.minecraft.client.renderer.WorldRenderer; 6 | import net.minecraft.client.renderer.vertex.DefaultVertexFormats; 7 | import net.minecraft.event.ClickEvent; 8 | import net.minecraft.util.ChatComponentText; 9 | import net.minecraft.util.IChatComponent; 10 | import net.minecraft.util.MathHelper; 11 | import org.lwjgl.opengl.GL11; 12 | 13 | import java.net.URI; 14 | import java.net.URISyntaxException; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | import static org.lwjgl.opengl.GL11.*; 19 | 20 | public class Utils { 21 | 22 | private static final Pattern linkPattern = Pattern.compile("((?:[a-z0-9]{2,}:\\/\\/)?(?:(?:[0-9]{1,3}\\.){3}[0-9]{1,3}|(?:[-\\w_\\.]{1,}\\.[a-z]{2,}?))(?::[0-9]{1,5})?.*?(?=[!\"\u00A7 \n]|$))", Pattern.CASE_INSENSITIVE); 23 | 24 | // Copied and adapted from Patcher 25 | public static boolean isDivider(String message) { 26 | if (message == null) return false; 27 | if (message.length() < 5) { 28 | return false; 29 | } else { 30 | // Dear god, forgive me, for I am tired. 31 | if (message.equals("-------------- Guild: Message Of The Day --------------") || message.equals("---------- Guild: Message Of The Day (Preview) ----------")) { 32 | return true; 33 | } else { 34 | for (int i = 0; i < message.length(); i++) { 35 | char c = message.charAt(i); 36 | if (c != '-' && c != '=' && c != '\u25AC') { 37 | return false; 38 | } 39 | } 40 | } 41 | } 42 | return true; 43 | } 44 | 45 | // Adapted from ForgeHooks::newChatWithLinks, may change linkPattern in the future 46 | public static IChatComponent newChatWithLinks(String string) { 47 | IChatComponent ichat = null; 48 | Matcher matcher = linkPattern.matcher(string); 49 | int lastEnd = 0; 50 | 51 | while (matcher.find()) { 52 | int start = matcher.start(); 53 | int end = matcher.end(); 54 | 55 | String part = string.substring(lastEnd, start); 56 | if (part.length() > 0) { 57 | if (ichat == null) { 58 | ichat = new ChatComponentText(part); 59 | } else { 60 | ichat.appendText(part); 61 | } 62 | } 63 | lastEnd = end; 64 | String url = string.substring(start, end); 65 | IChatComponent link = new ChatComponentText(url); 66 | 67 | try { 68 | if ((new URI(url)).getScheme() == null) { 69 | url = "http://" + url; 70 | } 71 | } catch (URISyntaxException e) { 72 | if (ichat == null) ichat = new ChatComponentText(url); 73 | else ichat.appendText(url); 74 | continue; 75 | } 76 | 77 | ClickEvent click = new ClickEvent(ClickEvent.Action.OPEN_URL, url); 78 | link.getChatStyle().setChatClickEvent(click); 79 | if (ichat == null) { 80 | ichat = link; 81 | } else { 82 | ichat.appendSibling(link); 83 | } 84 | } 85 | 86 | String end = string.substring(lastEnd); 87 | if (ichat == null) { 88 | ichat = new ChatComponentText(end); 89 | } else if (end.length() > 0) { 90 | ichat.appendText(string.substring(lastEnd)); 91 | } 92 | return ichat; 93 | } 94 | 95 | public static void renderBeamSegment(double x, double y, double z, double partialTicks, double textureScale, double totalWorldTime, int yOffset, int height, float[] colors) { 96 | double beamRadius = 0.2D; 97 | double glowRadius = 0.25D; 98 | int i = yOffset + height; 99 | GL11.glTexParameteri(3553, 10242, 10497); 100 | GL11.glTexParameteri(3553, 10243, 10497); 101 | GlStateManager.disableLighting(); 102 | GlStateManager.disableCull(); 103 | GlStateManager.disableBlend(); 104 | GlStateManager.depthMask(true); 105 | GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ZERO); 106 | Tessellator tessellator = Tessellator.getInstance(); 107 | WorldRenderer worldRenderer = tessellator.getWorldRenderer(); 108 | double d0 = totalWorldTime + partialTicks; 109 | double d1 = height < 0 ? d0 : -d0; 110 | double d2 = MathHelper.func_181162_h(d1 * 0.2D - (double)MathHelper.floor_double(d1 * 0.1D)); 111 | float f = colors[0]; 112 | float f1 = colors[1]; 113 | float f2 = colors[2]; 114 | double d3 = d0 * 0.025D * -1.5D; 115 | double d4 = 0.5D + Math.cos(d3 + 2.356194490192345D) * beamRadius; 116 | double d5 = 0.5D + Math.sin(d3 + 2.356194490192345D) * beamRadius; 117 | double d6 = 0.5D + Math.cos(d3 + (Math.PI / 4D)) * beamRadius; 118 | double d7 = 0.5D + Math.sin(d3 + (Math.PI / 4D)) * beamRadius; 119 | double d8 = 0.5D + Math.cos(d3 + 3.9269908169872414D) * beamRadius; 120 | double d9 = 0.5D + Math.sin(d3 + 3.9269908169872414D) * beamRadius; 121 | double d10 = 0.5D + Math.cos(d3 + 5.497787143782138D) * beamRadius; 122 | double d11 = 0.5D + Math.sin(d3 + 5.497787143782138D) * beamRadius; 123 | double d14 = -1.0D + d2; 124 | double d15 = (double)height * textureScale * (0.5D / beamRadius) + d14; 125 | worldRenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); 126 | worldRenderer.pos(x + d4, y + (double)i, z + d5).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 127 | worldRenderer.pos(x + d4, y + (double)yOffset, z + d5).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 128 | worldRenderer.pos(x + d6, y + (double)yOffset, z + d7).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 129 | worldRenderer.pos(x + d6, y + (double)i, z + d7).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 130 | worldRenderer.pos(x + d10, y + (double)i, z + d11).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 131 | worldRenderer.pos(x + d10, y + (double)yOffset, z + d11).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 132 | worldRenderer.pos(x + d8, y + (double)yOffset, z + d9).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 133 | worldRenderer.pos(x + d8, y + (double)i, z + d9).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 134 | worldRenderer.pos(x + d6, y + (double)i, z + d7).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 135 | worldRenderer.pos(x + d6, y + (double)yOffset, z + d7).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 136 | worldRenderer.pos(x + d10, y + (double)yOffset, z + d11).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 137 | worldRenderer.pos(x + d10, y + (double)i, z + d11).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 138 | worldRenderer.pos(x + d8, y + (double)i, z + d9).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 139 | worldRenderer.pos(x + d8, y + (double)yOffset, z + d9).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 140 | worldRenderer.pos(x + d4, y + (double)yOffset, z + d5).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); 141 | worldRenderer.pos(x + d4, y + (double)i, z + d5).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); 142 | tessellator.draw(); 143 | GlStateManager.enableBlend(); 144 | GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); 145 | GlStateManager.depthMask(false); 146 | d3 = 0.5D - glowRadius; 147 | d4 = 0.5D - glowRadius; 148 | d5 = 0.5D + glowRadius; 149 | d6 = 0.5D - glowRadius; 150 | d7 = 0.5D - glowRadius; 151 | d8 = 0.5D + glowRadius; 152 | d9 = 0.5D + glowRadius; 153 | d10 = 0.5D + glowRadius; 154 | double d13 = -1.0D + d2; 155 | d14 = (double)height * textureScale + d13; 156 | worldRenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); 157 | worldRenderer.pos(x + d3, y + (double)i, z + d4).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 158 | worldRenderer.pos(x + d3, y + (double)yOffset, z + d4).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 159 | worldRenderer.pos(x + d5, y + (double)yOffset, z + d6).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 160 | worldRenderer.pos(x + d5, y + (double)i, z + d6).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 161 | worldRenderer.pos(x + d9, y + (double)i, z + d10).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 162 | worldRenderer.pos(x + d9, y + (double)yOffset, z + d10).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 163 | worldRenderer.pos(x + d7, y + (double)yOffset, z + d8).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 164 | worldRenderer.pos(x + d7, y + (double)i, z + d8).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 165 | worldRenderer.pos(x + d5, y + (double)i, z + d6).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 166 | worldRenderer.pos(x + d5, y + (double)yOffset, z + d6).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 167 | worldRenderer.pos(x + d9, y + (double)yOffset, z + d10).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 168 | worldRenderer.pos(x + d9, y + (double)i, z + d10).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 169 | worldRenderer.pos(x + d7, y + (double)i, z + d8).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 170 | worldRenderer.pos(x + d7, y + (double)yOffset, z + d8).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 171 | worldRenderer.pos(x + d3, y + (double)yOffset, z + d4).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); 172 | worldRenderer.pos(x + d3, y + (double)i, z + d4).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); 173 | tessellator.draw(); 174 | GlStateManager.enableLighting(); 175 | GlStateManager.enableTexture2D(); 176 | GlStateManager.depthMask(true); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/main/resources/mcmod.info: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "modid": "synthesis", 4 | "name": "Synthesis", 5 | "description": "Hypixel SkyBlock/general QoL mod.", 6 | "version": "${version}", 7 | "mcversion": "1.8.9", 8 | "url": "", 9 | "updateUrl": "", 10 | "authorList": ["Luna, Desco"], 11 | "credits": "Heart DC, The CouncilTM, E and microwave guild for a lot of this mod's suggestions. Also Antonio32A for hosting the share service and making the entire backend.", 12 | "logoFile": "", 13 | "screenshots": [], 14 | "dependencies": [] 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /src/main/resources/synthesis.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "compatibilityLevel": "JAVA_8", 3 | "package": "com.luna.synthesis.mixins", 4 | "refmap": "synthesis.mixins.refmap.json", 5 | "mixins": [ 6 | "accessors.GuiChatAccessor", 7 | "accessors.GuiContainerAccessor", 8 | "accessors.GuiNewChatAccessor", 9 | "accessors.GuiRepairAccessor", 10 | "accessors.ItemModelMesherAccessor", 11 | "accessors.S2FPacketSetSlotAccessor", 12 | "neu.NEUEventListenerMixin", 13 | "optifine.CapeUtilsMixin", 14 | "optifine.PlayerItemsLayerMixin", 15 | "patcher.ChatHandlerMixin", 16 | "patcher.ImagePreviewerMixin", 17 | "skytils.ChatTabsMixin", 18 | "BlockStainedGlassPaneMixin", 19 | "ContainerMixin", 20 | "EntityPlayerMixin", 21 | "EntityPlayerSPMixin", 22 | "GuiContainerMixin", 23 | "GuiNewChatMixin", 24 | "GuiPlayerTabOverlayMixin", 25 | "GuiScreenMixin", 26 | "RenderItemMixin" 27 | ], 28 | "client": [], 29 | "server": [] 30 | } --------------------------------------------------------------------------------