diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..8dd3e2f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,24 @@ +name: build +on: [ pull_request, push ] + +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - name: checkout repository + uses: actions/checkout@v2 + - name: validate gradle wrapper + uses: gradle/wrapper-validation-action@v1 + - name: setup jdk 8 + uses: actions/setup-java@v1 + with: + java-version: 8 + - name: make gradle wrapper executable + run: chmod +x ./gradlew + - name: build + run: ./gradlew build + - name: capture build artifacts + uses: actions/upload-artifact@v2 + with: + name: Synthesis + path: build/libs/Synthesis-NONCANON.jar diff --git a/.gitignore b/.gitignore index 2c770e0..89c9b14 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ build # other eclipse run +.DS_Store +settings.json +src OLD \ No newline at end of file diff --git a/README.md b/README.md index d6d8660..8059d8d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,171 @@ -# Synthesis -Hypixel SkyBlock QoL Mod. Don't use yet, this is so alpha it hurts. \ No newline at end of file +# Synthesis-NONCANON +Hypixel SkyBlock QoL Mod. A collection of random mod features that SirDesco couldn't find anywhere else. + +> TLDR: Desco decided to rewrite the mod in Kotlin and Ery that wanted to add features decided to add new ones that he's sad he couldn't get in the base mod + +(Thanks to Ascynx and KTibow for the TLDR and fixing `build.yml` respectively) + +***NOTE: These are noncanon builds of SirDesco's Synthesis mod. As in, because SirDesco wants to port v0.3.1 of Synthesis to Kotlin for v0.4.0 and I (Erymanthus | RayDeeUx) suck at Kotlin, this is an alternative take on Synthesis which includes some of the suggestions I liked that never made it into Synthesis. Use of any releases of these noncanon Synthesis builds—regardless of where, how, and when you obtained it—implies your understanding that some of the features in these non-canon builds of Synthesis will not make it into the Kotlin rewrite.*** + +To prevent mayhem and in accordance with [GitHub's licensing guidelines](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository), this fork inherits the license as its parent previously assumed, which is ARR (all rights reserved): + +> You're under no obligation to choose a license. However, without a license, the default copyright laws apply, meaning that you retain all rights to your source code and no one may reproduce, distribute, or create derivative works from your work. + +However, as part of ARR, this fork does not violate any copyright laws as I have recieved explicit permission from SirDesco & friends (see below): + +![image](https://media.discordapp.net/attachments/728977460737081454/989883710381895700/FOR_GITHUB.png) + +(FUCK, I USED THE WRONG PRONOUNS FOR SIRDESCO. KILL ME) + +# SirDesco is currently on sabbatical in preparation for the Kotlin rewrite of Synthesis. All the information below this heading is solely for reference purposes only, and may not reflect all of the contents of this specific repository. + +Releases and announcements at the official [discord](https://discord.gg/vAUuKSwbp6). +Feedback such as suggestions, new features, bugs, etc. will also be collected there. + +*** + +## Features +
+ Cleanup + +### Cleanup +Features that help the game feel more clean. +- Coop cleanup, fully customizable + - Auction creation messages + - Auction cancellation messages + - Auction collection messages + - Collection tooltips + - Beacon stat change messages + - Co-op member traveled to island messages +- Dungeon cleanup, fully customizable + - Potion effects message + - Solo dungeon class message + - Ultimate ability message + - Blessing stats messages + - Silverfish messages + - Wither/Blood key usage messages + - Watcher messages + - Doesn't remove the final message +- Lore cleanup, still customizable (0.2.0+) + - Gear score line + - HPB stat bonuses + - Reforge stat bonuses + - Gemstone stat bonuses + - Gemstone icons + - Enchantment descriptions + - And an option to remove enchantment names + - Item abilities + - Full armor set bonuses + - Soulbound text + - Obfuscated text from recombobulator + - Option to not cleanup lore when in the auction house +- Tablist cleanup (0.2.0+) + - Option to remove tablist header + - Option to remove the last 2 lines from the tablist footer +- Chat cleanup (0.3.0+) + - Option to remove old reforge messages when a new one is received + - + +
+ +
+ Future features + +### Future features +Features from future versions of the game. Yes, I don't know to name this one. +- Chunk borders (F3 + G) +- Chat clear (F3 + D) not clearing sent messages, so up and down arrows still work. +
+ +
+ Utilities + +### Utilities +The actual collection of QoL features that doesn't fit any other category. +- Container Chat + - Allows you to type and chat while inside gui inventories +- Search Mode + - Allows you to toggle search mode by pressing Ctrl + F with chat open, + which will only display chat messages that contain what you type. + - Mode to scroll back to a message when you right click on it while on search mode. +- Backpack Retexturing +- HOTM Perk Level Display + - Displays perk level as stack size in the HOTM menu. +- Drop chance to drop rate + - Converts item drop chance to drop rate in the bestiary menu. +- Bestiary glance + - Displays bestiary level and progress in the bestiary menu. +- Armadillo fix + - Prevents your screen being blocked when you are inside a block while riding an armadillo pet. +- Wishing compass triangulation + - Locates where a wishing compass points to. Use one, wait for the particle trail to disappear, move away and use it again. + - Option to add a waypoint at the location while using [Skytils](https://github.com/Skytils/SkytilsMod/). +- Ancestral Spade triangulation + - Quite literally the same thing as wishing compass, but with a few changes. +- Wishing compass uses left display + - Displays a wishing compass' left uses as stack size. +- Visible links + - Makes clickable links in chat blue and underlined. +- Colorless panes + - Turns glass panes gray so glass blocks are more visible. Just used for some gemstone mining, really. +- Chat in portal + - Allows you to type and use chat while inside a nether portal, like the one in dungeon blood room. + - **Note**: It's possible to make portals not close containers such as player inventory, ender chest and others, + but won't for now since I don't know if Hypixel would like that. +- Better wither impact perspective (im good with names, 0.2.0+) + - Toggling perspective while holding a wither impact weapon will skip the front camera. + - Option to make it global instead of wither impact only (0.3.0+) +- Superpairs IDs (0.2.0+) + - Gives skyblock item IDs to items inside superpairs, so NEU and SBE can read them for price displays. + - Additionally, resource packs can also modify those items. + - 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. +- Shares + - Shares are a way to showcase your items to other users using the mod. + - To show an item, hold it and type "[item]" (configurable) in chat. + - Option to be able to scroll through the share tooltip while using [ScrollableTooltips](https://github.com/Sk1erLLC/ScrollableTooltips) + - Option to click a share to copy an embed for discord. Simply copy it and paste it in a channel on discord. +- Bridge messages + - Formats guild messages sent by a bridge bot. + - Detects username and message based on message format. + - Currently, only works with the formats "ign > msg" and "ign: msg". + - If your bridge bot has another format, let me know. + - If you don't have a bridge bot, [get one](https://neppy.antonio32a.com/). + - Customizable bot name. + - Customizable message format. + - Working links sent from discord while using the format. + - Compatible with [Skytils](https://github.com/Skytils/SkytilsMod/)' guild chat tab regardless of format. +- Optifine + - Allows you to have any optifine user's cape. Only you see this cape! + - Options to bring back from early SkyBlock: + - Yeti with trans cape. + - Terracotta with trans cape. + - Bonzo with non binary cape. + - Grinch with candy cane cape. + - Option to disable all of them, but come on, why would you. + - Option to disable optifine's santa/witch hat. +- [Patcher](https://github.com/Sk1erLLC/Patcher) + - Option to fix an issue that would make compact chat not work under very specific circumstance. + Also when using search mode/container chat in some instances. + - Option to add custom trusted domains to Patcher's Image Preview. + - 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. +
+
+ Commands + +### Commands + +The mod only really has one command, /synth, which hosts all other subcommands. +- /synth + - Aliases: /synthesis, /syn + - When used without an argument, it opens the config menu. + - Subcommands: + - bp + - Arguments: backpack number, texture name, texture meta. + - Re textures the backpack in the *backpack number* slot, with the texture *texture name* and *texture meta* + - 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. + - To remove a backpack's texture, don't add any texture name or meta to the command. + - domains + - Arguments: "add/remove/list", domain + - Adds or removes a domain to or from the trusted domain list for [Patcher](https://github.com/Sk1erLLC/Patcher)'s Image Preview. + - Can also list all the current trusted domains. +
diff --git a/Synthesis suggestions mass reply.txt b/Synthesis suggestions mass reply.txt new file mode 100644 index 0000000..1fee1fe --- /dev/null +++ b/Synthesis suggestions mass reply.txt @@ -0,0 +1,128 @@ +Erymanthus' catch-all reply to the Synthesis #mod-suggestions limbo [AS OF JUNE 24TH, 2022] +(Warning: some responses may be too snarky/sassy/blunt for your taste. Read with caution.) + +Suggestions 10 / 11: ...SmoothFont mod? I know it ain't the best solution, but why do you think Synthesis of all mods deserves to have this feature? + +Suggestion 13: VanillaHUD by W-OVERFLOW. + +Suggestion 15: The point of Synthesis is to provide features absolutely absent from other mods. Your suggestion invalidates itself the minute you mention SBA. Even Antonio32A said no to this. + +Suggestion 17: I'm aware the suggestion came at a different point in time where SBE was the only mod to have chat-based title alerts, but hopefully you found your solution now. If not: Skytils. + +Suggestion 20: Not a feature suggestion, but hopefully Desco gets around to doing that on the Kotlin rewrite. + +Suggestion 21: Is a chat bridge not enough? + +Suggestion 24: Hytils-Reborn by W-OVERFLOW does a better job at this without sacrificing any informativeness. Not sure if the original feature was already in Hytilities by Sk1er but my point is, another mod beat you to the punch when I typed this. + +Suggestion 25: Moot suggestion. Use the search bar in config menu. + +Suggestion 27: "the number created from museum", as you call it, is constantly changing as more people submit items to the museum. And the point is to keep it within your museum because that's where you flex how old your items are. + +Suggestion 28: NoScamSpam by meyi/symt. Or as an alternative, open private messages but keep party invites closed to friends/guildmates at minimum. + +Suggestion 31: HOW DARE YOU CALL NEU REDUN—*clears throat* sorry there. Point is, you already invalidated your suggestion from word one, much like a friend of yours did earlier in suggestion 15. The point of Synthesis is to provide features absolutely absent from other mods. + +Suggestion 32: Grandma Wolf pet was released before you made that suggestion (January 2022). Lots of other mods already had this feature by then. + +Suggestion 33: `https://sky.shiiyu.moe/api/v2/profile/` is a good start... I'll look into it. Update: DONE + +Suggestion 38: Skyclient Updater should provide similar features for a much wider range of mods. + +Suggestion 39: Considering how heavily the game relies on leather armor and skulls for portraying items, this is probably not the wisest idea. + +Suggestion 40: Skytils now has a "Hide Cheap Coins" feature. Not sure what led up to that, but there you go. + +Suggestion 41: ...there's a mod named after the feature you just suggested. + +Suggestion 43: See the first two sentences of my response to suggestion 15, but replace SBA with SoopyAddons instead. + +Suggestion 44: Considering finding the source code to NEU's Builder Wand Overlay is already challenging enough of a task... yeah no. Doesn't fit the theme that Synthesis' current features set at the moment. + +Suggestion 45: ...is this some Floor 7 slang I'm too underleveled to understand? + +Suggestion 48: Dungeons Guide by syeyoung. + +Suggestion 49: Chatting by W-OVERFLOW. + +Suggestion 51: That would be rejecting packets sent from Hypixel, which violates mod guidelines. + +Suggestion 52: See Desco and Antonio32A's comments. Also, from this point on anything related to the chat bridge or Discord integration is not going to be addressed from my perspective. + +Suggestion 53: Chatting by W-OVERFLOW and Skytils by Lily (my-name-is-jeff) and Sychic. + +Suggestion 54: Chatting by W-OVERFLOW or Cowlection by Cow. + +Suggestion 55: /patcher sounds from Patcher by Sk1er LLC. + +Suggestion 56: Antonio32A explains why this is a bad idea regardless of how it's implemented. Not gonna repeat his words here. + +Suggestion 57: Hypixel staff beat you to the punch as of June 2022. Could this change? Sure. When? Who knows. + +Suggestion 58: Chatting by W-OVERFLOW. + +Suggestion 60: Seems like it's been implemented. GG! + +Suggestion 62: Just tab the person's username. + +Suggestion 63: Sounds interesting... but the only solution at the time is for the user to keep the bestiary stuff up to date via item tooltip tracking because Hypixel API is terrible with being informative. I'll look into it. Update: DONE + +Suggestion 65: Patcher by Sk1er LLC. + +Suggestion 66: The reason why is because no one wants their mod to DDoS Hypixel's API and burn it down. Also, I swear I've seen this suggestion elsewhere—but for my sake and due to the unpopularity of your suggestion, I'll save myself from growing more gray hairs and not look into it deeper. + +Suggestion 69: Actually sounds interesting and fairly simple to accomplish based on code Desco already wrote. My only concern is where the item lore line would end up, since all mod that tout a feature to add item lore lines with certain info end up conflicting with each other. I'll look into it. UPDATE: DONE + +Suggestion 70: Way to be rankist, even this far into Hypixel Skyblock's existence as a video game. If NoScamSpam has shown us anything, it's that accounts with any rank will spam party you. SBE won't solve shit. (Sorry ilo for being harsh.) + +Suggestion 71: Nope. Nope. Nope. No way am I going to enable the recent and rampant behavioral pattern common among today's teens where all they do is perpetuate the month's latest joke in every format possible to the point where its comedic value plummets faster than the American stock market did back in 1929. No thanks. Stick to SBE. + +Suggestion 72: Hytilis-Reborn by W-OVERFLOW. + +Suggestion 73: NotEnoughUpdates by Moulberry for item renaming and why do you want to change an item's rarity color? Use Photoshop, I'm not going to enable any item forgeries on my watch. + +Suggestion 75: See the first five sentences of my response to suggestion 71 for more info. + +Suggestion 77: ...is this some Floor 6 slang I'm too underleveled to understand? + +Suggestion 79: wait people still do dragons to this day (february 2022)? impossible. Also Hypixel player list info spacing is very inconsistent. + +Suggestion 80: ...do you not have a phone to do this? + +Suggestion 82: "auto send specific message in party chat after server sends specific message for it." So if the server has already sent the message for it, why repeat it in party chat? + +Suggestion 83: Sure, but where though? Grabbing the info is easy enough, but with NEU's custom trade menu in the equation... (I guess sending it to chat and leaving it up to user to find it via Container Chat is the best option. I'll look into it.) Update: DONE + +Suggestion 84: Given how many edits I've made to pet item lore for Synthesis, my best option is to edit an item tooltip line noting the percentage situation. I will need around 20 million coins to test this, though. Update: ALMOST THERE + +Suggestion 86: Ah yes, let's hide vital information. I'm sure nothing will go wrong! + +Suggestion 87: Skytils by Lily (my-name-is-jeff) and Sychic. + +Suggestion 88: Every mod that has a dungeons map feature + Dungeons Room Mod by Quantizr for room names. + +Suggestion 89: SkyblockHUD by ThatGravyBoat. + +Suggestion 90: Nope. + +Suggestion 92: See my response to suggestion 55. + +Suggestion 93: Chatting by W-OVERFLOW, and no to the keyboard shortcuts. + +Suggestion 94: Cowlection by Cow. + +Suggestion 95: Get the fuck out of this house. + +Suggestion 96: Hypixel commands are generally short enough that this is unnecessary. Longest command I can think of that I've ever used while on Hypixel is usually from a mod whose config I change once every time Technoblade uploads. + +Suggestion 97: Actually a decent suggestion and I hope this isn't a problem in v0.3.1 or the upcoming v0.4.0. I'll look into it. UPDATE: DONE. + +Suggestion 98: IS IT THAT HARD TO PRESS THE 'T' KEY??? + +Suggestion 99: Decent suggestion but much like my earlier ventures with pet names in the pet menu, this COULD fuck with Skytils again. Probably not but eh. I'll look into it. UPDATE: DONE. + +Suggestion 100: Already implemented. + +Suggestion 101: I'll look into it. + +Suggestion 102: ...no. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 035dfb2..eab9bd5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { repositories { - jcenter() + mavenCentral() maven { name = "forge" url = "https://maven.minecraftforge.net/" @@ -15,7 +15,11 @@ buildscript { } } dependencies { - classpath "com.github.asbyth:ForgeGradle:6f53277" + // classpath "com.github.RayDeeUx:ForgeGradle:6f5327" + // classpath "com.github.Skytils:ForgeGradle:6f5327" + // classpath "com.github.ReplayMod:ForgeGradle:ceb83c0" + // classpath "net.minecraftforge.gradle:ForgeGradle:2.1-SNAPSHOT" + classpath "com.github.DJtheRedstoner:ForgeGradle:8708bf3" classpath "com.github.jengelman.gradle.plugins:shadow:6.1.0" classpath "com.github.xcfrg:MixinGradle:0.6-SNAPSHOT" } @@ -26,7 +30,7 @@ apply plugin: "net.minecraftforge.gradle.forge" apply plugin: "com.github.johnrengelman.shadow" apply plugin: "org.spongepowered.mixin" -version = "Alpha-v4" +version = "0.3.1" group = "com.luna" archivesBaseName = "Synthesis" @@ -70,7 +74,7 @@ repositories { dependencies { embed "gg.essential:loader-launchwrapper:1.1.3" - compileOnly "gg.essential:essential-1.8.9-forge:1725" + compileOnly "gg.essential:essential-1.8.9-forge:1759" annotationProcessor "org.spongepowered:mixin:0.8.4" compileOnly "org.spongepowered:mixin:0.8.4" @@ -86,7 +90,7 @@ dependencies { } shadowJar { - archiveName = tasks.jar.archiveName + archiveName = "Synthesis-NONCANON.jar" classifier = "" duplicatesStrategy = DuplicatesStrategy.EXCLUDE @@ -130,4 +134,118 @@ processResources { } from(file("LICENSE")) -} \ No newline at end of file +} +// import dev.architectury.pack200.java.Pack200Adapter + +// plugins { +// id "dev.architectury.architectury-pack200" version "0.1.3" +// id "gg.essential.loom" version "0.10.0.3" +// id "net.kyori.blossom" version "1.3.0" +// id "java" +// } + +// version = projectVersion +// group = projectGroup +// archivesBaseName = projectName + +// sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 +// compileJava.options.encoding = 'UTF-8' + +// loom { +// launchConfigs { +// client { +// arg("--tweakClass", "gg.essential.loader.stage0.EssentialSetupTweaker") +// } +// } + +// runConfigs { +// client { +// ideConfigGenerated = true +// } +// } + +// forge { +// pack200Provider = new Pack200Adapter() +// mixinConfig("mixins.${projectId}.json") +// mixin.defaultRefmapName.set("mixins.${projectId}.refmap.json") +// } +// } + +// blossom { +// replaceToken("@VER@", projectVersion) +// replaceToken("@NAME@", projectName) +// replaceToken("@ID@", projectId) +// } + +// repositories { +// mavenCentral() +// maven { url "https://repo.essential.gg/repository/maven-public" } +// maven { url("https://repo.spongepowered.org/repository/maven-public/") } +// } + +// configurations { +// shade +// implementation.extendsFrom(shade) +// } + +// dependencies { +// minecraft("com.mojang:minecraft:1.8.9") +// mappings("de.oceanlabs.mcp:mcp_stable:22-1.8.9") +// forge("net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9") +// // Spongepowered Mixins +// compileOnly("org.spongepowered:mixin:${spongePoweredMixinVersion}") +// // Essential +// shade ("gg.essential:loader-launchwrapper:${essentialVersion}") +// compileOnly("gg.essential:essential-1.8.9-forge:1788") +// } + +// def mcVersion = "1.8.9" +// processResources { +// duplicatesStrategy = DuplicatesStrategy.EXCLUDE +// inputs.property("version", projectVersion) +// inputs.property("mcversion", mcVersion) +// inputs.property("name", projectName) +// inputs.property("id", projectId) + +// filesMatching("mcmod.info") { +// expand( +// "id": projectId, +// "name": projectName, +// "version": projectVersion, +// "mcversion": mcVersion +// ) +// } + +// filesMatching("mixins.${projectId}.json") { +// expand( +// "id": projectId +// ) +// } +// } + +// sourceSets { +// main { +// output.resourcesDir = java.classesDirectory +// } +// } + +// jar { +// dependsOn configurations.shade +// duplicatesStrategy = DuplicatesStrategy.EXCLUDE + +// from(configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }) { +// def i = 0 +// filesMatching("META-INF/NOTICE*") { name = "$name.${i++}" } +// filesMatching("META-INF/LICENSE*") { name = "$name.${i++}" } +// filesMatching("META-INF/mods.toml") { name = "$name.${i++}" } +// filesMatching("LICENSE*") { name = "$name.${i++}" } +// } + +// manifest.attributes( +// 'ModSide': 'CLIENT', +// 'ForceLoadAsMod': true, +// "TweakClass": "gg.essential.loader.stage0.EssentialSetupTweaker", +// 'MixinConfigs': "mixins.${projectId}.json", +// "TweakOrder": "0" +// ) +// } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index d73eaba..a16c87e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -org.gradle.jvmargs=-Xmx4G \ No newline at end of file +org.gradle.jvmargs=-Xmx4G +# org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk-17.0.3.1.jdk/Contents/Home \ No newline at end of file diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/luna/synthesis/Comment.java b/src/main/java/com/luna/synthesis/Comment.java deleted file mode 100644 index 6592baf..0000000 --- a/src/main/java/com/luna/synthesis/Comment.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.luna.synthesis; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Comment("Didn't totally steal this from Oringo Client, move along.") -public @interface Comment { - String value(); -} diff --git a/src/main/java/com/luna/synthesis/Synthesis.java b/src/main/java/com/luna/synthesis/Synthesis.java index 088d9ec..a6e0aa4 100644 --- a/src/main/java/com/luna/synthesis/Synthesis.java +++ b/src/main/java/com/luna/synthesis/Synthesis.java @@ -1,12 +1,15 @@ package com.luna.synthesis; +import com.luna.synthesis.commands.CopyToClipboardCommand; import com.luna.synthesis.commands.SynthesisCommand; import com.luna.synthesis.core.Config; import com.luna.synthesis.events.packet.PacketEvent; -import com.luna.synthesis.features.cleanup.CoopCleanup; -import com.luna.synthesis.features.future.ChunkBorders; +import com.luna.synthesis.features.cleanup.*; +import com.luna.synthesis.features.future.*; +import com.luna.synthesis.features.misc.*; import com.luna.synthesis.features.utilities.*; import com.luna.synthesis.managers.BackpackManager; +import com.luna.synthesis.utils.ReflectionUtils; import lombok.Getter; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.Mod; @@ -24,7 +27,7 @@ public class Synthesis { public static final String NAME = "Synthesis"; public static final String MODID = "synthesis"; - public static final String VERSION = "Alpha-v4"; + public static final String VERSION = "0.3.1"; public static final String configLocation = "./config/synthesis.toml"; @Getter private static Synthesis instance; @@ -47,10 +50,24 @@ public void init(FMLInitializationEvent event) { MinecraftForge.EVENT_BUS.register(new BestiaryDropRate()); MinecraftForge.EVENT_BUS.register(new ContainerChat()); MinecraftForge.EVENT_BUS.register(new WishingCompass()); + MinecraftForge.EVENT_BUS.register(new OccupancyOverlay()); MinecraftForge.EVENT_BUS.register(new ChatBridge()); MinecraftForge.EVENT_BUS.register(new VisibleLinks()); - MinecraftForge.EVENT_BUS.register(new ShareParser()); + MinecraftForge.EVENT_BUS.register(new Share()); + MinecraftForge.EVENT_BUS.register(new DungeonCleanup()); + MinecraftForge.EVENT_BUS.register(new BetterWitherImpactPerspective()); + MinecraftForge.EVENT_BUS.register(new LoreCleanup()); + MinecraftForge.EVENT_BUS.register(new AncestralSpade()); + MinecraftForge.EVENT_BUS.register(new BestiaryWarning()); + MinecraftForge.EVENT_BUS.register(new PreventDeleteReset()); + MinecraftForge.EVENT_BUS.register(new TrophyFishingMoment()); + MinecraftForge.EVENT_BUS.register(new HypixelBooksAreStupid()); + MinecraftForge.EVENT_BUS.register(new MilaysWontStopAskingForBurgers()); + MinecraftForge.EVENT_BUS.register(new MasterModeSoulDetector()); + MinecraftForge.EVENT_BUS.register(new HexatorumUtils()); config.preload(); new SynthesisCommand().register(); + new CopyToClipboardCommand().register(); + ReflectionUtils.onInit(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/luna/synthesis/commands/CopyToClipboardCommand.java b/src/main/java/com/luna/synthesis/commands/CopyToClipboardCommand.java new file mode 100644 index 0000000..c99770c --- /dev/null +++ b/src/main/java/com/luna/synthesis/commands/CopyToClipboardCommand.java @@ -0,0 +1,28 @@ +package com.luna.synthesis.commands; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import com.luna.synthesis.utils.ChatLib; +import gg.essential.api.commands.Command; +import gg.essential.api.commands.DefaultHandler; + +import java.awt.*; +import java.awt.datatransfer.StringSelection; + +public class CopyToClipboardCommand extends Command { + + public CopyToClipboardCommand() { + super("ctcc"); + } + + private final Config config = Synthesis.getInstance().getConfig(); + + // I will let you know that I despise having to create commands to run code on chat click. + // I'll end up rewriting clicks eventually. JUST YOU WAIT. + @DefaultHandler + public void handle(String toCopy) { + if (!config.utilitiesShareCopyEmbed) return; + ChatLib.chat("Copied &a" + toCopy + "&r to clipboard."); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(toCopy), null); + } +} diff --git a/src/main/java/com/luna/synthesis/commands/SynthesisCommand.java b/src/main/java/com/luna/synthesis/commands/SynthesisCommand.java index 588f7b9..9ecf4a6 100644 --- a/src/main/java/com/luna/synthesis/commands/SynthesisCommand.java +++ b/src/main/java/com/luna/synthesis/commands/SynthesisCommand.java @@ -1,46 +1,32 @@ package com.luna.synthesis.commands; -import com.google.gson.*; +import gg.essential.api.EssentialAPI; +import gg.essential.api.commands.*; + +// import com.google.gson.*; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.managers.BackpackManager; -import com.luna.synthesis.utils.ChatLib; -import gg.essential.api.EssentialAPI; -import gg.essential.api.commands.Command; -import gg.essential.api.commands.DefaultHandler; -import gg.essential.api.commands.Options; -import gg.essential.api.commands.SubCommand; +import com.luna.synthesis.utils.*; + import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.inventory.ContainerChest; +// import net.minecraft.client.Minecraft; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.StringUtils; import net.minecraftforge.fml.common.Loader; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.StandardCharsets; + import java.util.*; +// import java.io.InputStream; +// import java.net.HttpURLConnection; +// import java.net.URL; +// import java.nio.charset.StandardCharsets; + +// import org.apache.commons.io.IOUtils; + public class SynthesisCommand extends Command { public SynthesisCommand() { super("synthesis"); @@ -59,7 +45,7 @@ public void handle() { } @SubCommand("bp") - public void bp(int number, Optional name, Optional meta) { + public void bp(@DisplayName("backpack number") int number, @DisplayName("texture name") Optional name, @DisplayName("texture meta") Optional meta) { BackpackManager bpm = Synthesis.getInstance().getBackpackManager(); if (number < 1 || number > 18) { ChatLib.chat("That's not a valid backpack number."); @@ -95,7 +81,7 @@ public void bp(int number, Optional name, Optional meta) { } @SubCommand("domains") - public void domains(@Options({"add", "remove", "list"}) String options, Optional domain) { + public void domains(@Options({"add", "remove", "list"}) String options, @DisplayName("domain") Optional domain) { if (!Loader.isModLoaded("patcher")) { ChatLib.chat("You can only use this feature if you use patcher."); return; @@ -103,7 +89,7 @@ public void domains(@Options({"add", "remove", "list"}) String options, Optional switch (options) { case "add": if (!domain.isPresent()) { - ChatLib.chat("You need to specify a domain. Example: boob.li"); + ChatLib.chat("You need to specify a domain. Example: bigraccoon.monster"); return; } if (config.patcherCustomDomains.contains(domain.get().toLowerCase())) { @@ -117,7 +103,7 @@ public void domains(@Options({"add", "remove", "list"}) String options, Optional break; case "remove": if (!domain.isPresent()) { - ChatLib.chat("You need to specify a domain. Example: boob.li"); + ChatLib.chat("You need to specify a domain. Example: bigraccoon.monster"); return; } if (!config.patcherCustomDomains.contains(domain.get().toLowerCase())) { @@ -145,59 +131,107 @@ public void domains(@Options({"add", "remove", "list"}) String options, Optional } } - @SubCommand("share") - public void share() { - ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); - if (item == null) { - ChatLib.chat("You need to be holding something for this to work."); - return; - } - NBTTagCompound extraAttributes = item.getSubCompound("ExtraAttributes", false); - if (extraAttributes != null && extraAttributes.hasKey("uuid")) { - JsonObject body = new JsonObject(); - body.add("owner", new JsonPrimitive(Minecraft.getMinecraft().getSession().getPlayerID())); - JsonObject itemJson = new JsonObject(); - itemJson.add("name", new JsonPrimitive(item.getDisplayName())); - JsonArray loreArray = new JsonArray(); - for (String s : item.getTooltip(Minecraft.getMinecraft().thePlayer, false)) { - loreArray.add(new JsonPrimitive(s)); - } - itemJson.add("lore", loreArray); - itemJson.add("uuid", new JsonPrimitive(extraAttributes.getString("uuid"))); - body.add("item", itemJson); - - (new Thread(() -> { - try { - HttpClient httpclient = HttpClients.createDefault(); - HttpPost httppost = new HttpPost("https://synthesis-share.antonio32a.workers.dev/share"); - - StringEntity entity1 = new StringEntity(body.toString(), ContentType.APPLICATION_JSON); - httppost.setEntity(entity1); - - HttpResponse response = httpclient.execute(httppost); - HttpEntity responseEntity = response.getEntity(); - - if (responseEntity != null) { - try (InputStream instream = responseEntity.getContent()) { - JsonParser parser = new JsonParser(); - JsonObject shareJson = parser.parse(IOUtils.toString(instream)).getAsJsonObject(); - if (!shareJson.get("success").getAsBoolean()) { - ChatLib.chat("Share was not successful. Reason: " + shareJson.get("error").getAsString()); - return; - } - String shareId = shareJson.get("share").getAsJsonObject().get("id").getAsString(); - Minecraft.getMinecraft().thePlayer.sendChatMessage("{SynthesisShare:" + shareId + "}"); - } catch (JsonParseException e) { - ChatLib.chat("Something went wrong trying to read share."); - e.printStackTrace(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - })).start(); - } else { - ChatLib.chat("This item doesn't have a uuid."); - } + @SubCommand("wtf") + public void wtf() { + try { + ChatLib.chat("config.utilitiesOccupancyOverlay: " + config.utilitiesOccupancyOverlay); + ChatLib.chat("Minecraft.getMinecraft().currentScreen instanceof GuiChest: " + (boolean)(Minecraft.getMinecraft().currentScreen instanceof GuiChest)); + String menuName = StringUtils.stripControlCodes((((ContainerChest)((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots).getLowerChestInventory().getDisplayName().getUnformattedText())); + ChatLib.chat("menuName: " + menuName); + ChatLib.chat("menuName.endsWith(\" Hub Selector\") || menuName.startsWith(\"Visit\"): " + (menuName.endsWith(" Hub Selector") || menuName.startsWith("Visit"))); + ChatLib.chat("Minecraft.getMinecraft().thePlayer != null: " + (Minecraft.getMinecraft().thePlayer != null)); + } catch (Exception ex) {} } + + // @SubCommand("pronouns") + // public void pronouns(@DisplayName("username") Optional username) { + // new Thread(() -> { + // String nameToCheck = "", uuid = "", pronounResult = "", pronounsToBe = "", apostrophe = "'s"; + // if (username.isPresent()) { + // nameToCheck = username.get(); + // } else { + // nameToCheck = Minecraft.getMinecraft().thePlayer.getName(); + // } + // if (!(nameToCheck.contains("-"))) { + // try { + // URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + nameToCheck); + // HttpURLConnection http = (HttpURLConnection) url.openConnection(); + // http.connect(); + // try (InputStream instream = http.getInputStream()) { + // if (http.getResponseCode() != 200) { + // ChatLib.chat("Something went wrong with grabbing this player's Minecraft UUID. Aborting mission."); + // return; + // } + // JsonParser parser = new JsonParser(); + // JsonObject data = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); + // if (!data.has("id") || !data.has("name")) { + // ChatLib.chat("Synthesis failed in getting this player's UUID from Mojang's API. Either their API is down (most likely) or a player with this username doesn't exist. Aborting mission."); + // return; + // } + + // String uuidToBe = data.get("id").getAsString(); + // uuid = uuidToBe.substring(0, 8) + "-" + uuidToBe.substring(8, 12) + "-" + uuidToBe.substring(12, 16) + "-" + uuidToBe.substring(16, 20) + "-" + uuidToBe.substring(20); + // nameToCheck = data.get("name").getAsString(); + // } + // } catch (Exception e) { + // ChatLib.chat("Something went wrong with grabbing this player's Minecraft UUID via Mojang's API. Aborting mission."); + // e.printStackTrace(); + // } + // } else { + // uuid = nameToCheck; + // } + // ChatLib.chat(uuid); + // //b43d7457-9da4-408b-a9fb-51239022cec9 + // //https://pronoundb.org/api/v1/lookup?platform=minecraft&id=b43d7457-9da4-408b-a9fb-51239022cec9 + // //"https://pronoundb.org/api/v1/lookup?platform=minecraft&id=" + uuid + // try { + // URL url = new URL("https://pronoundb.org/api/v1/lookup?platform=minecraft&id=" + uuid); + // HttpURLConnection http = (HttpURLConnection) url.openConnection(); + // http.setDoOutput(true); + // http.setDoInput(true); + // http.setRequestProperty("User-Agent", "Synthesis-NONCANON"); + // http.setRequestProperty("Accept", "application/json"); + // http.setRequestProperty("Method", "GET"); + // http.connect(); + // try (InputStream instream = http.getInputStream()) { + // if (http.getResponseCode() != 200) { + // ChatLib.chat("Something went wrong with grabbing this player's pronouns from PronounDB. Aborting mission."); + // return; + // } + // JsonParser parser = new JsonParser(); + // JsonObject data = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); + // if (!data.has("pronouns")) { + // ChatLib.chat("Synthesis failed in getting this player's pronouns from PronounDB's API. Either their API is down (most likely) or a player with this UUID doesn't exist. Aborting mission."); + // return; + // } + + // pronounsToBe = data.get("pronouns").getAsString(); + // Pronouns.doTheThingWithPronouns(); + // pronounsToBe = Pronouns.dict.get(pronounsToBe); + // } + // } catch (Exception e) { + // ChatLib.chat("Something went wrong with grabbing this player's PronounDB data. Aborting mission."); + // e.printStackTrace(); + // return; + // } + // if (nameToCheck.endsWith("s")) apostrophe = "'"; + // if (nameToCheck.contains("-")) pronounResult += ("The player with UUID "); + // pronounResult += (nameToCheck); + // if (pronounsToBe == "any") { + // pronounResult += " doesn't mind what pronouns you use for them."; + // } else if (pronounsToBe == "other") { + // pronounResult += " has personal pronoun preferences."; + // } else if (pronounsToBe == "ask") { + // pronounResult += " says, \"ask me for my preferred pronouns\"."; + // } else if (pronounsToBe == "avoid") { + // pronounResult += " says, \"use my name instead of any pronouns\"."; + // } else if (pronounsToBe == "unspecified") { + // pronounResult += " has yet to set a pronoun preference."; + // } else { + + // pronounResult += (apostrophe + " preferred pronouns are " + pronounsToBe); + // } + // ChatLib.chat(pronounResult); + // }).start(); + // } } \ No newline at end of file diff --git a/src/main/java/com/luna/synthesis/core/Config.java b/src/main/java/com/luna/synthesis/core/Config.java index 7395aa4..c888b58 100644 --- a/src/main/java/com/luna/synthesis/core/Config.java +++ b/src/main/java/com/luna/synthesis/core/Config.java @@ -1,25 +1,23 @@ package com.luna.synthesis.core; import com.luna.synthesis.Synthesis; -import gg.essential.api.EssentialAPI; -import gg.essential.api.data.OnboardingData; import gg.essential.vigilance.Vigilant; import gg.essential.vigilance.data.JVMAnnotationPropertyCollector; import gg.essential.vigilance.data.Property; import gg.essential.vigilance.data.PropertyType; import net.minecraft.client.Minecraft; import net.minecraft.util.ChatComponentText; -import net.minecraftforge.common.MinecraftForge; +import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.fml.common.Loader; -import scala.sys.Prop; import java.awt.*; import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; public class Config extends Vigilant { + // Me englando is no bueno. + // If you find something that could be rewritten to be more concise and clear, let me know + @Property( type = PropertyType.SELECTOR, name = "Collection tooltips", @@ -106,6 +104,342 @@ public class Config extends Vigilant { ) public boolean cleanupCoopTravel = false; + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon potion effects message", + description = "Removes the chat message when you join a dungeon with active potion effects outside.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonPotionEffects = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon class message", + description = "Removes the chat message when you're the only player using a class.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonSoloClassMessage = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon ultimate message", + description = "Removes the dungeon reminder that your ultimate is ready to use.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonUltimateMessage = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon blessing stats messages", + description = "Removes the chat message that shows the stats of the collected blessing.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonBlessingStatMessages = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon blessing messages", + description = "Also removes the message that a blessing has been obtained, not only stats.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonBlessingMessages = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon silverfish messages", + description = "Removes the chat message when you hit the silverfish while it's moving.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonSilverfishMessages = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon key usage messages", + description = "Removes the chat message that explains how to use blood and wither keys.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonKeyUsageMessages = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon watcher messages", + description = "Removes all watcher messages except for the last one.", + category = "Cleanup", + subcategory = "Dungeon" + ) + public boolean cleanupDungeonWatcherMessages = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove gear score", + description = "Removes the gear score line.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreGearScore = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove HPB stat bonuses", + description = "Removes the text of bonus stats from hot/fuming potato books.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreHPB = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove reforge stat bonuses", + description = "Removes the text of bonus stats from reforge.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreReforge = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove gemstone stat bonuses", + description = "Removes the text of bonus stats from gemstones.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreGemstones = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove dungeon stat bonuses", + description = "Removes the text of the weapon's dungeon stats.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreDungeon = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove gemstone icons", + description = "Removes the line that indicates applied gemstones.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreGemstoneSlots = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove enchantment descriptions", + description = "Removes the explanation of what each enchantment does when the item has a low amount of enchantments.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreEnchantmentDescriptions = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove enchantments and reforge abilities", + description = "Removes both the paragraph of enchantments and any mention of reforge abilities.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreEnchantments = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove reforge abilities", + description = "Removes only the reforge ability text and leaves the paragraph of enchantments alone.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreReforgeAbility = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove item abilities", + description = "Removes the item ability text.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreAbilities = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove armor piece bonuses", + description = "Removes the armor piece bonus text.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePieceBonus = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove armor full set bonuses", + description = "Removes the armor full set bonus text.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreFullSetBonus = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove co-op soulbound text", + description = "Removes the \"§8* Co-op Soulbound *§r\" text.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreCoopSoulbound = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove solo soulbound text", + description = "Removes the \"§8* Soulbound *§r\" text.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreSoloSoulbound = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove recombobulated obfuscated text", + description = "Removes the obfuscated text (§ka§r) on the rarity of a recombobulated item.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreRecombobulatedObfuscated = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove \"§7Lvl§r\" from pet names in the pet menu", + description = "Shows only the pet's level number in the pet menu.\n\n" + + "§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" + + "§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.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupPetDisplayName = false; + + @Property( + type = PropertyType.SELECTOR, + name = "Remove pet type text in the pet menu", + description = "Removes the pet's type (type and/or skill, your choice) from its lore in the pet menu.\n" + + "Example (show skill only): §8Mining Pet§r -> §8Mining\n" + + "Example (show type only): §8Combat Morph§r -> §8Morph\n", + category = "Cleanup", + subcategory = "Lore", + options = { + "Off", + "Show skill only and remove pet type", + "Show type only and remove pet's skill", + "Remove both skill and type" + } + ) + public int cleanupLorePetType = 0; + + @Property( + type = PropertyType.SWITCH, + name = "Remove pet perk names in the pet menu", + description = "Examples: §6Hive§r, §6Ridable§r, §6Run§r, §6Odyssey§r, §6Mining Exp Boost§r.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetPerkName = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove pet \"§6Held Item: §r\" prefix in the pet menu", + description = "Example: §6Held Item: §aGold Claws\nThis will §lNOT§r remove the ability text\n§rof the held pet item in question.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetHeldItemPrefix = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove pet lore's empty lines in the pet menu", + description = "This line intentionally left uninformative.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetEmptyLines = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove pet lore's \"§b§lMAX LEVEL§r\" line in the pet menu", + description = "This line intentionally left uninformative.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetMaxLevel = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove pet lore's \"§eClick to summon!§r\" line in the pet menu", + description = "This line intentionally left uninformative.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetClickToSummon = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove pet lore's \"§cClick to despawn!§r\" line in the pet menu", + description = "This line intentionally left uninformative.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetClickToDespawn = false; + + @Property( + type = PropertyType.SWITCH, + name = "Compact pet lore's \"§a(X/10) Pet Candy Used§r\" line in the pet menu", + description = "Example: §a(X/10) Pet Candy Used§r -> §aX Cand[y/ies]", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLorePetCandiesUsed = false; + + @Property( + type = PropertyType.SWITCH, + name = "Auction house exception", + description = "Stops the lore being cleaned up when the auction house menu is opened.", + category = "Cleanup", + subcategory = "Lore" + ) + public boolean cleanupLoreAuctionException = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove old reforge messages", + description = "Removes past reforge messages from chat when a new one is received.", + category = "Cleanup", + subcategory = "Chat" + ) + public boolean cleanupChatOldReforgeMessages = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove tablist header", + description = "Removes the message at the top of the tablist.", + category = "Cleanup", + subcategory = "Tablist" + ) + public boolean cleanupTablistHeader = false; + + @Property( + type = PropertyType.SWITCH, + name = "Remove tablist footer", + description = "Removes the last 2 lines at the bottom of the tablist.", + category = "Cleanup", + subcategory = "Tablist" + ) + public boolean cleanupTablistFooter = false; + + //FUTURE + @Property( type = PropertyType.SWITCH, name = "Keep sent messages", @@ -122,6 +456,8 @@ public class Config extends Vigilant { ) public boolean futureChunkBorders = false; + //UTILITIES + @Property( type = PropertyType.SWITCH, name = "Container chat", @@ -130,6 +466,14 @@ public class Config extends Vigilant { ) public boolean utilitiesContainerChat = false; + @Property( + type = PropertyType.SWITCH, + name = "Container control", + 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.", + category = "Utilities" + ) + public boolean utilitiesContainerControl = false; + @Property( type = PropertyType.SWITCH, name = "Resize chat", @@ -223,6 +567,51 @@ public class Config extends Vigilant { ) public boolean utilitiesBestiaryGlance = false; + @Property( + type = PropertyType.SWITCH, + name = "Server occupancy glance", + description = "Draws a background around any item representing the occupancy of a lobby or player island.\nDepending on the occupancy level of a server or island, the highlight's color can range from something near §athis highight§r (empty lobby/island) to something near §cthis highight§r (full lobby/island), with the occasional highlight of somewhere near §ethis color in particular§r (half-empty/half-full lobby/island).", + category = "Utilities", + subcategory = "Server occupancy overlay" + ) + public boolean utilitiesOccupancyOverlay = false; + + @Property( + type = PropertyType.SWITCH, + name = "§9Friend§r highlight", + description = "Uses §9this unique color§r for lobbies with at least one Hypixel friend.\n§e§lNOTE: §r§eThis highlight does not apply when a lobby\n§eis at or over its maximum capacity.", + category = "Utilities", + subcategory = "Server occupancy overlay" + ) + public boolean utilitiesOccupancyOverlayFriendHighlght = false; + + @Property( + type = PropertyType.SWITCH, + name = "§2Guildmate§r highlight", + description = "Uses §2this unique color§r for lobbies with at least one Hypixel guildmate.\n§e§lNOTE: §r§eThis highlight does not apply when a lobby\n§eis at or over its maximum capacity.", + category = "Utilities", + subcategory = "Server occupancy overlay" + ) + public boolean utilitiesOccupancyOverlayGuildHighlght = false; + + @Property( + type = PropertyType.SWITCH, + name = "§dFriend(s) §land§r§d guildmate(s)§r highlight", + description = "Uses §dthis unique color§r for lobbies with both at least one Hypixel friend and one Hypixel guildmate.\nIf this is disabled, then either §9the friend highlight§r or §2the guildmate highlight§r takes priority, depending on your settings.\n§e§lNOTE: §r§eThis highlight does not apply when a lobby\n§eis at or over its maximum capacity.", + category = "Utilities", + subcategory = "Server occupancy overlay" + ) + public boolean utilitiesOccupancyOverlayFriendAndGuildHighlght = false; + + @Property( + type = PropertyType.SWITCH, + name = "§bCurrently connected§r highlight", + description = "Uses §bthis unique color§r for lobbies you're already connected to.\nIf this is disabled, then at least one of the above settings (§9friend§r, §2guildmate§r, or §dboth§r) takes priority.\n§e§lNOTE: §r§eBecause of how Hypixel's hub selector tooltips work,\n§ethis highlight still applies even if a lobby is at or over its maximum capacity.", + category = "Utilities", + subcategory = "Server occupancy overlay" + ) + public boolean utilitiesOccupancyOverlayAlreadyConnectedHighlght = true; + @Property( type = PropertyType.SWITCH, name = "Armadillo fix", @@ -233,15 +622,15 @@ public class Config extends Vigilant { @Property( type = PropertyType.SWITCH, - name = "Wishing compass triangulation", - description = "Triangulates the location wishing compass points to. Use wishing compass once, wait until the particle trail has disappeared, move away a bit and use it again. Make sure /pq is NOT \"off\".", + name = "WishingCompass helper", + 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\".", category = "Utilities" ) public boolean utilitiesWishingCompass = false; @Property( type = PropertyType.SWITCH, - name = "Block wishing compass", + name = "Block triangulation item", description = "Blocks using wishing compass if the last trail hasn't disappeared.", category = "Utilities" ) @@ -249,12 +638,61 @@ public class Config extends Vigilant { @Property( type = PropertyType.SWITCH, - name = "Wishing compass waypoints", - description = "Sets a waypoint at the location calculated by wishing compass. Uses Skytils' waypoints.", + name = "Wishing Compass waypoints", + description = "Sets a waypoint at the location calculated by triangulation. Uses Skytils' waypoints.", category = "Utilities" ) public boolean utilitiesWishingCompassWaypoint = false; + @Property( + type = PropertyType.SWITCH, + name = "AncestralSpade helper", + description = "Triangulates the location ancestral spade points to. §cLook straight up or down§r, 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\".", + category = "Utilities" + ) + public boolean utilitiesAncestralSpade = false; + + @Property( + type = PropertyType.SWITCH, + name = "Burrow waypoints", + description = "Sets a waypoint at the location calculated by ancestral spade triangulation.", + category = "Utilities" + ) + public boolean utilitiesAncestralSpadeWaypoint = false; + + @Property( + type = PropertyType.COLOR, + name = "Burrow waypoint color", + description = "The color of the waypoint beacon.", + category = "Utilities", + allowAlpha = false + ) + public Color utilitiesAncestralSpadeWaypointColor = Color.RED; + + @Property( + type = PropertyType.SWITCH, + name = "Parse burrow arrow", + description = "Saves the direction arrow from a burrow, making it only require an extra use of Ancestral Spade.", + category = "Utilities" + ) + public boolean utilitiesAncestralSpadeArrow = false; + + @Property( + type = PropertyType.SWITCH, + name = "Display wishing compass uses left", + description = "Displays the uses left on wishing compasses.", + category = "Utilities" + ) + public boolean utilitiesWishingCompassUsesLeft = false; + + @Property( + type = PropertyType.SWITCH, + name = "Always display wishing compass uses left", + description = "Also displays uses left on wishing compasses when they have 3 uses left.", + category = "Utilities" + ) + public boolean utilitiesWishingCompassAlwaysUsesLeft = false; + @Property( type = PropertyType.SWITCH, name = "Visible links", @@ -271,6 +709,125 @@ public class Config extends Vigilant { ) public boolean utilitiesColorlessPanes = false; + @Property( + type = PropertyType.SWITCH, + name = "Chat in portal", + description = "Lets you open and use chat inside a nether portal.", + category = "Utilities" + ) + public boolean utilitiesPortalChat = false; + + @Property( + type = PropertyType.SWITCH, + name = "Better wither impact perspective", + description = "Toggling third person view will skip the front camera if holding a wither impact weapon.", + category = "Utilities" + ) + public boolean utilitiesWitherImpactPerspective = false; + + @Property( + type = PropertyType.SWITCH, + name = "Better perspective", + description = "Makes Better wither impact perspective skip the wither impact test and will always skip the front camera.", + category = "Utilities" + ) + public boolean utilitiesWitherImpactPerspectiveGlobal = false; + + @Property( + type = PropertyType.SWITCH, + name = "Superpairs IDs", + description = "Gives superpairs item rewards Skyblock IDs so mods like NEU and SBE can display price and resource packs can display custom textures.", + category = "Utilities" + ) + public boolean utilitiesSuperpairsIDs = false; + + @Property( + type = PropertyType.SWITCH, + name = "Trophy Fishing Overlay", + description = "Colors a trophy fish in Odger's menu with the highest tier of it that you've caught.", + category = "Utilities" +) + public boolean utilitiesTrophyFishingOverlay = false; + + @Property( + type = PropertyType.SWITCH, + name = "Hexatorum Overlay", + description = "Displays the progress of your item's individual traits in color form according to the Hex.", + category = "Utilities" +) + public boolean utilitiesHexatorumOverlay = false; + + @Property( + type = PropertyType.SWITCH, + name = "Hexatorum Debug", + description = "Displays debug information in case the Hexatorum overlay decides to break.\nCan and WILL flood your chat-enable with great caution!", + category = "Utilities" +) + public boolean utilitiesHexatorumDebug = false; + + @Property( + type = PropertyType.TEXT, + name = "Share held item text", + description = "Hold an item and type the text to show the item to other Synthesis users.", + category = "Utilities", + subcategory = "Share" + ) + public String utilitiesShareText = "[item]"; + + @Property( + type = PropertyType.TEXT, + name = "Share helmet text", + description = "Type the text to show your helmet slot to other Synthesis users.", + category = "Utilities", + subcategory = "Share" + ) + public String utilitiesShareHelmetText = "[helmet]"; + + @Property( + type = PropertyType.TEXT, + name = "Share chestplate text", + description = "Type the text to show your chestplate slot to other Synthesis users.", + category = "Utilities", + subcategory = "Share" + ) + public String utilitiesShareChestplateText = "[chestplate]"; + + @Property( + type = PropertyType.TEXT, + name = "Share leggings text", + description = "Type the text to show your leggings slot to other Synthesis users.", + category = "Utilities", + subcategory = "Share" + ) + public String utilitiesShareLeggingsText = "[leggings]"; + + @Property( + type = PropertyType.TEXT, + name = "Share boots text", + description = "Type the text to show your boots slot to other Synthesis users.", + category = "Utilities", + subcategory = "Share" + ) + public String utilitiesShareBootsText = "[boots]"; + + @Property( + type = PropertyType.SWITCH, + name = "Share scroll", + description = "Scrolling while hovering a share and holding control will not scroll the chat.", + category = "Utilities", + subcategory = "Share" + ) + public boolean utilitiesShareScroll = false; + + @Property( + type = PropertyType.SWITCH, + name = "Share copy embed", + description = "Clicking on shares copies a link to clipboard, that embeds an item preview on discord.", + category = "Utilities", + subcategory = "Share" + ) + public boolean utilitiesShareCopyEmbed = false; + @Property( type = PropertyType.SWITCH, name = "Better bridge message", @@ -305,58 +862,413 @@ public class Config extends Vigilant { name = "Test bridge message", description = "Send in chat a message formatted like the above format. Useful for testing that format.", category = "Utilities", - subcategory = "Bridge" + subcategory = "Bridge", + placeholder = "Test" ) public void utilitiesBridgeTestFormat() { Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(utilitiesBridgeMessageFormat.replaceAll("&", "§").replace("", "Luna").replace("", "This is an example message. Thank you for using Synthesis!"))); } + @Property( + type = PropertyType.BUTTON, + name = "Color code guide", + description = "Sends a chat message with all formatting codes.", + category = "Utilities", + subcategory = "Bridge", + placeholder = "Show" + ) + public void utilitiesBridgeColorCodeGuide() { + for (EnumChatFormatting value : EnumChatFormatting.values()) { + if (value.getFriendlyName().equals("obfuscated")) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( "&" + value.toString().replace("§", "") + " - " + value + value.getFriendlyName())); + } else { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(value + "&" + value.toString().replace("§", "") + " - " + value.getFriendlyName())); + } + } + } + + @Property( + type = PropertyType.SWITCH, + name = "Bridge guild chat tab", + description = "If using skytils' chattabs, moves formatted bridge messages to the guild tab.", + category = "Utilities", + subcategory = "Bridge" + ) + public boolean utilitiesBridgeGuildChatTab = true; + @Property( type = PropertyType.TEXT, name = "Custom cape", description = "Use someone else's optifine cape. Only you will see this! Leave empty to not use someone else's cape.", category = "Utilities", - subcategory = "Capes", + subcategory = "Optifine", min = 1, max = 16 ) - public String utilitiesCapesCustomCape = ""; + public String utilitiesOptifineCustomCape = ""; @Property( type = PropertyType.SWITCH, name = "Trans yeti", description = "Gives the yeti a trans cape.", category = "Utilities", - subcategory = "Capes" + subcategory = "Optifine" ) - public boolean utilitiesCapesTransYeti = true; + public boolean utilitiesOptifineTransYeti = true; @Property( type = PropertyType.SWITCH, name = "Trans terracotta", description = "Gives the terracotta a trans cape.", category = "Utilities", - subcategory = "Capes" + subcategory = "Optifine" ) - public boolean utilitiesCapesTransTerracotta = true; + public boolean utilitiesOptifineTransTerracotta = true; @Property( type = PropertyType.SWITCH, name = "Non binary bonzo", description = "Gives bonzo a non binary cape.", category = "Utilities", - subcategory = "Capes" + subcategory = "Optifine" ) - public boolean utilitiesCapesNonBinaryBonzo = true; + public boolean utilitiesOptifineNonBinaryBonzo = true; @Property( type = PropertyType.SWITCH, name = "Candy cane grinch", description = "Gives the grinch a candy cane cape.", category = "Utilities", - subcategory = "Capes" + subcategory = "Optifine" + ) + public boolean utilitiesOptifineCandyCaneGrinch = true; + + @Property( + type = PropertyType.SWITCH, + name = "Hide santa/witch hat", + description = "Hides the witch/santa hat given to players with capes on halloween/christmas.", + category = "Utilities", + subcategory = "Optifine" + ) + public boolean utilitiesOptifineHideHats = false; + + @Property( + type = PropertyType.NUMBER, + name = "Bestiary Level", + description = "If you're somehow reading this in-game, something isn't right.", + category = "Advanced", + max = 10000, + hidden = true + ) + public int personalBestiaryLevel = 0; + + @Property( + type = PropertyType.SELECTOR, + name = "Bestiary Milestone Warning", + description = "Specify how (if at all) you want your Bestiary Milestone warning to be delivered.\n§cIn order for this to work, you need to view the \"Bestiary Milestone\" item tooltip via §r/be §cfirst.", + category = "Utilities", + subcategory = "Bestiary", + options = {"Off", "Chat", "Notification"} + ) + public int utilitiesBestiaryMilestoneWarningDeliveryMethod = 0; + + @Property( + type = PropertyType.NUMBER, + name = "Bestiary Milestone Frequency (in seconds)", + description = "Specify how frequently (in units of \"every X seconds\") Synthesis will (notify you via chat/send notifications) if you're close to reaching a Bestiary Milestone that rewards combat experience.", + category = "Utilities", + subcategory = "Bestiary", + min = 5, max = 60 + ) + public int utilitiesBestiaryMilestoneWarningSeconds = 5; + + @Property( + type = PropertyType.NUMBER, + name = "Bestiary Milestone Notification Duration (in seconds)", + description = "Specify how long (in units of \"X seconds\") Synthesis' Bestiary Milestone notification will last.\n§cFor an optimal experience, it is recommended to keep this value lower than what you have for \"Bestiary Milestone Frequency (in seconds)\".", + category = "Utilities", + subcategory = "Bestiary", + min = 5, max = 120 ) - public boolean utilitiesCapesCandyCaneGrinch = true; + public int utilitiesBestiaryMilestoneWarningDuration = 5; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Item UUID at Item Lore", + description = "Displays the item's UUID (if there is one) at the end of an item's tooltip.\n§cFor compatibility reasons, UUIDs for all pets will not be displayed while viewing the pet menu.", + category = "Utilities", + subcategory = "Item Lore", + options = {"Off", "With \"-\"s", "Without \"-\"s"} + ) + public int utilitiesLoreItemUUID = 0; + + @Property( + type = PropertyType.SWITCH, + name = "Show Item Origin at Item Lore", + description = "Displays the item's origin (if there is one) at the end of an item's tooltip.\n§cFor compatibility reasons, item origins for all pets will not be displayed while viewing the pet menu.", + category = "Utilities", + subcategory = "Item Lore" + ) + public boolean utilitiesLoreOriginTag = false; + + @Property( + type = PropertyType.SELECTOR, + name = "Master Star Display Options", + description = "Choose how you want master stars in item names to be displayed.\n§eWill affect output provided by SkyblockAddons' §r/sba dev §ecommand.\n§cMay not apply to items renamed via NEU.", + category = "Utilities", + options = {"Whatever Hypixel has right now (§6✪§6✪§6✪§6✪§6✪§c➍§r)", "Go old school (§c✪§c✪§c✪§c✪§6✪§r)", "Append to previous stars (§6✪§6✪§6✪§6✪§6✪§c✪§c✪§c✪§c✪§r)"} + ) + public int utilitiesMasterStarDisplay = 0; + + @Property( + type = PropertyType.SWITCH, + name = "Master Mode Soul Detection per Item", + description = "Check if an item is filled §aexclusively§r or §epartially§r of Master Mode souls.\nAdditionally indicates which souls are from Master Mode on item tooltips.", + category = "Utilities" +) + public boolean utilitiesMasterModeSoulDetection = true; + + @Property( + type = PropertyType.SWITCH, + name = "Enable Senither and Lily weight search", + description = "The toggle to enable/disable checking exclusively for someone's weights in both the Senither calculation system and the Lily calculation system. §e(Type \"[weight ]\" in chat to check someone's weight calculations, or \"[weight]\" to check your own.)\n§c§lEnable with caution!", + category = "Utilities" + ) + public boolean utilitiesCheckWeight = false; + + @Property( + type = PropertyType.SWITCH, + name = "Enable checking for Player's SkyCrypt Stats", + description = "The toggle to enable/disable checking for someone's stats in the SkyCrypt API. §e(Type \"[stats ]\" in chat to check someone's SkyCrypt stats, or \"[stats]\" to check your own. Additionally, this also activates when sending trade requests to someone.)\n§c§lEnable with caution!", + category = "Utilities" + ) + public boolean utilitiesCheckStats = false; + + @Property( + type = PropertyType.SELECTOR, + name = "SkyCrypt Stats Level of Detail (§dLOD§r)", + description = "Choose how much detail you should see when checking someone's SkyCrypt info.\n§eApplies to all players without exception regardless of your choice; choose wisely!\n§cDoes not influence load time of SkyCrypt player data.\nGo experiment!", + category = "Utilities", + options = {"\"give me the bare minimum\"", "\"Maybe a bit of extra info would be nice.\"", "\"I DEMAND TO KNOW EVERY SINGLE DETAIL!\""} + ) + public int utilitiesCheckStatsLvlOfDetail = 0; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent HOTM Reset", + description = "Prevent clicking on that one button which resets your HOTM tree.", + category = "Utilities" + ) + public boolean utilitiesPreventHOTMReset = false; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent Profile Deletion", + description = "Prevent clicking on that one button which deletes your profiles.", + category = "Utilities" + ) + public boolean utilitiesPreventProfileDeletion = false; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent Portal Destruction", + description = "Prevent destroying portals on your private island.", + category = "Utilities" +) + public boolean utilitiesPreventPortalDestruction = false; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent Voting for Barry", + description = "Prevent voting for Barry in Skyblock mayor elections. (Sorry not sorry, arithemonkey.)", + category = "Utilities" + ) + public boolean utilitiesPreventVotingBarry = false; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent Voting for Diaz", + description = "Prevent voting for Diaz in Skyblock mayor elections.", + category = "Utilities" + ) + public boolean utilitiesPreventVotingDiaz = false; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent Voting for Dante", + description = "Prevent voting for Dante in Skyblock mayor elections.", + category = "Utilities" + ) + public boolean utilitiesPreventVotingDante = false; + + @Property( + type = PropertyType.SWITCH, + name = "Prevent Voting for Unknown Special Mayors", + description = "Prevent voting for new special mayors besides Derpy, Jerry, or Scorpius in Skyblock mayor elections. Enabling this will prevent voting for Dante as well.", + category = "Utilities" + ) + public boolean utilitiesPreventVotingSusSpecialMayors = false; + + @Property( + type = PropertyType.NUMBER, + name = "Prevent Voting for Mayors with Less Than [number] Perks", + description = "If left at the default value of \"1\", Synthesis will not prevent you from voting for any mayors.\nHowever, if you chose \"2\", Synthesis would prevent you from voting for mayors with only one perk (as one is less than two).", //\" + category = "Utilities", + min = 1, max = 3 + ) + public int utilitiesPreventVotingXPerkMayors = 1; + + @Property( + type = PropertyType.SWITCH, + name = "Show Collections as Stack Size", + description = "Applies to the collection menus of most Skyblock skills.", + category = "Utilities" + ) + public boolean utilitiesShowCollectionStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show Highest Crafted Minions as Stack Size", + description = "Applies to the Crafted Minions menu.", + category = "Utilities" + ) + public boolean utilitiesShowCraftedMinionsStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show Skills as Stack Size", + description = "Applies to both the \"Dungeoneering\" and \"Your Skills\" menus\n§e§lCAUTION§r§e: If you enabled Skytils' \"Show Potion Tier\" option, there will be a \"1\" as the stack size for the Healer icon in the \"Dungeoneering\" menu. There is no known solution to this besides building your own copies of Skytils.", + category = "Utilities" + ) + public boolean utilitiesShowSkillStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show Dojo Progress as Stack Size", + description = "Shows your Rank on all attempted §9Tests§r at the Dojo as well as your overall §6Rank§r.", + category = "Utilities" + ) + public boolean utilitiesShowDojoProgressStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show §aCompleted Quest§r count as Stack Size", + description = "This line intentionally left uninformative.", + category = "Utilities" + ) + public boolean utilitiesShowCompletedQuestCountStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show Wardrobe Slot # as Stack Size", + description = "This line intentionally left uninformative.", + category = "Utilities" + ) + public boolean utilitiesShowWardrobeSlotStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show Bank Tier as Stack Size", + description = "This line intentionally left uninformative.", + category = "Utilities" + ) + public boolean utilitiesShowBankTierStackSize = false; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Skill Average as Stack Size", + description = "Rounded: Rounds this value to the nearest integer.\nExact: Embraces the decimal point of this value.", + category = "Utilities", + options = {"Off", "Rounded", "Exact"} + ) + public int utilitiesShowSkillAverageStackSize = 0; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Overall Unlocked Recipes Percent as Stack Size", + description = "Rounded: Rounds this value to the nearest integer.\nExact: Embraces the decimal point of this value.\nFor compatibility reasons, this is limited to the \"SkyBlock Menu\".", + category = "Utilities", + options = {"Off", "Rounded", "Exact"} + ) + public int utilitiesShowUnlockedRecipePercentStackSize = 0; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Categorized Unlocked Recipes Percent as Stack Size", + description = "Rounded: Rounds this value to the nearest integer.\nExact: Embraces the decimal point of this value.", + category = "Utilities", + options = {"Off", "Rounded", "Exact"} + ) + public int utilitiesShowUnlockedSpecificRecipePercentStackSize = 0; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Overall Unlocked Collections Percent as Stack Size", + description = "Rounded: Rounds this value to the nearest integer.\nExact: Embraces the decimal point of this value.", + category = "Utilities", + options = {"Off", "Rounded", "Exact"} + ) + public int utilitiesShowUnlockedCollectionStackSize = 0; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Museum Donated Percent as Stack Size", + description = "Rounded: Rounds this value to the nearest integer.\nExact: Embraces the decimal point of this value.", + category = "Utilities", + options = {"Off", "Rounded", "Exact"} + ) + public int utilitiesShowMuseumPercentagesStackSize = 0; + + @Property( + type = PropertyType.SWITCH, + name = "Show New Year's Cake Year as Stack Size", + description = "This line intentionally left uninformative.", + category = "Utilities" + ) + public boolean utilitiesShowNYCakeStackSize = false; + + @Property( + type = PropertyType.SWITCH, + name = "Show Active Effects count as Stack Size", + description = "This line intentionally left uninformative.", + category = "Utilities" + ) + public boolean utilitiesShowActiveEffectsStackSize = false; + + @Property( + type = PropertyType.SELECTOR, + name = "Show Spooky Pie Stack Size", + description = "SB Year: Shows the SB year the Pie was obtained.\nnth Festival: Shows the nth Spooky Festival the Pie was obtained.\n(For compatibility reasons, this will only apply to the general SkyBlock Menu.)", + category = "Utilities", + options = {"Off", "SB Year", "nth Festival"} + ) + public int utilitiesShowSpookyPieStackSize = 0; + + //MISC + + @Property( + type = PropertyType.SWITCH, + name = "Ignore Hypixel's Books GUIs", + description = "Automatically close any book GUI in all Hypixel lobbies. Originally designed to automate ignoring all those books about Hypixel's seasonal sales on their online store, but §efalse positives CAN and WILL happen.\n§c§lEnable with caution, and disable when in doubt!", + category = "Miscellaneous" + ) + public boolean miscIgnoreHypixelBooks = false; + + @Property( + type = PropertyType.SWITCH, + name = "Send Notifications When Book GUIs are ignored", + description = "Sends a notification if Synthesis ignores a book GUI. Only turn this off if you know what you're doing.", + category = "Miscellaneous" + ) + public boolean miscIgnoreHypixelBooksWarning = true; + + @Property( + type = PropertyType.SWITCH, + name = "More burger", + description = "WHY WOULD YOU ENABLE THIS WHY.", + category = "Miscellaneous" + ) + public boolean miscMoreBurgers = false; //PATCHER @@ -386,13 +1298,26 @@ public void utilitiesBridgeTestFormat() { public String patcherCustomDomains = ""; public Config() { - super(new File(Synthesis.configLocation), "§dSynthesis", new JVMAnnotationPropertyCollector(), new CustomSortingBehavior()); + super(new File(Synthesis.configLocation), "§dSynthesis§r - §bNON-CANON EDITION BY ERYMANTHUS", new JVMAnnotationPropertyCollector(), new CustomSortingBehavior()); + initialize(); + setSubcategoryDescription("Utilities", "Server occupancy overlay", "Ever wondered how full a lobby is?\nEver wanted a visual indicator of that metric?\nHere you go!"); + 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."); hidePropertyIf("patcherCompactChatFix", () -> !Loader.isModLoaded("patcher")); hidePropertyIf("patcherCustomImagePreviewer", () -> !Loader.isModLoaded("patcher")); + hidePropertyIf("utilitiesShareScroll", () -> !Loader.isModLoaded("text_overflow_scroll")); hidePropertyIf("utilitiesWishingCompassWaypoint", () -> !Loader.isModLoaded("skytils")); + hidePropertyIf("miscMoreBurgers", () -> (!(Minecraft.getMinecraft().getSession().getPlayerID().equalsIgnoreCase("1f20d60f1bc242dd82669a173a7af77c")) && !(Minecraft.getMinecraft().getSession().getPlayerID().equalsIgnoreCase("b43d74579da4408ba9fb51239022cec9")))); addDependency("utilitiesWishingCompassWaypoint", "utilitiesWishingCompass"); addDependency("utilitiesBlockWishingCompass", "utilitiesWishingCompass"); + addDependency("utilitiesContainerControl", "utilitiesContainerChat"); + addDependency("cleanupDungeonBlessingMessages", "cleanupDungeonBlessingStatMessages"); + addDependency("utilitiesWitherImpactPerspectiveGlobal", "utilitiesWitherImpactPerspective"); + addDependency("utilitiesOccupancyOverlayFriendHighlght", "utilitiesOccupancyOverlay"); + addDependency("utilitiesOccupancyOverlayGuildHighlght", "utilitiesOccupancyOverlay"); + addDependency("utilitiesOccupancyOverlayFriendAndGuildHighlght", "utilitiesOccupancyOverlay"); + addDependency("utilitiesOccupancyOverlayAlreadyConnectedHighlght", "utilitiesOccupancyOverlay"); + addDependency("miscIgnoreHypixelBooksWarning", "miscIgnoreHypixelBooks"); + addDependency("utilitiesHexatorumDebug", "utilitiesHexatorumOverlay"); registerListener("utilitiesColorlessPanes", (z) -> Minecraft.getMinecraft().renderGlobal.loadRenderers()); - initialize(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/luna/synthesis/events/MessageSentEvent.java b/src/main/java/com/luna/synthesis/events/MessageSentEvent.java new file mode 100644 index 0000000..4f7e5d4 --- /dev/null +++ b/src/main/java/com/luna/synthesis/events/MessageSentEvent.java @@ -0,0 +1,13 @@ +package com.luna.synthesis.events; + +import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.fml.common.eventhandler.Event; + +@Cancelable +public class MessageSentEvent extends Event { + public String message; + + public MessageSentEvent(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/src/main/java/com/luna/synthesis/features/cleanup/CoopCleanup.java b/src/main/java/com/luna/synthesis/features/cleanup/CoopCleanup.java index 61c9c44..2481abe 100644 --- a/src/main/java/com/luna/synthesis/features/cleanup/CoopCleanup.java +++ b/src/main/java/com/luna/synthesis/features/cleanup/CoopCleanup.java @@ -1,16 +1,15 @@ package com.luna.synthesis.features.cleanup; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.events.packet.PacketReceivedEvent; -import com.luna.synthesis.utils.ChatLib; import com.luna.synthesis.utils.Utils; import net.minecraft.client.Minecraft; import net.minecraft.event.HoverEvent; import net.minecraft.network.play.server.S02PacketChat; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IChatComponent; import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -29,9 +28,10 @@ public class CoopCleanup { private List messageQueue = new ArrayList<>(); private boolean isDividerBlock = false; + private IChatComponent theMessage = null; private final AtomicReference price = new AtomicReference<>(""); - @Comment("Collection tooltips. I could have used regexes for other people's contributions but they are laggy and this is invoked a lot of times per second. If there is any problem with this I'll eventually swap to regex but for now, this is decent. Also no, that Minecraft.getMinecraft().getSession().getUsername() further down is not a session stealer.") + // 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. @SubscribeEvent public void onTooltip(ItemTooltipEvent event) { if (config.cleanupCoopCollections == 0) return; @@ -39,9 +39,8 @@ public void onTooltip(ItemTooltipEvent event) { event.toolTip.removeIf(s -> EnumChatFormatting.getTextWithoutFormattingCodes(s).endsWith(": 0")); } else if (config.cleanupCoopCollections == 2) { Iterator iterator = event.toolTip.iterator(); - iterator.forEachRemaining(s -> { - String actualLine = EnumChatFormatting.getTextWithoutFormattingCodes(s); - + while (iterator.hasNext()) { + String actualLine = EnumChatFormatting.getTextWithoutFormattingCodes(iterator.next()); if (actualLine.equals("")) { onContributions = false; } @@ -54,12 +53,12 @@ public void onTooltip(ItemTooltipEvent event) { if (actualLine.startsWith("Co-op Contributions:")) { onContributions = true; } - }); + } onContributions = false; } else if (config.cleanupCoopCollections == 3) { Iterator iterator = event.toolTip.iterator(); - iterator.forEachRemaining(s -> { - String actualLine = EnumChatFormatting.getTextWithoutFormattingCodes(s); + while (iterator.hasNext()) { + String actualLine = EnumChatFormatting.getTextWithoutFormattingCodes(iterator.next()); if (actualLine.startsWith("Co-op Contributions:")) { shouldRemove = true; } @@ -72,13 +71,12 @@ public void onTooltip(ItemTooltipEvent event) { if (actualLine.equals("")) { shouldRemove = false; } - }); + } shouldRemove = false; } } - @Comment("Travel messages. Same thing as earlier, but as long as it works without regexes and people can't fake the message, I won't use regexes.") - // &9&l» &aaliasalias &eis traveling to &aPrivate Island &e&lFOLLOW&r + // 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 @SubscribeEvent public void onChatMessage(ClientChatReceivedEvent event) { if (!config.cleanupCoopTravel) return; @@ -106,13 +104,18 @@ public void onChatMessage(ClientChatReceivedEvent event) { event.setCanceled(true); } } - if (event.message.getUnformattedText().startsWith("BIN Auction started for ") && !price.get().equals("")) { - event.message = new ChatComponentText(event.message.getFormattedText().replace("!", "") + EnumChatFormatting.YELLOW + " at " + EnumChatFormatting.GOLD + price.get() + " coins" + EnumChatFormatting.YELLOW + "!"); - price.set(""); + if (event.message.getUnformattedText().startsWith("BIN Auction started for ")) { + if (!price.get().equals("")) { + event.message = new ChatComponentText(event.message.getFormattedText().replace("!", "") + EnumChatFormatting.YELLOW + " at " + EnumChatFormatting.GOLD + price.get() + " coins" + EnumChatFormatting.YELLOW + "!"); + price.set(""); + } else { + theMessage = event.message; + event.setCanceled(true); + } } } - @Comment("Used as a way to detect bulk/block messages (that are surrounded by dividers, like coop messages).") + // Used as a way to detect bulk messages (the ones between dividers) and filter out potential messages that got caught between them. @SubscribeEvent public void onPacketReceived(PacketReceivedEvent event) { if (event.getPacket() instanceof S02PacketChat) { @@ -186,6 +189,11 @@ public void onPacketReceived(PacketReceivedEvent event) { return false; }).collect(Collectors.toList()); if (messageQueue.size() <= 2) messageQueue.clear(); + if (theMessage != null && !price.get().equals("")) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(theMessage.getFormattedText().replace("!", "") + EnumChatFormatting.YELLOW + " at " + EnumChatFormatting.GOLD + price.get() + " coins" + EnumChatFormatting.YELLOW + "!")); + theMessage = null; + price.set(""); + } } else { isDividerBlock = true; messageQueue.add(packet.getChatComponent().getUnformattedText()); diff --git a/src/main/java/com/luna/synthesis/features/cleanup/DungeonCleanup.java b/src/main/java/com/luna/synthesis/features/cleanup/DungeonCleanup.java new file mode 100644 index 0000000..40dad2a --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/cleanup/DungeonCleanup.java @@ -0,0 +1,47 @@ +package com.luna.synthesis.features.cleanup; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class DungeonCleanup { + + private final Config config = Synthesis.getInstance().getConfig(); + + @SubscribeEvent + public void onChatMessage(ClientChatReceivedEvent event) { + if (event.type != 0) return; + String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); + if (!msg.contains(":")) { + 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.")) { + event.setCanceled(true); + } + if (config.cleanupDungeonSoloClassMessage) { + if (msg.startsWith("Your ") && msg.endsWith(" stats are doubled because you are the only player using this class!")) { + event.setCanceled(true); + } else if (msg.startsWith("[Healer] ") || msg.startsWith("[Berserk] ") || msg.startsWith("[Mage] ") || msg.startsWith("[Archer] ") || msg.startsWith("[Tank] ")) { + event.setCanceled(true); + } + } + if (config.cleanupDungeonUltimateMessage && msg.endsWith(" is ready to use! Press DROP to activate it!")) { + event.setCanceled(true); + } + if (config.cleanupDungeonBlessingStatMessages) { + 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 ")) { + event.setCanceled(true); + } + } + if (config.cleanupDungeonSilverfishMessages && msg.equals("You cannot hit the silverfish while it's moving!")) { + event.setCanceled(true); + } + 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!"))) { + event.setCanceled(true); + } + } + if (config.cleanupDungeonWatcherMessages && msg.startsWith("[BOSS] The Watcher: ") && !msg.equals("[BOSS] The Watcher: You have proven yourself. You may pass.")) { + event.setCanceled(true); + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/cleanup/LoreCleanup.java b/src/main/java/com/luna/synthesis/features/cleanup/LoreCleanup.java new file mode 100644 index 0000000..3e872a2 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/cleanup/LoreCleanup.java @@ -0,0 +1,282 @@ +package com.luna.synthesis.features.cleanup; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.Minecraft; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StringUtils; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import net.minecraft.item.ItemSkull; + +import java.util.Iterator; + +public class LoreCleanup { + + private final Config config = Synthesis.getInstance().getConfig(); + // Some fucking tasty spaghetti + + @SubscribeEvent(priority = EventPriority.LOW) + public void onItemTooltip(ItemTooltipEvent event) { + if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { + ContainerChest containerChest = (ContainerChest)Minecraft.getMinecraft().thePlayer.openContainer; + String title = StringUtils.stripControlCodes(containerChest.getLowerChestInventory().getDisplayName().getUnformattedText()); + if (config.cleanupLoreAuctionException && (title.startsWith("Auctions") || title.endsWith("Auction View") || title.endsWith("'s Auctions"))) return; + } + ItemStack item = event.itemStack; + if (!item.hasTagCompound() || !item.getTagCompound().hasKey("ExtraAttributes") || !item.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("id")) return; + Iterator iterator = event.toolTip.iterator(); + int index = 0; + boolean inEnchantments = false; + boolean inAbility = false; + boolean petHoldingItem = false; + 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]).+"))); + boolean isBlackCat = false; + String previousLine = ""; + while (iterator.hasNext()) { + // Thank you vanilla, very cool + String line = iterator.next().replace("§5§o", ""); + // GEAR SCORE, GEMSTONE SLOTS, SOULBOUND, PET STUFF + if (config.cleanupPetDisplayName && inPetsMenuAndIsAPet && StringUtils.stripControlCodes(item.getDisplayName()).startsWith("[Lvl ") && StringUtils.stripControlCodes(item.getDisplayName()).contains("] ")){ + item.setStackDisplayName(item.getDisplayName().replace("Lvl ", "")); + if (StringUtils.stripControlCodes(item.getDisplayName()).contains("Black Cat")) { + /** + * + * Suggestion #84 by minhperry#2803 + * "fix" black cat description + * + */ + isBlackCat = true; + } + } + /* CONDITIONAL TO SKIP BASE CASE LINES, EDIT WITH CAUTION! -ERY */ + else if (inPetsMenuAndIsAPet && (previousLine.startsWith("§6") && previousLine.contains("Held Item"))) { + //(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 + previousLine = line; + } 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"))) { + previousLine = line; + if (config.cleanupLorePetType == 3 || line.contains("All Skills")) + if (isBlackCat) { + //suggestion #84 implementation + event.toolTip.set(index, line.replace(line, "§7Note: Magic Find and Pet Luck increases are not additive, but rather percentage-based.")); + } else { + iterator.remove(); + } + else { + if (config.cleanupLorePetType == 2 && !line.contains("All Skills")) { + event.toolTip.set(index, line.replace("Mining ", "").replace("Combat ", "").replace("Fishing ", "").replace("Farming ", "").replace("Foraging ", "").replace("Enchanting ", "").replace("Alchemy ", "").replace("Gabagool ", "")); + } + else if (config.cleanupLorePetType == 1) { + event.toolTip.set(index, line.replace(" Pet", "").replace(" Mount", "").replace(" Morph", "").replace(", feed to gain XP", "")); + } + if (isBlackCat) { + //suggestion #84 implementation + event.toolTip.set(index, line.replace(line, line + " §7(Magic Find and Pet Luck increases are not additive, but rather percentage-based)")); + } + } + } else if ((config.cleanupLorePetType == 0) && (isBlackCat)) { + //suggestion #84 implementation + event.toolTip.set(index, line.replace(line, line + " §7(Magic Find and Pet Luck increases are not additive, but rather percentage-based)")); + } else if (config.cleanupLorePetPerkName && inPetsMenuAndIsAPet && line.startsWith("§6") && !line.contains("Held Item")) { + previousLine = line; + iterator.remove(); + } + /* PLAN: SOMEHOW DETECT THE BEGINNING OF A NEW PERK DESCRIPTION AND ADD A HYPHEN TO THE BEGINNING OF IT. + I ALREADY TRIED THE "inXYZ" CONDITIONAL STRATEGY AND IT WENT TERRIBLY WRONG BECAUSE, AGAIN, HYPIXEL + PET MENU LORE HAS NO STANDARD CONVENTION WHATSOEVER. -ERY + + else if (config.cleanupLorePetPerkHyphens && inPetsMenuAndIsAPet && line.contains("§7§7") && !line.contains(":") && line.matches(".*§7§7[A-Z].*") && !previousLine.contains("Held Item")) { + event.toolTip.set(index, ("§e§r§7- " + line)); + previousLine = line; + continue; + */ + else if (config.cleanupLorePetHeldItemPrefix && inPetsMenuAndIsAPet && line.contains("Held Item")) { + previousLine = line; + event.toolTip.set(index, line.replace("Held Item: ", "")); + petHoldingItem = true; + } else if (config.cleanupLorePetMaxLevel && inPetsMenuAndIsAPet && line.contains("MAX LEVEL")) { + previousLine = line; + iterator.remove(); + } else if (config.cleanupLorePetClickToSummon && inPetsMenuAndIsAPet && line.contains("Click to summon!")) { + previousLine = line; + iterator.remove(); + } else if (config.cleanupLorePetClickToDespawn && inPetsMenuAndIsAPet && line.contains("Click to despawn!")) { + previousLine = line; + iterator.remove(); + } else if (config.cleanupLorePetCandiesUsed && inPetsMenuAndIsAPet && line.contains("Pet Candy Used")) { + previousLine = line; + // 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 + int ifPetHeldItemEnabledOffset = 2; + if (!config.cleanupLorePetHeldItemPrefix) + if (!petHoldingItem) + ifPetHeldItemEnabledOffset = 0; + else + ifPetHeldItemEnabledOffset = 1; + else if (!petHoldingItem) + ifPetHeldItemEnabledOffset = 0; + // end hacky solution -ery + String pluralOrSingular = "Candies"; + if (line.contains("1/") && !line.contains("10/")) + pluralOrSingular = "Candy"; + event.toolTip.set(index + ifPetHeldItemEnabledOffset, line.replace("/10", "").replace("Pet Candy Used", pluralOrSingular).replace("(", "").replace(")", "")); + } else if (config.cleanupLorePetEmptyLines && inPetsMenuAndIsAPet && line.equals("")) { + previousLine = line; + iterator.remove(); + } + /* PLAN: SOMEHOW REMOVE PROGRESS BAR WITHOUT EDGE CASES OF PROGRESS COUNT DUPLICATING ITSELF. + ATTEMPTED AND FAILED BECAUSE AAAAAAAAAAAAAAAAAA -ERY + + else if (config.cleanupLorePetLevelProgressBar && inPetsMenuAndIsAPet && line.contains("--") && (line.contains("f-") || line.contains("2-"))) { + event.toolTip.set(index, line.replaceAll("-", "")); + previousLine = line; + // iterator.remove(); + continue; + } + */ + /* PLAN: SOMEHOW REMOVE TEXT PRECEDING PERCENTAGE PROGRESS. + ATTEMPTED AND FAILED BECAUSE AAAAAAAAAAAAAAAAAA -ERY + + else if (config.cleanupLorePetLevelPercent && inPetsMenuAndIsAPet && line.contains("Progress to Level")) { + event.toolTip.set(index, line.replaceAll(".*Progress to Level [0-9]{1,3}.*", "% of next Lvl")); + // previousLine = line; + continue; + } + */ + else if (StringUtils.stripControlCodes(line).startsWith("Gear Score: ") && config.cleanupLoreGearScore) { + iterator.remove(); + } else if (StringUtils.stripControlCodes(line).startsWith(" [") && config.cleanupLoreGemstoneSlots) { + iterator.remove(); + } else if ((line.contains("§8§l") && line.contains("*") && line.contains("8Co-op Soulbound")) && config.cleanupLoreCoopSoulbound) { + iterator.remove(); + } else if ((line.contains("§8§l") && line.contains("*") && line.contains("8Soulbound")) && config.cleanupLoreSoloSoulbound) { + iterator.remove(); + } else { + // STAT BONUSES, RECOMBOBULATED TEXT + if (line.contains(" ")) { + for (String s : line.split(" ")) { + String replacement = line.replace(s + " ", "").replace(s, ""); + if (s.startsWith("§8(+") && config.cleanupLoreDungeon) { + event.toolTip.set(index, replacement); + line = replacement; + } else if (s.startsWith("§d(+") && config.cleanupLoreGemstones) { + event.toolTip.set(index, replacement); + line = replacement; + } else if (s.startsWith("§9(+") && config.cleanupLoreReforge) { + event.toolTip.set(index, replacement); + line = replacement; + } else if (s.startsWith("§e(+") && config.cleanupLoreHPB) { + event.toolTip.set(index, replacement); + line = replacement; + } else if (s.contains("§l§ka") && config.cleanupLoreRecombobulatedObfuscated) { + event.toolTip.set(index, replacement); + line = replacement; + } + } + } + + // ENCHANTMENTS + if (!StringUtils.stripControlCodes(item.getDisplayName()).equals("Enchanted Book")) { + if (((line.startsWith("§9") || line.startsWith("§d§l")) && config.cleanupLoreEnchantmentDescriptions && !(inPetsMenuAndIsAPet && item.getItem() instanceof ItemSkull))) inEnchantments = true; + if (inEnchantments) { + if (!config.cleanupLoreEnchantments && (line.startsWith("§9") || line.startsWith("§d§l"))) { + index++; + continue; + } + if (StringUtils.stripControlCodes(line).equals("")) { + iterator.remove(); + continue; + } + inEnchantments = false; + if (config.cleanupLoreEnchantments) { + iterator.remove(); + continue; + } + } + } + + // ABILITIES + if (!line.endsWith("RIGHT CLICK") && !line.endsWith("LEFT CLICK") && !line.equals("§aScroll Abilities:")) { + if (config.cleanupLoreReforgeAbility && line.startsWith("§9") && line.endsWith(" Bonus")) inAbility = true; + else if (config.cleanupLoreFullSetBonus && line.startsWith("§6Full Set Bonus: ")) inAbility = true; + else if (config.cleanupLorePieceBonus && line.startsWith("§6Piece Bonus: ")) inAbility = true; + } else if (config.cleanupLoreAbilities) { + inAbility = true; + } + if (inAbility) { + iterator.remove(); + if (line.equals("")) inAbility = false; + } else { + index++; + } + } + } + if ((item.getSubCompound("ExtraAttributes", false) != null) && !inPetsMenuAndIsAPet) { + /* + * Suggestion #69 by aHuman#6726 + * option to show uuid of an item in it's lore + * + */ + // UUID — THIS MUST BE OUTSIDE THE WHILE LOOP TO PREVENT TOOLTIP CO-MODIFICATION CRASHES + if (item.getSubCompound("ExtraAttributes", false).hasKey("uuid") && config.utilitiesLoreItemUUID != 0) { + if (config.utilitiesLoreItemUUID == 1) {event.toolTip.add("§d[Synthesis]§7 Item UUID: §l" + item.getSubCompound("ExtraAttributes", false).getString("uuid"));} + if (config.utilitiesLoreItemUUID == 2) {event.toolTip.add("§d[Synthesis]§7 Item UUID: §l" + (item.getSubCompound("ExtraAttributes", false).getString("uuid")).replaceAll("-", ""));} + } + + // ITEM ORIGIN — MUST BE OUTSIDE WHILE LOOP TO PREVENT CRASHES + if (config.utilitiesLoreOriginTag && item.getSubCompound("ExtraAttributes", false).getString("originTag") != null && item.getSubCompound("ExtraAttributes", false).getString("originTag") != "") { + event.toolTip.add("§d[Synthesis]§7 Item origin: §l" + item.getSubCompound("ExtraAttributes", false).getString("originTag").replaceAll("_", " ")); + } + /* + * + * Suggestion #99 by FledGuy#3686 + * old master stars + * + */ + if ((item.getDisplayName().contains("§6✪§c")) && config.utilitiesMasterStarDisplay != 0) { + /* + * force .replace() everywhere. could've used while loops + * but those didnt work apparently and .replace() is far + * easier to manage + */ + if (config.utilitiesMasterStarDisplay == 2) { + item.setStackDisplayName( + item.getDisplayName() + .replace("§c➎","§c✪§c✪§c✪§c✪§c✪") + .replace("§c➍","§c✪§c✪§c✪§c✪") + .replace("§c➌","§c✪§c✪§c✪") + .replace("§c➋","§c✪§c✪") + .replace("§c➊","§c✪") + ); + } else { + String masterPlan = item.getDisplayName() + .replace("§c➎","") + .replace("§c➍","") + .replace("§c➌","") + .replace("§c➋","") + .replace("§c➊",""); + int numStarsOne = item.getSubCompound("ExtraAttributes", false).getInteger("upgrade_level"); + int numStarsTwo = item.getSubCompound("ExtraAttributes", false).getInteger("dungeon_item_level"); + int numMasters = (((numStarsTwo < numStarsOne ? numStarsOne : numStarsTwo)) - 5); + String maxStars = "§6✪§6✪§6✪§6✪§6✪"; + if (config.utilitiesMasterStarDisplay == 1) { + if (numMasters == 1) { + masterPlan = masterPlan.replace(maxStars,"§c✪§6✪§6✪§6✪§6✪"); + } else if (numMasters == 2) { + masterPlan = masterPlan.replace(maxStars,"§c✪§c✪§6✪§6✪§6✪"); + } else if (numMasters == 3) { + masterPlan = masterPlan.replace(maxStars,"§c✪§c✪§c✪§6✪§6✪"); + } else if (numMasters == 4) { + masterPlan = masterPlan.replace(maxStars,"§c✪§c✪§c✪§c✪§6✪"); + } else if (numMasters == 5) { + masterPlan = masterPlan.replace(maxStars,"§c✪§c✪§c✪§c✪§c✪"); + } + } + item.setStackDisplayName(masterPlan); + } + } + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/future/ChunkBorders.java b/src/main/java/com/luna/synthesis/features/future/ChunkBorders.java index 8be0e2b..088382b 100644 --- a/src/main/java/com/luna/synthesis/features/future/ChunkBorders.java +++ b/src/main/java/com/luna/synthesis/features/future/ChunkBorders.java @@ -1,6 +1,5 @@ package com.luna.synthesis.features.future; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import net.minecraft.client.Minecraft; @@ -20,7 +19,7 @@ public class ChunkBorders { private final Config config = Synthesis.getInstance().getConfig(); private boolean isToggled = false; - @Comment("Code directly taken from 1.12.2, translated to 1.8.9 and cleaned up a little.") + // Directly taken from 1.12.2, translated and adapted a bit. @SubscribeEvent public void onRenderWorld(RenderWorldLastEvent event) { if (!config.futureChunkBorders) return; @@ -114,7 +113,7 @@ public void onRenderWorld(RenderWorldLastEvent event) { GlStateManager.enableTexture2D(); } - @Comment("61 is F3, 34 is G") + // F3 + G, like in future versions of the game. Should this be configurable? Eh.. @SubscribeEvent public void onKeyPress(InputEvent.KeyInputEvent event) { if (!Keyboard.getEventKeyState()) return; diff --git a/src/main/java/com/luna/synthesis/features/misc/HypixelBooksAreStupid.java b/src/main/java/com/luna/synthesis/features/misc/HypixelBooksAreStupid.java new file mode 100644 index 0000000..62e4e90 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/misc/HypixelBooksAreStupid.java @@ -0,0 +1,26 @@ +package com.luna.synthesis.features.misc; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; + +import gg.essential.api.EssentialAPI; +import net.minecraft.client.gui.GuiScreenBook; + +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class HypixelBooksAreStupid { + + private final Config config = Synthesis.getInstance().getConfig(); + + @SubscribeEvent + public void onBook(GuiOpenEvent e) { + if (!config.miscIgnoreHypixelBooks) {return;} + if ((e.gui instanceof GuiScreenBook) && (EssentialAPI.getMinecraftUtil().isHypixel())) { + e.setCanceled(true); + if (config.miscIgnoreHypixelBooksWarning) { + EssentialAPI.getNotifications().push("§dSynthesis", ("Synthesis detected a book GUI and ignored it. Check the server you're on and review your configs if ignoring the book GUI was a mistake or if this notification was a mistake."), 5); + } + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/misc/MilaysWontStopAskingForBurgers.java b/src/main/java/com/luna/synthesis/features/misc/MilaysWontStopAskingForBurgers.java new file mode 100644 index 0000000..5c84004 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/misc/MilaysWontStopAskingForBurgers.java @@ -0,0 +1,34 @@ +package com.luna.synthesis.features.misc; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ChatComponentText; + +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class MilaysWontStopAskingForBurgers { + + private final Config config = Synthesis.getInstance().getConfig(); + + private final boolean ISMILAYS = Minecraft.getMinecraft().getSession().getPlayerID().equalsIgnoreCase("1f20d60f1bc242dd82669a173a7af77c"); + private final boolean ISERY = Minecraft.getMinecraft().getSession().getPlayerID().equalsIgnoreCase("b43d74579da4408ba9fb51239022cec9"); + + @SubscribeEvent + public void onChatRecievedEvent(ClientChatReceivedEvent e) { + if (!ISMILAYS && !ISERY) {config.miscMoreBurgers = false; return;} + if (config.miscMoreBurgers) { + String[] bruh = e.message.getFormattedText().replaceAll("§r","").split(" "); + String newMessage = ""; + e.setCanceled(true); + for (String s : bruh) { + s = s.substring(0, 2); + newMessage += s + "burger§r "; + } + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(newMessage)); + } + } + +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/AncestralSpade.java b/src/main/java/com/luna/synthesis/features/utilities/AncestralSpade.java new file mode 100644 index 0000000..3b666eb --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/AncestralSpade.java @@ -0,0 +1,155 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import com.luna.synthesis.events.packet.PacketReceivedEvent; +import com.luna.synthesis.utils.ChatLib; +import com.luna.synthesis.utils.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.item.ItemStack; +import net.minecraft.network.play.server.S2APacketParticles; +import net.minecraft.util.*; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +public class AncestralSpade { + + private final Config config = Synthesis.getInstance().getConfig(); + private final ResourceLocation beaconBeam = new ResourceLocation("textures/entity/beacon_beam.png"); + private boolean awaiting = false; + private boolean awaitingForArrow = false; + private long lastSpoon = -1L; + private Vec3 pos1 = null; + private Vec3 pos2 = null; + private Vec3 vec1 = null; + private Vec3 vec2 = null; + private BlockPos solution = null; + + @SubscribeEvent + public void onPacketReceived(PacketReceivedEvent event) { + if (!config.utilitiesAncestralSpade) return; + if (event.getPacket() instanceof S2APacketParticles) { + S2APacketParticles packet = (S2APacketParticles) event.getPacket(); + if (packet.getParticleType() == EnumParticleTypes.FIREWORKS_SPARK && packet.getXOffset() == 0 && packet.getYOffset() == 0 && packet.getZOffset() == 0) { + if (packet.getParticleSpeed() == 0 && packet.getParticleCount() == 1) { + if (awaiting) { + if (pos1 == null) { + pos1 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); + awaiting = false; + } else if (pos2 == null) { + pos2 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); + awaiting = false; + } + } else { + if (vec1 == null && pos1 != null) { + vec1 = new Vec3(packet.getXCoordinate() - pos1.xCoord, packet.getYCoordinate() - pos1.yCoord, packet.getZCoordinate() - pos1.zCoord).normalize(); + } else if (vec2 == null && pos2 != null) { + vec2 = new Vec3(packet.getXCoordinate() - pos2.xCoord, packet.getYCoordinate() - pos2.yCoord, packet.getZCoordinate() - pos2.zCoord).normalize(); + calculateIntercept(); + } + } + } + } else if (packet.getParticleType() == EnumParticleTypes.REDSTONE && packet.getParticleSpeed() == 1 && packet.getParticleCount() == 0) { + if (awaitingForArrow) { + if (pos1 == null) { + pos1 = new Vec3(packet.getXCoordinate(), packet.getYCoordinate(), packet.getZCoordinate()); + } else if (vec1 == null) { + if (packet.getXCoordinate() - pos1.xCoord == 0 && packet.getZCoordinate() - pos1.zCoord == 0) return; + vec1 = new Vec3(packet.getXCoordinate() - pos1.xCoord, packet.getYCoordinate() - pos1.yCoord, packet.getZCoordinate() - pos1.zCoord).normalize(); + awaitingForArrow = false; + } + } + } + } + } + + @SubscribeEvent + public void onRightClick(PlayerInteractEvent event) { + if (!config.utilitiesAncestralSpade) return; + if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR || event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); + if (item == null) return; + if (StringUtils.stripControlCodes(item.getDisplayName()).contains("Ancestral Spade")) { + if (System.currentTimeMillis() >= lastSpoon + 3000) { + if (Minecraft.getMinecraft().thePlayer.rotationPitch == 90 || Minecraft.getMinecraft().thePlayer.rotationPitch == -90) { + awaiting = true; + lastSpoon = System.currentTimeMillis(); + } + } + } + } + } + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event) { + if (solution != null && Minecraft.getMinecraft().thePlayer != null) { + if (Math.pow(Minecraft.getMinecraft().thePlayer.posX - solution.getX(), 2) + Math.pow(Minecraft.getMinecraft().thePlayer.posZ - solution.getZ(), 2) <= 9) { + solution = null; + } + } + } + + @SubscribeEvent + public void onChatMessage(ClientChatReceivedEvent event) { + if (event.type == 2) return; + if (!config.utilitiesAncestralSpade || !config.utilitiesAncestralSpadeArrow) return; + String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); + if (msg.startsWith("You dug out a Griffin Burrow!")) { + awaitingForArrow = true; + } + } + + @SubscribeEvent + public void onRenderWorld(RenderWorldLastEvent event) { + if (config.utilitiesAncestralSpadeWaypoint && solution != null) { + double renderPosX = Minecraft.getMinecraft().getRenderManager().viewerPosX; + double renderPosY = Minecraft.getMinecraft().getRenderManager().viewerPosY; + double renderPosZ = Minecraft.getMinecraft().getRenderManager().viewerPosZ; + GlStateManager.pushMatrix(); + GlStateManager.translate(-renderPosX, -renderPosY, -renderPosZ); + Minecraft.getMinecraft().getTextureManager().bindTexture(beaconBeam); + Utils.renderBeamSegment(solution.getX(), 0, solution.getZ(), event.partialTicks, 1.0, Minecraft.getMinecraft().theWorld.getTotalWorldTime(), 0, 256, config.utilitiesAncestralSpadeWaypointColor.getColorComponents(null)); + GlStateManager.translate(renderPosX, renderPosY, renderPosZ); + GlStateManager.popMatrix(); + } + } + + @SubscribeEvent + public void onWorldLoad(WorldEvent.Load event) { + pos1 = null; + pos2 = null; + vec1 = null; + vec2 = null; + awaiting = false; + solution = null; + } + + // All math in the mod is thanks to Lucy, this included, thank you, Lucy! + // If you don't understand something don't blame me, I just copied her notes. + // And no, you cannot expect me to do very simple math, I will simply ask the math genius when possible. + private void calculateIntercept() { + double p1x = pos1.xCoord; + double p1z = pos1.zCoord; + double v1x = vec1.xCoord; + double v1z = vec1.zCoord; + // + double p2x = pos2.xCoord; + double p2z = pos2.zCoord; + double v2x = vec2.xCoord; + double v2z = vec2.zCoord; + double a = v1z / v1x * p1x - p1z; + double b = v2z / v2x * p2x - p2z; + double x = (a - b) / (v1z / v1x - v2z / v2x); + double z = v1z / v1x * x - a; + + BlockPos solution = new BlockPos(x, 0, z); + ChatLib.chat("Solution: (" + solution.getX() + ", " + solution.getZ() + ")"); + this.solution = solution; + pos1 = pos2 = vec1 = vec2 = null; + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/BestiaryDropRate.java b/src/main/java/com/luna/synthesis/features/utilities/BestiaryDropRate.java index 7298394..cf62acd 100644 --- a/src/main/java/com/luna/synthesis/features/utilities/BestiaryDropRate.java +++ b/src/main/java/com/luna/synthesis/features/utilities/BestiaryDropRate.java @@ -30,11 +30,13 @@ public void onItemTooltip(ItemTooltipEvent event) { it.forEachRemaining(s -> { String line = StringUtils.stripControlCodes(s); if (line.endsWith("%)")) { - double number = Double.parseDouble(line.split("\\(")[1].replace("%)", "")); - if (number < 100) { - event.toolTip.set(i.get(), s.replaceAll("\\(§a[\\d.]+%§8\\)", - EnumChatFormatting.DARK_GRAY + "(" + EnumChatFormatting.GREEN + "1/" + Math.floor(10000/number + 0.5) / 100 + EnumChatFormatting.DARK_GRAY + ")")); - } + try { + double number = Double.parseDouble(line.split("\\(")[1].replace("%)", "")); + if (number < 100) { + event.toolTip.set(i.get(), s.replaceAll("\\(§a[\\d.]+%§8\\)", + EnumChatFormatting.DARK_GRAY + "(" + EnumChatFormatting.GREEN + "1/" + Math.floor(10000 / number + 0.5) / 100 + EnumChatFormatting.DARK_GRAY + ")")); + } + } catch (NumberFormatException ignored) {} } i.getAndIncrement(); }); diff --git a/src/main/java/com/luna/synthesis/features/utilities/BestiaryWarning.java b/src/main/java/com/luna/synthesis/features/utilities/BestiaryWarning.java new file mode 100644 index 0000000..12b8bcf --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/BestiaryWarning.java @@ -0,0 +1,130 @@ +package com.luna.synthesis.features.utilities; + +import gg.essential.api.EssentialAPI; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import com.luna.synthesis.utils.ChatLib; + +import net.minecraft.client.Minecraft; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.util.StringUtils; +import net.minecraft.item.ItemSkull; + +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.List; +import java.util.regex.Pattern; + +/** + *
+ * BestiaryWarning
+ * A Java class by Erymanthus | RayDeeUx for Synthesis-NONCANON.
+ * 
+ * Suggestion #63 by minhperry#2803
+ * warning if you are near the 1m combat xp bestiary rhing (sic)
+ * 
+ * two options: chat or essential notification
+ * options for duration (notification) and frequency
+ * stops when you've passed 1m combat xp neighborhood
+ * 
+ */ + +public class BestiaryWarning { + + private final Config config = Synthesis.getInstance().getConfig(); + private final Pattern bestiaryFamilyPattern = Pattern.compile(".*3.*BESTIARY.*"); + private final Pattern bestiaryLevelPattern = Pattern.compile(".*6.*BESTIARY.*MILESTONE.*"); + + private boolean isAboutToLevelUp = false; + private int bestiaryLevel = 0; + private int levelProgress = 0; + private int ticks = 0; + + @SubscribeEvent + public void onItemTooltip(ItemTooltipEvent event) { + if (!(Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) || + !(StringUtils.stripControlCodes(event.itemStack.getDisplayName()).startsWith("Bestiary Milestone ")) || + !(event.itemStack.getItem() instanceof ItemSkull)) return; + try { + bestiaryLevel = Integer.parseInt(StringUtils.stripControlCodes(event.itemStack.getDisplayName()).replace("Bestiary Milestone ", "")); + config.personalBestiaryLevel = bestiaryLevel; //write to config + if ((((bestiaryLevel+1) % 2) == 0) && ((bestiaryLevel+1) != 4) && ((bestiaryLevel+1) != 6) && ((bestiaryLevel+1) != 8)) { //source: https://hypixel-skyblock.fandom.com/wiki/Bestiary + isAboutToLevelUp = true; + } + List lore = event.toolTip; + if (lore != null) { + for (String s : lore) { + if (s.endsWith("e10")) { + levelProgress = Integer.parseInt(StringUtils.stripControlCodes(s).replaceAll("-", "").replaceAll(" ", "").replaceAll("/10", "")); + } + if (!isAboutToLevelUp && (s.contains("Combat"))) { //failsafe method to cover rare edge cases + isAboutToLevelUp = true; + } + } + } + } catch (Exception ex) { + ChatLib.chat("Please disable \"Skill Numerals\" within your Personal Settings in /sbmenu. This is a tempotary hotfix until v0.4.0 manages to get its own conversion system between the Roman and Arabic numeral systems."); + } + } + + @SubscribeEvent + public void onChatRecievedEvent(ClientChatReceivedEvent event) { + if (config.utilitiesBestiaryMilestoneWarningDeliveryMethod == 0) {return;} + if ((bestiaryFamilyPattern.matcher(event.message.getFormattedText())).find() && + event.message.getFormattedText().contains("3") && + event.message.getFormattedText().contains("BESTIARY ") && + event.message.getUnformattedText().indexOf("MILESTONE") == -1 && + event.message.getUnformattedText().indexOf("Guild >") == -1 && + event.message.getUnformattedText().indexOf("Party >") == -1 && + event.message.getUnformattedText().indexOf("+]") == -1) { + ChatLib.chat("Level progress updating! Original value was " + levelProgress + "/10."); + levelProgress++; + ChatLib.chat("Level progress updated! Updated value should be " + levelProgress + "/10."); + if (levelProgress == 9) { + ChatLib.chat("Level progress is getting *very* close to 10/10."); + if (isAboutToLevelUp) { + ChatLib.chat("Preparing friendly reminder."); + } else { + ChatLib.chat("However, you are not close to a Bestiary Milestone that rewards Combat XP when unlocked. Train harder, soldier!"); + } + } + } + if ((bestiaryLevelPattern.matcher(event.message.getFormattedText())).find() && + event.message.getFormattedText().contains("6") && + event.message.getFormattedText().contains("BESTIARY ") && + event.message.getUnformattedText().indexOf("MILESTONE") != -1) { + ChatLib.chat("Ended friendly warning."); + levelProgress = 0; + bestiaryLevel++; + config.personalBestiaryLevel = bestiaryLevel; //write to config + } + } + + @SubscribeEvent + public void sendTheWarning(TickEvent.ClientTickEvent event) { + if (Minecraft.getMinecraft().thePlayer == null) {return;} + if (event.phase != TickEvent.Phase.START){return;} + if (config.utilitiesBestiaryMilestoneWarningDeliveryMethod == 0) {return;} + if (config.utilitiesBestiaryMilestoneWarningSeconds < 5 || config.utilitiesBestiaryMilestoneWarningSeconds > 60){config.utilitiesBestiaryMilestoneWarningSeconds = 5;} + if (config.utilitiesBestiaryMilestoneWarningDeliveryMethod != 0 && config.utilitiesBestiaryMilestoneWarningDeliveryMethod != 1 && config. utilitiesBestiaryMilestoneWarningDeliveryMethod != 2){config. utilitiesBestiaryMilestoneWarningDeliveryMethod = 0;} + if (config.utilitiesBestiaryMilestoneWarningDuration < 5 || config.utilitiesBestiaryMilestoneWarningDuration > 120){config.utilitiesBestiaryMilestoneWarningDuration = 5;} + if (Minecraft.getMinecraft().thePlayer != null && EssentialAPI.getMinecraftUtil().isHypixel()) { + if (levelProgress != 9 || !isAboutToLevelUp) {ticks = 0;return;} + ticks++; + if (((ticks % (20 * config.utilitiesBestiaryMilestoneWarningSeconds)) == 0 && (StringUtils.stripControlCodes(Minecraft.getMinecraft().theWorld.getScoreboard().getObjectiveInDisplaySlot(1).getDisplayName()).contains("SKYBLOCK")))) { + if (config. utilitiesBestiaryMilestoneWarningDeliveryMethod == 1) { + ChatLib.chat(("Here's a friendly reminder that you are very close to reaching Bestiary Milestone " + (config.personalBestiaryLevel+1) + " (currently at Milestone " + (config.personalBestiaryLevel) + " with progress " + (levelProgress) + "/10).")); + } else if (config. utilitiesBestiaryMilestoneWarningDeliveryMethod == 2 && (StringUtils.stripControlCodes(Minecraft.getMinecraft().theWorld.getScoreboard().getObjectiveInDisplaySlot(1).getDisplayName()).contains("SKYBLOCK"))) { + EssentialAPI.getNotifications().push("§dSynthesis", ("Here's a friendly reminder that you are very close to reaching Bestiary Milestone " + (config.personalBestiaryLevel+1) + " (currently at Milestone " + (config.personalBestiaryLevel) + " with progress " + (levelProgress) + "/10)."), config.utilitiesBestiaryMilestoneWarningDuration); + } + ticks = 0; + } + } else { + ticks = 0; + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/BetterWitherImpactPerspective.java b/src/main/java/com/luna/synthesis/features/utilities/BetterWitherImpactPerspective.java new file mode 100644 index 0000000..a322223 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/BetterWitherImpactPerspective.java @@ -0,0 +1,40 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.InputEvent; +import org.lwjgl.input.Keyboard; + +public class BetterWitherImpactPerspective { + + private final Config config = Synthesis.getInstance().getConfig(); + + // InputEvent has to be the absolute worst event in forge + @SubscribeEvent + public void onKey(InputEvent.KeyInputEvent event) { + if (!config.utilitiesWitherImpactPerspective) return; + if (!Keyboard.getEventKeyState()) return; + if (Keyboard.getEventKey() == Minecraft.getMinecraft().gameSettings.keyBindTogglePerspective.getKeyCode()) { + if (Minecraft.getMinecraft().gameSettings.thirdPersonView == 2) { + if (config.utilitiesWitherImpactPerspectiveGlobal) { + Minecraft.getMinecraft().gameSettings.thirdPersonView = 0; + } else { + ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); + if (item == null) return; + if (item.hasTagCompound()) { + if (item.getTagCompound().hasKey("ExtraAttributes")) { + if (item.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("ability_scroll")) { + if (item.getTagCompound().getCompoundTag("ExtraAttributes").getTagList("ability_scroll", 8).tagCount() == 3) { + Minecraft.getMinecraft().gameSettings.thirdPersonView = 0; + } + } + } + } + } + } + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/ChatBridge.java b/src/main/java/com/luna/synthesis/features/utilities/ChatBridge.java index 4262e99..8d07f6d 100644 --- a/src/main/java/com/luna/synthesis/features/utilities/ChatBridge.java +++ b/src/main/java/com/luna/synthesis/features/utilities/ChatBridge.java @@ -1,31 +1,22 @@ package com.luna.synthesis.features.utilities; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; -import net.minecraft.client.Minecraft; -import net.minecraft.event.ClickEvent; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.IChatComponent; +import com.luna.synthesis.utils.Utils; import net.minecraft.util.StringUtils; import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import java.net.URI; -import java.net.URISyntaxException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ChatBridge { private final Config config = Synthesis.getInstance().getConfig(); - private final Pattern msgPattern = Pattern.compile("^Guild > (?\\[[A-Z+]+] )?(?[a-zA-Z0-9_]{3,16})(? \\[.+])?: (?[^>: ]{1,32})(?( > |: ))(?.+)"); - private 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); + private final Pattern msgPattern = Pattern.compile("^Guild > (?\\[[A-Z+]+] )?(?[a-zA-Z0-9_]{3,16})(? \\[.+])?: (?.*)(?( >|:))(? .*)"); - @Comment("That second if is to not try to match that pattern on a message that will never be correct.") - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.HIGHEST) public void onClientChatMessage(ClientChatReceivedEvent event) { if (!config.utilitiesBridge) return; String message = StringUtils.stripControlCodes(event.message.getUnformattedText()); @@ -36,58 +27,8 @@ public void onClientChatMessage(ClientChatReceivedEvent event) { if (msgSender.equals(config.utilitiesBridgeBotName)) { String ign = matcher.group(4); String msg = matcher.group(7); - event.message = newChatWithLinks(config.utilitiesBridgeMessageFormat.replaceAll("&", "§").replace("", ign).replace("", msg)); + event.message = Utils.newChatWithLinks(config.utilitiesBridgeMessageFormat.replaceAll("&", "§").replace("", ign).replace("", msg)); } } } - - @Comment("Adapted from ForgeHooks::newChatWithLinks") - private IChatComponent newChatWithLinks(String string) { - IChatComponent ichat = null; - Matcher matcher = linkPattern.matcher(string); - int lastEnd = 0; - - while (matcher.find()) { - int start = matcher.start(); - int end = matcher.end(); - - String part = string.substring(lastEnd, start); - if (part.length() > 0) { - if (ichat == null) { - ichat = new ChatComponentText(part); - } else { - ichat.appendText(part); - } - } - lastEnd = end; - String url = string.substring(start, end); - IChatComponent link = new ChatComponentText(url); - - try { - if ((new URI(url)).getScheme() == null) { - url = "http://" + url; - } - } catch (URISyntaxException e) { - if (ichat == null) ichat = new ChatComponentText(url); - else ichat.appendText(url); - continue; - } - - ClickEvent click = new ClickEvent(ClickEvent.Action.OPEN_URL, url); - link.getChatStyle().setChatClickEvent(click); - if (ichat == null) { - ichat = link; - } else { - ichat.appendSibling(link); - } - } - - String end = string.substring(lastEnd); - if (ichat == null) { - ichat = new ChatComponentText(end); - } else if (end.length() > 0) { - ichat.appendText(string.substring(lastEnd)); - } - return ichat; - } } diff --git a/src/main/java/com/luna/synthesis/features/utilities/ContainerChat.java b/src/main/java/com/luna/synthesis/features/utilities/ContainerChat.java index 11dce96..8727a5f 100644 --- a/src/main/java/com/luna/synthesis/features/utilities/ContainerChat.java +++ b/src/main/java/com/luna/synthesis/features/utilities/ContainerChat.java @@ -1,32 +1,22 @@ package com.luna.synthesis.features.utilities; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; -import com.luna.synthesis.mixins.GuiContainerMixin; -import com.luna.synthesis.utils.ChatLib; +import com.luna.synthesis.mixins.accessors.GuiRepairAccessor; import com.luna.synthesis.utils.MixinUtils; -import lombok.Getter; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.GuiChat; +import net.minecraft.client.gui.GuiRepair; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.gui.inventory.GuiContainerCreative; import net.minecraft.util.MathHelper; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; -import java.security.Key; -import java.util.ArrayList; -import java.util.List; - public class ContainerChat { private final Config config = Synthesis.getInstance().getConfig(); @@ -34,31 +24,37 @@ public class ContainerChat { private String historyBuffer = ""; private int sentHistoryCursor = -1; - @Comment("For chat transfer, don't think I can make it in mixin in a decent way") + // For chat transfer magic @SubscribeEvent public void onGuiOpen(GuiOpenEvent event) { if (!config.utilitiesContainerChat) return; - if (config.utilitiesReopenContainerChat && MixinUtils.inputField != null) { - if (event.gui == null) { - if (Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { - if (MixinUtils.inputField.isFocused()) { - event.gui = new GuiChat(MixinUtils.inputField.getText()); + try { + sentHistoryCursor = Minecraft.getMinecraft().ingameGUI.getChatGUI().getSentMessages().size(); + if (config.utilitiesReopenContainerChat && MixinUtils.inputField != null) { + if (event.gui == null) { + if (Minecraft.getMinecraft().currentScreen instanceof GuiContainer) { + if (MixinUtils.inputField.isFocused()) { + event.gui = new GuiChat(MixinUtils.inputField.getText()); + } + } else { + MixinUtils.inputField = null; } - } else { - MixinUtils.inputField = null; } } - } + } catch (Exception e) {} } - @Comment("Originally in mixin, had to rewrite in events because sbe and cowlection would have bad bad compatibility issues.") + // Originally in mixin, had to rewrite because SBE and Cowlection would have bad compatibility issues. + // 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. @SubscribeEvent public void onKeyTyped(GuiScreenEvent.KeyboardInputEvent event) { if (!(event.gui instanceof GuiContainer)) return; + if (event.gui instanceof GuiContainerCreative) return; if (!config.utilitiesContainerChat) return; if (!Keyboard.getEventKeyState()) return; int keyCode = Keyboard.getEventKey(); if (MixinUtils.inputField == null) return; + if (event.gui instanceof GuiRepair && ((GuiRepairAccessor) event.gui).getNameField().isFocused()) return; if (event instanceof GuiScreenEvent.KeyboardInputEvent.Pre) { if (MixinUtils.inputField.isFocused()) { if (keyCode == 1) { @@ -67,9 +63,18 @@ public void onKeyTyped(GuiScreenEvent.KeyboardInputEvent event) { Keyboard.enableRepeatEvents(false); Minecraft.getMinecraft().ingameGUI.getChatGUI().resetScroll(); } - event.setCanceled(true); + if (keyCode != Minecraft.getMinecraft().gameSettings.keyBindScreenshot.getKeyCode()) { + event.setCanceled(true); + } } else { if (keyCode == Minecraft.getMinecraft().gameSettings.keyBindChat.getKeyCode()) { + if (config.utilitiesContainerControl && !GuiScreen.isCtrlKeyDown()) return; + if (!config.utilitiesContainerControl && GuiScreen.isCtrlKeyDown()) return; + MixinUtils.inputField.setFocused(true); + Keyboard.enableRepeatEvents(true); + return; + } else if (keyCode == Minecraft.getMinecraft().gameSettings.keyBindCommand.getKeyCode()) { + MixinUtils.inputField.setText("/"); MixinUtils.inputField.setFocused(true); Keyboard.enableRepeatEvents(true); return; diff --git a/src/main/java/com/luna/synthesis/features/utilities/FindSomeonesSkyblockInfo.java b/src/main/java/com/luna/synthesis/features/utilities/FindSomeonesSkyblockInfo.java new file mode 100644 index 0000000..e414a23 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/FindSomeonesSkyblockInfo.java @@ -0,0 +1,395 @@ +// File is now defunct as NEU's profile viewer displays both weight calculations. +// Source code remains in case someone wants to pick up this mess. +// - Erymanthus + +// package com.luna.synthesis.features.utilities; + +// import com.luna.synthesis.Synthesis; +// import com.luna.synthesis.core.Config; +// import com.luna.synthesis.events.MessageSentEvent; +// import com.luna.synthesis.utils.ChatLib; + +// import net.minecraft.client.Minecraft; +// import net.minecraftforge.client.event.ClientChatReceivedEvent; +// import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +// import org.apache.commons.io.IOUtils; + +// import java.io.InputStream; +// import java.util.Calendar; +// import java.util.Date; +// import java.util.Map; +// import java.util.Set; +// import java.net.HttpURLConnection; +// import java.net.URL; +// import java.nio.charset.StandardCharsets; +// import java.text.SimpleDateFormat; + +// import com.google.gson.*; + + +// /** +// *
+//  * FindSomeonesSkyblockInfo
+//  * A Java class by Erymanthus | RayDeeUx for Synthesis-NONCANON.
+//  * 
+//  * Suggestion #33 by OutlawMC#0001
+//  * Add the commands "/lilyweight" and "/senweight"
+//  * to get ingame weight calcs (basically same as
+//  * sbe has but add options to view both)
+//  * 
+//  * Suggestion #83 by Shy#9999
+//  * Show a short version of a players stats in trade menu's
+//  * so you can determine you (sic) SUSSY they are
+//  * 
+//  * 
+// **/ +// //to #33: SIKE! IT'S IN `[share]` FORMAT—writing it in SynthesisCommand.java won't be fun! +// //to #83: SIKE! it's shown in chat instead because i do NOT want to mess with the custom NEU trade menu. +// //event.setCanceled(true) abused because NO ONE should get muted over using this and going to appeals = going to limbo +// public class FindSomeonesSkyblockInfo { +// private final Config config = Synthesis.getInstance().getConfig(); +// private final String skyCryptURL = ("https://sky.shiiyu.moe/api/v2/profile/"); + +// @SubscribeEvent +// public void onMessageSent(MessageSentEvent event) { +// if (event.message.endsWith(config.utilitiesShareText) || event.message.endsWith(config.utilitiesShareBootsText) || event.message.endsWith(config.utilitiesShareHelmetText) || event.message.endsWith(config.utilitiesShareLeggingsText) || event.message.endsWith(config.utilitiesShareChestplateText)) {return;} +// if (event.message.startsWith("[weight")) {event.setCanceled(true); if (!config.utilitiesCheckWeight){ChatLib.chat("You have the setting disabled. Please enable it and try again, but do so with extreme caution.");return;}} +// if (event.message.startsWith("[stats") && event.message.endsWith("]")) {event.setCanceled(true); new Thread(() -> {checkSomeonesStats(event.message);}).start(); return;} +// new Thread(() -> { +// String nameToCheck = ""; +// if (event.message.startsWith("[weight")) { +// if (event.message.endsWith("[weight]")) { +// nameToCheck = Minecraft.getMinecraft().thePlayer.getName(); +// } else { +// nameToCheck = (event.message.toLowerCase().replace("[weight ", "").replace("]", "")).replace(" ", ""); +// } +// } else { +// return; +// } +// try { +// URL url = new URL(skyCryptURL + nameToCheck); +// HttpURLConnection http = (HttpURLConnection) url.openConnection(); +// http.setDoOutput(true); +// http.setDoInput(true); +// http.setRequestProperty("User-Agent", "SynthesisMod-NONCANON"); +// http.setRequestProperty("Accept", "application/json"); +// http.setRequestProperty("Method", "GET"); +// http.connect(); +// try (InputStream instream = http.getInputStream()) { +// JsonParser parser = new JsonParser(); +// JsonObject data = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); +// if (!data.has("profiles")) { +// ChatLib.chat("Synthesis failed in getting information from SkyCrypt. Either their API is down or this player doesn't have any profiles at all. Aborting mission."); +// return; +// } + +// JsonObject profiles = data.get("profiles").getAsJsonObject(); +// Set> profileSet = profiles.entrySet(); +// JsonElement currentSbProfileWeightData = null; +// String displayName = ""; + +// for (Map.Entry me : profileSet) +// { +// if (me.getValue().getAsJsonObject().get("current").getAsBoolean()) { +// displayName = ((JsonObject)(me.getValue().getAsJsonObject().get("data"))).get("display_name").getAsString(); +// currentSbProfileWeightData = ((JsonObject)(me.getValue().getAsJsonObject().get("data"))).get("weight"); +// } +// } + +// int overallSenitherWeight = ((int)((JsonObject)(currentSbProfileWeightData).getAsJsonObject().get("senither")).get("overall").getAsDouble()); +// int overallLilyWeight = ((int)((JsonObject)(currentSbProfileWeightData).getAsJsonObject().get("lily")).get("total").getAsDouble()); + +// ChatLib.chat(displayName + "'s weight info is as follows: "); +// ChatLib.chat("Overall Lily Weight: " + overallLilyWeight + "\nOverall Senither Weight: " + overallSenitherWeight); + +// } catch (Exception e) { +// ChatLib.chat("Synthesis did not get an A-OK response from SkyCrypt. The response code Synthesis got instead was " + http.getResponseCode() + ". Aborting mission."); +// System.out.println("Synthesis did not get an A-OK response from SkyCrypt. The response code Synthesis got instead was " + http.getResponseCode() + ". Aborting mission, see below."); +// return; +// } +// } catch (Exception e) { +// ChatLib.chat("Synthesis ran into a problem checking " + nameToCheck + "'s weight. See logs."); +// System.out.println("Synthesis ran into a problem checking " + nameToCheck + "'s weight. See below."); +// e.printStackTrace(); +// } +// }).start(); +// } + +// @SubscribeEvent +// public void onChatEvent(ClientChatReceivedEvent e) { +// String message = e.message.getUnformattedText(); +// if (!(message.startsWith("You have sent a trade request to "))) {return;} +// String theirName = message.replace("You have sent a trade request to ", "").replace(".", ""); +// if (!config.utilitiesCheckStats) {ChatLib.chat("You have currently disabled player analyses at this time. Run away as far as possible from " + theirName + " to cancel the trade and re-enable the setting in the config if you want to get an analysis on them."); /* Minecraft.getMinecraft().thePlayer.sendChatMessage("wait hold on a sec need to tweak my mod configs"); */ return;} +// ChatLib.chat("Running analysis on " + theirName + "..."); +// new Thread(() -> {checkSomeonesStats("[stats " + theirName + "]");}).start(); +// } + +// public void checkSomeonesStats(String thatOneParameter) { +// String theNameToCheck = ""; +// if (thatOneParameter.endsWith(config.utilitiesShareText) || thatOneParameter.endsWith(config.utilitiesShareBootsText) || thatOneParameter.endsWith(config.utilitiesShareHelmetText) || thatOneParameter.endsWith(config.utilitiesShareLeggingsText) || thatOneParameter.endsWith(config.utilitiesShareChestplateText) || thatOneParameter.startsWith("[weight")) {return;} +// if (!config.utilitiesCheckStats) {ChatLib.chat("You have currently disabled player analyses at this time. Re-enable the setting in the config if you want to get an analysis on them."); return;} +// if (thatOneParameter.startsWith("[stats") && thatOneParameter.endsWith("]")) { +// if (thatOneParameter.endsWith("[stats]")) { +// theNameToCheck = Minecraft.getMinecraft().thePlayer.getName(); +// } else { +// theNameToCheck = (thatOneParameter.toLowerCase().replace("[stats ", "").replace("]", "")).replace(" ", ""); +// } +// } else { +// ChatLib.chat("Are you sure you have a coherent username whose stats you want to see?"); +// return; +// } +// try { +// URL url = new URL(skyCryptURL + theNameToCheck); +// HttpURLConnection http = (HttpURLConnection) url.openConnection(); +// http.setDoOutput(true); +// http.setDoInput(true); +// http.setRequestProperty("User-Agent", "SynthesisMod-NONCANON"); +// http.setRequestProperty("Accept", "application/json"); +// http.setRequestProperty("Method", "GET"); +// http.connect(); +// try (InputStream instream = http.getInputStream()) { +// if (http.getResponseCode() != 200) { +// ChatLib.chat("Synthesis did not get an A-OK response from SkyCrypt. The response code Synthesis got instead was " + http.getResponseCode() + ". Aborting mission."); +// return; +// } +// JsonParser parser = new JsonParser(); +// JsonObject data = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); +// if (!data.has("profiles")) { +// ChatLib.chat("Synthesis failed in getting information from SkyCrypt. Either their API is down or this player doesn't have any profiles at all. Aborting mission."); +// return; +// } + +// JsonObject profiles = data.get("profiles").getAsJsonObject(); +// Set> profileSet = profiles.entrySet(); +// long currentSbProfileSkillAverage = 0; +// long currentSbProfileSlayerXp = 0; +// String displayName = ""; +// String uuidFromJson = ""; +// String cuteName = ""; +// String profileId = ""; +// String firstJoinText = ""; +// long totalSkillXp = 0; +// long collectedFairySouls = 0; +// long totalFairySouls = 0; +// long catacombsLevel = 0; +// long iceEssence = 0; +// long witherEssence = 0; +// long spiderEssence = 0; +// long undeadEssence = 0; +// long diamondEssence = 0; +// long dragonEssence = 0; +// long goldEssence = 0; +// long crimsonEssence = 0; +// long totalEssence = 0; +// JsonElement currentSbProfileWeightData = null; +// JsonObject currentSbProfileData = null; +// String rankPrefix = ""; +// String gameMode = ""; +// String catacombsLvlString = ""; +// boolean isInGuild = false; +// boolean isCata = false; +// boolean currentAreaUpdatedFromJson = false; +// String guildName = ""; +// String guildTag = ""; +// long guildMembers = 0; +// long guildLevel = 0; +// String guildRank = ""; +// String guildMaster = ""; +// String guildInfo = ""; +// long purse = 0; +// long bank = 0; +// String lastActiveString = ""; +// String dClassesInfo = ""; + +// for (Map.Entry me : profileSet) +// { +// if (me.getValue().getAsJsonObject().get("current").getAsBoolean()) { +// currentSbProfileData = ((me.getValue().getAsJsonObject().get("data").getAsJsonObject())); +// } +// } + +// displayName = currentSbProfileData.get("display_name").getAsString(); +// uuidFromJson = currentSbProfileData.get("uuid").getAsString(); +// rankPrefix = currentSbProfileData.get("rank_prefix").getAsString(); +// cuteName = currentSbProfileData.get("profile").getAsJsonObject().get("cute_name").getAsString(); +// profileId = currentSbProfileData.get("profile").getAsJsonObject().get("profile_id").getAsString(); +// try { +// gameMode = currentSbProfileData.get("profile").getAsJsonObject().get("game_mode").getAsString(); +// } catch (Exception e) { +// gameMode = ("Classic"); +// } +// currentSbProfileSkillAverage = currentSbProfileData.get("average_level").getAsLong(); +// currentSbProfileSlayerXp = currentSbProfileData.get("slayer_xp").getAsLong(); +// firstJoinText = currentSbProfileData.get("first_join").getAsJsonObject().get("text").getAsString(); +// totalSkillXp = currentSbProfileData.get("total_skill_xp").getAsLong(); +// collectedFairySouls = currentSbProfileData.get("fairy_souls").getAsJsonObject().get("collected").getAsLong(); +// totalFairySouls = currentSbProfileData.get("fairy_souls").getAsJsonObject().get("total").getAsLong(); +// try { +// JsonObject dungeonsData = currentSbProfileData.get("dungeons").getAsJsonObject(); +// catacombsLevel = dungeonsData.get("catacombs").getAsJsonObject().get("level").getAsJsonObject().get("level").getAsLong(); +// isCata = true; +// String currentClass = ""; +// if (dungeonsData.get("used_classes").getAsBoolean()) { +// currentClass = dungeonsData.get("selected_class").getAsString(); +// JsonObject classData = dungeonsData.get("classes").getAsJsonObject(); +// long healerLvl = classData.get("healer").getAsJsonObject().get("experience").getAsJsonObject().get("level").getAsLong(); +// long mageLvl = classData.get("mage").getAsJsonObject().get("experience").getAsJsonObject().get("level").getAsLong(); +// long berserkLvl = classData.get("berserk").getAsJsonObject().get("experience").getAsJsonObject().get("level").getAsLong(); +// long archerLvl = classData.get("archer").getAsJsonObject().get("experience").getAsJsonObject().get("level").getAsLong(); +// long tankLvl = classData.get("tank").getAsJsonObject().get("experience").getAsJsonObject().get("level").getAsLong(); +// long avgClassLvl = ((healerLvl+mageLvl+berserkLvl+archerLvl+tankLvl)/(5L)); +// dClassesInfo = "§r | §aH§r: §a" + healerLvl + "§r, §dM§r: §d" + mageLvl + "§r, §6B§r: §6" + berserkLvl + "§r, §eA§r: §e" + archerLvl + "§r, §2T§r: §2" + tankLvl + "§r, AVG: " + avgClassLvl; +// currentClass = ("" + currentClass.charAt(0)).toUpperCase(); +// dClassesInfo = dClassesInfo.replace(currentClass, "§l§n§o" + currentClass); +// } +// } catch (Exception e) { +// isCata = false; +// e.printStackTrace(); +// } +// if (isCata) { +// JsonObject essenceData = currentSbProfileData.get("essence").getAsJsonObject(); +// iceEssence = essenceData.get("ice").getAsLong(); +// witherEssence = essenceData.get("wither").getAsLong(); +// spiderEssence = essenceData.get("spider").getAsLong(); +// undeadEssence = essenceData.get("undead").getAsLong(); +// diamondEssence = essenceData.get("diamond").getAsLong(); +// dragonEssence = essenceData.get("dragon").getAsLong(); +// goldEssence = essenceData.get("gold").getAsLong(); +// crimsonEssence = essenceData.get("crimson").getAsLong(); +// totalEssence = iceEssence + witherEssence + spiderEssence + undeadEssence + diamondEssence + dragonEssence + goldEssence + crimsonEssence; +// } +// purse = currentSbProfileData.get("purse").getAsLong(); +// try { +// bank = currentSbProfileData.get("bank").getAsLong(); +// } catch (Exception e) {bank = -1;} +// try { +// currentAreaUpdatedFromJson = currentSbProfileData.get("current_area_updated").getAsBoolean(); +// } catch (Exception e) {currentAreaUpdatedFromJson = false;} +// if (!currentAreaUpdatedFromJson) { +// lastActiveString = ("Last seen in SB on " + new SimpleDateFormat("EEEE, MMM d, yyy h:mm:ss a z").format((new Date(currentSbProfileData.get("last_updated").getAsJsonObject().get("unix").getAsLong())))); +// } else { +// lastActiveString = "Probably in Skyblock right now"; +// } +// currentSbProfileWeightData = currentSbProfileData.get("weight"); +// double overallSenitherWeight = (((JsonObject)(currentSbProfileWeightData).getAsJsonObject().get("senither")).get("overall").getAsDouble()); +// double overallLilyWeight = (((JsonObject)(currentSbProfileWeightData).getAsJsonObject().get("lily")).get("total").getAsDouble()); +// try { +// JsonObject guildData = currentSbProfileData.get("guild").getAsJsonObject(); +// isInGuild = true; +// guildName = guildData.get("name").getAsString(); +// guildTag = "[" + guildData.get("tag").getAsString() + "]"; +// guildLevel = guildData.get("level").getAsLong(); +// guildMembers = guildData.get("members").getAsLong(); +// guildRank = guildData.get("rank").getAsString(); +// guildMaster = guildData.get("gmUser").getAsJsonObject().get("display_name").getAsString(); +// if (guildMaster.equals(displayName)) { +// guildRank = "§2as §6the guildmaster"; +// guildMaster = ""; +// } else { +// guildRank = "§2with guild rank §a\"" + guildRank + "\""; +// guildMaster = "Their guildmaster is §a" + guildMaster + "§2."; +// } +// } catch (Exception e) { +// isInGuild = false; +// } + +// String linePrefix = ("\n §8- "); +// String skillAvg = ("§9" + currentSbProfileSkillAverage + " Skill Average"); +// firstJoinText = ("§aProfile created " + firstJoinText); +// String activityString = (firstJoinText + ((config.utilitiesCheckStatsLvlOfDetail == 2) ? ("§r | §a" + lastActiveString) : "")); +// cuteName = ("§6" + cuteName); +// String uuidFromJsonString = ("§7UUID: §2" + uuidFromJson); +// String totalAndSlayerXp = ("§3" + totalSkillXp + " total Skill XP" + ((config.utilitiesCheckStatsLvlOfDetail == 2) ? ("§r | §c" + currentSbProfileSlayerXp + " Slayer XP") : "")); +// String fairySoulFraction = ("§dCollected " + collectedFairySouls + "/" + totalFairySouls + " fairy souls"); +// catacombsLvlString = ("§4Catacombs Level " + catacombsLevel); +// String essenceString = ("§5Total essence: §r" + totalEssence + " Essence (§9" + iceEssence + " Ice§r, §7" + witherEssence + " Wither§r, §4" + spiderEssence + " Spider§r, §5" + undeadEssence + " Undead§r, §b" + diamondEssence + " Diamond§r, §e" + dragonEssence + " Dragon§r, §6" + goldEssence + " Gold§r, §c" + crimsonEssence + " Crimson§r)"); +// String weightString = ("§eOverall Lily Weight: " + ((int)(overallLilyWeight)) + (config.utilitiesCheckStatsLvlOfDetail == 2 ? " §r| §eOverall Senither Weight: " + ((int)(overallSenitherWeight)) : "")); +// String coinsString = ("§6Purse: " + purse + " coin" + (purse != 1 ? "s" : "") + ((config.utilitiesCheckStatsLvlOfDetail > 0) ? " §r| " + (bank != -1 ? "§6Bank: " + bank + " coin" + (bank != 1 ? "s" : "") : "§cBank API disabled.") : "")); +// String profileIdString = ("§7Profile ID: §2" + profileId); +// gameMode = ("§6" + Character.toUpperCase(gameMode.charAt(0)) + gameMode.substring(1)); +// if (rankPrefix.equals("")) { +// rankPrefix = ("§7"); +// } else { +// try { +// // things to remove! +// //
+// //
+// //
+// //
", "") +// .replace("
", "").replace("
", "") +// .replace("
0) ? linePrefix + (isInGuild ? guildInfo : "§2They do not appear to be in a guild.") : "") +// + linePrefix + coinsString +// + linePrefix + skillAvg + ((config.utilitiesCheckStatsLvlOfDetail > 0) ? ("§r | " + totalAndSlayerXp) : "") +// + linePrefix + (isCata ? catacombsLvlString + ((config.utilitiesCheckStatsLvlOfDetail > 0) ? dClassesInfo : "") : "§4They have not explored the Catacombs yet.") +// + ((isCata && config.utilitiesCheckStatsLvlOfDetail == 2) ? linePrefix + essenceString : "") +// + linePrefix + weightString +// + linePrefix + activityString +// + (config.utilitiesCheckStatsLvlOfDetail == 2 ? linePrefix + fairySoulFraction + linePrefix + uuidFromJsonString + linePrefix + profileIdString : "") +// ); +// if (displayName.equals("Technoblade") || uuidFromJson.contains("b876ec32e396476ba1158438d83c67d4")) { +// Calendar c = Calendar.getInstance(); +// ChatLib.chat("Please donate to the Sarcoma Foundation of America (https://www.curesarcoma.org/technoblade-tribute/), or buy his memorial merchandise at https://technoblade.com."); +// if (c.get(Calendar.YEAR) == 2022 && c.get(Calendar.MONTH) == 6) { +// ChatLib.chat("Make sure you visit Technoblade's memorial at the main Hypixel lobby and speak to the Book Keeper NPC there as well."); +// } +// } else if (displayName.equals("SirDesco") || uuidFromJson.contains("e710ff36fe334c0e8401bda9d24fa121")) { +// ChatLib.chat("Oh look, it's the Synthesis developer!"); +// } +// if (uuidFromJson.equals(profileId) && config.utilitiesCheckStatsLvlOfDetail == 2) { +// ChatLib.chat("You may notice that their Minecraft UUID and Skyblock profile ID are the same. Why? Listen, I didn't make the rules, and neither did SkyCrypt devs. Don't ask any of us."); +// } +// } catch (Exception e) { +// if (http.getResponseCode() != 200) { +// ChatLib.chat("Synthesis did not get an A-OK response from SkyCrypt. The response code Synthesis got instead was " + http.getResponseCode() + ". Aborting mission."); +// System.out.println("Synthesis did not get an A-OK response from SkyCrypt. The response code Synthesis got instead was " + http.getResponseCode() + ". See below."); +// } else { +// ChatLib.chat("Synthesis got information from SkyCrypt, but couldn't successfully parse it. See logs."); +// System.out.println("Synthesis got information from SkyCrypt, but couldn't successfully parse it. See below."); +// } +// e.printStackTrace(); +// return; +// } +// } catch (Exception e) { +// ChatLib.chat("Synthesis ran into a problem checking " + theNameToCheck + "'s weight. See logs."); +// System.out.println("Synthesis ran into a problem checking " + theNameToCheck + "'s weight. See below."); +// e.printStackTrace(); +// } +// } +// } diff --git a/src/main/java/com/luna/synthesis/features/utilities/HexatorumUtils.java b/src/main/java/com/luna/synthesis/features/utilities/HexatorumUtils.java new file mode 100644 index 0000000..d374b72 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/HexatorumUtils.java @@ -0,0 +1,189 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import com.luna.synthesis.utils.ChatLib; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import org.lwjgl.opengl.GL11; + +public class HexatorumUtils { + + private final Config config = Synthesis.getInstance().getConfig(); + private final Pattern fractionRegex = Pattern.compile("(?\\d+)\\/(?\\d+)"); + private EntityPlayerSP mcgmtp = Minecraft.getMinecraft().thePlayer; + private List itemLore = new ArrayList(); + private ArrayList floats = new ArrayList(); + private List slots; + private String menuName = ""; + private float r = 0F, g = 0F, floatForArrayList = 0F; + + @SubscribeEvent + public void onHexUI(GuiScreenEvent.BackgroundDrawnEvent e) { + if (!(config.utilitiesHexatorumOverlay)) return; + if ((Minecraft.getMinecraft().thePlayer == null) || !(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) return; + menuName = StringUtils.stripControlCodes((((ContainerChest)((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots).getLowerChestInventory().getDisplayName().getUnformattedText())); + if (!(menuName.equals("The Hex"))) return; + int aMagicNumber = (((new ScaledResolution(Minecraft.getMinecraft())).getScaledWidth() - 176) / 2); + int anotherMagicNumber = (((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2); + slots = ((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots.inventorySlots; + for (Slot sl : slots) { + boolean colorThisSlot = false; + try {if (!(itemLore.isEmpty())) itemLore.clear();} catch (Exception ex) {} + if (!(floats.isEmpty())) floats.clear(); + floatForArrayList = 0F; + if (sl.getStack() == null || !(sl.getStack().hasDisplayName())) continue; + ItemStack is = sl.getStack(); + String dName = is.getDisplayName(); + if (dName.contains("aEnchantments")) { + itemLore = is.getTooltip(mcgmtp, false); + for (String s : itemLore) { + if (s.contains("7Enchantments") && !(s.contains("and"))) { + s = StringUtils.stripControlCodes(s); + findFracInStrForFloatArrLst(s, false); + colorThisSlot = true; + } + } + } + if (dName.contains("aUltimate Enchantments")) { + itemLore = is.getTooltip(mcgmtp, false); + for (String s : itemLore) { + s = StringUtils.stripControlCodes(s); + if (fractionRegex.matcher(s).find()) { + findFracInStrForFloatArrLst(s, false); + colorThisSlot = true; + } + } + } + if (dName.contains("aReforges")) { + itemLore = is.getTooltip(mcgmtp, false); + for (String s : itemLore) { + s = StringUtils.stripControlCodes(s); + if (s.contains("Reforge")) { + containsCheckmark(s, false); + colorThisSlot = true; + } + } + } + if (dName.contains("aModifiers") || dName.contains("aBooks")) { + colorThisSlot = true; + itemLore = is.getTooltip(mcgmtp, false); + for (String s : itemLore) { + s = StringUtils.stripControlCodes(s); + containsCheckmark(s, true); + findFracInStrForFloatArrLst(s, true); + } + } + if (dName.contains("aItem Upgrades")) { + colorThisSlot = true; + itemLore = is.getTooltip(mcgmtp, false); + for (String s : itemLore) { + s = StringUtils.stripControlCodes(s); + containsCheckmark(s, true); + if (s.contains("Upgrade Level")) { + s = s.replaceAll(" ","").replace("§7Upgrade Level", ""); + float currStars = 0F, maxStars = 10F; + if (s.contains("➎")) currStars = 10F; + else if (s.contains("➍")) currStars = 9F; + else if (s.contains("➌")) currStars = 8F; + else if (s.contains("➋")) currStars = 7F; + else if (s.contains("➊")) currStars = 6F; + String[] sa = s.split("§"); + if (sa.length < 1) return; + else for (String str : sa) if (str.endsWith("✪")) currStars++; + floats.add(currStars / maxStars); + } + } + } + if (dName.contains("aGemstones")) { + colorThisSlot = true; + itemLore = is.getTooltip(mcgmtp, false); + String[] sa = {}; + for (String s : itemLore) if (s.contains("7Gemstones")) sa = s.split(" "); + if (sa.length < 1) return; + float filledGemstones = 0, availableGemstones = 0F; + for (String sTwo : sa) { + if (sTwo.contains("[") && sTwo.contains("]")) { + availableGemstones++; + if (!(sTwo.contains("8"))) { + filledGemstones++; + } + } + } + compareFloats(filledGemstones, availableGemstones); + } + if (!colorThisSlot) continue; + if (!(floats.isEmpty())) { + for (float f : floats) { + if (f >= 1F) f = 1F; + floatForArrayList += f; + } + compareFloats(floatForArrayList, ((float)(floats.size()))); + } + Color bgColor = new Color(((int)(r)), ((int)(g)), (0)); + if (config.utilitiesHexatorumDebug) {ChatLib.chat(bgColor.toString() + " was selected for item named " + dName);} + GL11.glTranslated(0, 0, 1); + Gui.drawRect(((aMagicNumber) + sl.xDisplayPosition), ((slots.size() != 90) ? (((anotherMagicNumber) + sl.yDisplayPosition) + ((6 - (slots.size() - 36) / 9) * 9)) : ((anotherMagicNumber) + sl.yDisplayPosition)), (((aMagicNumber) + sl.xDisplayPosition) + 16), (((slots.size() != 90) ? (((anotherMagicNumber) + sl.yDisplayPosition) + ((6 - (slots.size() - 36) / 9) * 9)) : ((anotherMagicNumber) + sl.yDisplayPosition)) + 16), bgColor.getRGB()); + GL11.glTranslated(0, 0, -1); + } + } + + private void containsCheckmark(String s, boolean isArrayList) { + if (s.contains("✔")) { + if (isArrayList){floats.add(1F);} + else {g = 255F; r = 0F;} + } else if (s.contains("✖")) { + if (isArrayList){floats.add(0F);} + else {r = 255F; g = 0F;} + } + } + + private void findFracInStrForFloatArrLst(String s, boolean isArrayList) { + if (!(fractionRegex.matcher(s).find())) return; + String[] sa = s.split(" "); + s = sa[sa.length - 1]; + float numerator = Float.parseFloat(s.substring(0, s.indexOf("/") + 1).replace("/", "")); + float denominator = Float.parseFloat(s.substring(s.indexOf("/"), s.length()).replace("/", "")); + if (isArrayList) { + if (denominator <= numerator) floats.add(1F); + else floats.add((numerator / denominator)); + } else compareFloats(numerator, denominator); + } + + private void compareFloats(float f1, float f2) { + if (f1 >= f2) { + f1 = f2; + g = 255F; + r = 0F; + } else { + float tempFloat = (f1 / f2); + if (tempFloat == 0.5F) { + r = g = 255F; + } else { + if (tempFloat > 0.5F) { + r = 255 - (tempFloat * 255F); + g = 255F; + } else { + r = 255F; + g = (tempFloat * 255F); + } + } + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/MasterModeSoulDetector.java b/src/main/java/com/luna/synthesis/features/utilities/MasterModeSoulDetector.java new file mode 100644 index 0000000..dbee247 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/MasterModeSoulDetector.java @@ -0,0 +1,82 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import org.lwjgl.opengl.GL11; + +public class MasterModeSoulDetector { + private final Config config = Synthesis.getInstance().getConfig(); + private int numSouls = 0; + private ArrayList whichOnesAreMasterSouls = new ArrayList(); + private int r,g,b = 0; + + @SubscribeEvent + public void onTooltip(ItemTooltipEvent e) { + if (!config.utilitiesMasterModeSoulDetection) return; + if (e.toolTip == null) return; + ItemStack itemStack = e.itemStack; + List tooltip = e.toolTip; + try { + for (String s : tooltip) { + if (s.contains("Absorbed Souls")) { + findSouls(itemStack); + int anchor = tooltip.indexOf(s); + for (int h = 0; h < numSouls; h++) if (whichOnesAreMasterSouls.get(h)) tooltip.set(h + 1 + anchor, tooltip.get(h + 1 + anchor) + " §d(from Master Mode)"); + } + } + } catch (Exception e) {} + } + + @SubscribeEvent + public void guiRender(GuiScreenEvent.BackgroundDrawnEvent e) { + if (!config.utilitiesMasterModeSoulDetection) return; + if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) return; + if ((!(StringUtils.stripControlCodes(((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)).getLowerChestInventory().getDisplayName().getUnformattedText()).contains("You"))) && (!(StringUtils.stripControlCodes(((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)).getLowerChestInventory().getDisplayName().getUnformattedText()).contains("Auctions:"))) && (!(StringUtils.stripControlCodes(((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)).getLowerChestInventory().getDisplayName().getUnformattedText()).contains("Auction View")))) return; + List slots = ((GuiChest)(e.gui)).inventorySlots.inventorySlots; + for (Slot s : slots) { + int numTrues = 0, numFalses = 0; + if (s.getStack() != null) { + findSouls(s.getStack()); + for (boolean bool : whichOnesAreMasterSouls) if (bool) numTrues++; else numFalses++; + if (!(whichOnesAreMasterSouls.isEmpty()) && numFalses != whichOnesAreMasterSouls.size()) { + if ((numTrues == whichOnesAreMasterSouls.size())) { + r = b = 0; + g = 255; + } else { + r = g = 255; + b = 0; + } + Color bgColor = new Color(r, g, b); + GL11.glTranslated(0, 0, 1); + Gui.drawRect(((((new ScaledResolution(Minecraft.getMinecraft())).getScaledWidth() - 176) / 2) + s.xDisplayPosition), ((slots.size() != 90) ? (((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition) + ((6 - (slots.size() - 36) / 9) * 9)) : ((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition)), (((((new ScaledResolution(Minecraft.getMinecraft())).getScaledWidth() - 176) / 2) + s.xDisplayPosition) + 16), (((slots.size() != 90) ? (((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition) + ((6 - (slots.size() - 36) / 9) * 9)) : ((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition)) + 16),bgColor.getRGB()); + GL11.glTranslated(0, 0, -1); + } + } + } + } + + private void findSouls(ItemStack is) { + if (!config.utilitiesMasterModeSoulDetection) return; + if (!(whichOnesAreMasterSouls.isEmpty())) whichOnesAreMasterSouls.clear(); + if ((!(is.hasTagCompound())) || (is.getSubCompound("ExtraAttributes", false) == null || (!(is.getSubCompound("ExtraAttributes", false).hasKey("necromancer_souls"))))) return; + NBTTagList tl = ((NBTTagList)((is.getSubCompound("ExtraAttributes", false)).getTag("necromancer_souls"))); + if (tl.tagCount() == 0) return; + numSouls = tl.tagCount(); + for (int i = 0; i < numSouls; i++) whichOnesAreMasterSouls.add(tl.get(i).toString().contains("MASTER_")); + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/OccupancyOverlay.java b/src/main/java/com/luna/synthesis/features/utilities/OccupancyOverlay.java new file mode 100644 index 0000000..afe7398 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/OccupancyOverlay.java @@ -0,0 +1,173 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.Slot; +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.awt.Color; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import org.lwjgl.opengl.GL11; + +/** + *
+ * OccupancyOverlay
+ *
+ * A Java class by Erymanthus / RayDeeUx for the Hypixel Skyblock-specific
+ * Minecraft Forge 1.8.9 mod named "Synthesis".
+ *
+ * Ever wondered how full a lobby is? Ever wanted a visual indicator of that metric?
+ * Here you go!
+ *
+ * Originally a feature from SkyblockReinvented by theCudster,
+ * which adapted it from an earlier Hypixel Skyblock mod
+ * named "Nate's Secret Mod" by Nat3z.
+ *
+ * Except this time it doesn't just use the same two or three predefined colors!
+ *
+ * We truly are living in the future.
+ * 
+ * @author Erymanthus(#5074) / [u/]RayDeeUx + */ + +public class OccupancyOverlay { + + private final Config config = Synthesis.getInstance().getConfig(); + private final Pattern playerCapacity = Pattern.compile("(?[1-9][0-9]+)/(?[1-9]+).*"); + private boolean hasFriend, hasGuildmate, alreadyConnected, couldNotConnect = false; + /* alreadyConnected and couldNotConnect are for debugging purposes in case + * i ever get back to refining the regex solution */ + private float r = 0F, g = 0F, b = 0F; + private Float currentCapacity = 0F; + private Float maxCapacity = 1F; //prevent ArithmeticExceptions + private String menuName = ""; + private String hubName = ""; + private List itemLore; + private List slots; + private EntityPlayerSP mcgmtp = Minecraft.getMinecraft().thePlayer; + + @SubscribeEvent + public void onGuiScreen(GuiScreenEvent.BackgroundDrawnEvent e) { + if (config.utilitiesOccupancyOverlay) { + if (mcgmtp != null && Minecraft.getMinecraft().currentScreen instanceof GuiChest) { + menuName = StringUtils.stripControlCodes((((ContainerChest)((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots).getLowerChestInventory().getDisplayName().getUnformattedText())); + if (menuName.toLowerCase().contains("skyblock hub") || menuName.toLowerCase().contains("dungeon hub") || menuName.toLowerCase().startsWith("visit")) { + slots = ((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots.inventorySlots; + int aMagicNumber = (((new ScaledResolution(Minecraft.getMinecraft())).getScaledWidth() - 176) / 2); + int anotherMagicNumber = (((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2); + for (Slot s : slots) { + + /* PREVENT CACHING */ + currentCapacity = 0F; + maxCapacity = 1F; //prevent ArithmeticExceptions + hubName = ""; + currentCapacity = 0F; + maxCapacity = 1F; + hubName = ""; + hasFriend = hasGuildmate = alreadyConnected = couldNotConnect = false; + + if (s.getStack() != null && s.getStack().hasDisplayName() && !(s.getStack().getDisplayName().toLowerCase().contains(" skyblock hub")) && (s.getStack().getDisplayName().toLowerCase().contains("skyblock hub") || s.getStack().getDisplayName().toLowerCase().contains("dungeon hub") || s.getStack().getDisplayName().toLowerCase().contains("visit player "))) { + hubName = StringUtils.stripControlCodes(s.getStack().getDisplayName()); + itemLore = s.getStack().getTooltip(mcgmtp, false); + if (itemLore != null) { + for (String line : itemLore) { + if (line != null && line.toLowerCase().contains("online friend")) { + hasFriend = true; + } else if (line != null && line.toLowerCase().contains("online guild")) { + hasGuildmate = true; + } else if (line != null && (line.toLowerCase().contains("players: "))) { + String avoidFalseNegatives = StringUtils.stripControlCodes(line); + avoidFalseNegatives = avoidFalseNegatives.replace("Players: ", ""); + Matcher playerCapacityMatcher = playerCapacity.matcher(avoidFalseNegatives); + if (playerCapacityMatcher.find()) { + currentCapacity = Float.parseFloat(playerCapacityMatcher.group(1)); + maxCapacity = Float.parseFloat(playerCapacityMatcher.group(2)); + } else { + //"What the fu...?" - [MCU] Spider-Man, Spider-Man: No Way Home (2021) + System.out.println("[Synthesis — DEBUG] For some reason, Synthesis couldn't find the player capacity using regex. Here's the relevant info: Inside the menu named " + menuName + " at item slot " + s.getSlotIndex() + "'s item lore line `" + line + "` at itemLore.indexOf(line) " + itemLore.indexOf(line) + " with hubName " + hubName + ". hasFriend was " + hasFriend + ", hasGuildmate was " + hasGuildmate + ", couldNotConnect was " + couldNotConnect + ", and alreadyConnected was " + alreadyConnected + ". -Erymanthus#5074"); + System.out.println("[Synthesis — DEBUG] Synthesis is now attempting a failsafe solution using Java's replace() and substring() methods. -Erymanthus#5074"); + String regexIsFun = avoidFalseNegatives.replace("Players: ", ""); + currentCapacity = Float.parseFloat(regexIsFun.substring(0, regexIsFun.indexOf("/") + 1).replace("/", "")); + maxCapacity = Float.parseFloat(regexIsFun.substring(regexIsFun.indexOf("/"), regexIsFun.length()).replace("/", "")); + //So why does Java regex never work 100% of the time? Beats me, but the user shouldn't be punished for it! + } + if (currentCapacity >= maxCapacity) { + currentCapacity = maxCapacity; //prevent java.awt.Color crashes + r = 255F; + g = b = 0F; + break; + } else { + //"You know what's cooler than magic? Math!" - [MCU] Spider-Man, Spider-Man: No Way Home (2021) + if (currentCapacity / maxCapacity == .5F) { + r = g = 255F; + b = 0F; + } else if (currentCapacity / maxCapacity > .5F) { + r = 255F; + g = 255 - ((currentCapacity / maxCapacity) * 255F); + b = 0F; + } else { + r = ((currentCapacity / maxCapacity) * 255F); + g = 255F; + b = 0F; + } + //Instead of predefined RGB values, why not factor current occupancy in to make some degree of yellow? + /*Disclaimer: usually not that noticable with skyblock hub selector npc because all hubs are usually close + to full, try dungeon hub selector npc for better effect. i swear the code works as intended*/ + } + } else if (config.utilitiesOccupancyOverlayFriendAndGuildHighlght && hasFriend && hasGuildmate) { + r = b = 255F; + g = 85F; + } else if (config.utilitiesOccupancyOverlayFriendHighlght && hasFriend) { + r = g = 85F; + b = 255F; + } else if (config.utilitiesOccupancyOverlayGuildHighlght && hasGuildmate) { + r = b = 0F; + g = 170F; + } else if (line != null && (line.toLowerCase().contains("full") || line.toLowerCase().contains("offline") || line.toLowerCase().contains("doesn't support guests yet") || line.toLowerCase().contains("island disallows guests"))) { + r = 255; + g = b = 0F; + couldNotConnect = true; + } else if (line != null && (line.toLowerCase().contains("already "))) { + if (config.utilitiesOccupancyOverlayAlreadyConnectedHighlght) { + r = 85F; + g = b = 255F; + } + alreadyConnected = true; + } + } + Color bgColor = new Color(((int)(r)), ((int)(g)), ((int)(b))); + System.out.println("[Synthesis — DEBUG] Inside the menu named " + menuName + ", the color " + bgColor + " was selected for the hub named " + hubName + " because it was at a capacity of " + currentCapacity + " / " + maxCapacity + " (" + ((currentCapacity/maxCapacity)*100) + "% full) and hasFriend was " + hasFriend + ", hasGuildmate was " + hasGuildmate + ", couldNotConnect was " + couldNotConnect + ", and alreadyConnected was " + alreadyConnected); + GL11.glTranslated(0, 0, 1); + Gui.drawRect( + ((aMagicNumber) + s.xDisplayPosition), + ((slots.size() != 90) ? + (((anotherMagicNumber) + s.yDisplayPosition) + + ((6 - (slots.size() - 36) / 9) * 9)) : + ((anotherMagicNumber) + s.yDisplayPosition)), + (((aMagicNumber) + s.xDisplayPosition) + 16), + (((slots.size() != 90) ? + (((anotherMagicNumber) + s.yDisplayPosition) + + ((6 - (slots.size() - 36) / 9) * 9)) : + ((anotherMagicNumber) + s.yDisplayPosition)) + 16), + bgColor.getRGB()); + GL11.glTranslated(0, 0, -1); + } + } + } + return; + } + } + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/PreventDeleteReset.java b/src/main/java/com/luna/synthesis/features/utilities/PreventDeleteReset.java new file mode 100644 index 0000000..dc98a48 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/PreventDeleteReset.java @@ -0,0 +1,161 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import com.luna.synthesis.utils.ChatLib; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.inventory.Slot; +import net.minecraft.inventory.ContainerChest; + +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.List; + +import org.lwjgl.input.Mouse; + +public class PreventDeleteReset { + private final Config config = Synthesis.getInstance().getConfig(); + + @SubscribeEvent + public void onMouseClick(GuiScreenEvent.MouseInputEvent.Pre e) { + boolean isBarry = false, isDiaz = false, isDante = false, isSpecialSus = false; + if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) return; + if (!Mouse.getEventButtonState()) return; + + if (e.gui instanceof GuiContainer) { + GuiContainer guiContainer = (GuiContainer) e.gui; + if ((Mouse.getEventButton() > -1)) { + Slot slot = guiContainer.getSlotUnderMouse(); + + if (slot == null) return; + if (!slot.getHasStack()) return; + + List itemLore = slot.getStack().getTooltip(Minecraft.getMinecraft().thePlayer, false); + + if ((StringUtils.stripControlCodes(((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)).getLowerChestInventory().getDisplayName().getUnformattedText()).contains("Auction"))) { + for (String string : itemLore) { + if (string.contains("7Seller: Unknown")) { + preventThatClick(e, "buying an auctioned item from an unknown seller", ""); + break; + } + } + } + + if (config.utilitiesPreventHOTMReset && + (slot.getStack().getDisplayName().toLowerCase() + .contains("reset heart of the mountain"))) { + preventThatClick(e, "resetting", "HOTM tree"); + } + + if (config.utilitiesPreventProfileDeletion && + slot.getStack().getDisplayName().toLowerCase() + .contains("delete profile")) { + preventThatClick(e, "deleting", "Skyblock profile"); + } + + if (slot.getStack().getDisplayName().toLowerCase() + .contains("confirm")) { + for (String string : itemLore) { + if (string.contains("portal") && config.utilitiesPreventPortalDestruction) { + preventThatClick(e, "destroying one of", "island's \"Warp to\" portals"); + break; + } + } + } + + if (!(StringUtils.stripControlCodes( + ((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)) + .getLowerChestInventory().getDisplayName().getUnformattedText()) + .contains("Election, Year ")) + && + !(StringUtils.stripControlCodes( + ((ContainerChest)(Minecraft.getMinecraft().thePlayer.openContainer)) + .getLowerChestInventory().getDisplayName().getUnformattedText()) + .equals("Election"))) return; + + if (config.utilitiesPreventVotingBarry && + slot.getStack().getDisplayName().toLowerCase() + .endsWith("barry") && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("mayor")))) { + preventThatClick(e, "voting Barry as", "Skyblock mayor"); + isBarry = true; + } + + if (config.utilitiesPreventVotingDiaz && + slot.getStack().getDisplayName().toLowerCase() + .endsWith("diaz") && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("mayor")))) { + preventThatClick(e, "voting Diaz as", "Skyblock mayor"); + isDiaz = true; + } + + if ((config.utilitiesPreventVotingDante || config.utilitiesPreventVotingSusSpecialMayors) && + slot.getStack().getDisplayName().toLowerCase() + .endsWith("dante") && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("mayor")))) { + preventThatClick(e, "voting Dante as", "Skyblock mayor"); + isDante = true; + } + + if ((config.utilitiesPreventVotingSusSpecialMayors) && + slot.getStack().getDisplayName().toLowerCase() + .contains("\u00a7d")) { + if ((!(slot.getStack().getDisplayName().toLowerCase() + .contains("mayor"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("derpy"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("jerry"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("aatrox"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("barry"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("cole"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("diana"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("diaz"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("foxy"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("marina"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("paul"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("scorpius"))) && (!(slot.getStack().getDisplayName().toLowerCase() + .contains("technoblade")))) { + preventThatClick(e, "voting an unknown special mayor as", "Skyblock mayor"); + isSpecialSus = true; + } + } + + if (config.utilitiesPreventVotingXPerkMayors != 1) { + String colorCode = slot.getStack().getDisplayName().substring(0, 2); + int numPerks = 0; + for (String s : itemLore) { + s = s.replaceAll("§5§o", ""); + if (s.startsWith(colorCode) && + !(s.contains("You voted for this candidate!")) && + !(s.contains("Leading in votes!")) && + !(s.contains("Click to vote for ")) && + !(s.startsWith(colorCode + "§"))) { + numPerks++; + } + } + if (isBarry || isDiaz || isDante || isSpecialSus) return; + if (numPerks < config.utilitiesPreventVotingXPerkMayors) { + preventThatClick(e, "voting for " + (StringUtils.stripControlCodes(slot.getStack().getDisplayName())) + " as", "Skyblock mayor because they only have " + numPerks + " perk" + ((numPerks != 1) ? "s" : "")); + } + } + } + } + } + + private void preventThatClick(GuiScreenEvent.MouseInputEvent.Pre e, String action, String type) { + e.setCanceled(true); + Minecraft.getMinecraft().thePlayer.playSound("note.bass", 1, ((float)(0.5))); + if (type == "" && action == "buying an auctioned item from an unknown seller") {ChatLib.chat("Synthesis has prevented you from buying an auctioned item from an unknown seller, as doing so could cause a loss in coins. There is no config option to disable this."); return;} + ChatLib.chat( + "Synthesis has prevented you from " + action + " your " + type + ". " + + ((action.equals("voting Dante as")) ? + "Why would you vote for that dictator again?" : + "Check your configs if you actually wanted to do this." + ) + ); + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/SearchMode.java b/src/main/java/com/luna/synthesis/features/utilities/SearchMode.java index fc9bcf3..4ae2407 100644 --- a/src/main/java/com/luna/synthesis/features/utilities/SearchMode.java +++ b/src/main/java/com/luna/synthesis/features/utilities/SearchMode.java @@ -1,20 +1,16 @@ package com.luna.synthesis.features.utilities; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.mixins.accessors.GuiNewChatAccessor; -import com.luna.synthesis.utils.ChatLib; import com.luna.synthesis.utils.MixinUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ChatLine; import net.minecraft.client.gui.GuiChat; -import net.minecraft.client.gui.GuiUtilRenderComponents; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.IChatComponent; import net.minecraft.util.MathHelper; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -29,7 +25,6 @@ public class SearchMode { public static boolean isSearchMode = false; private final Config config = Synthesis.getInstance().getConfig(); - @Comment("Ctrl is 29, f is 33") @SubscribeEvent public void onKeyTyped(GuiScreenEvent.KeyboardInputEvent.Pre event) { if (!(event.gui instanceof GuiChat || (event.gui instanceof GuiContainer && config.utilitiesContainerChat && MixinUtils.inputField != null && MixinUtils.inputField.isFocused()))) return; @@ -39,33 +34,40 @@ public void onKeyTyped(GuiScreenEvent.KeyboardInputEvent.Pre event) { if (Keyboard.getEventKey() == 33 && Keyboard.isKeyDown(29)) { isSearchMode = !isSearchMode; if (isSearchMode) { - Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesis".hashCode()); + ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).invokeSetChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); } else { - Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesis".hashCode()); + Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesissearchmode".hashCode()); } event.setCanceled(true); if (!isSearchMode) { Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); } } else if (Keyboard.getEventKey() == 1) { - if (isSearchMode) isSearchMode = false; - Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesis".hashCode()); - Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); + if (isSearchMode) { + isSearchMode = false; + Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesissearchmode".hashCode()); + Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); + } } else if (Keyboard.getEventKey() == 28 && isSearchMode) { if (!config.utilitiesChatSearchKeyRefresh) { Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); + if (((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().size() == 0) { + ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).invokeSetChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); + } } event.setCanceled(true); } } - @Comment("Keyboard::getKeyEventState is always false inside a GuiContainer??") @SubscribeEvent public void onKeyTypedPost(GuiScreenEvent.KeyboardInputEvent.Post event) { if (!(event.gui instanceof GuiChat || (event.gui instanceof GuiContainer && config.utilitiesContainerChat && MixinUtils.inputField != null && MixinUtils.inputField.isFocused()))) return; if (!Keyboard.getEventKeyState() && event.gui instanceof GuiChat) return; if (config.utilitiesChatSearchKeyRefresh && isSearchMode) { Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); + if (((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines().size() == 0) { + ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).invokeSetChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); + } } } @@ -88,7 +90,7 @@ public void onMouseClicked(GuiScreenEvent.MouseInputEvent.Pre event) { } } isSearchMode = false; - Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesis".hashCode()); + Minecraft.getMinecraft().ingameGUI.getChatGUI().deleteChatLine("synthesissearchmode".hashCode()); Minecraft.getMinecraft().ingameGUI.getChatGUI().refreshChat(); Minecraft.getMinecraft().ingameGUI.getChatGUI().resetScroll(); chatLines = ((GuiNewChatAccessor) Minecraft.getMinecraft().ingameGUI.getChatGUI()).getDrawnChatLines(); diff --git a/src/main/java/com/luna/synthesis/features/utilities/Share.java b/src/main/java/com/luna/synthesis/features/utilities/Share.java new file mode 100644 index 0000000..b5c928c --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/Share.java @@ -0,0 +1,248 @@ +package com.luna.synthesis.features.utilities; + +import com.google.gson.*; +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import com.luna.synthesis.events.MessageSentEvent; +import com.luna.synthesis.utils.ChatLib; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiChat; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.event.ClickEvent; +import net.minecraft.event.HoverEvent; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IChatComponent; +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.commons.io.IOUtils; +import org.lwjgl.input.Mouse; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +//event.setCanceled(true) abused because NO ONE should get muted over using this and going to appeals = going to limbo + +public class Share { + + 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); + private final Config config = Synthesis.getInstance().getConfig(); + + @SubscribeEvent + public void onMessageSent(MessageSentEvent event) { + String message = event.message; + if (message.endsWith(config.utilitiesShareText)) { + event.setCanceled(true); + doTheMagic(Minecraft.getMinecraft().thePlayer.getHeldItem(), message, config.utilitiesShareText); + } + /** + * + * Suggestion #29 by AstroFuture#0932 + * suggested this before but it disappeared randomly, + * in addition to [item], have [helmet], [chestplate], + * [leggings] and [boots] to make it easier to show armour + * pieces without having to take them off and hold them + * which is a pain especially when you have armour pieces + * slot bound via neu + * + */ + else if (message.endsWith(config.utilitiesShareHelmetText)) { + event.setCanceled(true); + doTheMagic(Minecraft.getMinecraft().thePlayer.getEquipmentInSlot(4), message, config.utilitiesShareHelmetText); + } else if (message.endsWith(config.utilitiesShareChestplateText)) { + event.setCanceled(true); + doTheMagic(Minecraft.getMinecraft().thePlayer.getEquipmentInSlot(3), message, config.utilitiesShareChestplateText); + } else if (message.endsWith(config.utilitiesShareLeggingsText)) { + event.setCanceled(true); + doTheMagic(Minecraft.getMinecraft().thePlayer.getEquipmentInSlot(2), message, config.utilitiesShareLeggingsText); + } else if (message.endsWith(config.utilitiesShareBootsText)) { + event.setCanceled(true); + doTheMagic(Minecraft.getMinecraft().thePlayer.getEquipmentInSlot(1), message, config.utilitiesShareBootsText); + } + } + + @SubscribeEvent + public void onChatReceived(ClientChatReceivedEvent event) { + if (event.type == 0 || event.type == 1) { + String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); + if (!msg.contains("{SynthesisShare:") || !msg.contains("}")) return; + + Matcher matcher = shareRegexPattern.matcher(msg); + event.setCanceled(true); + + (new Thread(() -> { + ArrayList shares = new ArrayList<>(); + while (matcher.find()) { + String shareId = matcher.group(1); + + try { + URL url = new URL("https://synthesis-share.antonio32a.com/share/" + shareId); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setDoOutput(true); + http.setDoInput(true); + http.setRequestProperty("User-Agent", "SynthesisMod"); + http.setRequestProperty("Accept", "application/json"); + http.setRequestProperty("Method", "GET"); + http.connect(); + try (InputStream instream = http.getInputStream()) { + if (http.getResponseCode() != 200) { + Minecraft.getMinecraft().thePlayer.addChatMessage(event.message); + return; + } + JsonParser parser = new JsonParser(); + JsonObject shareJson = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); + if (!shareJson.get("success").getAsBoolean()) { + Minecraft.getMinecraft().thePlayer.addChatMessage(event.message); + return; + } + + JsonObject shareItem = shareJson.get("share").getAsJsonObject().get("item").getAsJsonObject(); + String itemName = shareItem.get("name").getAsString(); + JsonArray itemLore = shareItem.get("lore").getAsJsonArray(); + boolean isItemVerified = shareJson.get("share").getAsJsonObject().get("verified").getAsBoolean(); + + IChatComponent verifiedComponent = new ChatComponentText((isItemVerified ? EnumChatFormatting.GREEN + "✔ " : EnumChatFormatting.RED + "✖ ")); + verifiedComponent.getChatStyle().setChatHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + 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.")) + )); + + AtomicReference s = new AtomicReference<>(""); + if (shareItem.has("extra")) { + if (shareItem.get("extra").getAsJsonObject().has("color")) { + s.set(EnumChatFormatting.GRAY + "Color: #" + Integer.toHexString(shareItem.get("extra").getAsJsonObject().get("color").getAsInt()).toUpperCase() + "\n"); + } + } + itemLore.iterator().forEachRemaining(jsonElement -> s.set(s.get() + jsonElement.getAsString() + "\n")); + String shareLore = itemName + "\n" + s.get(); + + IChatComponent shareComponent = new ChatComponentText(EnumChatFormatting.LIGHT_PURPLE + + "[Synthesis " + itemName + EnumChatFormatting.LIGHT_PURPLE + "]"); + shareComponent.getChatStyle().setChatHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + new ChatComponentText(shareLore.substring(0, shareLore.length() - 1)) + )).setChatClickEvent(new ClickEvent( + ClickEvent.Action.RUN_COMMAND, + "/ctcc https://synthesis-share.antonio32a.com/share/" + shareId + "?embed" + )); + verifiedComponent.appendSibling(shareComponent); + shares.add(verifiedComponent); + } + } catch (IOException | JsonParseException e) { + Minecraft.getMinecraft().thePlayer.addChatMessage(event.message); + e.printStackTrace(); + } + } + + IChatComponent toSend = new ChatComponentText(""); + ListIterator it = Arrays.asList(event.message.getFormattedText().split(shareRegexPattern.pattern())).listIterator(); + while (it.hasNext()) { + String s = it.next(); + toSend.appendSibling(new ChatComponentText(s)); + if (it.hasNext()) { + toSend.appendSibling(shares.get(it.nextIndex() - 1)); + } + } + + Minecraft.getMinecraft().thePlayer.addChatMessage(toSend); + })).start(); + + } + } + + @SubscribeEvent + public void onScroll(GuiScreenEvent.MouseInputEvent.Pre event) { + if (!config.utilitiesShareScroll) return; + if (!GuiScreen.isCtrlKeyDown()) return; + if (!(event.gui instanceof GuiChat)) return; + int i = Mouse.getEventDWheel(); + if (i != 0) { + IChatComponent comp = Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatComponent(Mouse.getX(), Mouse.getY()); + if (comp != null && comp.getChatStyle().getChatHoverEvent() != null && comp.getChatStyle().getChatHoverEvent().getAction() == HoverEvent.Action.SHOW_TEXT) { + event.setCanceled(true); + } + } + } + + private void doTheMagic(ItemStack itemParam, String messageParam, String whateverWasMatchedParam) { + if (itemParam == null || messageParam == null || whateverWasMatchedParam == null) {return;} + NBTTagCompound extraAttributes = itemParam.getSubCompound("ExtraAttributes", false); + JsonArray loreArray = new JsonArray(); + NBTTagList lore = itemParam.getSubCompound("display", false).getTagList("Lore", 8); + for (int i = 0; i < lore.tagCount(); i++) { + loreArray.add(new JsonPrimitive(lore.getStringTagAt(i))); + } + + JsonObject itemJson = new JsonObject(); + itemJson.add("name", new JsonPrimitive(itemParam.getSubCompound("display", false).getString("Name"))); + itemJson.add("lore", loreArray); + JsonObject extraObject = new JsonObject(); + if (itemParam.hasTagCompound()) { + if (itemParam.getTagCompound().hasKey("display")) { + if (itemParam.getTagCompound().getCompoundTag("display").hasKey("color")) { + extraObject.add("color", new JsonPrimitive(itemParam.getTagCompound().getCompoundTag("display").getInteger("color"))); + } + } + } + if (extraAttributes != null && extraAttributes.hasKey("uuid")) { + itemJson.add("uuid", new JsonPrimitive(extraAttributes.getString("uuid"))); + } + + itemJson.add("extra", extraObject); + + JsonObject body = new JsonObject(); + body.add("owner", new JsonPrimitive(Minecraft.getMinecraft().getSession().getPlayerID())); + body.add("item", itemJson); + + (new Thread(() -> { + try { + URL url = new URL("https://synthesis-share.antonio32a.com/share"); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setDoOutput(true); + http.setDoInput(true); + http.setRequestProperty("Content-Type", "application/json"); + http.setRequestProperty("User-Agent", "SynthesisMod"); + http.setRequestProperty("Accept", "application/json"); + http.setRequestProperty("Method", "POST"); + http.connect(); + try (OutputStream os = http.getOutputStream()) { + os.write(body.toString().getBytes(StandardCharsets.UTF_8)); + os.close(); + if (http.getResponseCode() != 200) { + ChatLib.chat("Something went wrong trying to upload share. Check logs maybe?"); + return; + } + JsonParser parser = new JsonParser(); + JsonObject shareJson = parser.parse(IOUtils.toString(http.getInputStream())).getAsJsonObject(); + if (!shareJson.get("success").getAsBoolean()) { + ChatLib.chat("Share was not successful. Reason: " + shareJson.get("error").getAsString()); + return; + } + + String shareId = shareJson.get("share").getAsJsonObject().get("id").getAsString(); + String share = "{SynthesisShare:" + shareId + "}"; + //Can't write event.message because this is a thread + Minecraft.getMinecraft().thePlayer.sendChatMessage(messageParam.replace(whateverWasMatchedParam, share)); + ChatLib.chat(messageParam.replace(whateverWasMatchedParam, share)); + } + } catch (IOException e) { + ChatLib.chat("Something went wrong trying to upload share. Check logs maybe?"); + e.printStackTrace(); + } + })).start(); + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/ShareParser.java b/src/main/java/com/luna/synthesis/features/utilities/ShareParser.java deleted file mode 100644 index d2d87f1..0000000 --- a/src/main/java/com/luna/synthesis/features/utilities/ShareParser.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.luna.synthesis.features.utilities; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.luna.synthesis.utils.ChatLib; -import net.minecraft.client.Minecraft; -import net.minecraft.event.HoverEvent; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.IChatComponent; -import net.minecraft.util.StringUtils; -import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ShareParser { - - private final Pattern shareRegex = 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); - - @SubscribeEvent - public void onChatReceived(ClientChatReceivedEvent event) { - if (event.type == 0 || event.type == 1) { - String msg = StringUtils.stripControlCodes(event.message.getUnformattedText()); - if (!msg.contains("{SynthesisShare:") || !msg.contains("}")) return; - Matcher matcher = shareRegex.matcher(msg); - if (matcher.find() && matcher.groupCount() == 1) { - String shareId = matcher.group(1); - String message = event.message.getFormattedText().split(": ")[0] + ": "; - event.setCanceled(true); - (new Thread(() -> { - try { - HttpClient httpclient = HttpClients.createDefault(); - HttpGet httpGet = new HttpGet("https://synthesis-share.antonio32a.workers.dev/share/" + shareId); - - HttpResponse response = httpclient.execute(httpGet); - HttpEntity entity = response.getEntity(); - - if (entity != null) { - try (InputStream instream = entity.getContent()) { - JsonParser parser = new JsonParser(); - JsonObject shareJson = parser.parse(new String(IOUtils.toByteArray(instream), StandardCharsets.UTF_8)).getAsJsonObject(); - if (!shareJson.get("success").getAsBoolean()) { - ChatLib.chat("Share was not successful. Reason: " + shareJson.get("error").getAsString()); - return; - } - JsonObject shareItem = shareJson.get("share").getAsJsonObject().get("item").getAsJsonObject(); - String itemName = shareItem.get("name").getAsString(); - JsonArray itemLore = shareItem.get("lore").getAsJsonArray(); - boolean isItemVerified = shareJson.get("share").getAsJsonObject().get("verified").getAsBoolean(); - IChatComponent newComp = new ChatComponentText(EnumChatFormatting.LIGHT_PURPLE + "[Synthesis " + itemName + EnumChatFormatting.LIGHT_PURPLE + "]"); - AtomicReference s = new AtomicReference<>(""); - itemLore.iterator().forEachRemaining(jsonElement -> { - s.set(s.get() + jsonElement.getAsString() + "\n"); - }); - newComp.getChatStyle().setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(s.get()))); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(message + (isItemVerified ? EnumChatFormatting.GREEN + "✔ " : EnumChatFormatting.RED + "✖ ")).appendSibling(newComp)); - } catch (JsonParseException e) { - ChatLib.chat("Something went wrong trying to read share."); - e.printStackTrace(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - })).start(); - } - } - } -} diff --git a/src/main/java/com/luna/synthesis/features/utilities/TrophyFishingMoment.java b/src/main/java/com/luna/synthesis/features/utilities/TrophyFishingMoment.java new file mode 100644 index 0000000..8753513 --- /dev/null +++ b/src/main/java/com/luna/synthesis/features/utilities/TrophyFishingMoment.java @@ -0,0 +1,81 @@ +package com.luna.synthesis.features.utilities; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.Slot; +import net.minecraft.util.StringUtils; + +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.awt.Color; +import java.util.List; + +import org.lwjgl.opengl.GL11; + +public class TrophyFishingMoment { + + private final Config config = Synthesis.getInstance().getConfig(); + + private float r, g, b = 0F; + private String highestTrophyName = ""; + private List itemLore; + private List slots; + private int slotIndex = 0; + + @SubscribeEvent + public void onGuiScreen(GuiScreenEvent.BackgroundDrawnEvent e) { + if (!config.utilitiesTrophyFishingOverlay || Minecraft.getMinecraft().thePlayer == null || !(Minecraft.getMinecraft().currentScreen instanceof GuiChest) || !(StringUtils.stripControlCodes((((ContainerChest)((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots).getLowerChestInventory().getDisplayName().getUnformattedText())).toLowerCase().contains("trophy fishing"))) return; + + slots = ((GuiChest)(Minecraft.getMinecraft().currentScreen)).inventorySlots.inventorySlots; + + for (Slot s : slots) { + highestTrophyName = ""; + slotIndex = s.getSlotIndex(); + + if (slotIndex == 45) break; + if ((((slotIndex + 1) % 9) == 0) || (((slotIndex + 1) % 9) == 1) || (slotIndex < 8)) continue; + + if (s.getStack() != null && s.getStack().hasDisplayName() && !(s.getStack().getDisplayName().isEmpty()) && (!(s.getStack().getDisplayName().contains("§c§k")))) { + itemLore = s.getStack().getTooltip(Minecraft.getMinecraft().thePlayer, false); + for (String line : itemLore) { + if (line.contains("a\u2714")) { + highestTrophyName = StringUtils.stripControlCodes(line); + break; + } + } + + if (highestTrophyName.contains("Diamond")) { + r = 85; b = g = 255; + } else if (highestTrophyName.contains("Gold")) { + r = 255; b = 0; g = 170; + } else if (highestTrophyName.contains("Silver")) { + r = b = g = 170; + } else if (highestTrophyName.contains("Bronze")) { + r = b = g = 85; + } + Color bgColor = new Color(((int)(r)), ((int)(g)), ((int)(b))); + GL11.glTranslated(0, 0, 1); + Gui.drawRect( + ((((new ScaledResolution(Minecraft.getMinecraft())).getScaledWidth() - 176) / 2) + s.xDisplayPosition), + ((slots.size() != 90) ? + (((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition) + + ((6 - (slots.size() - 36) / 9) * 9)) : + ((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition)), + (((((new ScaledResolution(Minecraft.getMinecraft())).getScaledWidth() - 176) / 2) + s.xDisplayPosition) + 16), + (((slots.size() != 90) ? + (((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition) + + ((6 - (slots.size() - 36) / 9) * 9)) : + ((((new ScaledResolution(Minecraft.getMinecraft())).getScaledHeight() - 222) / 2) + s.yDisplayPosition)) + 16), + bgColor.getRGB()); + GL11.glTranslated(0, 0, -1); + } + } + } +} diff --git a/src/main/java/com/luna/synthesis/features/utilities/VisibleLinks.java b/src/main/java/com/luna/synthesis/features/utilities/VisibleLinks.java index 1fba8aa..2cdb6da 100644 --- a/src/main/java/com/luna/synthesis/features/utilities/VisibleLinks.java +++ b/src/main/java/com/luna/synthesis/features/utilities/VisibleLinks.java @@ -1,5 +1,7 @@ package com.luna.synthesis.features.utilities; +import java.util.regex.*; + import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import net.minecraft.event.ClickEvent; @@ -13,9 +15,21 @@ public class VisibleLinks { private final Config config = Synthesis.getInstance().getConfig(); + private final Pattern domainPattern = Pattern.compile("((https?)://)?[-a-zA-Z0-9+&@#/%?=~_|!:,;]+\\.[-a-zA-Z0-9+&@#/%=~_|]"); + //modified from the java regex of https://urlregex.com/ + //it'll still falsely trigger on `...com` but fuck it + + // Low priority so it's compatible with bridge @SubscribeEvent(priority = EventPriority.LOW) public void onChatMessage(ClientChatReceivedEvent event) { if (!config.utilitiesVisibleLinks) return; + /** + * Suggestion #97 by Doppelclick#5993 + * make it so that visible links must include top level domains: + * https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains, + * as currently a simple ... can trigger the feature + */ + if (!domainPattern.matcher(event.message.getUnformattedText()).find()) return; if (event.type == 0 || event.type == 1) { for (IChatComponent iChatComponent : event.message.getSiblings()) { if (iChatComponent.getChatStyle().getChatClickEvent() != null) { diff --git a/src/main/java/com/luna/synthesis/features/utilities/WishingCompass.java b/src/main/java/com/luna/synthesis/features/utilities/WishingCompass.java index d52fe51..8fd02d2 100644 --- a/src/main/java/com/luna/synthesis/features/utilities/WishingCompass.java +++ b/src/main/java/com/luna/synthesis/features/utilities/WishingCompass.java @@ -1,6 +1,5 @@ package com.luna.synthesis.features.utilities; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.events.packet.PacketReceivedEvent; @@ -13,7 +12,6 @@ import net.minecraft.util.StringUtils; import net.minecraft.util.Vec3; import net.minecraftforge.client.ClientCommandHandler; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -22,7 +20,7 @@ public class WishingCompass { private final Config config = Synthesis.getInstance().getConfig(); private boolean awaiting = false; - private long lastCompass = -1L; + private long lastItem = -1L; private Vec3 pos1 = null; private Vec3 pos2 = null; private Vec3 vec1 = null; @@ -54,7 +52,6 @@ public void onPacketReceived(PacketReceivedEvent event) { } } - @Comment("Will eventually have something for checking the item's sb id instead of name but ehhhh") @SubscribeEvent public void onRightClick(PlayerInteractEvent event) { if (!config.utilitiesWishingCompass) return; @@ -62,13 +59,13 @@ public void onRightClick(PlayerInteractEvent event) { ItemStack item = Minecraft.getMinecraft().thePlayer.getHeldItem(); if (item == null) return; if (StringUtils.stripControlCodes(item.getDisplayName()).contains("Wishing Compass")) { - if (config.utilitiesBlockWishingCompass && System.currentTimeMillis() - lastCompass < 4000) { - ChatLib.chat("Last wishing compass hasn't disappeared yet, chill."); + if (config.utilitiesBlockWishingCompass && System.currentTimeMillis() - lastItem < 4000) { + ChatLib.chat("Last trail hasn't disappeared yet, chill."); event.setCanceled(true); return; } awaiting = true; - lastCompass = System.currentTimeMillis(); + lastItem = System.currentTimeMillis(); } } } @@ -82,7 +79,9 @@ public void onWorldLoad(WorldEvent.Load event) { awaiting = false; } - @Comment("All math credit in the mod (this included) goes to Lucy. Thank you Lucy!") + // All math in the mod is thanks to Lucy, this included, thank you, Lucy! + // If you don't understand something don't blame me, I just copied her notes. + // And no, you cannot expect me to do very simple math, I will simply ask the math genius when possible. private void calculateIntercept() { double a = pos1.xCoord; double b = pos1.yCoord; @@ -106,11 +105,11 @@ private void calculateIntercept() { } else { 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); if (Math.abs(solution.getX() - 513) < 65 && Math.abs(solution.getZ() - 513) < 65) { - ChatLib.chat("This compass points to the nucleus! You need to place crystals so the compass points somewhere else."); + 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."); } else { ChatLib.chat("Solution: (" + solution.getX() + ", " + solution.getY() + ", " + solution.getZ() + ")"); if (config.utilitiesWishingCompassWaypoint) { - ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/sthw set WishingCompass " + solution.getX() + " " + solution.getY() + " " + solution.getZ()); + ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/sthw set " + solution.getX() + " " + solution.getY() + " " + solution.getZ() + " WishingCompass"); } } } diff --git a/src/main/java/com/luna/synthesis/managers/BackpackManager.java b/src/main/java/com/luna/synthesis/managers/BackpackManager.java index 14fc2ca..67d736a 100644 --- a/src/main/java/com/luna/synthesis/managers/BackpackManager.java +++ b/src/main/java/com/luna/synthesis/managers/BackpackManager.java @@ -12,6 +12,7 @@ public class BackpackManager { private JsonObject jsonObject; private File file; + // Damn this is old and garbage lmao public BackpackManager(File file) { if (!file.exists()) { try { diff --git a/src/main/java/com/luna/synthesis/mixins/ContainerMixin.java b/src/main/java/com/luna/synthesis/mixins/ContainerMixin.java new file mode 100644 index 0000000..b3f6c57 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/ContainerMixin.java @@ -0,0 +1,80 @@ +package com.luna.synthesis.mixins; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.Minecraft; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.NBTTagString; +import net.minecraft.util.StringUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(Container.class) +public class ContainerMixin { + + private final Config config = Synthesis.getInstance().getConfig(); + + @ModifyArg(method = {"putStackInSlot", "putStacksInSlots"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/Slot;putStack(Lnet/minecraft/item/ItemStack;)V")) + public ItemStack overridePutStack(ItemStack in) { + if (!config.utilitiesSuperpairsIDs) return in; + if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { + ContainerChest containerChest = (ContainerChest) Minecraft.getMinecraft().thePlayer.openContainer; + String title = StringUtils.stripControlCodes(containerChest.getLowerChestInventory().getDisplayName().getUnformattedText()); + if (!title.startsWith("Superpairs (")) return in; + if (in == null) return in; + String itemName = StringUtils.stripControlCodes(in.getDisplayName()); + if (itemName.equals("Experiment the Fish")) return in; + + if (!in.getTagCompound().hasKey("ExtraAttributes")) { + in.getTagCompound().setTag("ExtraAttributes", new NBTTagCompound()); + } + NBTTagCompound ea = in.getTagCompound().getCompoundTag("ExtraAttributes"); + + if (itemName.startsWith("+")) { + if (itemName.endsWith(" Enchanting Exp")) { + ea.setTag("id", new NBTTagString("ENCHANTING_EXPERIENCE")); + } else if (itemName.endsWith(" XP")) { + ea.setTag("id", new NBTTagString("POWER_UP_EXPERIENCE")); + } + } + + switch (itemName) { + case "Gained +3 Clicks": + ea.setTag("id", new NBTTagString("POWER_UP_EXTRA_CLICKS")); + break; + case "Instant Find": + ea.setTag("id", new NBTTagString("POWER_UP_INSTANT_FIND")); + break; + case "Titanic Experience Bottle": + ea.setTag("id", new NBTTagString("TITANIC_EXP_BOTTLE")); + break; + case "Grand Experience Bottle": + ea.setTag("id", new NBTTagString("GRAND_EXP_BOTTLE")); + break; + case "Experience Bottle": + ea.setTag("id", new NBTTagString("EXP_BOTTLE")); + break; + case "Enchanted Book": + ea.setTag("id", new NBTTagString("ENCHANTED_BOOK")); + ea.setTag("enchantments", new NBTTagCompound()); + String enchant = StringUtils.stripControlCodes(in.getSubCompound("display", false).getTagList("Lore", 8).getStringTagAt(2)); + String enchantName = ""; + for (int i = 0; i < enchant.split(" ").length - 1; i++) { + enchantName += enchant.split(" ")[i]; + if (i != enchant.split(" ").length - 2) { + enchantName += "_"; + } + } + enchantName = enchantName.toLowerCase(); + ea.getCompoundTag("enchantments").setTag(enchantName, new NBTTagInt(in.stackSize)); + break; + } + } + return in; + } +} diff --git a/src/main/java/com/luna/synthesis/mixins/EntityPlayerSPMixin.java b/src/main/java/com/luna/synthesis/mixins/EntityPlayerSPMixin.java new file mode 100644 index 0000000..57678a6 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/EntityPlayerSPMixin.java @@ -0,0 +1,26 @@ +package com.luna.synthesis.mixins; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.GuiChat; +import net.minecraft.client.gui.GuiScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(EntityPlayerSP.class) +public class EntityPlayerSPMixin { + + private final Config config = Synthesis.getInstance().getConfig(); + + // It's possible (and very easy) to make portals never close any gui (since it closes it only clientside, server would not care) + // BUT I'm not sure if Hypixel would like that/there's any potential false bans SO only chat for now. + @Redirect(method = "onLivingUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiScreen;doesGuiPauseGame()Z")) + public boolean overrideDoesGuiPauseGame(GuiScreen gui) { + if (config.utilitiesPortalChat) { + return gui.doesGuiPauseGame() || gui instanceof GuiChat; //|| gui instanceof GuiContainer; + } + return gui.doesGuiPauseGame(); + } +} diff --git a/src/main/java/com/luna/synthesis/mixins/GuiContainerMixin.java b/src/main/java/com/luna/synthesis/mixins/GuiContainerMixin.java index 01e04d5..4af719f 100644 --- a/src/main/java/com/luna/synthesis/mixins/GuiContainerMixin.java +++ b/src/main/java/com/luna/synthesis/mixins/GuiContainerMixin.java @@ -3,6 +3,7 @@ import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.utils.MixinUtils; +import com.luna.synthesis.utils.ReflectionUtils; import net.minecraft.client.gui.*; import net.minecraft.client.gui.inventory.GuiContainer; import org.spongepowered.asm.mixin.Mixin; @@ -10,26 +11,17 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; -import java.util.List; - @Mixin(GuiContainer.class) public class GuiContainerMixin extends GuiScreen { private final Config config = Synthesis.getInstance().getConfig(); + private final boolean patcherClearField = ReflectionUtils.getPatcherChatField(); private GuiTextField inputField; - private int sentHistoryCursor = -1; - private boolean playerNamesFound; - private boolean waitingOnAutocomplete; - private int autocompleteIndex; - private final List foundPlayerNames = new ArrayList<>(); - private String historyBuffer = ""; @Inject(method = "initGui", at = @At("RETURN")) public void initGui(CallbackInfo ci) { if (config.utilitiesContainerChat) { - this.sentHistoryCursor = this.mc.ingameGUI.getChatGUI().getSentMessages().size(); this.inputField = new GuiTextField(0, this.fontRendererObj, 4, this.height - 12, this.width - 4, 12); this.inputField.setMaxStringLength(256); this.inputField.setEnableBackgroundDrawing(false); @@ -53,7 +45,9 @@ public void updateScreen(CallbackInfo ci) { @Inject(method = "drawScreen", at = @At(value = "INVOKE", target = "net/minecraft/client/gui/GuiScreen.drawScreen(IIF)V")) public void drawScreen(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) { if (config.utilitiesContainerChat && this.inputField.isFocused()) { - Gui.drawRect(2, this.height - 14, this.width - 2, this.height - 2, Integer.MIN_VALUE); + if (!patcherClearField) { + Gui.drawRect(2, this.height - 14, this.width - 2, this.height - 2, Integer.MIN_VALUE); + } this.inputField.drawTextBox(); } } diff --git a/src/main/java/com/luna/synthesis/mixins/GuiNewChatMixin.java b/src/main/java/com/luna/synthesis/mixins/GuiNewChatMixin.java index deb6a04..279b3d4 100644 --- a/src/main/java/com/luna/synthesis/mixins/GuiNewChatMixin.java +++ b/src/main/java/com/luna/synthesis/mixins/GuiNewChatMixin.java @@ -1,16 +1,12 @@ package com.luna.synthesis.mixins; import com.google.common.collect.Lists; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.features.utilities.SearchMode; import com.luna.synthesis.mixins.accessors.GuiChatAccessor; import com.luna.synthesis.mixins.accessors.GuiContainerAccessor; -import com.luna.synthesis.utils.ChatLib; import com.luna.synthesis.utils.MixinUtils; -import com.luna.synthesis.utils.Utils; -import com.sun.org.apache.bcel.internal.generic.GETFIELD; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; import net.minecraft.client.gui.inventory.GuiContainer; @@ -18,6 +14,7 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; import net.minecraft.util.StringUtils; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.*; @@ -25,15 +22,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; @Mixin(GuiNewChat.class) public abstract class GuiNewChatMixin { private boolean needsRefresh = false; - @Shadow private final List chatLines = Lists.newArrayList(); + @Final @Shadow private final List chatLines = Lists.newArrayList(); + @Final @Shadow private final List drawnChatLines = Lists.newArrayList(); + @Shadow public abstract void deleteChatLine(int id); + @Shadow protected abstract void setChatLine(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly); private final Config config = Synthesis.getInstance().getConfig(); @Inject(method = "clearChatMessages", at = @At(value = "INVOKE", target = "Ljava/util/List;clear()V", ordinal = 2), cancellable = true) @@ -65,7 +63,7 @@ public void getChatOpen(CallbackInfoReturnable cir) { } } - @Comment("Walmart solution to not having continue inside mixins. Kind of a cool mixin, prevents lag with a ton of chat lines when trying to search.") + // 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. @ModifyVariable(method = "refreshChat", at = @At(value = "INVOKE", target = "Ljava/util/List;get(I)Ljava/lang/Object;", shift = At.Shift.BEFORE), index = 1) public int i(int in) { GuiScreen gui = Minecraft.getMinecraft().currentScreen; @@ -88,7 +86,7 @@ public int i(int in) { return in; } - @Comment("And here's the failsafe to be able to 'continue' in the last iteration of the loop") + // This just here so it's possible to "continue" in the last iteration of the loop @Inject(method = "refreshChat", at = @At(value = "INVOKE", target = "Ljava/util/List;get(I)Ljava/lang/Object;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) public void refreshChat(CallbackInfo ci, int i) { if (i == -1) { @@ -107,4 +105,49 @@ public void setChatLine(IChatComponent chatComponent, int chatLineId, int update } } } + + // The section below is used so the SEARCH MODE ON message always stays at the bottom of the chat + + // Fix for refreshChat deleting messages with same id? For no reason either?? + // If you're not using the mod, go to a hub and tab player's names so the message of potential players shows up + // 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 + // THE MESSAGE WILL DISAPPEAR, FOR NO REASON EITHER, WHAT THE FWICK + @Redirect(method = "setChatLine", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;deleteChatLine(I)V")) + public void deleteChatLine(GuiNewChat chat, int id, IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly) { + if (!displayOnly) { + this.deleteChatLine(id); + } + } + + @ModifyArg(method = "setChatLine", at = @At(value = "INVOKE", target = "Ljava/util/List;add(ILjava/lang/Object;)V", ordinal = 0)) + public int modifyIndex(int in, Object line) { + ChatLine cl = (ChatLine) line; + if (SearchMode.isSearchMode && !cl.getChatComponent().getFormattedText().contains(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON")) { + if (this.drawnChatLines.size() == 0) { + this.deleteChatLine("synthesissearchmode".hashCode()); + this.setChatLine(new ChatComponentText(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "SEARCH MODE ON"), "synthesissearchmode".hashCode(), Minecraft.getMinecraft().ingameGUI.getUpdateCounter(), true); + } + return 1; + } + return in; + } + + // For reforge message cleanup - There's probably a better way to do this, but I'm blind + // Also regexes wack, you know how it goes with me and regexes + @ModifyArg(method = "printChatMessage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiNewChat;printChatMessageWithOptionalDeletion(Lnet/minecraft/util/IChatComponent;I)V"), index = 1) + public int overrideChatId(IChatComponent chatComponent, int in) { + if (config.cleanupChatOldReforgeMessages) { + String msg = StringUtils.stripControlCodes(chatComponent.getUnformattedText()); + // Why must I be punished like this. + // What have I done to deserve this. + // 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 + // 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. + if ((msg.startsWith("You reforged your ") && msg.contains(" into a ") && msg.endsWith("!")) || + (msg.startsWith("You applied the ") && msg.contains(" reforge to your ") && msg.endsWith("!")) || + (msg.startsWith("You selected the ") && msg.endsWith(" power for your Accessory Bag!"))) { + return "synthesisreforgemessagecleanup".hashCode(); + } + } + return in; + } } diff --git a/src/main/java/com/luna/synthesis/mixins/GuiPlayerTabOverlayMixin.java b/src/main/java/com/luna/synthesis/mixins/GuiPlayerTabOverlayMixin.java new file mode 100644 index 0000000..0e3433e --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/GuiPlayerTabOverlayMixin.java @@ -0,0 +1,37 @@ +package com.luna.synthesis.mixins; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.client.gui.GuiPlayerTabOverlay; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IChatComponent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(GuiPlayerTabOverlay.class) +public class GuiPlayerTabOverlayMixin { + + private final Config config = Synthesis.getInstance().getConfig(); + + // mhm tasty spaghetti + + @ModifyVariable(method = "setFooter", at = @At("HEAD"), argsOnly = true) + public IChatComponent overrideFooter(IChatComponent in) { + if (config.cleanupTablistFooter) { + String s = in.getFormattedText() + .replace("\n§r§r§r§r§s§r\n§r§r§aRanks, Boosters & MORE! §r§c§lSTORE.HYPIXEL.NET§r", "") + .replace("§r§aRanks, Boosters & MORE! §r§c§lSTORE.HYPIXEL.NET§r", ""); + return s.length() == 0 ? null : new ChatComponentText(s); + } + return in; + } + + @ModifyVariable(method = "setHeader", at = @At("HEAD"), argsOnly = true) + public IChatComponent overrideHeader(IChatComponent in) { + if (config.cleanupTablistHeader) { + return null; + } + return in; + } +} diff --git a/src/main/java/com/luna/synthesis/mixins/GuiScreenMixin.java b/src/main/java/com/luna/synthesis/mixins/GuiScreenMixin.java new file mode 100644 index 0000000..d3f5566 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/GuiScreenMixin.java @@ -0,0 +1,37 @@ +package com.luna.synthesis.mixins; + +import com.luna.synthesis.events.MessageSentEvent; +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.common.MinecraftForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiScreen.class) +public class GuiScreenMixin { + + private String newMessage = ""; + + @Inject(method = "sendChatMessage(Ljava/lang/String;)V", at = @At("HEAD"), cancellable = true) + public void onMessageSent(String message, CallbackInfo ci) { + MessageSentEvent event = new MessageSentEvent(message); + MinecraftForge.EVENT_BUS.post(event); + + if (event.isCanceled()) { + ci.cancel(); + } else if (!event.message.equals(message)) { + newMessage = event.message; + } + } + + @ModifyVariable(method = "sendChatMessage(Ljava/lang/String;)V", at = @At("HEAD")) + public String overrideMessageSent(String msg) { + if (!newMessage.equals("")) { + msg = newMessage; + newMessage = ""; + } + return msg; + } +} diff --git a/src/main/java/com/luna/synthesis/mixins/RenderItemMixin.java b/src/main/java/com/luna/synthesis/mixins/RenderItemMixin.java index 89aa212..c47135c 100644 --- a/src/main/java/com/luna/synthesis/mixins/RenderItemMixin.java +++ b/src/main/java/com/luna/synthesis/mixins/RenderItemMixin.java @@ -1,9 +1,9 @@ package com.luna.synthesis.mixins; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import com.luna.synthesis.managers.BackpackManager; +import com.luna.synthesis.utils.ChatLib; import com.luna.synthesis.utils.MixinUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; @@ -11,16 +11,19 @@ import net.minecraft.client.renderer.ItemModelMesher; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.StringUtils; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.Iterator; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; @Mixin(RenderItem.class) @@ -28,7 +31,7 @@ public class RenderItemMixin { private final Config config = Synthesis.getInstance().getConfig(); - @Comment("Might make these two mixins onto a forge event because they're very cool") + // Might make these two onto a forge event because they're very cool @Redirect(method = "renderItemIntoGUI", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemModelMesher;getItemModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/resources/model/IBakedModel;")) public IBakedModel iBakedModel(ItemModelMesher imm, ItemStack stack) { String name = StringUtils.stripControlCodes(stack.getDisplayName()); @@ -45,6 +48,7 @@ public IBakedModel iBakedModel(ItemModelMesher imm, ItemStack stack) { @Inject(method = "renderItemOverlayIntoGUI", at = @At(value = "JUMP", ordinal = 1, shift = At.Shift.BEFORE), cancellable = true) public void renderItemOverlayIntoGUI(FontRenderer fr, ItemStack stack, int xPosition, int yPosition, String text, CallbackInfo ci) { if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) { + if (stack.getItem() == Item.getItemFromBlock(Blocks.glass_pane)) return; ContainerChest containerChest = (ContainerChest) Minecraft.getMinecraft().thePlayer.openContainer; String title = StringUtils.stripControlCodes(containerChest.getLowerChestInventory().getDisplayName().getUnformattedText()); if (config.utilitiesPerkLevelDisplay && title.equals("Heart of the Mountain")) { @@ -59,13 +63,14 @@ public void renderItemOverlayIntoGUI(FontRenderer fr, ItemStack stack, int xPosi level = level.split("/")[0]; } if (level.equals("1")) return; - drawStringAsStackSize(level, xPosition, yPosition); + drawAsStackSize(level, xPosition, yPosition); ci.cancel(); } } else if (config.utilitiesBestiaryGlance && (title.equals("Bestiary") || title.contains(" ➜ "))) { - if (StringUtils.stripControlCodes(stack.getDisplayName()).startsWith("Bestiary Milestone ")) { - String level = StringUtils.stripControlCodes(stack.getDisplayName()).replace("Bestiary Milestone ", ""); - drawStringAsStackSize(level, xPosition, yPosition); + String dName = stack.getDisplayName(); + if (StringUtils.stripControlCodes(dName).startsWith("Bestiary Milestone ")) { + String level = StringUtils.stripControlCodes(dName).replace("Bestiary Milestone ", ""); + drawAsStackSize(level, xPosition, yPosition); ci.cancel(); } else if (stack == containerChest.getInventory().get(52)) { ItemStack bestiary = containerChest.getInventory().get(51); @@ -79,20 +84,248 @@ public void renderItemOverlayIntoGUI(FontRenderer fr, ItemStack stack, int xPosi } }); if (progress.get().equals("")) return; - drawStringAsStackSize(progress.get(), xPosition, yPosition); + drawAsStackSize(progress.get(), xPosition, yPosition); ci.cancel(); } + } else if (config.utilitiesShowCollectionStackSize && (title.contains(" Collection"))) { + String[] splitStr = StringUtils.stripControlCodes(stack.getDisplayName()).split(" "); + if (splitStr.length < 1) return; + String romanNumeral = splitStr[(splitStr.length - 1)]; + if (!((romanNumeral.contains("I") || romanNumeral.contains("V") || romanNumeral.contains("X") || romanNumeral.contains("L") || romanNumeral.contains("C") || romanNumeral.contains("D") || romanNumeral.contains("M")))) return; + if ((stack.getDisplayName().contains(" Minion"))) return; + int finalResult = 0; + //BRUTEFORCE CONVERSION. + //I SURE AS FUCK GOT NO TIME TO WRITE THAT ROMAN TO ARABIC NUMERAL CONVERSION FUNCTION. + //S_A_D ISTG IF YOU SCREENSHOT THIS I WILL COMMIT COPIOUS AMOUNTS OF VIDEO GAME CRIMES -ERY + if (romanNumeral.equals("I")) finalResult = 1; else if (romanNumeral.equals("II")) finalResult = 2; else if (romanNumeral.equals("III")) finalResult = 3; else if (romanNumeral.equals("IV")) finalResult = 4; else if (romanNumeral.equals("V")) finalResult = 5; else if (romanNumeral.equals("VI")) finalResult = 6; else if (romanNumeral.equals("VII")) finalResult = 7; else if (romanNumeral.equals("VIII")) finalResult = 8; else if (romanNumeral.equals("IX")) finalResult = 9; else if (romanNumeral.equals("X")) finalResult = 10; else if (romanNumeral.equals("XI")) finalResult = 11; else if (romanNumeral.equals("XII")) finalResult = 12; else if (romanNumeral.equals("XIII")) finalResult = 13; else if (romanNumeral.equals("XIV")) finalResult = 14; else if (romanNumeral.equals("XV")) finalResult = 15; else if (romanNumeral.equals("XVI")) finalResult = 16; else if (romanNumeral.equals("XVII")) finalResult = 17; else if (romanNumeral.equals("XVIII")) finalResult = 18; else if (romanNumeral.equals("XIX")) finalResult = 19; else if (romanNumeral.equals("XX")) finalResult = 20; else return; + drawAsStackSize(finalResult, xPosition, yPosition); + ci.cancel(); + } else if (config.utilitiesShowCraftedMinionsStackSize && title.contains("Crafted Minions")) { + if (!(stack.getItem() == Items.skull)) return; + if (!(stack.getDisplayName().endsWith(" Minion"))) return; + int numTiers = 0; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + for (String s : itemLore) if (s.contains("a")) numTiers++; else if (s.contains("c")) break; + drawAsStackSize(numTiers, xPosition, yPosition); + ci.cancel(); + } else if ((title.equals("Your Skills") || title.equals("Dungeoneering") || title.equals("Dungeon Classes"))) { + if (config.utilitiesShowSkillAverageStackSize != 0 && stack.getDisplayName().contains("Your Skill")) { + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String skillAvg = ""; + for (String s : itemLore) { + if ((StringUtils.stripControlCodes(s)).contains(" Skill Avg")) { + String[] temp = s.split(" "); + if (temp.length < 1) break; //prevent crash + skillAvg = StringUtils.stripControlCodes(temp[0]); + break; + } + } + if (skillAvg == "") return; + if (config.utilitiesShowSkillAverageStackSize == 1) drawAsStackSize(Math.round(Float.valueOf(skillAvg)), xPosition, yPosition); + else if (config.utilitiesShowSkillAverageStackSize == 2) drawAsStackSize(skillAvg, xPosition, yPosition); + ci.cancel(); + } else if (config.utilitiesShowSkillStackSize) { + String[] splitStr = StringUtils.stripControlCodes(stack.getDisplayName()).split(" "); + if (splitStr.length < 2) return; + String skillNumeral = splitStr[(splitStr.length - 1)]; + if (title.equals("Dungeon Classes")) skillNumeral = splitStr[1]; + char c = skillNumeral.charAt(0); + if (c < '0' || c > '9') return; //HUGE SHOUTOUT TO Jonas K from StackOverflow for this: https://stackoverflow.com/a/237204 + skillNumeral = skillNumeral.replace("[", "").replace("]", "").replace("(", "").replace(")", ""); + drawAsStackSize(skillNumeral, xPosition, yPosition); + ci.cancel(); + } + } else if (config.utilitiesShowDojoProgressStackSize && title.equals("Challenges")) { + if (!stack.getDisplayName().startsWith("§9Test of ") && !stack.getDisplayName().equals("§6Rank")) return; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String[] splitStr = {}; + if (stack.getDisplayName().equals("§6Rank")) splitStr = itemLore.get(3).split(" "); + if (stack.getDisplayName().startsWith("§9Test of ")) splitStr = itemLore.get(1).split(" "); + if (splitStr.length < 2) return; + String result = splitStr[2]; + if (stack.getDisplayName().equals("§6Rank")) result = result.substring(0, 3); + drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } else if (config.utilitiesShowCompletedQuestCountStackSize && title.equals("Quest Log")) { + if (!stack.getDisplayName().equals("§aCompleted Quests")) return; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String[] splitStr = StringUtils.stripControlCodes(itemLore.get(5)).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[1]; + drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } else if (config.utilitiesShowWardrobeSlotStackSize && title.startsWith("Wardrobe")) { + if (!stack.getDisplayName().startsWith("§7Slot ")) return; + String[] splitStr = StringUtils.stripControlCodes(stack.getDisplayName()).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[1].replace(":", ""); + drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } else if (title.startsWith("SkyBlock Menu")) { + if (!stack.getDisplayName().contains("Your Skill") && !stack.getDisplayName().equals("§aRecipe Book") && !stack.getDisplayName().equals("§aCollection") && !stack.getDisplayName().equals("§a§aActive Effects")) return; + if (config.utilitiesShowSkillAverageStackSize == 0 && config.utilitiesShowUnlockedRecipePercentStackSize == 0 && config.utilitiesShowUnlockedCollectionStackSize == 0) return; + String skillAvg = ""; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + if (stack.getDisplayName().contains("Your Skill") && config.utilitiesShowSkillAverageStackSize != 0) { + for (String s : itemLore) { + if ((StringUtils.stripControlCodes(s)).contains(" Skill Avg")) { + String[] temp = s.split(" "); + if (temp.length < 1) break; //prevent crash + skillAvg = StringUtils.stripControlCodes(temp[0]); + break; + } + } + if (skillAvg == "") return; + if (config.utilitiesShowSkillAverageStackSize == 1) drawAsStackSize(Math.round(Float.valueOf(skillAvg)), xPosition, yPosition); + else if (config.utilitiesShowSkillAverageStackSize == 2) drawAsStackSize(skillAvg, xPosition, yPosition); + ci.cancel(); + } else if (stack.getDisplayName().equals("§aRecipe Book") && config.utilitiesShowUnlockedRecipePercentStackSize != 0) { + String[] splitStr = StringUtils.stripControlCodes(itemLore.get(6)).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[3].replace("%", ""); + if (config.utilitiesShowUnlockedRecipePercentStackSize == 1) drawAsStackSize(Math.round(Float.valueOf(result)), xPosition, yPosition); + else if (config.utilitiesShowUnlockedRecipePercentStackSize == 2) drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } else if (stack.getDisplayName().equals("§aCollection") && config.utilitiesShowUnlockedCollectionStackSize != 0) { + String[] splitStr = StringUtils.stripControlCodes(itemLore.get(7)).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[2].replace("%", ""); + char c = result.charAt(0); + if (c < '0' || c > '9') result = splitStr[3].replace("%", ""); //HUGE SHOUTOUT TO Jonas K from StackOverflow for this: https://stackoverflow.com/a/237204 + result = result.replace("100", "§a✔"); + if (config.utilitiesShowUnlockedCollectionStackSize == 1) { + try { + drawAsStackSize(Math.round(Float.valueOf(result)), xPosition, yPosition); + } catch (Exception why) { + drawAsStackSize(result, xPosition, yPosition); + } + } + else if (config.utilitiesShowUnlockedCollectionStackSize == 2) drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } else if (config.utilitiesShowActiveEffectsStackSize && stack.getDisplayName().equals("§a§aActive Effects")) { + String[] splitStr = StringUtils.stripControlCodes(itemLore.get(7)).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[splitStr.length - 1].replace("%", ""); + char c = result.charAt(0); + if (c < '0' || c > '9') return; //HUGE SHOUTOUT TO Jonas K from StackOverflow for this: https://stackoverflow.com/a/237204 + drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } + } else if ((title.equals("Recipe Book") || title.endsWith(" Recipes"))) { + if (!stack.getDisplayName().startsWith("§a") || !stack.getDisplayName().endsWith(" Recipes")) return; + if (config.utilitiesShowUnlockedRecipePercentStackSize == 0 && config.utilitiesShowUnlockedSpecificRecipePercentStackSize == 0) return; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String[] splitStr = StringUtils.stripControlCodes(itemLore.get(4)).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[2].replace("%", ""); + char c = result.charAt(0); + if (c < '0' || c > '9') result = splitStr[3].replace("%", ""); //HUGE SHOUTOUT TO Jonas K from StackOverflow for this: https://stackoverflow.com/a/237204 + result = result.replace("100", "§a✔"); + if (config.utilitiesShowUnlockedSpecificRecipePercentStackSize == 1) { + try { + drawAsStackSize(Math.round(Float.valueOf(result)), xPosition, yPosition); + } catch (Exception why) { + drawAsStackSize(result, xPosition, yPosition); + } + } else if (config.utilitiesShowUnlockedSpecificRecipePercentStackSize == 2) drawAsStackSize(result, xPosition, yPosition); + ci.cancel(); + } else if (title.equals("Collection")) { + if (!stack.getDisplayName().startsWith("§a") || !stack.getDisplayName().endsWith("Collection")) return; + if (config.utilitiesShowUnlockedCollectionStackSize == 0) return; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String[] splitStr = {}; + if (stack.getDisplayName().equals("§aCollection")) splitStr = StringUtils.stripControlCodes(itemLore.get(7)).split(" "); + else splitStr = StringUtils.stripControlCodes(itemLore.get(3)).split(" "); + if (splitStr.length < 1) return; + String result = splitStr[2].replace("%", ""); + char c = result.charAt(0); + if (c < '0' || c > '9') result = splitStr[3].replace("%", ""); //HUGE SHOUTOUT TO Jonas K from StackOverflow for this: https://stackoverflow.com/a/237204 + result = result.replace("100", "§a✔"); + if (config.utilitiesShowUnlockedCollectionStackSize == 1) { + try { + drawAsStackSize(Math.round(Float.valueOf(result)), xPosition, yPosition); + } catch (Exception why) { + drawAsStackSize(result, xPosition, yPosition); + } + } else if (config.utilitiesShowUnlockedCollectionStackSize == 2) drawAsStackSize(result, xPosition, yPosition); + } else if (title.contains("Museum") && config.utilitiesShowMuseumPercentagesStackSize != 0) { + if (!stack.getDisplayName().startsWith("§a") && !stack.getDisplayName().startsWith("§9")) return; + if (stack.getItem() == Items.sign || stack.getItem() == Items.name_tag) return; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String result = ""; + if (stack.getDisplayName().equals("§9Museum")) result = StringUtils.stripControlCodes(itemLore.get(11)).split(" ")[2].replace("%", ""); + if (stack.getDisplayName().equals("§aRarities") || stack.getDisplayName().equals("§aArmor Sets") || stack.getDisplayName().equals("§aWeapons")) result = StringUtils.stripControlCodes(itemLore.get(5)).split(" ")[2].replace("%", ""); + if (stack.getDisplayName().equals("§aSpecial Items")) result = StringUtils.stripControlCodes(itemLore.get(13)).split(" ")[2].replace("%", ""); + if (result == "") return; + char c = result.charAt(0); + if (c < '0' || c > '9') return; //HUGE SHOUTOUT TO Jonas K from StackOverflow for this: https://stackoverflow.com/a/237204 + result = result.replace("100", "§a✔"); + if (config.utilitiesShowMuseumPercentagesStackSize == 1) { + try { + drawAsStackSize(Math.round(Float.valueOf(result)), xPosition, yPosition); + } catch (Exception why) { + drawAsStackSize(result, xPosition, yPosition); + } + } else if (config.utilitiesShowMuseumPercentagesStackSize == 2) drawAsStackSize(result, xPosition, yPosition); + } else if (config.utilitiesShowBankTierStackSize && title.equals("Bank")) { + if (!stack.getDisplayName().equals("§6Bank Upgrades")) return; + if (stack.getItem() != Item.getItemFromBlock(Blocks.gold_block)) return; + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String result = itemLore.get(4).split(" ")[2].substring(0, 3); + drawAsStackSize(result, xPosition, yPosition); + } + } + if (config.utilitiesWishingCompassUsesLeft) { + if (stack != null && stack.getDisplayName().contains("Wishing Compass")) { + NBTTagCompound tag = stack.getTagCompound(); + if (tag.hasKey("ExtraAttributes")) { + if (tag.getCompoundTag("ExtraAttributes").hasKey("wishing_compass_uses")) { + drawAsStackSize((3 - tag.getCompoundTag("ExtraAttributes").getInteger("wishing_compass_uses")), xPosition, yPosition); + } else { + if (config.utilitiesWishingCompassAlwaysUsesLeft) { + drawAsStackSize(3, xPosition, yPosition); + } + } + } + } + } + if (config.utilitiesShowNYCakeStackSize) { + if (stack != null && stack.getDisplayName().contains("cNew Year Cake (Year") && stack.getDisplayName().contains(")")) { + NBTTagCompound tag = stack.getTagCompound(); + if (tag.hasKey("ExtraAttributes") && tag.getCompoundTag("ExtraAttributes").hasKey("new_years_cake")) { + drawAsStackSize((tag.getCompoundTag("ExtraAttributes").getInteger("new_years_cake")), xPosition, yPosition); + } + } + } + if (config.utilitiesShowSpookyPieStackSize < 3 && config.utilitiesShowSpookyPieStackSize > 0) { + if (stack != null && stack.getDisplayName().contains("Spooky Pie")) { + NBTTagCompound tag = stack.getTagCompound(); + if (tag.hasKey("ExtraAttributes")) { + List itemLore = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + for (String s : itemLore) { + if (s.contains("Obtained during the")) { + if (config.utilitiesShowSpookyPieStackSize == 2) { + drawAsStackSize((Integer.parseInt((tag.getCompoundTag("ExtraAttributes").getString("event").replace("spooky_festival_", ""))) + 1), xPosition, yPosition); + } else if (config.utilitiesShowSpookyPieStackSize == 1) { + drawAsStackSize((tag.getCompoundTag("ExtraAttributes").getInteger("new_years_cake") + 1), xPosition, yPosition); + } + } + } + } } } } - private void drawStringAsStackSize(String text, int xPosition, int yPosition) { + private void drawAsStackSize(String text, int xPosition, int yPosition) { GlStateManager.disableLighting(); GlStateManager.disableDepth(); GlStateManager.disableBlend(); Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(text, (float)(xPosition + 19 - 2 - Minecraft.getMinecraft().fontRendererObj.getStringWidth(text)), (float)(yPosition + 6 + 3), 16777215); GlStateManager.enableLighting(); GlStateManager.enableDepth(); - System.out.println(""); + } + + private void drawAsStackSize(int integer, int xPosition, int yPosition) { + drawAsStackSize(Integer.toString(integer), xPosition, yPosition); } } diff --git a/src/main/java/com/luna/synthesis/mixins/accessors/GuiNewChatAccessor.java b/src/main/java/com/luna/synthesis/mixins/accessors/GuiNewChatAccessor.java index c58cd68..457db4a 100644 --- a/src/main/java/com/luna/synthesis/mixins/accessors/GuiNewChatAccessor.java +++ b/src/main/java/com/luna/synthesis/mixins/accessors/GuiNewChatAccessor.java @@ -2,6 +2,7 @@ import net.minecraft.client.gui.ChatLine; import net.minecraft.client.gui.GuiNewChat; +import net.minecraft.util.IChatComponent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; @@ -14,4 +15,5 @@ public interface GuiNewChatAccessor { @Accessor List getChatLines(); @Accessor List getDrawnChatLines(); @Accessor int getScrollPos(); + @Invoker void invokeSetChatLine(IChatComponent chatComponent, int chatLineId, int updateCounter, boolean displayOnly); } diff --git a/src/main/java/com/luna/synthesis/mixins/accessors/GuiRepairAccessor.java b/src/main/java/com/luna/synthesis/mixins/accessors/GuiRepairAccessor.java new file mode 100644 index 0000000..d746960 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/accessors/GuiRepairAccessor.java @@ -0,0 +1,12 @@ +package com.luna.synthesis.mixins.accessors; + +import net.minecraft.client.gui.GuiRepair; +import net.minecraft.client.gui.GuiTextField; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GuiRepair.class) +public interface GuiRepairAccessor { + + @Accessor GuiTextField getNameField(); +} diff --git a/src/main/java/com/luna/synthesis/mixins/neu/NEUEventListenerMixin.java b/src/main/java/com/luna/synthesis/mixins/neu/NEUEventListenerMixin.java new file mode 100644 index 0000000..6d0a087 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/neu/NEUEventListenerMixin.java @@ -0,0 +1,22 @@ +package com.luna.synthesis.mixins.neu; + +import com.luna.synthesis.utils.MixinUtils; +import org.spongepowered.asm.mixin.Dynamic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Pseudo +@Mixin(targets = "io.github.moulberry.notenoughupdates.NEUEventListener", remap = false) +public class NEUEventListenerMixin { + + @Dynamic + @ModifyArg(method = "onTick", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Keyboard;enableRepeatEvents(Z)V")) + public boolean overrideKeyEvents(boolean in) { + if (MixinUtils.inputField != null && MixinUtils.inputField.isFocused()) { + return true; + } + return in; + } +} diff --git a/src/main/java/com/luna/synthesis/mixins/optifine/CapeUtilsMixin.java b/src/main/java/com/luna/synthesis/mixins/optifine/CapeUtilsMixin.java index f032a75..2ffcae9 100644 --- a/src/main/java/com/luna/synthesis/mixins/optifine/CapeUtilsMixin.java +++ b/src/main/java/com/luna/synthesis/mixins/optifine/CapeUtilsMixin.java @@ -2,7 +2,6 @@ import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; -import com.luna.synthesis.utils.ChatLib; import net.minecraft.client.Minecraft; import org.spongepowered.asm.mixin.Dynamic; import org.spongepowered.asm.mixin.Mixin; @@ -16,22 +15,25 @@ public class CapeUtilsMixin { private static final Config config = Synthesis.getInstance().getConfig(); + // I want to give people the ability to toggle anything in the mod they don't want. + // I don't know what would cause people to toggle them off. + // I wouldn't be mad, just disappointed. @Dynamic @ModifyVariable(method = "downloadCape(Lnet/minecraft/client/entity/AbstractClientPlayer;)V", at = @At("STORE"), name = "username") private static String downloadCape(String in) { - if (!config.utilitiesCapesCustomCape.equals("") && in.equals(Minecraft.getMinecraft().thePlayer.getName())) { - return config.utilitiesCapesCustomCape; + if (!config.utilitiesOptifineCustomCape.equals("") && in.equals(Minecraft.getMinecraft().getSession().getUsername())) { + return config.utilitiesOptifineCustomCape; } - if (config.utilitiesCapesTransYeti && in.equals("Yeti ")) { + if (config.utilitiesOptifineTransYeti && in.equals("Yeti ")) { return "Yeti"; } - if (config.utilitiesCapesTransTerracotta && in.equals("Terracotta ")) { + if (config.utilitiesOptifineTransTerracotta && in.equals("Terracotta ")) { return "Terracotta"; } - if (config.utilitiesCapesNonBinaryBonzo && in.equals("Bonzo ")) { + if (config.utilitiesOptifineNonBinaryBonzo && in.equals("Bonzo ")) { return "Bonzo"; } - if (config.utilitiesCapesCandyCaneGrinch && in.equals("Grinch ")) { + if (config.utilitiesOptifineCandyCaneGrinch && in.equals("Grinch ")) { return "Grinch"; } return in; diff --git a/src/main/java/com/luna/synthesis/mixins/optifine/PlayerItemsLayerMixin.java b/src/main/java/com/luna/synthesis/mixins/optifine/PlayerItemsLayerMixin.java new file mode 100644 index 0000000..b9469b8 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/optifine/PlayerItemsLayerMixin.java @@ -0,0 +1,25 @@ +package com.luna.synthesis.mixins.optifine; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.entity.EntityLivingBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Pseudo +@Mixin(targets = "net.optifine.player.PlayerItemsLayer") +public class PlayerItemsLayerMixin { + + private final Config config = Synthesis.getInstance().getConfig(); + + // 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. + @Inject(method = "renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;FF)V", at = @At("HEAD"), cancellable = true) + public void renderEquippedItems(EntityLivingBase entityLiving, float scale, float partialTicks, CallbackInfo ci) { + if (config.utilitiesOptifineHideHats) { + ci.cancel(); + } + } +} diff --git a/src/main/java/com/luna/synthesis/mixins/patcher/ChatHandlerMixin.java b/src/main/java/com/luna/synthesis/mixins/patcher/ChatHandlerMixin.java index 32c3f9c..d9059b4 100644 --- a/src/main/java/com/luna/synthesis/mixins/patcher/ChatHandlerMixin.java +++ b/src/main/java/com/luna/synthesis/mixins/patcher/ChatHandlerMixin.java @@ -1,6 +1,5 @@ package com.luna.synthesis.mixins.patcher; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import net.minecraft.client.gui.ChatLine; @@ -18,7 +17,7 @@ public class ChatHandlerMixin { private static final Config config = Synthesis.getInstance().getConfig(); - @Comment("ChatLine equals is bad. Calling GuiNewChat::refreshChat() creates a copy of the line, so equals doesn't actually work.") + // GuiNewChat::setChatLine breaks equals since ChatLine's is not overridden + the method creates a new chat line, this fixes that @Dynamic @Redirect(method = "deleteMessageByHash(I)Z", at = @At(value = "INVOKE", target = "Ljava/util/Set;contains(Ljava/lang/Object;)Z"), remap = false) private static boolean contains(Set toRemove, Object obj) { diff --git a/src/main/java/com/luna/synthesis/mixins/patcher/ImagePreviewerMixin.java b/src/main/java/com/luna/synthesis/mixins/patcher/ImagePreviewerMixin.java index 45db960..c0954c4 100644 --- a/src/main/java/com/luna/synthesis/mixins/patcher/ImagePreviewerMixin.java +++ b/src/main/java/com/luna/synthesis/mixins/patcher/ImagePreviewerMixin.java @@ -1,6 +1,5 @@ package com.luna.synthesis.mixins.patcher; -import com.luna.synthesis.Comment; import com.luna.synthesis.Synthesis; import com.luna.synthesis.core.Config; import gg.essential.api.utils.TrustedHostsUtil; @@ -20,7 +19,7 @@ public class ImagePreviewerMixin { private final Config config = Synthesis.getInstance().getConfig(); - @Comment("Most likely not the way to do it since TrustedHostsUtil::addTrustedHost exists BUT don't care") + // Probably not the way to do this since TrustedHostUtil::addTrustedHost exists BUT don't care. @Dynamic @Redirect(method = "handle(Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Lgg/essential/api/utils/TrustedHostsUtil;getTrustedHosts()Ljava/util/Set;")) public Set equalsIgnoreCase(TrustedHostsUtil util) { diff --git a/src/main/java/com/luna/synthesis/mixins/skytils/ChatTabsMixin.java b/src/main/java/com/luna/synthesis/mixins/skytils/ChatTabsMixin.java new file mode 100644 index 0000000..d31ad61 --- /dev/null +++ b/src/main/java/com/luna/synthesis/mixins/skytils/ChatTabsMixin.java @@ -0,0 +1,30 @@ +package com.luna.synthesis.mixins.skytils; + +import com.luna.synthesis.Synthesis; +import com.luna.synthesis.core.Config; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IChatComponent; +import org.spongepowered.asm.mixin.Dynamic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Pseudo +@Mixin(targets = "skytils.skytilsmod.features.impl.handlers.ChatTabs", remap = false) +public class ChatTabsMixin { + + private final Config config = Synthesis.getInstance().getConfig(); + + // Hacky way to add bridge messages to guild, shrug + @Dynamic + @ModifyVariable(method = "shouldAllow", at = @At("HEAD")) + public IChatComponent overrideShouldAllow(IChatComponent in) { + if (config.utilitiesBridgeGuildChatTab) { + if (in.getFormattedText().startsWith(config.utilitiesBridgeMessageFormat.replaceAll("&", "§").split("<")[0])) { + return new ChatComponentText("§r§2Guild > " + in.getFormattedText()); + } + } + return in; + } +} diff --git a/src/main/java/com/luna/synthesis/utils/MixinUtils.java b/src/main/java/com/luna/synthesis/utils/MixinUtils.java index 506c984..323564f 100644 --- a/src/main/java/com/luna/synthesis/utils/MixinUtils.java +++ b/src/main/java/com/luna/synthesis/utils/MixinUtils.java @@ -1,15 +1,12 @@ package com.luna.synthesis.utils; -import com.luna.synthesis.Comment; import com.luna.synthesis.mixins.accessors.ItemModelMesherAccessor; -import lombok.Getter; -import lombok.Setter; import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.renderer.ItemModelMesher; import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.item.Item; -@Comment("This is a walmart solution. There's probably a better way to do what I'm trying to do.") +// This is the absolute wrong way to do this BUT until I figure out something better, shrug public class MixinUtils { public static GuiTextField inputField; diff --git a/src/main/java/com/luna/synthesis/utils/ReflectionUtils.java b/src/main/java/com/luna/synthesis/utils/ReflectionUtils.java new file mode 100644 index 0000000..87e29db --- /dev/null +++ b/src/main/java/com/luna/synthesis/utils/ReflectionUtils.java @@ -0,0 +1,40 @@ +package com.luna.synthesis.utils; + +import net.minecraftforge.fml.common.Loader; + +import java.lang.reflect.Field; + +public class ReflectionUtils { + + private static final String PATCHER_CONFIG_NAME = "club.sk1er.patcher.config.PatcherConfig"; + private static Field patcherChatField = null; + + public static void onInit() { + if (Loader.isModLoaded("patcher")) { + handlePatcherReflection(); + } + } + + private static void handlePatcherReflection() { + try { + Class cls = Class.forName(PATCHER_CONFIG_NAME); + Field f = cls.getField("transparentChatInputField"); + if (f.getType() == boolean.class) { + patcherChatField = f; + } + } catch (ReflectiveOperationException e) { + // Why is there not a logger + System.out.println("Unable to execute Patcher Reflection"); + } + } + + public static boolean getPatcherChatField(){ + if (patcherChatField == null) return false; + try { + return patcherChatField.getBoolean(null); + } catch (ReflectiveOperationException ignored) {} + return false; + } + + +} diff --git a/src/main/java/com/luna/synthesis/utils/Utils.java b/src/main/java/com/luna/synthesis/utils/Utils.java index 5978a37..7fe894b 100644 --- a/src/main/java/com/luna/synthesis/utils/Utils.java +++ b/src/main/java/com/luna/synthesis/utils/Utils.java @@ -1,33 +1,179 @@ package com.luna.synthesis.utils; -import com.luna.synthesis.Comment; -import com.luna.synthesis.mixins.GuiContainerMixin; -import com.luna.synthesis.mixins.accessors.GuiNewChatAccessor; -import com.luna.synthesis.mixins.accessors.ItemModelMesherAccessor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.ChatLine; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiTextField; -import net.minecraft.client.renderer.ItemModelMesher; -import net.minecraft.client.resources.model.IBakedModel; -import net.minecraft.item.Item; - -import java.util.List; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.event.ClickEvent; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IChatComponent; +import net.minecraft.util.MathHelper; + +import org.lwjgl.opengl.GL11; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.lwjgl.opengl.GL11.*; public class Utils { - @Comment("Copied and adapted from Patcher") + 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); + + // Copied and adapted from Patcher public static boolean isDivider(String message) { + if (message == null) return false; if (message.length() < 5) { return false; } else { - for (int i = 0; i < message.length(); i++) { - char c = message.charAt(i); - if (c != '-' && c != '=' && c != '\u25AC') { - return false; + // Dear god, forgive me, for I am tired. + if (message.equals("-------------- Guild: Message Of The Day --------------") || message.equals("---------- Guild: Message Of The Day (Preview) ----------")) { + return true; + } else { + for (int i = 0; i < message.length(); i++) { + char c = message.charAt(i); + if (c != '-' && c != '=' && c != '\u25AC') { + return false; + } } } } return true; } + + // Adapted from ForgeHooks::newChatWithLinks, may change linkPattern in the future + public static IChatComponent newChatWithLinks(String string) { + IChatComponent ichat = null; + Matcher matcher = linkPattern.matcher(string); + int lastEnd = 0; + + while (matcher.find()) { + int start = matcher.start(); + int end = matcher.end(); + + String part = string.substring(lastEnd, start); + if (part.length() > 0) { + if (ichat == null) { + ichat = new ChatComponentText(part); + } else { + ichat.appendText(part); + } + } + lastEnd = end; + String url = string.substring(start, end); + IChatComponent link = new ChatComponentText(url); + + try { + if ((new URI(url)).getScheme() == null) { + url = "http://" + url; + } + } catch (URISyntaxException e) { + if (ichat == null) ichat = new ChatComponentText(url); + else ichat.appendText(url); + continue; + } + + ClickEvent click = new ClickEvent(ClickEvent.Action.OPEN_URL, url); + link.getChatStyle().setChatClickEvent(click); + if (ichat == null) { + ichat = link; + } else { + ichat.appendSibling(link); + } + } + + String end = string.substring(lastEnd); + if (ichat == null) { + ichat = new ChatComponentText(end); + } else if (end.length() > 0) { + ichat.appendText(string.substring(lastEnd)); + } + return ichat; + } + + public static void renderBeamSegment(double x, double y, double z, double partialTicks, double textureScale, double totalWorldTime, int yOffset, int height, float[] colors) { + double beamRadius = 0.2D; + double glowRadius = 0.25D; + int i = yOffset + height; + GL11.glTexParameteri(3553, 10242, 10497); + GL11.glTexParameteri(3553, 10243, 10497); + GlStateManager.disableLighting(); + GlStateManager.disableCull(); + GlStateManager.disableBlend(); + GlStateManager.depthMask(true); + GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ZERO); + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldRenderer = tessellator.getWorldRenderer(); + double d0 = totalWorldTime + partialTicks; + double d1 = height < 0 ? d0 : -d0; + double d2 = MathHelper.func_181162_h(d1 * 0.2D - (double)MathHelper.floor_double(d1 * 0.1D)); + float f = colors[0]; + float f1 = colors[1]; + float f2 = colors[2]; + double d3 = d0 * 0.025D * -1.5D; + double d4 = 0.5D + Math.cos(d3 + 2.356194490192345D) * beamRadius; + double d5 = 0.5D + Math.sin(d3 + 2.356194490192345D) * beamRadius; + double d6 = 0.5D + Math.cos(d3 + (Math.PI / 4D)) * beamRadius; + double d7 = 0.5D + Math.sin(d3 + (Math.PI / 4D)) * beamRadius; + double d8 = 0.5D + Math.cos(d3 + 3.9269908169872414D) * beamRadius; + double d9 = 0.5D + Math.sin(d3 + 3.9269908169872414D) * beamRadius; + double d10 = 0.5D + Math.cos(d3 + 5.497787143782138D) * beamRadius; + double d11 = 0.5D + Math.sin(d3 + 5.497787143782138D) * beamRadius; + double d14 = -1.0D + d2; + double d15 = (double)height * textureScale * (0.5D / beamRadius) + d14; + worldRenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldRenderer.pos(x + d4, y + (double)i, z + d5).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d4, y + (double)yOffset, z + d5).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d6, y + (double)yOffset, z + d7).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d6, y + (double)i, z + d7).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d10, y + (double)i, z + d11).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d10, y + (double)yOffset, z + d11).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d8, y + (double)yOffset, z + d9).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d8, y + (double)i, z + d9).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d6, y + (double)i, z + d7).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d6, y + (double)yOffset, z + d7).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d10, y + (double)yOffset, z + d11).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d10, y + (double)i, z + d11).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d8, y + (double)i, z + d9).tex(1.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d8, y + (double)yOffset, z + d9).tex(1.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d4, y + (double)yOffset, z + d5).tex(0.0D, d14).color(f, f1, f2, 1.0F).endVertex(); + worldRenderer.pos(x + d4, y + (double)i, z + d5).tex(0.0D, d15).color(f, f1, f2, 1.0F).endVertex(); + tessellator.draw(); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + GlStateManager.depthMask(false); + d3 = 0.5D - glowRadius; + d4 = 0.5D - glowRadius; + d5 = 0.5D + glowRadius; + d6 = 0.5D - glowRadius; + d7 = 0.5D - glowRadius; + d8 = 0.5D + glowRadius; + d9 = 0.5D + glowRadius; + d10 = 0.5D + glowRadius; + double d13 = -1.0D + d2; + d14 = (double)height * textureScale + d13; + worldRenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + worldRenderer.pos(x + d3, y + (double)i, z + d4).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d3, y + (double)yOffset, z + d4).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d5, y + (double)yOffset, z + d6).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d5, y + (double)i, z + d6).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d9, y + (double)i, z + d10).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d9, y + (double)yOffset, z + d10).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d7, y + (double)yOffset, z + d8).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d7, y + (double)i, z + d8).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d5, y + (double)i, z + d6).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d5, y + (double)yOffset, z + d6).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d9, y + (double)yOffset, z + d10).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d9, y + (double)i, z + d10).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d7, y + (double)i, z + d8).tex(1.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d7, y + (double)yOffset, z + d8).tex(1.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d3, y + (double)yOffset, z + d4).tex(0.0D, d13).color(f, f1, f2, 0.125F).endVertex(); + worldRenderer.pos(x + d3, y + (double)i, z + d4).tex(0.0D, d14).color(f, f1, f2, 0.125F).endVertex(); + tessellator.draw(); + GlStateManager.enableLighting(); + GlStateManager.enableTexture2D(); + GlStateManager.depthMask(true); + } } diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index de19737..41f6dd3 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -3,12 +3,12 @@ "modid": "synthesis", "name": "Synthesis", "description": "Hypixel SkyBlock/general QoL mod.", - "version": "Alpha-v3", + "version": "${version}", "mcversion": "1.8.9", "url": "", "updateUrl": "", "authorList": ["Luna, Desco"], - "credits": "Heart DC or The CouncilTM or E for a lot of this mod's suggestions.", + "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.", "logoFile": "", "screenshots": [], "dependencies": [] diff --git a/src/main/resources/synthesis.mixins.json b/src/main/resources/synthesis.mixins.json index c2ae550..22a9d89 100644 --- a/src/main/resources/synthesis.mixins.json +++ b/src/main/resources/synthesis.mixins.json @@ -6,15 +6,23 @@ "accessors.GuiChatAccessor", "accessors.GuiContainerAccessor", "accessors.GuiNewChatAccessor", + "accessors.GuiRepairAccessor", "accessors.ItemModelMesherAccessor", "accessors.S2FPacketSetSlotAccessor", + "neu.NEUEventListenerMixin", "optifine.CapeUtilsMixin", + "optifine.PlayerItemsLayerMixin", "patcher.ChatHandlerMixin", "patcher.ImagePreviewerMixin", + "skytils.ChatTabsMixin", "BlockStainedGlassPaneMixin", + "ContainerMixin", "EntityPlayerMixin", + "EntityPlayerSPMixin", "GuiContainerMixin", "GuiNewChatMixin", + "GuiPlayerTabOverlayMixin", + "GuiScreenMixin", "RenderItemMixin" ], "client": [],