diff --git a/.github/actions/setup-normal-workspace/action.yml b/.github/actions/setup-normal-workspace/action.yml new file mode 100644 index 000000000000..a0781d53c46c --- /dev/null +++ b/.github/actions/setup-normal-workspace/action.yml @@ -0,0 +1,13 @@ +name: 'Setup Java, Gradle and check out the source code' + +runs: + using: composite + steps: + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 21 + cache: gradle + - name: Setup gradle + uses: gradle/actions/setup-gradle@v4 diff --git a/.github/scripts/process_detekt_sarif.sh b/.github/scripts/process_detekt_sarif.sh new file mode 100644 index 000000000000..7fb4f7e4e11f --- /dev/null +++ b/.github/scripts/process_detekt_sarif.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# This script processes the Detekt SARIF file and outputs results in a format +# suitable for annotation in CI/CD systems. + +SARIF_FILE="$1" + +# Check if SARIF file exists +if [ ! -f "$SARIF_FILE" ]; then + echo "SARIF file not found: $SARIF_FILE" + exit 1 +fi + +# Define jq command to parse SARIF file +read -r -d '' jq_command <<'EOF' +.runs[].results[] | +{ + "full_path": .locations[].physicalLocation.artifactLocation.uri | sub("file://$(pwd)/"; ""), + "file_name": (.locations[].physicalLocation.artifactLocation.uri | split("/") | last), + "l": .locations[].physicalLocation, + "level": .level, + "message": .message.text, + "ruleId": .ruleId +} | +( + "::" + (.level) + + " file=" + (.full_path) + + ",line=" + (.l.region.startLine|tostring) + + ",title=" + (.ruleId) + + ",col=" + (.l.region.startColumn|tostring) + + ",endColumn=" + (.l.region.endColumn|tostring) + + "::" + (.message.text) +) +EOF + +# Run jq command to format the output +jq -r "$jq_command" < "$SARIF_FILE" diff --git a/.github/workflows/assign-relevant-labels.yml b/.github/workflows/assign-relevant-labels.yml new file mode 100644 index 000000000000..4118c7172093 --- /dev/null +++ b/.github/workflows/assign-relevant-labels.yml @@ -0,0 +1,64 @@ +name: "Assign relevant labels" +on: + pull_request_target: + types: [ opened, edited ] +jobs: + assign-label: + if: github.event.pull_request.state == 'open' + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + contents: read + steps: + - name: label + env: + TITLE: ${{ github.event.pull_request.title }} + LABEL_FIX: Bug Fix + LABEL_BACKEND: Backend + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN}} + script: | + const labelsToAdd = []; + const labelsToRemove = []; + const title = process.env.TITLE.split(":")[0].toUpperCase(); + + if(title.includes("FIX")){ + labelsToAdd.push(process.env.LABEL_FIX); + } else { + labelsToRemove.push(process.env.LABEL_FIX); + } + + if(title.includes("BACKEND")){ + labelsToAdd.push(process.env.LABEL_BACKEND); + } else { + labelsToRemove.push(process.env.LABEL_BACKEND); + } + + for (const label of labelsToAdd) { + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [label] + }); + } + + const {data} = await github.rest.issues.listLabelsOnIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + for (const label of labelsToRemove) { + const filtered = data.filter(l => l.name == label); + if(filtered.length == 1){ + github.rest.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: label + }); + } + } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c75f0eef805..143c59466cd1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,15 +18,9 @@ jobs: runs-on: ubuntu-latest name: "Build and test" steps: - - uses: actions/checkout@v3 - - name: Set up JDK 21 - uses: actions/setup-java@v3 - with: - java-version: 21 - distribution: temurin - cache: gradle - - name: Setup gradle - uses: gradle/gradle-build-action@v2 + - name: Checkout code + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-normal-workspace - name: Build with Gradle run: ./gradlew assemble -x test --stacktrace - uses: actions/upload-artifact@v3 @@ -42,19 +36,32 @@ jobs: with: name: "Test Results" path: versions/1.8.9/build/reports/tests/test/ + #detekt: + # name: Run detekt + # runs-on: ubuntu-latest + + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - uses: ./.github/actions/setup-normal-workspace + # # detektMain is a LOT slower than detekt, but it does type analysis + # - name: Run detekt main (w/typing analysis) + # run: | + # ./gradlew detektMain --stacktrace + # - name: Annotate detekt failures + # if: ${{ !cancelled() }} + # run: | + # chmod +x .github/scripts/process_detekt_sarif.sh + # ./.github/scripts/process_detekt_sarif.sh versions/1.8.9/build/reports/detekt/main.sarif + + preprocess: runs-on: ubuntu-latest name: "Build multi version" steps: - - uses: actions/checkout@v3 - - name: Set up JDK 21 - uses: actions/setup-java@v3 - with: - java-version: 21 - distribution: temurin - cache: gradle - - name: Setup gradle - uses: gradle/gradle-build-action@v2 + - name: Checkout code + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-normal-workspace - name: Enable preprocessor run: | mkdir -p .gradle diff --git a/.github/workflows/check-style.yaml.disabled b/.github/workflows/check-style.yaml.disabled deleted file mode 100644 index ff172208f8bc..000000000000 --- a/.github/workflows/check-style.yaml.disabled +++ /dev/null @@ -1,16 +0,0 @@ -name: check-style -on: - - pull_request -jobs: - ktlint: - name: Check Style - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - name: Checkout code - - name: ktlint - uses: ScaCap/action-ktlint@master - with: - github_token: ${{ secrets.github_token }} - reporter: github-pr-check diff --git a/.github/workflows/illegal-imports.txt b/.github/workflows/illegal-imports.txt index f53a5da78e25..83354f622960 100644 --- a/.github/workflows/illegal-imports.txt +++ b/.github/workflows/illegal-imports.txt @@ -5,7 +5,8 @@ at/hannibal2/skyhanni/ scala. at/hannibal2/skyhanni/ jline. -at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.util.Constants at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.events.SlotClickEvent at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.events.ReplaceItemEvent +at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.util.Constants +at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.util.Utils at/hannibal2/skyhanni/ java.util.function.Supplier diff --git a/.github/workflows/label-bug-fix.yml b/.github/workflows/label-bug-fix.yml deleted file mode 100644 index dae2980de630..000000000000 --- a/.github/workflows/label-bug-fix.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: "Bug Fix label" -on: - pull_request_target: - types: [ opened, edited ] -jobs: - assign-label: - if: github.event.pull_request.state == 'open' # Condition to check if PR is open - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - contents: read - steps: - - name: label - env: - TITLE: ${{ github.event.pull_request.title }} - LABEL: Bug Fix - Sooner than Very Soon - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN}} - script: | - if(process.env.TITLE.split(":")[0].toUpperCase().includes("FIX")){ - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: [process.env.LABEL] - }) - }else{ - const {data} = await github.rest.issues.listLabelsOnIssue({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - }) - const filtered = data.filter(label => label.name == process.env.LABEL) - if(filtered.length == 1){ - github.rest.issues.removeLabel({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - name: process.env.LABEL - }) - } - } diff --git a/.gitignore b/.gitignore index d77f4bd8b6f0..7f4081e02e52 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ !.idea/icon.svg !.idea/dictionaries/default_user.xml !.idea/scopes/Mixins.xml +!.idea/liveTemplates/SkyHanni.xml .vscode/ run/ build/ diff --git a/.idea/dictionaries/default_user.xml b/.idea/dictionaries/default_user.xml index cb91301718f0..4c56b1303ca0 100644 --- a/.idea/dictionaries/default_user.xml +++ b/.idea/dictionaries/default_user.xml @@ -193,6 +193,8 @@ pling pocalypse polarvoid + powerup + powerups preinitialization procs prospection @@ -251,9 +253,11 @@ supercraft supercrafting superlite + superpair superpairs tablist terracottas + tessellator thaumaturgist thaumaturgy townsquare diff --git a/.idea/liveTemplates/SkyHanni.xml b/.idea/liveTemplates/SkyHanni.xml new file mode 100644 index 000000000000..08c6737b5ce2 --- /dev/null +++ b/.idea/liveTemplates/SkyHanni.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc0f2d5c4f90..fe6410c9d11e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,6 +13,7 @@ We use [IntelliJ](https://www.jetbrains.com/idea/) as an example. - Download IntelliJ from the [JetBrains Website](https://www.jetbrains.com/idea/download/). - Use the Community Edition. (Scroll down a bit.) +- When you encounter any bug with IntelliJ, please make sure to use the version `2024.1.6`, not `2024.2.x` or above. ### Cloning the project @@ -30,6 +31,7 @@ We use [IntelliJ](https://www.jetbrains.com/idea/) as an example. ### Setting up IntelliJ + Once your project is imported into IntelliJ from the previous step, all dependencies like Minecraft, NEU, and so on should be automatically downloaded. If not, you might need to link the Gradle project in the Gradle tab (little elephant) on the right. @@ -97,6 +99,13 @@ format like "- #821" to illustrate the dependency. - Follow the [Hypixel Rules](https://hypixel.net/rules). - Use the coding conventions for [Kotlin](https://kotlinlang.org/docs/coding-conventions.html) and [Java](https://www.oracle.com/java/technologies/javase/codeconventions-contents.html). +- **My build is failing due to `detekt`, what do I do?** + - `detekt` is our code quality tool. It checks for code smells and style issues. + - If you have a build failure stating `Analysis failed with ... weighted issues.`, you can check `versions/[target version]/build/reports/detekt/` for a comprehensive list of issues. + - **There are valid reasons to deviate from the norm** + - If you have such a case, either use `@Supress("rule_name")`, or re-build the `baseline.xml` file, using `./gradlew detektBaselineMain`. + After running detektBaselineMain, you should find a file called `baseline-main.xml` in the `version/1.8.9` folder, rename the file to + `baseline.xml` replacing the old one. You also should copy the new contents of this file to the [main baseline file](detekt/baseline.xml) - Do not copy features from other mods. Exceptions: - Mods that are paid to use. - Mods that have reached their end of life. (Rip SBA, Dulkir and Soopy). diff --git a/README.md b/README.md index 07bf336a172c..3c7721cfb176 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ SkyHanni is a Forge mod for Minecraft 1.8.9 that adds many useful features to [H * **Helpful GUIs:** View important information at a glance. * **Extra Chat Messages:** Receive reminders and tips at the right moment. * **Object Highlighters:** Focus on important items in inventories or highlight mobs in the world. -* **Highly Customizeable Displays:** Personalise your Scoreboard, Tab List or chat format. +* **Highly Customizable Displays:** Personalise your Scoreboard, Tab List or chat format. * [And **much** more!](docs/FEATURES.md) SkyHanni is especially useful when doing farming, slayers, Bingo, Diana, fishing, Rift or mining. @@ -35,7 +35,7 @@ SkyHanni is especially useful when doing farming, slayers, Bingo, Diana, fishing Give feedback or just chat with others on our community Discord! * **Bug Reports:** Use the `#bug-reports` channel when you find broken features (please check out `#faq` and `#known-bugs`). -* **Quick Help** Ask in `#support` for questions and problems with the the mod or Minecraft in general. +* **Quick Help** Ask in `#support` for questions and problems with the mod or Minecraft in general. * **Feature Suggestions:** Feel fre to tell your ideas in `#suggestions` channel for new features and improvements to the mod. (Don't copy from existing mods or break Hypixel rules). * **General Chat:** Chat with other SkyHanni users in `#skyblock-general` channel about the game. diff --git a/build.gradle.kts b/build.gradle.kts index e8464ada27e8..190385c1e4ee 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,8 @@ import at.skyhanni.sharedvariables.versionString import net.fabricmc.loom.task.RunGameTask import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import io.gitlab.arturbosch.detekt.Detekt +import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask plugins { idea @@ -18,31 +20,12 @@ plugins { kotlin("plugin.power-assert") `maven-publish` id("moe.nea.shot") version "1.0.0" + id("io.gitlab.arturbosch.detekt") + id("net.kyori.blossom") } val target = ProjectTarget.values().find { it.projectPath == project.path }!! -repositories { - mavenCentral() - mavenLocal() - maven("https://maven.minecraftforge.net") { - metadataSources { - artifact() // We love missing POMs - } - } - maven("https://repo.spongepowered.org/maven/") // mixin - maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") // DevAuth - maven("https://jitpack.io") { // NotEnoughUpdates (compiled against) - content { - includeGroupByRegex("(com|io)\\.github\\..*") - } - } - maven("https://repo.nea.moe/releases") // libautoupdate - maven("https://maven.notenoughupdates.org/releases") // NotEnoughUpdates (dev env) - maven("https://repo.hypixel.net/repository/Hypixel/") // mod-api - maven("https://maven.teamresourceful.com/repository/thatgravyboat/") // DiscordIPC -} - // Toolchains: java { toolchain.languageVersion.set(target.minecraftVersion.javaLanguageVersion) @@ -56,11 +39,15 @@ val runDirectory = rootProject.file("run") runDirectory.mkdirs() // Minecraft configuration: loom { - if (this.isForgeLike) + if (this.isForgeLike) { forge { - pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter()) + pack200Provider.set( + dev.architectury.pack200.java + .Pack200Adapter(), + ) mixinConfig("mixins.skyhanni.json") } + } mixin { useLegacyMixinAp.set(true) defaultRefmapName.set("mixins.skyhanni.refmap.json") @@ -84,11 +71,12 @@ loom { } } -if (target == ProjectTarget.MAIN) +if (target == ProjectTarget.MAIN) { sourceSets.main { resources.destinationDirectory.set(kotlin.destinationDirectory) output.setResourcesDir(kotlin.destinationDirectory) } +} val shadowImpl: Configuration by configurations.creating { configurations.implementation.get().extendsFrom(this) @@ -108,9 +96,11 @@ val headlessLwjgl by configurations.creating { isVisible = false } tasks.runClient { - this.javaLauncher.set(javaToolchains.launcherFor { - languageVersion.set(target.minecraftVersion.javaLanguageVersion) - }) + this.javaLauncher.set( + javaToolchains.launcherFor { + languageVersion.set(target.minecraftVersion.javaLanguageVersion) + }, + ) } val shot = shots.shot("minecraft", rootProject.file("shots.txt")) @@ -121,8 +111,9 @@ dependencies { } else { mappings(target.mappingDependency) } - if (target.forgeDep != null) + if (target.forgeDep != null) { "forge"(target.forgeDep!!) + } // Discord RPC client shadowImpl("com.jagrosh:DiscordIPC:0.5.3") { @@ -159,9 +150,9 @@ dependencies { exclude(module = "unspecified") isTransitive = false } - // June 3, 2024, 9:30 PM AEST - // https://github.com/NotEnoughUpdates/NotEnoughUpdates/tree/2.3.0 - devenvMod("com.github.NotEnoughUpdates:NotEnoughUpdates:2.3.0:all") { + // October 3, 2024, 11:43 PM AEST + // https://github.com/NotEnoughUpdates/NotEnoughUpdates/tree/2.4.0 + devenvMod("com.github.NotEnoughUpdates:NotEnoughUpdates:2.4.0:all") { exclude(module = "unspecified") isTransitive = false } @@ -177,10 +168,17 @@ dependencies { exclude(module = "unspecified") isTransitive = false } - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.11.0") testImplementation("io.mockk:mockk:1.12.5") implementation("net.hypixel:mod-api:0.3.1") + + // getting clock offset + shadowImpl("commons-net:commons-net:3.8.0") + + detektPlugins("org.notenoughupdates:detektrules:1.0.0") + detektPlugins(project(":detekt")) + detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7") } afterEvaluate { @@ -231,10 +229,11 @@ if (target == ProjectTarget.MAIN) { } } -if (target == ProjectTarget.MAIN) +if (target == ProjectTarget.MAIN) { tasks.compileJava { dependsOn(tasks.processResources) } +} if (target.parent == ProjectTarget.MAIN) { val mainRes = project(ProjectTarget.MAIN.projectPath).tasks.getAt("processResources") @@ -285,6 +284,7 @@ tasks.shadowJar { relocate("io.github.notenoughupdates.moulconfig", "at.hannibal2.skyhanni.deps.moulconfig") relocate("moe.nea.libautoupdate", "at.hannibal2.skyhanni.deps.libautoupdate") relocate("com.jagrosh.discordipc", "at.hannibal2.skyhanni.deps.discordipc") + relocate("org.apache.commons.net", "at.hannibal2.skyhanni.deps.commons.net") } tasks.jar { archiveClassifier.set("nodeps") @@ -312,12 +312,18 @@ if (!MultiVersionStage.activeState.shouldCompile(target)) { onlyIf { false } } } + preprocess { vars.put("MC", target.minecraftVersion.versionNumber) vars.put("FORGE", if (target.forgeDep != null) 1 else 0) vars.put("JAVA", target.minecraftVersion.javaVersion) patternAnnotation.set("at.hannibal2.skyhanni.utils.compat.Pattern") } + +blossom { + replaceToken("@MOD_VERSION@", version) +} + val sourcesJar by tasks.creating(Jar::class) { destinationDirectory.set(layout.buildDirectory.dir("badjars")) archiveClassifier.set("src") @@ -343,3 +349,32 @@ publishing.publications { } } } + +detekt { + buildUponDefaultConfig = true // preconfigure defaults + config.setFrom(rootProject.layout.projectDirectory.file("detekt/detekt.yml")) // point to your custom config defining rules to run, overwriting default behavior + baseline = file(layout.projectDirectory.file("detekt/baseline.xml")) // a way of suppressing issues before introducing detekt + source.setFrom(project.sourceSets.named("main").map { it.allSource }) +} + +tasks.withType().configureEach { + onlyIf { + false // TODO: Remove onlyIf when we're ready to enforce + } + + reports { + html.required.set(true) // observe findings in your browser with structure and code snippets + xml.required.set(true) // checkstyle like format mainly for integrations like Jenkins + sarif.required.set(true) // standardized SARIF format (https://sarifweb.azurewebsites.net/) to support integrations with GitHub Code Scanning + md.required.set(true) // simple Markdown format + } +} + +tasks.withType().configureEach { + jvmTarget = target.minecraftVersion.formattedJavaLanguageVersion + outputs.cacheIf { false } // Custom rules won't work if cached +} +tasks.withType().configureEach { + jvmTarget = target.minecraftVersion.formattedJavaLanguageVersion + outputs.cacheIf { false } // Custom rules won't work if cached +} diff --git a/detekt/baseline.xml b/detekt/baseline.xml new file mode 100644 index 000000000000..ac35c2f6d1a8 --- /dev/null +++ b/detekt/baseline.xml @@ -0,0 +1,339 @@ + + + + + AnnotationOnSeparateLine:GraphEditor.kt$GraphEditor$@Suppress("MapGetWithNotNullAssertionOperator") node.neighbours.map { GraphingEdge( translation[node]!!, translation[it.key]!!, ) } + AnnotationOnSeparateLine:GraphEditor.kt$GraphEditor$@Suppress("MapGetWithNotNullAssertionOperator") nodes[indexedTable[otherNode.id]!!] + ArrayPrimitive:CropMoneyDisplay.kt$CropMoneyDisplay$Array<Double> + ArrayPrimitive:CropMoneyDisplay.kt$CropMoneyDisplay$arrayOf(npcPrice) + ArrayPrimitive:CropMoneyDisplay.kt$CropMoneyDisplay$arrayOf(sellOffer) + ArrayPrimitive:LorenzVec.kt$Array<Double> + ArrayPrimitive:LorenzVec.kt$LorenzVec$Array<Double> + ArrayPrimitive:LorenzVec.kt$LorenzVec$Array<Float> + ArrayPrimitive:LorenzVec.kt$LorenzVec$arrayOf(x, y, z) + ArrayPrimitive:LorenzVec.kt$LorenzVec$arrayOf(x.toFloat(), y.toFloat(), z.toFloat()) + CyclomaticComplexMethod:AdvancedPlayerList.kt$AdvancedPlayerList$fun newSorting(original: List<String>): List<String> + CyclomaticComplexMethod:CropMoneyDisplay.kt$CropMoneyDisplay$private fun calculateMoneyPerHour(debugList: MutableList<List<Any>>): Map<NEUInternalName, Array<Double>> + CyclomaticComplexMethod:CropMoneyDisplay.kt$CropMoneyDisplay$private fun drawDisplay(): List<List<Any>> + CyclomaticComplexMethod:DamageIndicatorManager.kt$DamageIndicatorManager$private fun checkThorn(realHealth: Long, realMaxHealth: Long): String? + CyclomaticComplexMethod:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator$private fun addEnchantments(stack: ItemStack, list: MutableList<String>): Double + CyclomaticComplexMethod:GardenBestCropTime.kt$GardenBestCropTime$fun drawBestDisplay(currentCrop: CropType?): List<List<Any>> + CyclomaticComplexMethod:GardenCropMilestoneDisplay.kt$GardenCropMilestoneDisplay$private fun drawProgressDisplay(crop: CropType): List<Renderable> + CyclomaticComplexMethod:GardenVisitorFeatures.kt$GardenVisitorFeatures$private fun readToolTip(visitor: VisitorAPI.Visitor, itemStack: ItemStack?, toolTip: MutableList<String>) + CyclomaticComplexMethod:GhostCounter.kt$GhostCounter$private fun drawDisplay() + CyclomaticComplexMethod:GraphEditor.kt$GraphEditor$private fun input() + CyclomaticComplexMethod:GraphEditorBugFinder.kt$GraphEditorBugFinder$private fun asyncTest() + CyclomaticComplexMethod:IslandAreas.kt$IslandAreas$private fun buildDisplay() + CyclomaticComplexMethod:ItemDisplayOverlayFeatures.kt$ItemDisplayOverlayFeatures$private fun getStackTip(item: ItemStack): String? + CyclomaticComplexMethod:ItemNameResolver.kt$ItemNameResolver$internal fun getInternalNameOrNull(itemName: String): NEUInternalName? + CyclomaticComplexMethod:MinecraftConsoleFilter.kt$MinecraftConsoleFilter$override fun filter(event: LogEvent?): Filter.Result + CyclomaticComplexMethod:OverviewPage.kt$OverviewPage$private fun getPage(): Pair<List<List<Renderable>>, List<Renderable>> + CyclomaticComplexMethod:PacketTest.kt$PacketTest$private fun Packet<*>.print() + CyclomaticComplexMethod:ParkourHelper.kt$ParkourHelper$fun render(event: LorenzRenderWorldEvent) + CyclomaticComplexMethod:Renderable.kt$Renderable.Companion$internal fun shouldAllowLink(debug: Boolean = false, bypassChecks: Boolean): Boolean + CyclomaticComplexMethod:SkillProgress.kt$SkillProgress$private fun drawDisplay() + CyclomaticComplexMethod:VampireSlayerFeatures.kt$VampireSlayerFeatures$private fun EntityOtherPlayerMP.process() + CyclomaticComplexMethod:VisualWordGui.kt$VisualWordGui$override fun drawScreen(unusedX: Int, unusedY: Int, partialTicks: Float) + DestructuringDeclarationWithTooManyEntries:SackDisplay.kt$SackDisplay$val (internalName, rough, flawed, fine, roughPrice, flawedPrice, finePrice) = gem + Filename:AreaChangeEvents.kt$at.hannibal2.skyhanni.events.skyblock.AreaChangeEvents.kt + InjectDispatcher:ClipboardUtils.kt$ClipboardUtils$IO + InjectDispatcher:GardenNextJacobContest.kt$GardenNextJacobContest$IO + InjectDispatcher:HypixelBazaarFetcher.kt$HypixelBazaarFetcher$IO + InjectDispatcher:MayorAPI.kt$MayorAPI$IO + LongMethod:CopyNearbyEntitiesCommand.kt$CopyNearbyEntitiesCommand$fun command(args: Array<String>) + LongMethod:CropMoneyDisplay.kt$CropMoneyDisplay$private fun drawDisplay(): List<List<Any>> + LongMethod:DefaultConfigOptionGui.kt$DefaultConfigOptionGui$override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) + LongMethod:GhostCounter.kt$GhostCounter$private fun drawDisplay() + LongMethod:GraphEditor.kt$GraphEditor$private fun input() + LongMethod:ItemDisplayOverlayFeatures.kt$ItemDisplayOverlayFeatures$private fun getStackTip(item: ItemStack): String? + LongMethod:MinecraftConsoleFilter.kt$MinecraftConsoleFilter$override fun filter(event: LogEvent?): Filter.Result + LongMethod:OverviewPage.kt$OverviewPage$private fun getPage(): Pair<List<List<Renderable>>, List<Renderable>> + LongMethod:RenderableTooltips.kt$RenderableTooltips$private fun drawHoveringText() + LongMethod:TabListRenderer.kt$TabListRenderer$private fun drawTabList() + LongMethod:VisualWordGui.kt$VisualWordGui$override fun drawScreen(unusedX: Int, unusedY: Int, partialTicks: Float) + LoopWithTooManyJumpStatements:AdvancedPlayerList.kt$AdvancedPlayerList$for + LoopWithTooManyJumpStatements:CropMoneyDisplay.kt$CropMoneyDisplay$for + LoopWithTooManyJumpStatements:CustomScoreboard.kt$CustomScoreboard$for + LoopWithTooManyJumpStatements:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator$for + LoopWithTooManyJumpStatements:GardenComposterInventoryFeatures.kt$GardenComposterInventoryFeatures$for + LoopWithTooManyJumpStatements:GardenVisitorFeatures.kt$GardenVisitorFeatures$for + LoopWithTooManyJumpStatements:IslandAreas.kt$IslandAreas$for + LoopWithTooManyJumpStatements:RiftBloodEffigies.kt$RiftBloodEffigies$for + LoopWithTooManyJumpStatements:SkyBlockItemModifierUtils.kt$SkyBlockItemModifierUtils$for + LoopWithTooManyJumpStatements:SkyHanniConfigSearchResetCommand.kt$SkyHanniConfigSearchResetCommand$for + LoopWithTooManyJumpStatements:SuperpairsClicksAlert.kt$SuperpairsClicksAlert$for + MapGetWithNotNullAssertionOperator:NavigationHelper.kt$NavigationHelper$distances[node]!! + MatchingDeclarationName:AreaChangeEvents.kt$ScoreboardAreaChangeEvent : SkyHanniEvent + MaxLineLength:GraphEditor.kt$GraphEditor$@Suppress("MapGetWithNotNullAssertionOperator") nodes[indexedTable[otherNode.id]!!] to node.position.distance(otherNode.position) + MemberNameEqualsClassName:CaptureFarmingGear.kt$CaptureFarmingGear$fun captureFarmingGear() + MemberNameEqualsClassName:Commands.kt$Commands$// command -> description private val commands = mutableListOf<CommandInfo>() + MemberNameEqualsClassName:FameRanks.kt$FameRanks$var fameRanks = emptyMap<String, FameRank>() private set + MemberNameEqualsClassName:FirstMinionTier.kt$FirstMinionTier$fun firstMinionTier( otherItems: Map<NEUInternalName, Int>, minions: MutableMap<String, NEUInternalName>, tierOneMinions: MutableList<NEUInternalName>, tierOneMinionsDone: MutableSet<NEUInternalName>, ) + MemberNameEqualsClassName:LastServers.kt$LastServers$private val lastServers = mutableMapOf<String, SimpleTimeMark>() + MemberNameEqualsClassName:PestSpawn.kt$PestSpawn$private fun pestSpawn(amount: Int, plotNames: List<String>, unknownAmount: Boolean) + MemberNameEqualsClassName:Shimmy.kt$Shimmy.Companion$private fun shimmy(source: Any?, fieldName: String): Any? + MemberNameEqualsClassName:TestBingo.kt$TestBingo$var testBingo = false + MemberNameEqualsClassName:Text.kt$Text$fun text(text: String, init: IChatComponent.() -> Unit = {}) + NoNameShadowing:BucketedItemTrackerData.kt$BucketedItemTrackerData${ it.hidden = !it.hidden } + NoNameShadowing:BurrowWarpHelper.kt$BurrowWarpHelper${ it.startsWith("§bWarp to ") } + NoNameShadowing:ChunkedStat.kt$ChunkedStat.Companion${ it.showWhen() } + NoNameShadowing:ContributorManager.kt$ContributorManager${ it.isAllowed() } + NoNameShadowing:Graph.kt$Graph.Companion${ out.name("Name").value(it) } + NoNameShadowing:Graph.kt$Graph.Companion${ out.name("Tags") out.beginArray() for (tagName in it) { out.value(tagName) } out.endArray() } + NoNameShadowing:GraphEditorBugFinder.kt$GraphEditorBugFinder${ it.position.distanceSqToPlayer() } + NoNameShadowing:GuiOptionEditorUpdateCheck.kt$GuiOptionEditorUpdateCheck$width + NoNameShadowing:HoppityCollectionStats.kt$HoppityCollectionStats${ val displayAmount = it.amount.shortFormat() val operationFormat = when (milestoneType) { HoppityEggType.CHOCOLATE_SHOP_MILESTONE -> "spending" HoppityEggType.CHOCOLATE_FACTORY_MILESTONE -> "reaching" else -> "" // Never happens } // List indexing is weird existingLore[replaceIndex - 1] = "§7Obtained by $operationFormat §6$displayAmount" existingLore[replaceIndex] = "§7all-time §6Chocolate." return existingLore } + NoNameShadowing:HotmData.kt$HotmData.Companion${ it.setCurrent(it.getTotal()) } + NoNameShadowing:LorenzVec.kt$LorenzVec.Companion$pitch + NoNameShadowing:LorenzVec.kt$LorenzVec.Companion$yaw + NoNameShadowing:Renderable.kt$Renderable.Companion.<no name provided>$posX + NoNameShadowing:Renderable.kt$Renderable.Companion.<no name provided>$posY + NoNameShadowing:Renderable.kt$Renderable.Companion.<no name provided>${ it.value?.contains(textInput.textBox, ignoreCase = true) ?: true } + NoNameShadowing:RenderableUtils.kt$RenderableUtils${ it != null } + NoNameShadowing:ReplaceRomanNumerals.kt$ReplaceRomanNumerals${ it.isValidRomanNumeral() && it.removeFormatting().romanToDecimal() != 2000 } + NoNameShadowing:RepoManager.kt$RepoManager${ unsuccessfulConstants.add(it) } + NoNameShadowing:RepoPatternManager.kt$RepoPatternManager${ it == '.' } + NoNameShadowing:Shimmy.kt$Shimmy.Companion$source + NoNameShadowing:SkyHanniBucketedItemTracker.kt$SkyHanniBucketedItemTracker${ ItemPriceSource.entries[it.ordinal] } + ReturnCount:AnitaMedalProfit.kt$AnitaMedalProfit$private fun readItem(slot: Int, item: ItemStack, table: MutableList<DisplayTableEntry>) + ReturnCount:BingoNextStepHelper.kt$BingoNextStepHelper$private fun readDescription(description: String): NextStep? + ReturnCount:BroodmotherFeatures.kt$BroodmotherFeatures$private fun onStageUpdate() + ReturnCount:ChatPeek.kt$ChatPeek$@JvmStatic fun peek(): Boolean + ReturnCount:ChestValue.kt$ChestValue$private fun isValidStorage(): Boolean + ReturnCount:CollectionTracker.kt$CollectionTracker$fun command(args: Array<String>) + ReturnCount:CompactBingoChat.kt$CompactBingoChat$private fun onSkyBlockLevelUp(message: String): Boolean + ReturnCount:CrimsonMinibossRespawnTimer.kt$CrimsonMinibossRespawnTimer$private fun updateArea() + ReturnCount:CropMoneyDisplay.kt$CropMoneyDisplay$private fun drawDisplay(): List<List<Any>> + ReturnCount:DamageIndicatorManager.kt$DamageIndicatorManager$private fun checkThorn(realHealth: Long, realMaxHealth: Long): String? + ReturnCount:DamageIndicatorManager.kt$DamageIndicatorManager$private fun getCustomHealth( entityData: EntityData, health: Long, entity: EntityLivingBase, maxHealth: Long, ): String? + ReturnCount:EnchantParser.kt$EnchantParser$private fun parseEnchants( loreList: MutableList<String>, enchants: Map<String, Int>, chatComponent: IChatComponent?, ) + ReturnCount:EstimatedItemValue.kt$EstimatedItemValue$private fun draw(stack: ItemStack): List<List<Any>> + ReturnCount:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator$private fun calculateStarPrice( internalName: NEUInternalName, inputStars: Int, ): Pair<EssenceItemUtils.EssenceUpgradePrice, Pair<Int, Int>>? + ReturnCount:FishingAPI.kt$FishingAPI$fun seaCreatureCount(entity: EntityArmorStand): Int + ReturnCount:GardenVisitorFeatures.kt$GardenVisitorFeatures$private fun showGui(): Boolean + ReturnCount:GraphEditor.kt$GraphEditor$private fun input() + ReturnCount:HideNotClickableItems.kt$HideNotClickableItems$private fun hideSalvage(chestName: String, stack: ItemStack): Boolean + ReturnCount:IslandGraphs.kt$IslandGraphs$private fun handleTick() + ReturnCount:ItemDisplayOverlayFeatures.kt$ItemDisplayOverlayFeatures$private fun getStackTip(item: ItemStack): String? + ReturnCount:ItemNameResolver.kt$ItemNameResolver$internal fun getInternalNameOrNull(itemName: String): NEUInternalName? + ReturnCount:ItemPriceUtils.kt$ItemPriceUtils$fun NEUInternalName.getPriceOrNull( priceSource: ItemPriceSource = ItemPriceSource.BAZAAR_INSTANT_BUY, pastRecipes: List<PrimitiveRecipe> = emptyList(), ): Double? + ReturnCount:ItemUtils.kt$ItemUtils$private fun NEUInternalName.grabItemName(): String + ReturnCount:MinecraftConsoleFilter.kt$MinecraftConsoleFilter$override fun filter(event: LogEvent?): Filter.Result + ReturnCount:MiningEventTracker.kt$MiningEventTracker$private fun sendData(eventName: String, time: String?) + ReturnCount:MobDetection.kt$MobDetection$private fun entitySpawn(entity: EntityLivingBase, roughType: Mob.Type): Boolean + ReturnCount:MobFilter.kt$MobFilter$internal fun createSkyblockEntity(baseEntity: EntityLivingBase): MobResult + ReturnCount:MobFilter.kt$MobFilter$private fun armorStandOnlyMobs(baseEntity: EntityLivingBase, armorStand: EntityArmorStand): MobResult? + ReturnCount:MobFilter.kt$MobFilter$private fun exceptions(baseEntity: EntityLivingBase, nextEntity: EntityLivingBase?): MobResult? + ReturnCount:MobFinder.kt$MobFinder$private fun tryAddEntitySpider(entity: EntityLivingBase): EntityResult? + ReturnCount:MobFinder.kt$MobFinder$private fun tryAddRift(entity: EntityLivingBase): EntityResult? + ReturnCount:MultiFilter.kt$MultiFilter$fun matchResult(string: String): String? + ReturnCount:PacketTest.kt$PacketTest$private fun Packet<*>.print() + ReturnCount:PowderMiningChatFilter.kt$PowderMiningChatFilter$@Suppress("CyclomaticComplexMethod") fun block(message: String): String? + ReturnCount:PurseAPI.kt$PurseAPI$private fun getCause(diff: Double): PurseChangeCause + ReturnCount:QuestLoader.kt$QuestLoader$private fun addQuest(name: String, state: QuestState, needAmount: Int): Quest + ReturnCount:ShowFishingItemName.kt$ShowFishingItemName$fun inCorrectArea(): Boolean + ReturnCount:SkillAPI.kt$SkillAPI$fun onCommand(it: Array<String>) + ReturnCount:SkyHanniConfigSearchResetCommand.kt$SkyHanniConfigSearchResetCommand$private suspend fun setCommand(args: Array<String>): String + ReturnCount:TabComplete.kt$TabComplete$private fun customTabComplete(command: String): List<String>? + SpreadOperator:ItemUtils.kt$ItemUtils$(tag, displayName, *lore.toTypedArray()) + SpreadOperator:LimboPlaytime.kt$LimboPlaytime$( itemID.getItemStack().item, ITEM_NAME, *createItemLore() ) + SpreadOperator:Text.kt$Text$(*component.toTypedArray(), separator = separator) + TooManyFunctions:CollectionUtils.kt$CollectionUtils + TooManyFunctions:DailyQuestHelper.kt$DailyQuestHelper + TooManyFunctions:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator + TooManyFunctions:GuiRenderUtils.kt$GuiRenderUtils + TooManyFunctions:HypixelCommands.kt$HypixelCommands + TooManyFunctions:InventoryUtils.kt$InventoryUtils + TooManyFunctions:LocationUtils.kt$LocationUtils + TooManyFunctions:LorenzUtils.kt$LorenzUtils + TooManyFunctions:LorenzVec.kt$LorenzVec + TooManyFunctions:MobFinder.kt$MobFinder + TooManyFunctions:NumberUtil.kt$NumberUtil + TooManyFunctions:RegexUtils.kt$RegexUtils + TooManyFunctions:RenderUtils.kt$RenderUtils + TooManyFunctions:Renderable.kt$Renderable$Companion + TooManyFunctions:ScoreboardElements.kt$at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardElements.kt + TooManyFunctions:ScoreboardEvent.kt$at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardEvent.kt + TooManyFunctions:SkyBlockItemModifierUtils.kt$SkyBlockItemModifierUtils + TooManyFunctions:StringUtils.kt$StringUtils + UnsafeCallOnNullableType:BasketWaypoints.kt$BasketWaypoints$Basket.entries.minByOrNull { it.waypoint.distanceSqToPlayer() }!! + UnsafeCallOnNullableType:BasketWaypoints.kt$BasketWaypoints$notFoundBaskets.minByOrNull { it.waypoint.distanceSqToPlayer() }!! + UnsafeCallOnNullableType:BucketedItemTrackerData.kt$BucketedItemTrackerData$it.value[internalName]?.hidden!! + UnsafeCallOnNullableType:ChocolateFactoryDataLoader.kt$ChocolateFactoryDataLoader$upgradeCost!! + UnsafeCallOnNullableType:CollectionUtils.kt$CollectionUtils$this.merge(key, number, Double::plus)!! + UnsafeCallOnNullableType:CollectionUtils.kt$CollectionUtils$this.merge(key, number, Float::plus)!! + UnsafeCallOnNullableType:CollectionUtils.kt$CollectionUtils$this.merge(key, number, Int::plus)!! + UnsafeCallOnNullableType:CollectionUtils.kt$CollectionUtils$this.merge(key, number, Long::plus)!! + UnsafeCallOnNullableType:CombatUtils.kt$CombatUtils$a!! + UnsafeCallOnNullableType:CompactBestiaryChatMessage.kt$CompactBestiaryChatMessage$it.groups[1]!! + UnsafeCallOnNullableType:ConfigManager.kt$ConfigManager$file!! + UnsafeCallOnNullableType:CorpseTracker.kt$CorpseTracker$applicableKeys.first().key!! + UnsafeCallOnNullableType:CosmeticFollowingLine.kt$CosmeticFollowingLine$latestLocations[b]!! + UnsafeCallOnNullableType:CosmeticFollowingLine.kt$CosmeticFollowingLine$locations[b]!! + UnsafeCallOnNullableType:CropMoneyDisplay.kt$CropMoneyDisplay$cropNames[internalName]!! + UnsafeCallOnNullableType:DailyMiniBossHelper.kt$DailyMiniBossHelper$getByDisplayName(name)!! + UnsafeCallOnNullableType:DamageIndicatorManager.kt$DamageIndicatorManager$data.deathLocation!! + UnsafeCallOnNullableType:DefaultConfigFeatures.kt$DefaultConfigFeatures$resetSuggestionState[cat]!! + UnsafeCallOnNullableType:DefaultConfigOptionGui.kt$DefaultConfigOptionGui$resetSuggestionState[cat]!! + UnsafeCallOnNullableType:DicerRngDropTracker.kt$DicerRngDropTracker$event.toolItem!! + UnsafeCallOnNullableType:DiscordStatus.kt$ownerRegex.find(colorlessLine)!! + UnsafeCallOnNullableType:DungeonAPI.kt$DungeonAPI$dungeonFloor!! + UnsafeCallOnNullableType:EasterEggWaypoints.kt$EasterEggWaypoints$EasterEgg.entries.minByOrNull { it.waypoint.distanceSqToPlayer() }!! + UnsafeCallOnNullableType:EasterEggWaypoints.kt$EasterEggWaypoints$notFoundEggs.minByOrNull { it.waypoint.distanceSqToPlayer() }!! + UnsafeCallOnNullableType:EntityMovementData.kt$EntityMovementData$entityLocation[entity]!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$entityRenderCache.noXrayCache!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$entityRenderCache.xrayCache!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$frameToCopy!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$frameToPaste!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$isAntialiasing!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$isFastRender!! + UnsafeCallOnNullableType:EntityOutlineRenderer.kt$EntityOutlineRenderer$isShaders!! + UnsafeCallOnNullableType:FFGuideGUI.kt$FFGuideGUI$currentCrop!! + UnsafeCallOnNullableType:FarmingContestAPI.kt$FarmingContestAPI$contestCrop!! + UnsafeCallOnNullableType:FarmingContestAPI.kt$FarmingContestAPI$contests[bracket]!! + UnsafeCallOnNullableType:FarmingContestAPI.kt$FarmingContestAPI$currentCrop!! + UnsafeCallOnNullableType:FarmingWeightDisplay.kt$FarmingWeightDisplay$weightPerCrop[CropType.CACTUS]!! + UnsafeCallOnNullableType:FarmingWeightDisplay.kt$FarmingWeightDisplay$weightPerCrop[CropType.SUGAR_CANE]!! + UnsafeCallOnNullableType:FeatureToggleProcessor.kt$FeatureToggleProcessor$latestCategory!! + UnsafeCallOnNullableType:FeatureTogglesByDefaultAdapter.kt$FeatureTogglesByDefaultAdapter$gson!! + UnsafeCallOnNullableType:FishingProfitTracker.kt$FishingProfitTracker$itemCategories[currentCategory]!! + UnsafeCallOnNullableType:FishingProfitTracker.kt$FishingProfitTracker.Data$itemCategories["Trophy Fish"]!! + UnsafeCallOnNullableType:FortuneUpgrades.kt$FortuneUpgrades$nextTalisman.upgradeCost?.first!! + UnsafeCallOnNullableType:GardenComposterUpgradesData.kt$GardenComposterUpgradesData$ComposterUpgrade.getByName(name)!! + UnsafeCallOnNullableType:GardenCropMilestoneDisplay.kt$GardenCropMilestoneDisplay$cultivatingData[crop]!! + UnsafeCallOnNullableType:GardenCropMilestonesCommunityFix.kt$GardenCropMilestonesCommunityFix$map[crop]!! + UnsafeCallOnNullableType:GardenPlotIcon.kt$GardenPlotIcon$originalStack[index]!! + UnsafeCallOnNullableType:GhostCounter.kt$GhostCounter$storage?.totalMF!! + UnsafeCallOnNullableType:Graph.kt$Graph.Companion$position!! + UnsafeCallOnNullableType:Graph.kt$distances.distances[end]!! + UnsafeCallOnNullableType:GriffinBurrowHelper.kt$GriffinBurrowHelper$particleBurrows[targetLocation]!! + UnsafeCallOnNullableType:HoppityCallWarning.kt$HoppityCallWarning$acceptUUID!! + UnsafeCallOnNullableType:IslandGraphs.kt$IslandGraphs$currentTarget!! + UnsafeCallOnNullableType:ItemBlink.kt$ItemBlink$offsets[item]!! + UnsafeCallOnNullableType:ItemPickupLog.kt$ItemPickupLog$listToCheckAgainst[key]!! + UnsafeCallOnNullableType:ItemPickupLog.kt$ItemPickupLog$listToCheckAgainst[key]?.second!! + UnsafeCallOnNullableType:ItemStackTypeAdapterFactory.kt$ItemStackTypeAdapterFactory$gson!! + UnsafeCallOnNullableType:ItemUtils.kt$ItemUtils$itemAmountCache[input]!! + UnsafeCallOnNullableType:JacobContestTimeNeeded.kt$JacobContestTimeNeeded$map[crop]!! + UnsafeCallOnNullableType:KSerializable.kt$KotlinTypeAdapterFactory$kotlinClass.memberProperties.find { it.name == param.name }!! + UnsafeCallOnNullableType:KSerializable.kt$KotlinTypeAdapterFactory$param.name!! + UnsafeCallOnNullableType:LorenzEvent.kt$LorenzEvent$this::class.simpleName!! + UnsafeCallOnNullableType:MinionFeatures.kt$MinionFeatures$newMinion!! + UnsafeCallOnNullableType:MobFinder.kt$MobFinder$floor6GiantsSeparateDelay[uuid]!! + UnsafeCallOnNullableType:NavigationHelper.kt$NavigationHelper$distances[node]!! + UnsafeCallOnNullableType:NumberUtil.kt$NumberUtil$romanSymbols[this]!! + UnsafeCallOnNullableType:PositionList.kt$PositionList$configLink!! + UnsafeCallOnNullableType:ReminderManager.kt$ReminderManager$storage[args.drop(1).first()]!! + UnsafeCallOnNullableType:ReminderManager.kt$ReminderManager$storage[args.first()]!! + UnsafeCallOnNullableType:RenderEntityOutlineEvent.kt$RenderEntityOutlineEvent$entitiesToChooseFrom!! + UnsafeCallOnNullableType:RenderEntityOutlineEvent.kt$RenderEntityOutlineEvent$entitiesToOutline!! + UnsafeCallOnNullableType:RenderGlobalHook.kt$RenderGlobalHook$camera!! + UnsafeCallOnNullableType:RenderLivingEntityHelper.kt$RenderLivingEntityHelper$entityColorCondition[entity]!! + UnsafeCallOnNullableType:RenderLivingEntityHelper.kt$RenderLivingEntityHelper$entityColorMap[entity]!! + UnsafeCallOnNullableType:RenderUtils.kt$RenderUtils$it.name!! + UnsafeCallOnNullableType:RepoManager.kt$RepoManager$latestRepoCommit!! + UnsafeCallOnNullableType:RepoUtils.kt$RepoUtils$file!! + UnsafeCallOnNullableType:SackAPI.kt$SackAPI$match.groups[1]!! + UnsafeCallOnNullableType:SackAPI.kt$SackAPI$match.groups[2]!! + UnsafeCallOnNullableType:SackAPI.kt$SackAPI$match.groups[3]!! + UnsafeCallOnNullableType:SackAPI.kt$SackAPI$oldData!! + UnsafeCallOnNullableType:SimpleCommand.kt$SimpleCommand$tabRunnable!! + UnsafeCallOnNullableType:SkyHanniBucketedItemTracker.kt$SkyHanniBucketedItemTracker$it.get(DisplayMode.SESSION).getItemsProp()[internalName]!! + UnsafeCallOnNullableType:SkyHanniBucketedItemTracker.kt$SkyHanniBucketedItemTracker$it.get(DisplayMode.TOTAL).getItemsProp()[internalName]!! + UnsafeCallOnNullableType:SkyHanniMod.kt$SkyHanniMod.Companion$Loader.instance().indexedModList[MODID]!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$distance!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$distance2!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$firstParticlePoint?.distance(pos)!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$lastParticlePoint2!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$lastParticlePoint2?.distance(particlePoint!!)!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$particlePoint!! + UnsafeCallOnNullableType:SoopyGuessBurrow.kt$SoopyGuessBurrow$particlePoint?.subtract(lastParticlePoint2!!)!! + UnsafeCallOnNullableType:SummoningSoulsName.kt$SummoningSoulsName$mobsName.getOrNull(nearestMob)!! + UnsafeCallOnNullableType:SuperpairsClicksAlert.kt$SuperpairsClicksAlert$match.groups[1]!! + UnsafeCallOnNullableType:TiaRelayWaypoints.kt$TiaRelayWaypoints$waypointName!! + UnsafeCallOnNullableType:Translator.kt$Translator$messageContentRegex.find(message)!! + UnsafeCallOnNullableType:TrevorFeatures.kt$TrevorFeatures$TrevorSolver.currentMob!! + UnsafeCallOnNullableType:TrevorSolver.kt$TrevorSolver$currentMob!! + UnsafeCallOnNullableType:TunnelsMaps.kt$TunnelsMaps$campfire.name!! + UnsafeCallOnNullableType:UpdateManager.kt$UpdateManager$potentialUpdate!! + UnsafeCallOnNullableType:VisitorRewardWarning.kt$VisitorRewardWarning$visitor.totalPrice!! + UnsafeCallOnNullableType:VisitorRewardWarning.kt$VisitorRewardWarning$visitor.totalReward!! + UnusedParameter:SkyHanniDebugsAndTests.kt$SkyHanniDebugsAndTests$args: Array<String> + UseIsNullOrEmpty:ItemUtils.kt$ItemUtils$name == null || name.isEmpty() + UseOrEmpty:SkyHanniDebugsAndTests.kt$SkyHanniDebugsAndTests$event.originalOre?.let { "$it " } ?: "" + VarCouldBeVal:AdvancedPlayerList.kt$AdvancedPlayerList$private var randomOrderCache = TimeLimitedCache<String, Int>(20.minutes) + VarCouldBeVal:BestiaryData.kt$BestiaryData$private var indexes = listOf( 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43 ) + VarCouldBeVal:BucketedItemTrackerData.kt$BucketedItemTrackerData$@Expose private var bucketedItems: MutableMap<E, MutableMap<NEUInternalName, TrackedItem>> = HashMap() + VarCouldBeVal:CarnivalZombieShootout.kt$CarnivalZombieShootout$private var lastUpdate = Updates(SimpleTimeMark.farPast(), SimpleTimeMark.farPast()) + VarCouldBeVal:ChocolateFactoryStrayTracker.kt$ChocolateFactoryStrayTracker$private var claimedStraysSlots = mutableListOf<Int>() + VarCouldBeVal:CompactBestiaryChatMessage.kt$CompactBestiaryChatMessage$private var bestiaryDescription = mutableListOf<String>() + VarCouldBeVal:CompactExperimentRewards.kt$CompactExperimentRewards$private var gainedRewards = mutableListOf<String>() + VarCouldBeVal:CraftRoomHolographicMob.kt$CraftRoomHolographicMob$private var entityToHolographicEntity = mapOf( EntityZombie::class.java to HolographicEntities.zombie, EntitySlime::class.java to HolographicEntities.slime, EntityCaveSpider::class.java to HolographicEntities.caveSpider, ) + VarCouldBeVal:CustomWardrobe.kt$CustomWardrobe$private var guiName = "Custom Wardrobe" + VarCouldBeVal:Enchant.kt$Enchant$@Expose private var goodLevel = 0 + VarCouldBeVal:Enchant.kt$Enchant$@Expose private var maxLevel = 0 + VarCouldBeVal:Enchant.kt$Enchant.Stacking$@Expose @Suppress("unused") private var statLabel: String? = null + VarCouldBeVal:Enchant.kt$Enchant.Stacking$@Expose private var nbtNum: String? = null + VarCouldBeVal:Enchant.kt$Enchant.Stacking$@Expose private var stackLevel: TreeSet<Int>? = null + VarCouldBeVal:ErrorManager.kt$ErrorManager$private var cache = TimeLimitedSet<Pair<String, Int>>(10.minutes) + VarCouldBeVal:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator$var comboPrice = combo.asInternalName().getPriceOrNull() + VarCouldBeVal:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator$var internalName = removeKuudraArmorPrefix(stack.getInternalName().asString().removePrefix("VANQUISHED_")) + VarCouldBeVal:EstimatedItemValueCalculator.kt$EstimatedItemValueCalculator$var nameColor = if (!useless) "§9" else "§7" + VarCouldBeVal:ExperimentsProfitTracker.kt$ExperimentsProfitTracker$private var currentBottlesInInventory = mutableMapOf<NEUInternalName, Int>() + VarCouldBeVal:ExperimentsProfitTracker.kt$ExperimentsProfitTracker$private var lastBottlesInInventory = mutableMapOf<NEUInternalName, Int>() + VarCouldBeVal:ExperimentsProfitTracker.kt$ExperimentsProfitTracker$private var lastSplashes = mutableListOf<ItemStack>() + VarCouldBeVal:FarmingWeightDisplay.kt$FarmingWeightDisplay$private var nextPlayers = mutableListOf<UpcomingLeaderboardPlayer>() + VarCouldBeVal:FlareDisplay.kt$FlareDisplay$private var flares = mutableListOf<Flare>() + VarCouldBeVal:FontRendererHook.kt$FontRendererHook$private var CHROMA_COLOR: Int = -0x1 + VarCouldBeVal:FontRendererHook.kt$FontRendererHook$private var CHROMA_COLOR_SHADOW: Int = -0xAAAAAB + VarCouldBeVal:GardenPlotIcon.kt$GardenPlotIcon$private var cachedStack = mutableMapOf<Int, ItemStack>() + VarCouldBeVal:GardenPlotIcon.kt$GardenPlotIcon$private var originalStack = mutableMapOf<Int, ItemStack>() + VarCouldBeVal:GardenPlotMenuHighlighting.kt$GardenPlotMenuHighlighting$private var highlightedPlots = mutableMapOf<GardenPlotAPI.Plot, PlotStatusType>() + VarCouldBeVal:GardenVisitorColorNames.kt$GardenVisitorColorNames$private var visitorColors = mutableMapOf<String, String>() // name -> color code + VarCouldBeVal:GhostData.kt$GhostData$private var session = mutableMapOf( Option.KILLS to 0.0, Option.SORROWCOUNT to 0.0, Option.VOLTACOUNT to 0.0, Option.PLASMACOUNT to 0.0, Option.GHOSTLYBOOTS to 0.0, Option.BAGOFCASH to 0.0, Option.TOTALDROPS to 0.0, Option.SCAVENGERCOINS to 0.0, Option.MAXKILLCOMBO to 0.0, Option.SKILLXPGAINED to 0.0 ) + VarCouldBeVal:GraphEditor.kt$GraphEditor$var vector = LocationUtils.calculatePlayerFacingDirection() + VarCouldBeVal:HoppityCollectionStats.kt$HoppityCollectionStats$private var highlightMap = mutableMapOf<String, LorenzColor>() + VarCouldBeVal:HoppityEggLocations.kt$HoppityEggLocations$// TODO add gui/command to show total data/missing islands private var collectedEggStorage: MutableMap<IslandType, MutableSet<LorenzVec>> get() = ChocolateFactoryAPI.profileStorage?.collectedEggLocations ?: mutableMapOf() set(value) { ChocolateFactoryAPI.profileStorage?.collectedEggLocations = value } + VarCouldBeVal:HoppityNpc.kt$HoppityNpc$private var slotsToHighlight = mutableSetOf<Int>() + VarCouldBeVal:IslandAreas.kt$IslandAreas$var suffix = "" + VarCouldBeVal:ItemPickupLog.kt$ItemPickupLog$private var itemList = mutableMapOf<Int, Pair<ItemStack, Int>>() + VarCouldBeVal:ItemPickupLog.kt$ItemPickupLog$private var itemsAddedToInventory = mutableMapOf<Int, PickupEntry>() + VarCouldBeVal:ItemPickupLog.kt$ItemPickupLog$private var itemsRemovedFromInventory = mutableMapOf<Int, PickupEntry>() + VarCouldBeVal:LocationUtils.kt$LocationUtils$var yaw = LocationUtils.calculatePlayerYaw() + 180 + VarCouldBeVal:LorenzLogger.kt$LorenzLogger.Companion$private var LOG_DIRECTORY = File("config/skyhanni/logs") + VarCouldBeVal:MobDetection.kt$MobDetection$private var shouldClear: AtomicBoolean = AtomicBoolean(false) + VarCouldBeVal:MobFinder.kt$MobFinder$private var floor2summonsDiedOnce = mutableListOf<EntityOtherPlayerMP>() + VarCouldBeVal:MobFinder.kt$MobFinder$private var floor6GiantsSeparateDelay = mutableMapOf<UUID, Pair<Long, BossType>>() + VarCouldBeVal:MobFinder.kt$MobFinder$private var guardians = mutableListOf<EntityGuardian>() + VarCouldBeVal:NeuReforgeJson.kt$NeuReforgeJson$private lateinit var itemTypeField: Pair<String, List<NEUInternalName>> + VarCouldBeVal:PowerStoneGuideFeatures.kt$PowerStoneGuideFeatures$private var missing = mutableMapOf<Int, NEUInternalName>() + VarCouldBeVal:PunchcardHighlight.kt$PunchcardHighlight$private var playerQueue = mutableListOf<String>() + VarCouldBeVal:QuiverWarning.kt$QuiverWarning$private var arrowsInInstance = mutableSetOf<ArrowType>() + VarCouldBeVal:ReforgeHelper.kt$ReforgeHelper$private var waitForChat = AtomicBoolean(false) + VarCouldBeVal:ReminderManager.kt$ReminderManager$private var listPage = 1 + VarCouldBeVal:RepoPatternGui.kt$RepoPatternGui$private var searchCache = ObservableList(mutableListOf<RepoPatternInfo>()) + VarCouldBeVal:RepoPatternManager.kt$RepoPatternManager$/** * Map containing all keys and their repo patterns. Used for filling in new regexes after an update, and for * checking duplicate registrations. */ private var usedKeys: NavigableMap<String, CommonPatternInfo<*, *>> = TreeMap() + VarCouldBeVal:RepoPatternManager.kt$RepoPatternManager$/** * Map containing the exclusive owner of a regex key */ private var exclusivity: MutableMap<String, RepoPatternKeyOwner> = mutableMapOf() + VarCouldBeVal:SeaCreatureFeatures.kt$SeaCreatureFeatures$private var entityIds = TimeLimitedSet<Int>(6.minutes) + VarCouldBeVal:SeaCreatureFeatures.kt$SeaCreatureFeatures$private var rareSeaCreatures = TimeLimitedSet<Mob>(6.minutes) + VarCouldBeVal:ShowFishingItemName.kt$ShowFishingItemName$private var itemsOnGround = TimeLimitedCache<EntityItem, String>(750.milliseconds) + VarCouldBeVal:SkyblockGuideHighlightFeature.kt$SkyblockGuideHighlightFeature.Companion$private var missing = mutableSetOf<Int>() + VarCouldBeVal:SlayerItemsOnGround.kt$SlayerItemsOnGround$private var itemsOnGround = TimeLimitedCache<EntityItem, String>(2.seconds) + VarCouldBeVal:SoopyGuessBurrow.kt$SoopyGuessBurrow$private var dingSlope = mutableListOf<Float>() + VarCouldBeVal:SoopyGuessBurrow.kt$SoopyGuessBurrow$private var locations = mutableListOf<LorenzVec>() + VarCouldBeVal:SuperpairExperimentInformationDisplay.kt$SuperpairExperimentInformationDisplay$// TODO remove string. use enum instead! maybe even create new data type instead of map of pairs private var found = mutableMapOf<Pair<Item?, ItemPair?>, String>() + VarCouldBeVal:SuperpairExperimentInformationDisplay.kt$SuperpairExperimentInformationDisplay$private var lastClicked = mutableListOf<Pair<Int, Int>>() + VarCouldBeVal:SuperpairExperimentInformationDisplay.kt$SuperpairExperimentInformationDisplay$private var toCheck = mutableListOf<Pair<Int, Int>>() + VarCouldBeVal:SuperpairExperimentInformationDisplay.kt$SuperpairExperimentInformationDisplay$private var uncoveredItems = mutableListOf<Pair<Int, String>>() + VarCouldBeVal:TiaRelayHelper.kt$TiaRelayHelper$private var resultDisplay = mutableMapOf<Int, Int>() + VarCouldBeVal:TiaRelayHelper.kt$TiaRelayHelper$private var sounds = mutableMapOf<Int, Sound>() + VarCouldBeVal:Translator.kt$Translator$var lang = config.languageCode.get() + VarCouldBeVal:TrevorFeatures.kt$TrevorFeatures$private var backupTrapperID: Int = 17 + VarCouldBeVal:TrevorFeatures.kt$TrevorFeatures$private var trapperID: Int = 56 + VarCouldBeVal:TrophyFishDisplay.kt$TrophyFishDisplay$private var recentlyDroppedTrophies = TimeLimitedCache<NEUInternalName, TrophyRarity>(5.seconds) + VarCouldBeVal:UserLuckBreakdown.kt$UserLuckBreakdown$private var fillerID = "STAINED_GLASS_PANE".asInternalName() + VarCouldBeVal:UserLuckBreakdown.kt$UserLuckBreakdown$private var limboID = "ENDER_PEARL".asInternalName() + VarCouldBeVal:UserLuckBreakdown.kt$UserLuckBreakdown$private var skillOverflowLuck = mutableMapOf<SkillType, Int>() + VarCouldBeVal:UserLuckBreakdown.kt$UserLuckBreakdown$private var skillsID = "DIAMOND_SWORD".asInternalName() + + diff --git a/detekt/build.gradle.kts b/detekt/build.gradle.kts new file mode 100644 index 000000000000..ce0de9ace8ce --- /dev/null +++ b/detekt/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + kotlin("jvm") + id("com.google.devtools.ksp") +} + +dependencies { + implementation("io.gitlab.arturbosch.detekt:detekt-api:1.23.7") + ksp(libs.autoservice.ksp) + implementation(libs.autoservice.annotations) + implementation("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7") + testImplementation("io.kotest:kotest-assertions-core:5.9.1") + testImplementation("io.gitlab.arturbosch.detekt:detekt-test:1.23.7") +} diff --git a/detekt/detekt.yml b/detekt/detekt.yml new file mode 100644 index 000000000000..ac5c9de53bcc --- /dev/null +++ b/detekt/detekt.yml @@ -0,0 +1,127 @@ + +config: + validation: true + +GrammarRules: + active: true + AvoidBritishSpelling: # custom rule to prefer american spellings over british ones + active: true + +FormattingRules: + active: true + CustomCommentSpacing: + active: true + + +style: + MagicNumber: # I, Linnea Gräf, of sound mind and body, disagree with disabling this rule + active: false + UnusedParameter: + active: true + ignoreAnnotated: + - 'SubscribeEvent' + - 'HandleEvent' + - 'Mod.EventHandler' + ReturnCount: + active: true + max: 5 + excludeGuardClauses: true + ignoreAnnotated: + - 'SubscribeEvent' + - 'HandleEvent' + - 'Mod.EventHandler' + MaxLineLength: + active: true + maxLineLength: 140 + excludeCommentStatements: true + LoopWithTooManyJumpStatements: + active: true + maxJumpCount: 3 + UnnecessaryAbstractClass: # gets horrendously messed up with Event classes + active: false + UnusedPrivateMember: # gets tripped up by API methods + active: false + UnusedPrivateProperty: # loops that don't use their iterator + active: true + allowedNames: "^(unused|_)$" + UseCheckOrError: + active: false + ForbiddenComment: # every TODO gets flagged + active: false + DestructuringDeclarationWithTooManyEntries: # too aggressive + active: true + maxDestructuringEntries: 5 + +formatting: + MaximumLineLength: # ktlint - handled by detekt + active: false + MultiLineIfElse: + active: false + ArgumentListWrapping: # ktlint - way too aggressive + active: false + NoBlankLineBeforeRbrace: # pedantic + active: false + NoConsecutiveBlankLines: # pedantic + active: false + NoEmptyFirstLineInMethodBlock: # pedantic + active: false + ParameterListWrapping: # pedantic, can be useful in compact code + active: false + CommentSpacing: # handled by custom rule + active: false + SpacingBetweenDeclarationsWithAnnotations: # nah + active: false + SpacingBetweenDeclarationsWithComments: # also nah + active: false + +complexity: + CyclomaticComplexMethod: # default threshold of 15, caught almost every complex method + active: true + threshold: 25 + ignoreAnnotated: + - 'SubscribeEvent' + - 'HandleEvent' + - 'Mod.EventHandler' + LongParameterList: # too aggressive, classes can need a lot of params + active: false + NestedBlockDepth: # too aggressive + active: false + TooManyFunctions: # ktlint - also way too aggressive by default (11 on all file types) + active: true + thresholdInFiles: 15 + thresholdInClasses: 20 + thresholdInInterfaces: 20 + thresholdInObjects: 20 + thresholdInEnums: 11 + ignoreAnnotated: + - 'SkyHanniModule' + ComplexCondition: # aggressive by default, at a complexity of 4 + active: true + threshold: 6 + LongMethod: # default max length of 60, caught way too much + active: true + threshold: 100 + ignoreAnnotated: + - 'SubscribeEvent' + - 'HandleEvent' + - 'Mod.EventHandler' + +exceptions: + SwallowedException: # there are valid reasons to do this + active: false + ThrowingExceptionsWithoutMessageOrCause: # again, valid reasons + active: false + TooGenericExceptionCaught: # sometimes you just need to catch Exception + active: false + TooGenericExceptionThrown: # we don't have our own custom exceptions + active: false + +naming: + ConstructorParameterNaming: # pedantic + active: false + +potential-bugs: + DoubleMutabilityForCollection: # went crazy about all the mutable collections + active: false + HasPlatformType: # false positives on config get() methods + active: false diff --git a/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt b/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt new file mode 100644 index 000000000000..aaf7896cfd17 --- /dev/null +++ b/detekt/src/main/kotlin/formatting/CustomCommentSpacing.kt @@ -0,0 +1,51 @@ +package at.hannibal2.skyhanni.detektrules.formatting + +import io.gitlab.arturbosch.detekt.api.CodeSmell +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.Debt +import io.gitlab.arturbosch.detekt.api.Entity +import io.gitlab.arturbosch.detekt.api.Issue +import io.gitlab.arturbosch.detekt.api.Rule +import io.gitlab.arturbosch.detekt.api.Severity +import org.jetbrains.kotlin.com.intellij.psi.PsiComment + +class CustomCommentSpacing(config: Config) : Rule(config) { + override val issue = Issue( + "CustomCommentSpacing", + Severity.Style, + "Enforces custom spacing rules for comments.", + Debt.FIVE_MINS + ) + + private val allowedPatterns = listOf( + "#if", + "#else", + "#elseif", + "#endif", + "$$" + ) + + override fun visitComment(comment: PsiComment) { + if (allowedPatterns.any { comment.text.contains(it) }) { + return + } + + /** + * REGEX-TEST: // Test comment + * REGEX-TEST: /* Test comment */ + */ + val commentRegex = Regex("""^(?:\/{2}|\/\*)(?:\s.*|$)""", RegexOption.DOT_MATCHES_ALL) + if (!commentRegex.matches(comment.text)) { + report( + CodeSmell( + issue, + Entity.from(comment), + "Expected space after opening comment." + ) + ) + } + + // Fallback to super (ostensibly a no-check) + super.visitComment(comment) + } +} diff --git a/detekt/src/main/kotlin/formatting/FormattingRuleSetProvider.kt b/detekt/src/main/kotlin/formatting/FormattingRuleSetProvider.kt new file mode 100644 index 000000000000..a0a969bcf503 --- /dev/null +++ b/detekt/src/main/kotlin/formatting/FormattingRuleSetProvider.kt @@ -0,0 +1,17 @@ +package at.hannibal2.skyhanni.detektrules.formatting + +import com.google.auto.service.AutoService +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.RuleSet +import io.gitlab.arturbosch.detekt.api.RuleSetProvider + +@AutoService(RuleSetProvider::class) +class FormattingRuleSetProvider : RuleSetProvider { + override val ruleSetId: String = "FormattingRules" + + override fun instance(config: Config): RuleSet { + return RuleSet(ruleSetId, listOf( + CustomCommentSpacing(config) + )) + } +} diff --git a/detekt/src/main/kotlin/grammar/AvoidBritishSpelling.kt b/detekt/src/main/kotlin/grammar/AvoidBritishSpelling.kt new file mode 100644 index 000000000000..6a4ea3d61eb4 --- /dev/null +++ b/detekt/src/main/kotlin/grammar/AvoidBritishSpelling.kt @@ -0,0 +1,46 @@ +package at.hannibal2.skyhanni.detektrules.grammar + +import io.gitlab.arturbosch.detekt.api.CodeSmell +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.Debt +import io.gitlab.arturbosch.detekt.api.Entity +import io.gitlab.arturbosch.detekt.api.Issue +import io.gitlab.arturbosch.detekt.api.Rule +import io.gitlab.arturbosch.detekt.api.Severity +import org.jetbrains.kotlin.psi.KtStringTemplateExpression + +/** + * This rule reports all usages of the british spelling over the american spelling in the codebase, + * this will ignore any type annotations, i.e., `@ConfigEditorColour` will not be reported. + */ +class AvoidBritishSpelling(config: Config) : Rule(config) { + override val issue = Issue( + "AvoidBritishSpelling", + Severity.Style, + "Avoid using the word british spelling over american spelling.", + Debt.FIVE_MINS, + ) + + private val scannedWords = mapOf( + "colour" to "color", + "armour" to "armor", + ) + + override fun visitStringTemplateExpression(expression: KtStringTemplateExpression) { + val text = + expression.text // Be aware .getText() returns the entire span of this template, including variable names contained within. This should be rare enough of a problem for us to not care about it. + + for (word in scannedWords) { + if (text.contains(word.key, ignoreCase = true)) { + report( + CodeSmell( + issue, + Entity.from(expression), + "Avoid using the word '${word.key}' in code, '${word.value}' is preferred instead.", + ), + ) + } + } + super.visitStringTemplateExpression(expression) + } +} diff --git a/detekt/src/main/kotlin/grammar/GrammarRuleSetProvider.kt b/detekt/src/main/kotlin/grammar/GrammarRuleSetProvider.kt new file mode 100644 index 000000000000..8001fe42b5b2 --- /dev/null +++ b/detekt/src/main/kotlin/grammar/GrammarRuleSetProvider.kt @@ -0,0 +1,20 @@ +package at.hannibal2.skyhanni.detektrules.grammar + +import com.google.auto.service.AutoService +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.RuleSet +import io.gitlab.arturbosch.detekt.api.RuleSetProvider + +@AutoService(RuleSetProvider::class) +class GrammarRuleSetProvider : RuleSetProvider { + override val ruleSetId: String = "GrammarRules" + + override fun instance(config: Config): RuleSet { + return RuleSet( + ruleSetId, + listOf( + AvoidBritishSpelling(config), + ), + ) + } +} diff --git a/detekt/src/main/kotlin/root.kt b/detekt/src/main/kotlin/root.kt new file mode 100644 index 000000000000..9b95a398f30a --- /dev/null +++ b/detekt/src/main/kotlin/root.kt @@ -0,0 +1 @@ +package at.hannibal2.skyhanni.detektrules diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d7172fe55739..d7381099902b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,6 @@ # SkyHanni - Change Log -## Version 0.27 (in Beta) +## Version 0.27 ### New Features @@ -14,6 +14,9 @@ #### Mining Features + Added a "Get from Sack" button in the forge recipe menu to retrieve ingredients. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2106) ++ Added Tracker for Glacite Corpses. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2306) + + Tracks overall loot and loot per type. ++ Hides tooltips of items inside the Fossil Excavator in Glacite Tunnels. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2539) #### Rift Features @@ -21,6 +24,10 @@ + Added Crafting Room Helper. - HiZe (https://github.com/hannibal002/SkyHanni/pull/2178) + Shows a holographic mob at the location where the mob is present in the real room inside the Mirrorverse in Rift. + Added Rift Time Real-Time Nametag Format. - Empa (https://github.com/hannibal002/SkyHanni/pull/2015) ++ Added a helper for tracking the Buttons Enigma Soul in the Rift. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) + + Using pathfinding to guide the player to the nearest spot with unpressed buttons and highlights them. ++ Added a route helper for Gunther's Rift Race in the West Village. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) ++ Added the ability to mute Wilted Berberis sounds when not farming. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) #### Dungeon Features @@ -44,6 +51,21 @@ + Use /shhoppitystats for live stats. + Added optional warning when Hoppity calls you with a rabbit to sell. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) + Added hotkey for picking up Abiphone calls from Hoppity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) ++ Added a draggable list for Hoppity's Collection menu rabbit highlighting. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) + + Factory/Shop milestones = Yellow/Gold. + + Stray rabbits = Dark Aqua. + + Abi = Dark Green. ++ Added a toggle to highlight found rabbits in Hoppity's Collection menu. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) ++ Added the ability to change the color of missing rabbit dyes in Hoppity's Collection to reflect rabbit rarity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2522) + +#### The Carnival Features + ++ Added a Reminder to claim Carnival Tickets. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2498) ++ Added display for Carnival Goals. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2498) ++ Added a feature to double-click the Carnival NPC to start the game without clicking in the chat. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2498) ++ Added Zombie Shootout QoL improvements for the Carnival. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2497) + + Colored hitboxes. + + Lamp timer + line. #### GUI Features @@ -68,6 +90,15 @@ + Shows what items are currently inside the personal compactor/deletor, and whether the accessory is turned on or off. + Added Accessory magical power display as stack size. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2243) + Only works inside the Accessory Bag and Auction House. ++ Added `/gfs` to fix a broken Piggy Bank. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2150) ++ Added Superpair Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Displays found and matched pairs, power-ups, and missing pairs/normals. ++ Added Experiments Dry-Streak Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Shows attempts and XP since the last ULTRA-RARE. ++ Added Experiments Profit Tracker. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Tracks profits in Coins and Enchanting XP. ++ Added Ultimate Enchant Star. - Empa (https://github.com/hannibal002/SkyHanni/pull/2612) + + Shows a star on Enchanted Books with an Ultimate Enchant. #### Chat Features @@ -95,12 +126,48 @@ + Added Arachne Kill Timer. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/1993) + Shows how long it took to kill Arachne when the fight ends. ++ Added Broodmother spawn alert, countdown and stage change messages. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) + + Countdown will not show until a spawning stage change is observed, and may be off by a few seconds. ++ Added Broodmother support to the Damage Indicator. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) ++ Added Carry Tracker. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2185) + + Use `/shcarry` to add carries to a customer, and set a price for a slayer boss. + + Automatically counts slayer bosses you carry. + + Automatically tracks coins received from customers via `/trade`. + +#### Fishing Features + ++ Added Golden Fish Timer. - Empa (https://github.com/hannibal002/SkyHanni/pull/1941) + + Includes an option to warn you when to throw your rod. + + Shows how weak the golden fish is, as a nametag. + + Also works on Stranded. ++ Added an alert for Gold or Diamond Trophy Fish catches. - ReyMaratov (https://github.com/hannibal002/SkyHanni/pull/2615) + + Displays a popup with the trophy name, rarity, and amount of the catch. + + Optionally, also plays a sound.+ Added an alert for Gold or Diamond Trophy Fish catches. - ReyMaratov (https://github.com/hannibal002/SkyHanni/pull/2615) + + Displays a popup with the trophy name, rarity, and amount of the catch. + + Optionally, also plays a sound. #### Misc Features + Added a notification when you join a server you have joined previously. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2046) + Added warning when Non-God Pot effects are about to expire. - saga (https://github.com/hannibal002/SkyHanni/pull/2004) + Sends a title and plays a sound at a customizable time before the effect expires. ++ Added Area Navigation. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2468) + + Reused the logic from the Tunnel Maps Graphs (Glacite Tunnels), now applied to other islands. + + Displays a list of all areas on your current island. Click on a name to find a path to that area via pathfinding. + + Find a route to the Hoppity egg. Useful for islands with small, nested corridors. + + Get a title warning when entering an area. + + See area names in the world. + + Does not yet work with Spider's Den and Dungeon Hub. Only partial support for Farming Islands and the Rift. ++ Added option to hide pet nametag text. - Empa + j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/1880) ++ Added Transfer Cooldown Prevention. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/1751) + + Wait for the transfer cooldown to complete before sending commands like warp/is/hub. ++ Added highlighting for the active Beacon Effect. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2546) ++ Added navigation command. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2575) + + Use `/shnavigate ` to find interesting locations on your current SkyBlock island by searching for them. + + Displays a pathfinder to the location. + + Works with NPCs, points of interest, areas, slayer spots, emissaries, crimson mini-bosses, spots to mine ores, break crops, and kill mobs. + + Does not yet work with Spider's Den and Dungeon Hub (still needs to be mapped out). ++ Added a message to warp to Winter Island spawn when a Reindrake spawns. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2569) ### Improvements @@ -112,13 +179,20 @@ + Some icons in the Mining Event Display now use the texture of the item they represent. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2425) + E.g., Raffle Event -> Raffle Ticket. + Changed how Powder Tracker works to account for powder buffs. - Jordyrat + Empa (https://github.com/hannibal002/SkyHanni/pull/2394) ++ Added an option to hide all tooltips inside the Fossil Excavator. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2579) ++ Added support for using the Pickobulus ability for the Mineshaft Pity Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/2540) ++ Added Area Navigation support to Glacite Tunnels. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2544) ++ Updated wording in mineshaft pity breakdown ("efficient miner" -> "spread"). - Luna (https://github.com/hannibal002/SkyHanni/pull/2633) ++ Improved the wording of the Mining Event data error chat message. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2671) ++ Added Mining Effects (Powder Pumpkin, Filet O' Fortune, and Chilled Pristine Potato) to the Non-God Effect Display. - jani (https://github.com/hannibal002/SkyHanni/pull/2677) #### Diana Improvements + Added /warp stonks to the Burrow Warp Helper. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2399) -+ Added per-election season Diana Trackers. - !nea (https://github.com/hannibal002/SkyHanni/pull/2487) ++ Added per-election season Diana Trackers. - nea (https://github.com/hannibal002/SkyHanni/pull/2487) + This includes the Diana Profit Tracker and the Mythological Creature Tracker. + The data is stored moving forward, but there is currently no way to view anything other than the current year. ++ Changed the Diana Profit Tracker and Mythological Creature Tracker to always be visible when holding the Ancestral Spade in hand, even if Diana is not the mayor. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2496) #### Scoreboard Improvements @@ -128,6 +202,7 @@ + Added an opacity slider for the Custom Background Image in the Custom Scoreboard. - Empa (https://github.com/hannibal002/SkyHanni/pull/1837) + Added an Undo message when auto alignment inCustom Scoreboard gets disabled. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2402) + Added an option to show SkyBlock time on the custom scoreboard rounded to 10 minutes, similar to the vanilla scoreboard. - Luna (https://github.com/hannibal002/SkyHanni/pull/2443) ++ Reduced the frequency of scoreboard errors being displayed. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2672) #### Inventory Improvements @@ -140,6 +215,7 @@ + Added exceptions to the enchant parser. - Vixid (https://github.com/hannibal002/SkyHanni/pull/2254) + Stonk and non-mining tools with Efficiency 5 use the maximum enchant color. + Added a short cooldown between Experimentation Table Guardian Pet chat warnings. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2459) ++ Prevented the SB Menu from replacing items from Dungeons and Kuudra that are placed in the item pickup log. - Fazfoxy (https://github.com/hannibal002/SkyHanni/pull/2599) #### Chat Improvements @@ -157,11 +233,17 @@ #### Hoppity Improvements + Added config option to disable rarity in Compact Hoppity messages. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2383) ++ Chocolate Factory: Shows "time to next milestone" instead of "max milestone" when you are at Prestige 6. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2503) ++ Added the required chocolate amount to the tooltip of milestone rabbits in Hoppity's Collection. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2523) ++ Improved the responsiveness of Hoppity Chat Compacting. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2488) ++ Added the ability to see how many duplicates you have previously found in Hoppity messages. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2556) ++ Improved the formatting of the Hoppity Event Stats card. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2638) #### Combat Improvements + Made the "Line to Arachne" width configurable. - azurejelly (https://github.com/hannibal002/SkyHanni/pull/2406) + Made the "Line to Miniboss" width configurable. - azurejelly (https://github.com/hannibal002/SkyHanni/pull/2406) ++ Added item cooldown support for Blaze Flares. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2601)+ Added item cooldown support for Blaze Flares. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2601) #### Config Improvements @@ -176,10 +258,25 @@ + Changed suggested cactus speed to 464 again. - DarkDash (https://github.com/hannibal002/SkyHanni/pull/2424) + Since the cactus knife now allows 500 max speed. + Made the waypoint to the middle of the plot for Pest Waypoint optional (off by default). - Luna (https://github.com/hannibal002/SkyHanni/pull/2469) ++ Reduced one click for supercrafting visitor materials by using `/viewrecipe` instead of `/recipe` when using the Shopping List button. - Miestiek (https://github.com/hannibal002/SkyHanni/pull/2505) ++ Added ignored crops for the Farming Lane feature. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2622) ++ Made the Visitor Timer GUI clickable to teleport to the Barn. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2658) #### Rift Improvements + Updated the description of the config for Enigma Soul Waypoints to help find the Rift Guide in the game. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2433) ++ Added Path Finder to Enigma Soul waypoints in the Rift. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2515) ++ Added the option to choose the color of the Living Metal Helper highlight. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) ++ Added an option to hide players while in Gunther's Rift Race. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2655) + +#### Dungeon Improvements + ++ Added dungeon stars and crimson stars to estimated item value. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2492) + +#### The Carnival Improvements + ++ Updated the Zombie Shootout Diamond color to be a deeper blue. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2511) ++ Added a cooldown to the Carnival NPC Quickstart feature. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2628) #### Misc Improvements @@ -187,6 +284,19 @@ + Added search functionality to some SkyHanni GUIs. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2477) + Search works in all SkyHanni Trackers and the Sack Display. + In your inventory, hover over the GUI with your mouse, then start typing to search. ++ Improved the performance of pathfinding logic in Area Navigation. - nea (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Added a toggle to force the `en_US` locale for number formatting. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2563) ++ Queued GfS will now always fall back to a default amount if one is not specified. - Luna (https://github.com/hannibal002/SkyHanni/pull/2584) ++ Improved pathfinding. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2597) + + The line to the target no longer jumps around as much. + + Progress to the target now shows up in chat, displaying blocks remaining and percentage completed. Clicking on the chat message cancels the pathfinding. ++ Added a warning in chat when the computer's time is inaccurate, along with a tutorial on how to fix it. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2623) ++ Improved the way pathfinding lines are rendered. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2634) ++ Automatically starts pathfinding after clicking on SkyHanni reminder chat messages about Carnival Reminder, Hoppity NPC, City Project, and account/profile upgrades. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2635) ++ Greatly improved performance by optimizing SkyHanni Chroma support for Patcher Font Renderer. - nopo (https://github.com/hannibal002/SkyHanni/pull/2666) ++ "Could not find server id" errors are now less common. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2680) ++ Clarified the wording of Bazaar Data Loading error messages. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2681) ++ Indicate in the CF menu when the chocolate amount has reached the cap and is therefore halted. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2688) ### Fixes @@ -199,6 +309,7 @@ #### Bingo Fixes + Fixed "show bingo rank number" feature toggle not functioning. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2445) ++ Fixed Custom Scoreboard not showing Carnival Lines on Bingo. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2631) #### Inventory Fixes @@ -215,6 +326,21 @@ + Fixed skull sizes inside the Personal Compactor Overlay. - Empa (https://github.com/hannibal002/SkyHanni/pull/2486) + Fixed the Auction House Price Comparison appearing in your own inventory as well. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2483) + Fixed "click to show tunnel map" from the Glacite Mines commission menu appearing in the inventory. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2485) ++ Fixed Mouse Keys not working as Wardrobe Slot Hotkeys. - j10a1n15, ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2506) ++ Fixed Estimated Item Value incorrectly showing all Kuudra armor as starred. - Luna (https://github.com/hannibal002/SkyHanni/pull/2550) ++ Fixed Experiments Profit Tracker & Superpair Data. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2560) ++ Fixed price per unit for Stonk of Stonks auction not working for the bracket you are in. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2572) ++ Fixed bugs in the Experiments Profit Tracker. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2594) + + Corrected the count for bottles applied while being inside the experimentation table. + + Fixed `/shedittracker` support not functioning properly. ++ Fixed an issue where the item stack size on Diamond/Golden Heads and Master Skulls could be incorrect. - Fazfoxy (https://github.com/hannibal002/SkyHanni/pull/2611) ++ Fixed item category detection for recombobulated items. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2608) ++ Fixed bugs in Superpair Data. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2566) + + Fixed pair detection. + + Fixed enchanting XP detection. ++ Fixed Minister in Calendar Perk description sometimes not using the gray color. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2632) ++ Fixed highlighting items in one's own inventory for some Bazaar features, e.g., in the "click to re-order" feature. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2640) ++ Automatically remove incorrect Account/Profile Upgrade warnings by talking to Elizabeth. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2674) #### Mining Fixes @@ -224,6 +350,26 @@ + Fixed Powder for 10 Levels overflowing over the max level. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2422) + Fixed Glacite Tunnel Maps repeatedly showing the last commission goal even when there is no new commission. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2432) + Fixed Mineshaft Pity Counter not working with some ore types. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2436) ++ Fixed Tungsten Ore and Hardstone detection after the mining update. - Empa (https://github.com/hannibal002/SkyHanni/pull/2437) ++ Fixed item category errors after the new mining update. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2529) ++ Fixed blocks mined by Efficient Miner not being detected. - Empa (https://github.com/hannibal002/SkyHanni/pull/2526) ++ Fixed Corpse Tracker resetting items between restarts. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2528) ++ Fixed the Corpse Tracker not displaying while in the Mineshaft. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2516) ++ Fixed Hardstone and Tungsten not being properly detected in Mineshafts. - Empa (https://github.com/hannibal002/SkyHanni/pull/2536) ++ Fixed Heart of the Mountain showing outdated perks and powder information. - Tryp0xd (https://github.com/hannibal002/SkyHanni/pull/2543) ++ Fixed Sky Mall perks not being read correctly after the Hypixel update. - Luna (https://github.com/hannibal002/SkyHanni/pull/2551) ++ Fixed Mining Commission Blocks Color not working properly with Connected Textures. - Empa (https://github.com/hannibal002/SkyHanni/pull/2553) ++ Fixed Gemstone Gauntlet item category. - Luna (https://github.com/hannibal002/SkyHanni/pull/2534) ++ Fixed Glacite powder being tracked as Glacite in Corpse Tracker. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2557) ++ Fixed "Mining Commissions Block Color" disabling OptiFine connected textures. - nopo (https://github.com/hannibal002/SkyHanni/pull/2559) ++ Fixed some blocks in the Crystal Hollows being detected as Mithril instead of Hard Stone. - Luna (https://github.com/hannibal002/SkyHanni/pull/2580) ++ Fixed "Mining Commissions Block Color" causing OptiFine connected textures not to connect properly. - nopo (https://github.com/hannibal002/SkyHanni/pull/2577) ++ Fixed the Mineshaft Pity Counter not working in the Great Glacite Lake. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2565) ++ Fixed Powder Tracker inaccuracies. - Empa (https://github.com/hannibal002/SkyHanni/pull/2591) ++ Fixed Jasper gemstones not being addressed in the Powder Mining filter. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2618) ++ Fixed the King Talisman Tracker sometimes not displaying the correct data. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2663) ++ Fixed the Powder Tracker not tracking items correctly. - HiZe (https://github.com/hannibal002/SkyHanni/pull/2645) ++ Fixed an error in Powder Tracker. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2678) #### Scoreboard Fixes @@ -242,6 +388,14 @@ + Fixed Custom Scoreboard errors while doing Carnival activities. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2455) + Fixed Custom Scoreboard error while in a Dungeon Queue. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2441) + Fixed Custom Scoreboard Error during the Barry Protestors Quest. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2480) ++ Fixed a Custom Scoreboard error during the Magma Boss Fight and Goblin Raid. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2531) ++ Fixed a Custom Scoreboard error while in the Dojo. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2519) ++ Fixed a Custom Scoreboard error during M7 Dragons. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2510) ++ Fixed Custom Scoreboard error during the Raffle Event. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2545) ++ Fixed both the Custom Scoreboard Active and Starting Soon Tab List events being active simultaneously in the Garden. - Empa, j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2592) ++ Fixed Custom Scoreboard not showing the Perkpocalypse Mayor. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2683) ++ Fixed some scoreboard error messages appearing in chat. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2672) ++ Fixed the custom scoreboard not updating when the Hypixel scoreboard is not updating. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2685) #### Hoppity Fixes @@ -250,27 +404,22 @@ + Fixed "Highlight Requirement Rabbits" requiring "Hoppity Collection Stats" to function. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2398) + Fixed minor formatting issues with Hoppity Event Summary. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2416) + Fixed Hoppity Event stats resetting. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2489) - -#### Misc Fixes - -+ Fixed Mayor Detection failing when Special Mayors are in office. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2389) -+ Updated Derpy's extra tax perk to use the correct name. - Luna (https://github.com/hannibal002/SkyHanni/pull/2393) -+ Fixed Christmas presents in the Hypixel lobby being visible outside of December. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2396) -+ Fixed the mod crashing on startup when the game directory path contains a "!". - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2427) -+ Fixed chat formatting for coin drops in profit trackers (Diana, Slayer, Fishing, Pest). - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2444) -+ Fixed Last Server Time Slider not functioning. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2440) -+ Fixed warning sounds being stuttered and cutting out. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2482) -+ Fixed an internal bug with `getItemName` that caused the `NEUInternalName.NONE has no name!` error messages to appear. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2471) -+ Fixed a typo in mob detection config. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2472) ++ Fixed an issue where Fish the Rabbit and El Dorado did not have compacted chat messages. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2488) ++ Fixed inconsistencies in Hoppity Duplicate Number counts. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2595) ++ Fixed Fish the Rabbit and El Dorado incorrectly counting as unique rabbits during Hoppity's Hunt. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2627) ++ Fixed Hoppity Collection Display not updating the rabbit count in some cases, e.g., when collecting rabbits on alpha or manually changing the config values. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2686) ++ Fixed the chocolate count increasing in other menus even when production is halted. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2688) #### Chat Fixes + Fixed an error with Patcher Coordinate Detection from chat. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2410) + Fixed ultimate enchants not showing in `/show`. - Vixid (https://github.com/hannibal002/SkyHanni/pull/2465) ++ Fixed being unable to shift-click on chat messages. - nopo (https://github.com/hannibal002/SkyHanni/pull/2650) #### Commands Fixes + Fixed the command `/shtps` printing nothing if the TPS display was currently showing nothing. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2446) ++ Fixed "/viewrecipe command replace" breaking pages. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2679) #### Dungeon Fixes @@ -282,6 +431,64 @@ + Fixed the reputation helper not updating after a sack update. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2439) + Fixed Heavy Pearls sometimes not being highlighted. - Luna (https://github.com/hannibal002/SkyHanni/pull/2479) ++ Added a delay to the Pablo helper message so it appears after he finishes his dialogue. - Luna (https://github.com/hannibal002/SkyHanni/pull/2662) + +#### Garden Fixes + ++ Fixed outdated Dicer gemstone fortune in FF guide. - not_a_cow (https://github.com/hannibal002/SkyHanni/pull/2499) ++ Fixed some garden messages not being blocked. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2532) ++ Fixed active sprays not being removed from the GUI when using a washer. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2532) + +#### Combat Fixes + ++ Updated Ghost Counter bestiary tiers to reflect Hypixel reducing the max kills needed from 250K to 100K. - Luna (https://github.com/hannibal002/SkyHanni/pull/2533) ++ Fixed a case where the Broodmother countdown could be wildly inaccurate. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2513) ++ Fixed Flare Display spamming chat with negative values when the server is lagging. - Stella (https://github.com/hannibal002/SkyHanni/pull/2567) ++ Fixed a case where the Imminent stage did not update the Broodmother countdown. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2602)v ++ Fixed some Islands Dummy mob types not being detected by the Damage Indicator. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2646) ++ Fixed the Ender Node Tracker not detecting some items. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2644) ++ Fixed Flare Expiration warnings not appearing in chat or as a title. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2643) + +#### The Carnival Fixes + ++ Fixed two "Catch a Fish" carnival goals not being properly detected from chat. - Luna (https://github.com/hannibal002/SkyHanni/pull/2517) ++ Fixed the bounding box of baby zombies in Zombie Shootout. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2512) + +#### Fishing Fixes + ++ Fixed error messages while using the Chum Bucket Hider feature. - nea (https://github.com/hannibal002/SkyHanni/pull/2587) ++ Fixed the Trophy Fish Title displaying an undefined character in the format. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2670) + +#### Rift Fixes + ++ Fixed the Rift Timer pausing while in Gunther's Rift Race. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) + +#### Misc Fixes + ++ Fixed Mayor Detection failing when Special Mayors are in office. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2389) ++ Updated Derpy's extra tax perk to use the correct name. - Luna (https://github.com/hannibal002/SkyHanni/pull/2393) ++ Fixed Christmas presents in the Hypixel lobby being visible outside of December. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2396) ++ Fixed the mod crashing on startup when the game directory path contains a "!". - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2427) ++ Fixed chat formatting for coin drops in profit trackers (Diana, Slayer, Fishing, Pest). - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2444) ++ Fixed Last Server Time Slider not functioning. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2440) ++ Fixed warning sounds being stuttered and cutting out. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2482) ++ Fixed an internal bug with `getItemName` that caused the `NEUInternalName.NONE has no name!` error messages to appear. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2471) ++ Fixed a typo in mob detection config. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2472) ++ Fixed performance issues with a high number of dungeon runs in one session. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2504) ++ Fixed `/shedittracker duplex` not working. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2501) ++ Fixed "Last Server Joined" spamming the chat. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2495) ++ Fixed lag spikes in Path Finder. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2525) ++ Fixed old mayor perks not being marked as inactive when the mayor changes. - Luna (https://github.com/hannibal002/SkyHanni/pull/2524) ++ Fixed direct GitHub downloads triggering the source checker. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2548) ++ Fixed reforge display not working with new mining stats. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2555) ++ Fixed Totem of Corruption expiry warning not working in some cases. - Luna (https://github.com/hannibal002/SkyHanni/pull/2554) ++ Fixed a few typos in the config. - rdbt (https://github.com/hannibal002/SkyHanni/pull/2585) ++ Fixed Area Navigation distances to player being incorrect. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2634) ++ Fixed item trackers displaying removed item names incorrectly. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2620) ++ Fixed some messages from Pablo NPC not being detected. - Luna (https://github.com/hannibal002/SkyHanni/pull/2636) ++ Fixed SkyHanni re-downloading the repository on every launch. - nopo (https://github.com/hannibal002/SkyHanni/pull/2669) ++ Fixed unknown Perkpocalypse Mayor chat spam. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2683) ++ Fixed the wiki keybind searching for "null" on items with no internal name. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2682) ### Technical Details @@ -313,11 +520,63 @@ + Changed RenderableTooltips to be more consistent with the vanilla ones. - Empa (https://github.com/hannibal002/SkyHanni/pull/1869) + Improved error logging for enchant parser. - Vixid (https://github.com/hannibal002/SkyHanni/pull/2454) + Added renderable search box. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2475) -+ Added the ability to add more optional display modes to trackers. - !nea (https://github.com/hannibal002/SkyHanni/pull/2487) ++ Added the ability to add more optional display modes to trackers. - nea (https://github.com/hannibal002/SkyHanni/pull/2487) + These extra trackers still need to provide their own storage. + Added perk descriptions to mayor perks. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2342) + These are loaded when checking the active mayor/minister from the API, so most of the perks will initially have no description. + Added a method to override an ItemStack's lore. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2342) ++ Updated HandleEvent onlyOnIslands to handle multiple islands. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2502) ++ Added an abstract "bucketed" tracker that can store where items came from. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2306) + + Takes an enum in instantiation and has built-in logic for swapping display types. ++ Graph Editor improvements. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2515) + + Code cleanup in Graph Editor, moving node lists into their own class. + + Fixed searchable tag list. + + Added more graph node tags; only display certain tags on specific islands in the editor. + + Added an option to limit the maximum render range of nodes and edges in the Graph Editor for better performance. ++ Hoppity's Collection highlighting now updates on event triggers instead of every frame. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) ++ Added `select near look` keybind in Graph Editor. - nea (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Added checks to avoid creating bugs with the area structure in Graph Editor. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Added options to the graph node list to hide nodes with certain tags. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Removed the use of `LorenzChatEvent()` for 'manually' adding data to Hoppity Chat Compact. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2488) + + Now uses `EggFoundEvent()`. ++ The Renderable Wrapped String now has an option to align text inside the wrapped string box. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2372) ++ Improved handling of unknown stats for ReforgeAPI. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2562) ++ Added `AreaChangeEvent`. - Empa (https://github.com/hannibal002/SkyHanni/pull/2535) ++ Updated `HandleEvent` to allow `onlyOnIsland` usage for a single island without brackets. - Empa (https://github.com/hannibal002/SkyHanni/pull/2535) ++ Created a Text method to display a paginated list. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2583) + + Moved existing paged lists in `/shcommands` and `/shremind` to use this. ++ Node Tags filter list in Graph Editor now sorts by nodes per tag. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2575) ++ Additional code cleanup around ingredients. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2576) ++ Removed duplicate rounding functions. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1931) ++ Added HTTP Request Patching. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2578) ++ Removed references to NEU code, especially code from the Utils class in NEU. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2419) ++ Banned importing `io.github.moulberry.notenoughupdates.util.Utils`. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2419) ++ Added common live templates. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2463) + + These can be automatically imported via the plugin "Live Templates Sharing". ++ Created and used primitive recipe and ingredient classes. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2460) + + These are added as a layer between SkyHanni and NEU so that we are not reliant on NEU functions. ++ Added Blossom Gradle plugin for token replacement in code. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2558) + + `@MOD_VERSION@` is now a token that will be replaced. ++ Added `detekt` runner to the build process. - Daveed & nea (https://github.com/hannibal002/SkyHanni/pull/2547) ++ Added Clock Offset Millis using an NTP server. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2623) ++ Added `EntityMovementData.onNextTeleport()` logic, which triggers a runnable after the world has changed or the player has teleported. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2635) ++ Added Bazaar Fetch information to `/shdebug`. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2675) ++ Removed the password from the download source check. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2649) ++ Added a missing SkyBlock check for debug commands `/shtrackparticles` and `/shtracksounds`. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2641) ++ Prepared for later migration of correct config name of Plhlegblast. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2684) ++ Added the ability to disable SkyHanni errors via repo configuration. - nopo (https://github.com/hannibal002/SkyHanni/pull/2668) ++ Added current server ID and fetch data to the `/shdebug` command. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2680) ++ Added more `/shdebug` checks for aspects like OS, Java version, and launcher. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2691) + +### Removed Features + ++ Removed Wild Strawberry Dye notification. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2520) + + Artist's Abode now sends a lobby-wide message for dye drops, making the notification obsolete. ++ Removed `Only Requirement Not Met` and `Highlight Requirement Rabbits` config options. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) + + Replaced then with a draggable list of different Hoppity collection highlight options. ++ Removed "Forge GfS". - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2564) + + Hypixel now pulls directly from sacks when using the forge. ++ Removed Mithril Powder from the Powder Tracker. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2656) ## Version 0.26 diff --git a/docs/FEATURES.md b/docs/FEATURES.md index c12bee86ac0d..a57725958d57 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -224,6 +224,8 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Can be enabled/disabled on the Item Number list. + Item Pickup Log. - catgirlseraid (https://github.com/hannibal002/SkyHanni/pull/1937) + Display the price per Stonk when taking the minimum bid in the Stonks Auction (Richard Menu). - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2195) ++ Added Ultimate Enchant Star. - Empa (https://github.com/hannibal002/SkyHanni/pull/2612) + + Shows a star on Enchanted Books with an Ultimate Enchant.
@@ -365,6 +367,13 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Option to show only when wearing a full hunter armor set. + Options to show checkmarks or crosses instead of numbers. + Hover over a trophy fish to see the percentage caught and how to gain progress. ++ Added Golden Fish Timer. - Empa (https://github.com/hannibal002/SkyHanni/pull/1941) + + Includes an option to warn you when to throw your rod. + + Shows how weak the golden fish is, as a nametag. + + Also works on Stranded. ++ Added an alert for Gold or Diamond Trophy Fish catches. - ReyMaratov (https://github.com/hannibal002/SkyHanni/pull/2615) + + Displays a popup with the trophy name, rarity, and amount of the catch. + + Optionally, also plays a sound.
@@ -387,6 +396,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. - Garden Pests in Damage Indicator - **Time to Kill** - Show the time it takes to kill the Slayer boss. ++ Added Broodmother support to the Damage Indicator. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) + **Vampire Slayer** + Show the amount of HP missing until the steak can be used on the vampire slayer on top of the boss. @@ -831,6 +841,10 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Added Crafting Room Helper. - HiZe (https://github.com/hannibal002/SkyHanni/pull/2178) + Shows a holographic mob at the location where the mob is present in the real room inside the Mirrorverse in Rift. + Added Rift Time Real-Time Nametag Format. - Empa (https://github.com/hannibal002/SkyHanni/pull/2015) ++ Added a helper for tracking the Buttons Enigma Soul in the Rift. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) + + Using pathfinding to guide the player to the nearest spot with unpressed buttons and highlights them. ++ Added a route helper for Gunther's Rift Race in the West Village. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616) ++ Added the ability to mute Wilted Berberis sounds when not farming. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2616)
@@ -859,6 +873,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Option to show the walls also when inside the Nucleus. + Fossil Excavator Solver. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1427) + Shows where to next click for optimal chance of solving the fossil. If there is a fossil this will find it within 18 moves. ++ Hides tooltips of items inside the Fossil Excavator in Glacite Tunnels. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2539) + Excavation Profit Tracker. - hannibal2 + Empa (https://github.com/hannibal002/SkyHanni/pull/1432) + Count all drops you gain while excavating in the Fossil Research Center. + Track Glacite Powder gained as well (no profit, but progress). @@ -892,6 +907,8 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Mineshaft Pity Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/1655) + Displays information about Mineshaft spawns, your progress towards a Pity Mineshaft, and more. + Added a "Get from Sack" button in the forge recipe menu to retrieve ingredients. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2106) ++ Added Tracker for Glacite Corpses. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2306) + + Tracks overall loot and loot per type.
@@ -982,6 +999,21 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Use /shhoppitystats for live stats. + Added optional warning when Hoppity calls you with a rabbit to sell. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) + Added hotkey for picking up Abiphone calls from Hoppity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) ++ Added a draggable list for Hoppity's Collection menu rabbit highlighting. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) + + Factory/Shop milestones = Yellow/Gold. + + Stray rabbits = Dark Aqua. + + Abi = Dark Green. ++ Added a toggle to highlight found rabbits in Hoppity's Collection menu. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) ++ Added the ability to change the color of missing rabbit dyes in Hoppity's Collection to reflect rabbit rarity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2522) + +### The Carnival + ++ Added a Reminder to claim Carnival Tickets. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2498) ++ Added display for Carnival Goals. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2498) ++ Added a feature to double-click the Carnival NPC to start the game without clicking in the chat. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2498) ++ Added Zombie Shootout QoL improvements for the Carnival. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2497) + + Colored hitboxes. + + Lamp timer + line.
@@ -1134,6 +1166,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Customizable GUI + Option to hide the chat messages + While on the Winter Island, show a timer until Jerry's Workshop closes. - hannibal2 ++ Added a message to warp to Winter Island spawn when a Reindrake spawns. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2569) + **Custom Text Box** - CalMWolfs + Write fancy text into a gui element to show on your screen at all time + Supports color codes @@ -1306,9 +1339,16 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Added to the Item Number list. + Added Compact Experimentation Table chat rewards. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2209) + Uses a compact chat message of rewards gained from Add-ons/Experiments. ++ Added Superpair Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Displays found and matched pairs, power-ups, and missing pairs/normals. ++ Added Experiments Dry-Streak Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Shows attempts and XP since the last ULTRA-RARE. ++ Added Experiments Profit Tracker. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Tracks profits in Coins and Enchanting XP. + In-Water Display. - Stella (https://github.com/hannibal002/SkyHanni/pull/1892) + Useful when using a Prismarine Blade in Stranded Mode. + Added Beacon Power Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/1901) ++ Added highlighting for the active Beacon Effect. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2546) + Added Hide Useless Armor Stands. - Empa (https://github.com/hannibal002/SkyHanni/pull/1962) + Hides armor stands that briefly appear on Hypixel. + **Custom Wardrobe**, a new look for the wardrobe. - j10an15, Empa (https://github.com/hannibal002/SkyHanni/pull/2039) @@ -1338,6 +1378,28 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Allows the display of information from the Tab (e.g., Bestiary info). + Added Accessory magical power display as stack size. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2243) + Only works inside the Accessory Bag and Auction House. ++ Added Area Navigation. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2468) + + Reused the logic from the Tunnel Maps Graphs (Glacite Tunnels), now applied to other islands. + + Displays a list of all areas on your current island. Click on a name to find a path to that area via pathfinding. + + Find a route to the Hoppity egg. Useful for islands with small, nested corridors. + + Get a title warning when entering an area. + + See area names in the world. + + Does not yet work with Spider's Den and Dungeon Hub. Only partial support for Farming Islands and the Rift. ++ Added navigation command. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2575) + + Use `/shnavigate ` to find interesting locations on your current SkyBlock island by searching for them. + + Displays a pathfinder to the location. + + Works with NPCs, points of interest, areas, slayer spots, emissaries, crimson mini-bosses, spots to mine ores, break crops, and kill mobs. + + Does not yet work with Spider's Den and Dungeon Hub (still needs to be mapped out). ++ Added `/gfs` to fix a broken Piggy Bank. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2150) ++ Added Broodmother spawn alert, countdown and stage change messages. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) + + Countdown will not show until a spawning stage change is observed, and may be off by a few seconds. ++ Added option to hide pet nametag text. - Empa + j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/1880) ++ Added Transfer Cooldown Prevention. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/1751) + + Wait for the transfer cooldown to complete before sending commands like warp/is/hub. ++ Added Carry Tracker. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2185) + + Use `/shcarry` to add carries to a customer, and set a price for a slayer boss. + + Automatically counts slayer bosses you carry. + + Automatically tracks coins received from customers via `/trade`.
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 634e49064ec5..926ed02850e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,3 +10,6 @@ libautoupdate = { module = "moe.nea:libautoupdate", version.ref = "libautoupdate headlessLwjgl = { module = "com.github.3arthqu4ke.HeadlessMc:headlessmc-lwjgl", version.ref = "headlessLwjgl" } jbAnnotations = { module = "org.jetbrains:annotations", version.ref = "jbAnnotations" } hotswapagentforge = { module = "moe.nea:hotswapagent-forge", version = "1.0.1" } +autoservice_ksp = {module="dev.zacsweers.autoservice:auto-service-ksp",version="1.1.0"} +autoservice_annotations = {module="com.google.auto.service:auto-service-annotations",version="1.1.1"} + diff --git a/pull_request_template.md b/pull_request_template.md index 2dd04bcec865..02769a0f8470 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,4 +1,6 @@ - + + ## Dependencies - pr_number_or_link_here @@ -21,7 +25,7 @@ Describe what this pull request does, including technical details, screenshots, ## Changelog New Features + Cool new feature. - your_name_here - * extra info + * Extra info. ## Changelog Improvements + Improved cool feature. - your_name_here diff --git a/root.gradle.kts b/root.gradle.kts index 6bfee57db573..a121d65f8dcb 100644 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -3,16 +3,39 @@ import com.replaymod.gradle.preprocess.Node plugins { id("dev.deftu.gradle.preprocess") version "0.6.1" + id("net.kyori.blossom") version "1.3.2" apply false id("gg.essential.loom") version "1.6.+" apply false kotlin("jvm") version "2.0.0" apply false kotlin("plugin.power-assert") version "2.0.0" apply false id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false id("dev.architectury.architectury-pack200") version "0.1.3" + id("io.gitlab.arturbosch.detekt") version "1.23.7" apply false } allprojects { group = "at.hannibal2.skyhanni" - version = "0.27.Beta.7" + version = "0.27" + repositories { + mavenCentral() + mavenLocal() + maven("https://maven.minecraftforge.net") { + metadataSources { + artifact() // We love missing POMs + } + } + maven("https://repo.spongepowered.org/maven/") // mixin + maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") // DevAuth + maven("https://jitpack.io") { + // NotEnoughUpdates (compiled against) + content { + includeGroupByRegex("(com|io)\\.github\\..*") + } + } + maven("https://repo.nea.moe/releases") // libautoupdate + maven("https://maven.notenoughupdates.org/releases") // NotEnoughUpdates (dev env) + maven("https://repo.hypixel.net/repository/Hypixel/") // mod-api + maven("https://maven.teamresourceful.com/repository/thatgravyboat/") // DiscordIPC + } } preprocess { @@ -20,8 +43,9 @@ preprocess { ProjectTarget.activeVersions().forEach { target -> nodes[target] = createNode(target.projectName, target.minecraftVersion.versionNumber, target.mappingStyle.identifier) val p = project(target.projectPath) - if (target.isForge) + if (target.isForge) { p.extra.set("loom.platform", "forge") + } } ProjectTarget.activeVersions().forEach { child -> val parent = child.linkTo ?: return@forEach diff --git a/settings.gradle.kts b/settings.gradle.kts index aaf0f02cf6d6..987b70013456 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,6 +14,7 @@ pluginManagement { maven("https://repo.nea.moe/releases") maven("https://repo.sk1er.club/repository/maven-releases/") maven("https://maven.deftu.dev/releases") + maven("https://maven.teamresourceful.com/repository/maven-private/") // Blossom maven("https://jitpack.io") { content { includeGroupByRegex("(com|io)\\.github\\..*") @@ -37,6 +38,7 @@ plugins { MultiVersionStage.initFrom(file(".gradle/private.properties")) include("annotation-processors") +include("detekt") rootProject.name = "SkyHanni" rootProject.buildFileName = "root.gradle.kts" diff --git a/sharedVariables/src/MinecraftVersion.kt b/sharedVariables/src/MinecraftVersion.kt index 7384c8fbd49b..796cc0d709a6 100644 --- a/sharedVariables/src/MinecraftVersion.kt +++ b/sharedVariables/src/MinecraftVersion.kt @@ -16,6 +16,9 @@ enum class MinecraftVersion( val javaLanguageVersion = JavaLanguageVersion.of(javaVersion) + val formattedJavaLanguageVersion: String + get() = if (javaVersion <= 8) "1.$javaVersion" else javaVersion.toString() + val versionNumber = run { val parts = versionName.split('.').mapTo(mutableListOf()) { it.toInt() } if (parts.size == 2) parts.add(0) diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 442441825a5c..45d02f5445f6 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -42,7 +42,7 @@ import org.apache.logging.log4j.Logger clientSideOnly = true, useMetadata = true, guiFactory = "at.hannibal2.skyhanni.config.ConfigGuiForgeInterop", - version = "0.27.Beta.7", + version = "@MOD_VERSION@", ) class SkyHanniMod { diff --git a/src/main/java/at/hannibal2/skyhanni/api/DataWatcherAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/DataWatcherAPI.kt index 94931dd8caf8..e7e7fd2b5ac3 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/DataWatcherAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/DataWatcherAPI.kt @@ -8,7 +8,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object DataWatcherAPI { - private val DATA_VALUE_CUSTOM_NAME = 2 + private const val DATA_VALUE_CUSTOM_NAME = 2 @SubscribeEvent fun onDataWatcherUpdate(event: DataWatcherUpdatedEvent) { diff --git a/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt index 7407dd66053a..4d7662b4f452 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt @@ -163,7 +163,7 @@ object GetFromSackAPI { } private fun bazaarMessage(item: String, amount: Int, isRemaining: Boolean = false) = ChatUtils.clickableChat( - "§lCLICK §r§eto get the ${if (isRemaining) "remaining " else ""}§ax${amount} §9$item §efrom bazaar", + "§lCLICK §r§eto get the ${if (isRemaining) "remaining " else ""}§ax$amount §9$item §efrom bazaar", onClick = { HypixelCommands.bazaar(item.removeColor()) }, "§eClick to find on the bazaar!", ) @@ -173,8 +173,6 @@ object GetFromSackAPI { // The last parameter could be "2*3". This does not support ending with ")", but it is good enough val argsNull = !args.last().last().isDigit() val arguments = if (argsNull) { - if (!config.defaultGFS) return CommandResult.WRONG_ARGUMENT to null - args + config.defaultAmountGFS.toString() } else args @@ -184,7 +182,7 @@ object GetFromSackAPI { if (!amountString.isDouble()) return CommandResult.WRONG_AMOUNT to null val itemString = arguments.dropLast(1).joinToString(" ").uppercase().replace(':', '-') - val replacedString = itemString.replace("_"," ") + val replacedString = itemString.replace("_", " ") val item = when { SackAPI.sackListInternalNames.contains(itemString) -> itemString.asInternalName() diff --git a/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt index 97e041a89475..f2b2756554a3 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt @@ -74,7 +74,7 @@ object HotmAPI { /** Use when new powder gets collected*/ fun gain(difference: Long) { - ChatUtils.debug("Gained §a${difference.addSeparators()} §e${displayName} Powder") + ChatUtils.debug("Gained §a${difference.addSeparators()} §e$displayName Powder") addTotal(difference) addCurrent(difference) PowderGainEvent(this, difference).post() @@ -91,10 +91,10 @@ object HotmAPI { var mineshaftMayhem: MayhemPerk? = null enum class SkymallPerk(chat: String, itemString: String) { - MINING_SPEED("Gain §r§a\\+100 §r§6⸕ Mining Speed§r§f\\.", "Gain §a\\+100 §6⸕ Mining Speed§7\\."), - MINING_FORTUNE("Gain §r§a\\+50 §r§6☘ Mining Fortune§r§f\\.", "Gain §a\\+50 §6☘ Mining Fortune§7\\."), + MINING_SPEED("Gain §r§6\\+100⸕ Mining Speed§r§f\\.", "Gain §6\\+100⸕ Mining Speed§7\\."), + MINING_FORTUNE("Gain §r§6\\+50☘ Mining Fortune§r§f\\.", "Gain §6\\+50☘ Mining Fortune§7\\."), EXTRA_POWDER("Gain §r§a\\+15% §r§fmore Powder while mining\\.", "Gain §a\\+15% §7more Powder while mining\\."), - ABILITY_COOLDOWN("Reduce Pickaxe Ability cooldown by §r§a20%§r§f\\.", "Reduce Pickaxe Ability cooldown by"), + ABILITY_COOLDOWN("§r§a-20%§r§f Pickaxe Ability cooldowns\\.", "§a-20%§7 Pickaxe Ability cooldowns\\."), GOBLIN_CHANCE("§r§a10x §r§fchance to find Golden and Diamond Goblins\\.", "§a10x §7chance to find Golden and"), TITANIUM("Gain §r§a5x §r§9Titanium §r§fdrops", "Gain §a5x §9Titanium §7drops\\.") ; diff --git a/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt index 987a864af77e..534d38d47c82 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt @@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.data.model.SkyblockStat import at.hannibal2.skyhanni.data.model.SkyblockStatList import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemCategory import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull @@ -176,7 +177,18 @@ object ReforgeAPI { while (reader.hasNext()) { val name = reader.nextName() val value = reader.nextDouble() - list[SkyblockStat.valueOf(name.uppercase())] = value + + val stat = SkyblockStat.getValueOrNull(name.uppercase()) ?: run { + ErrorManager.logErrorStateWithData( + "Unknown stat: '${name.uppercase()}'", + "Stat list could not parse stat", + "failed" to name.uppercase(), + betaOnly = true, + ) + continue + } + + list[stat] = value } reader.endObject() return list diff --git a/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt index b40255449226..0e35e602fc61 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt @@ -392,7 +392,7 @@ object SkillAPI { ChatUtils.chat("§bSkill Custom Goal Level") val map = storage?.filter { it.value.customGoalLevel != 0 } ?: return if (map.isEmpty()) { - ChatUtils.chat("§cYou haven't set any custom goals yet!") + ChatUtils.userError("You haven't set any custom goals yet!") } map.forEach { (skill, data) -> ChatUtils.chat("§e${skill.displayName}: §b${data.customGoalLevel}") diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt index cfc8e63b87a8..d164e0e774d7 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt @@ -5,7 +5,8 @@ import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.LorenzUtils.inAnyIsland +import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.chat.Text import java.lang.invoke.LambdaMetafactory import java.lang.invoke.MethodHandles @@ -91,7 +92,8 @@ class EventHandler private constructor(val name: String, priv errors++ if (errors <= 3) { val errorName = throwable::class.simpleName ?: "error" - val message = "Caught an $errorName in ${listener.name} at $name: ${throwable.message}" + val aOrAn = StringUtils.optionalAn(errorName) + val message = "Caught $aOrAn $errorName in ${listener.name} at $name: ${throwable.message}" ErrorManager.logErrorWithData(throwable, message, ignoreErrorCache = onError != null) } onError?.invoke(throwable) @@ -113,7 +115,7 @@ class EventHandler private constructor(val name: String, priv private fun shouldInvoke(event: SkyHanniEvent, listener: Listener): Boolean { if (SkyHanniEvents.isDisabledInvoker(listener.name)) return false if (listener.options.onlyOnSkyblock && !LorenzUtils.inSkyBlock) return false - if (listener.options.onlyOnIsland != IslandType.ANY && !listener.options.onlyOnIsland.isInIsland()) return false + if (IslandType.ANY !in listener.onlyOnIslandTypes && !inAnyIsland(listener.onlyOnIslandTypes)) return false if (event.isCancelled && !listener.options.receiveCancelled) return false if ( event is GenericSkyHanniEvent<*> && @@ -129,6 +131,14 @@ class EventHandler private constructor(val name: String, priv val name: String, val invoker: Consumer, val options: HandleEvent, - val generic: Class<*>? - ) + val generic: Class<*>?, + ) { + val onlyOnIslandTypes: Set = getIslands(options) + + companion object { + private fun getIslands(options: HandleEvent): Set = + if (options.onlyOnIslands.isEmpty()) setOf(options.onlyOnIsland) + else options.onlyOnIslands.toSet() + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt index 39b047a6e1de..a88f7f33724c 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt @@ -12,9 +12,16 @@ annotation class HandleEvent( /** * If the event should only be received while on a specific skyblock island. + * To specify multiple islands, use [onlyOnIslands] instead. */ val onlyOnIsland: IslandType = IslandType.ANY, + /** + * If the event should only be received while being on specific skyblock islands. + * To specify only one island, use [onlyOnIsland] instead. + */ + vararg val onlyOnIslands: IslandType = [], + /** * The priority of when the event will be called, lower priority will be called first, see the companion object. */ diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt index 4f3685c8bdff..c05b438cde20 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt @@ -1,5 +1,8 @@ package at.hannibal2.skyhanni.api.event +/** + * Use @[HandleEvent] + */ abstract class SkyHanniEvent protected constructor() { var isCancelled: Boolean = false diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigGuiForgeInterop.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigGuiForgeInterop.kt index 0c112d73a307..3f2d398368d6 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigGuiForgeInterop.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigGuiForgeInterop.kt @@ -12,6 +12,7 @@ import java.io.IOException @Suppress("unused") class ConfigGuiForgeInterop : IModGuiFactory { + @Suppress("EmptyFunctionBlock") override fun initialize(minecraft: Minecraft) {} override fun mainConfigGuiClass() = WrappedSkyHanniConfig::class.java diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt index 4ac3f7925ce5..b00fc7a8f749 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt @@ -66,7 +66,8 @@ class ConfigManager { private fun setConfigHolder(type: ConfigFileType, value: Any) { require(value.javaClass == type.clazz) - @Suppress("UNCHECKED_CAST") (type.property as KMutableProperty0).set(value) + @Suppress("UNCHECKED_CAST") + (type.property as KMutableProperty0).set(value) (jsonHolder as MutableMap)[type] = value } @@ -104,6 +105,7 @@ class ConfigManager { // commands "features.garden.GardenConfig.cropSpeedMeterPos", "features.misc.MiscConfig.collectionCounterPos", + "features.misc.MiscConfig.carryPosition", "features.misc.MiscConfig.lockedMouseDisplay", // debug features @@ -181,7 +183,7 @@ class ConfigManager { try { run() } catch (e: Throwable) { - e.printStackTrace() + logger.log(e.stackTraceToString()) LorenzUtils.shutdownMinecraft("Config is corrupt inside development environment.") } } else { @@ -193,7 +195,7 @@ class ConfigManager { logger.log("Loaded $fileName from file") } catch (e: Exception) { - e.printStackTrace() + logger.log(e.stackTraceToString()) val backupFile = file.resolveSibling("$fileName-${SimpleTimeMark.now().toMillis()}-backup.json") logger.log("Exception while reading $file. Will load blank $fileName and save backup to $backupFile") logger.log("Exception was $e") @@ -201,7 +203,7 @@ class ConfigManager { file.copyTo(backupFile) } catch (e: Exception) { logger.log("Could not create backup for $fileName file") - e.printStackTrace() + logger.log(e.stackTraceToString()) } } } @@ -238,7 +240,7 @@ class ConfigManager { move(unit, file, reason) } catch (e: IOException) { logger.log("Could not save $fileName file to $file") - e.printStackTrace() + logger.log(e.stackTraceToString()) } } diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index c881cc578ba4..7c41245fc7f8 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt @@ -12,7 +12,7 @@ import com.google.gson.JsonPrimitive object ConfigUpdaterMigrator { val logger = LorenzLogger("ConfigMigration") - const val CONFIG_VERSION = 57 + const val CONFIG_VERSION = 61 fun JsonElement.at(chain: List, init: Boolean): JsonElement? { if (chain.isEmpty()) return this if (this !is JsonObject) return null diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index 7a17c14620cd..4974c80f2d51 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -33,6 +33,7 @@ import at.hannibal2.skyhanni.features.event.diana.InquisitorWaypointShare import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggLocations +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggLocator import at.hannibal2.skyhanni.features.event.hoppity.HoppityEventSummary import at.hannibal2.skyhanni.features.event.jerry.frozentreasure.FrozenTreasureTracker import at.hannibal2.skyhanni.features.fishing.tracker.FishingProfitTracker @@ -56,12 +57,14 @@ import at.hannibal2.skyhanni.features.garden.pests.PestFinder import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker import at.hannibal2.skyhanni.features.mining.KingTalismanHelper import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay -import at.hannibal2.skyhanni.features.mining.glacitemineshaft.CorpseTracker import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker +import at.hannibal2.skyhanni.features.mining.glacitemineshaft.CorpseTracker import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker import at.hannibal2.skyhanni.features.minion.MinionFeatures +import at.hannibal2.skyhanni.features.misc.CarryTracker import at.hannibal2.skyhanni.features.misc.CollectionTracker import at.hannibal2.skyhanni.features.misc.LockMouseLook import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager @@ -69,6 +72,7 @@ import at.hannibal2.skyhanni.features.misc.TpsCounter import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager import at.hannibal2.skyhanni.features.misc.limbo.LimboTimeTracker import at.hannibal2.skyhanni.features.misc.massconfiguration.DefaultConfigFeatures +import at.hannibal2.skyhanni.features.misc.pathfind.NavigationHelper import at.hannibal2.skyhanni.features.misc.reminders.ReminderManager import at.hannibal2.skyhanni.features.misc.update.UpdateManager import at.hannibal2.skyhanni.features.misc.visualwords.VisualWordGui @@ -76,7 +80,6 @@ import at.hannibal2.skyhanni.features.rift.area.westvillage.VerminTracker import at.hannibal2.skyhanni.features.rift.everywhere.PunchcardHighlight import at.hannibal2.skyhanni.features.slayer.SlayerProfitTracker import at.hannibal2.skyhanni.test.DebugCommand -import at.hannibal2.skyhanni.test.GraphEditor import at.hannibal2.skyhanni.test.PacketTest import at.hannibal2.skyhanni.test.SkyBlockIslandTest import at.hannibal2.skyhanni.test.SkyHanniConfigSearchResetCommand @@ -91,7 +94,8 @@ import at.hannibal2.skyhanni.test.command.CopyScoreboardCommand import at.hannibal2.skyhanni.test.command.TestChatCommand import at.hannibal2.skyhanni.test.command.TrackParticlesCommand import at.hannibal2.skyhanni.test.command.TrackSoundsCommand -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.test.graph.GraphEditor +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ExtendedChatColor import at.hannibal2.skyhanni.utils.ItemPriceUtils @@ -179,9 +183,10 @@ object Commands { ) registerCommand("shremind", "Set a reminder for yourself") { ReminderManager.command(it) } registerCommand("shwords", "Opens the config list for modifying visual words") { openVisualWords() } + registerCommand("shnavigate", "Using path finder to go to locatons") { NavigationHelper.onCommand(it) } } - + @Suppress("LongMethod") private fun usersNormal() { registerCommand( "shmarkplayer", @@ -190,8 +195,7 @@ object Commands { registerCommand("shtrackcollection", "Tracks your collection gain over time") { CollectionTracker.command(it) } registerCommand( "shcroptime", - "Calculates with your current crop per second speed " + - "how long you need to farm a crop to collect this amount of items", + "Calculates with your current crop per second speed how long you need to farm a crop to collect this amount of items", ) { GardenCropTimeCommand.onCommand(it) } registerCommand( "shcropsin", @@ -248,8 +252,7 @@ object Commands { ) { FarmingWeightDisplay.lookUpCommand(it) } registerCommand( "shcopytranslation", - "Copy the English translation of a message in another language to the clipboard.\n" + - "Uses a 2 letter language code that can be found at the end of a translation message.", + "Copy the English translation of a message in another language to the clipboard.\n" + "Uses a 2 letter language code that can be found at the end of a translation message.", ) { Translator.fromEnglish(it) } registerCommand( "shtranslate", @@ -275,6 +278,10 @@ object Commands { "shresetpestprofittracker", "Resets the Pest Profit Tracker", ) { PestProfitTracker.resetCommand() } + registerCommand( + "shresetexperimentsprofittracker", + "Resets the Experiments Profit Tracker", + ) { ExperimentsProfitTracker.resetCommand() } registerCommand( "shresetmythologicalcreaturetracker", "Resets the Mythological Creature Tracker", @@ -361,8 +368,12 @@ object Commands { ) { ColorFormattingHelper.printColorCodeList() } registerCommand( "shtps", - "Informs in chat about the server ticks per second (TPS)." + "Informs in chat about the server ticks per second (TPS).", ) { TpsCounter.tpsCommand() } + registerCommand( + "shcarry", + "Keep track of carries you do.", + ) { CarryTracker.onCommand(it) } } private fun usersBugFix() { @@ -374,7 +385,7 @@ object Commands { registerCommand( "shtogglehypixelapierrors", "Show/hide hypixel api error messages in chat", - ) { APIUtil.toggleApiErrorMessages() } + ) { APIUtils.toggleApiErrorMessages() } registerCommand( "shclearcropspeed", "Reset garden crop speed data and best crop time data", @@ -484,7 +495,7 @@ object Commands { ) { SkyBlockIslandTest.onCommand(it) } registerCommand( "shdebugprice", - "Debug different price sources for an item." + "Debug different price sources for an item.", ) { ItemPriceUtils.debugItemPrice(it) } registerCommand( "shdebugscoreboard", @@ -492,9 +503,11 @@ object Commands { ) { ScoreboardData.toggleMonitor() } } + @Suppress("LongMethod") private fun developersCodingHelp() { registerCommand("shrepopatterns", "See where regexes are loaded from") { RepoPatternGui.open() } registerCommand("shtest", "Unused test command.") { SkyHanniDebugsAndTests.testCommand(it) } + registerCommand("shtestrabbitpaths", "Tests pathfinding to rabbit eggs. Use a number 0-14.") { HoppityEggLocator.testPathfind(it) } registerCommand( "shtestitem", "test item internal name resolving", @@ -578,9 +591,7 @@ object Commands { ) { TitleManager.command(it) } registerCommand( "shresetconfig", - "Reloads the config manager and rendering processors of MoulConfig. " + - "This §cWILL RESET §7your config, but also updating the java config files " + - "(names, description, orderings and stuff).", + "Reloads the config manager and rendering processors of MoulConfig. " + "This §cWILL RESET §7your config, but also updating the java config files " + "(names, description, orderings and stuff).", ) { SkyHanniDebugsAndTests.resetConfigCommand() } registerCommand( "shreadcropmilestonefromclipboard", @@ -657,8 +668,7 @@ object Commands { else -> currentStream } - val switchingToBeta = updateStream == UpdateStream.BETA && - (currentStream != UpdateStream.BETA || !UpdateManager.isCurrentlyBeta()) + val switchingToBeta = updateStream == UpdateStream.BETA && (currentStream != UpdateStream.BETA || !UpdateManager.isCurrentlyBeta()) if (switchingToBeta) { ChatUtils.clickableChat( "Are you sure you want to switch to beta? These versions may be less stable.", diff --git a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt index 3e64d5f5abff..0adf1bed5e56 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt @@ -27,11 +27,10 @@ import at.hannibal2.skyhanni.data.OtherInventoryData import at.hannibal2.skyhanni.mixins.transformers.gui.AccessorGuiContainer import at.hannibal2.skyhanni.utils.GuiRenderUtils import at.hannibal2.skyhanni.utils.KeyboardManager -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.compat.GuiScreenUtils import at.hannibal2.skyhanni.utils.compat.SkyhanniBaseScreen import net.minecraft.client.Minecraft -import net.minecraft.client.gui.ScaledResolution import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager import org.lwjgl.input.Keyboard @@ -58,7 +57,7 @@ class GuiPositionEditor( } override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) { - //Items aren't drawn due to a bug in neu rendering + // Items aren't drawn due to a bug in neu rendering drawDefaultBackground() if (oldScreen != null) { val accessor = oldScreen as AccessorGuiContainer @@ -100,7 +99,7 @@ class GuiPositionEditor( } val pos = positions[displayPos] - val location = "§7x: §e${pos.rawX}§7, y: §e${pos.rawY}§7, scale: §e${pos.scale.round(2)}" + val location = "§7x: §e${pos.rawX}§7, y: §e${pos.rawY}§7, scale: §e${pos.scale.roundTo(2)}" GuiRenderUtils.drawStringCentered("§b" + pos.internalName, getScaledWidth() / 2, 18) GuiRenderUtils.drawStringCentered(location, getScaledWidth() / 2, 28) if (pos.canJumpToConfigOptions()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java index 42a53f8dd3bf..cb1aae0e5e9c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java @@ -111,7 +111,7 @@ public String toString() { @Expose @ConfigOption(name = "Gemstones", desc = "") @Accordion - // TODO remove config + // TODO rename to "gemstoneFilter" public PowderMiningGemstoneFilterConfig gemstoneFilterConfig = new PowderMiningGemstoneFilterConfig(); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java index 3a44738ca6e8..e2b1c5d18143 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java @@ -42,6 +42,11 @@ public class PowderMiningGemstoneFilterConfig { @ConfigEditorDropdown public GemstoneFilterEntry topazGemstones = GemstoneFilterEntry.FINE_UP; + @Expose + @ConfigOption(name = "Jasper", desc = "Hide Jasper gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry jasperGemstones = GemstoneFilterEntry.FINE_UP; + public enum GemstoneFilterEntry { SHOW_ALL("Show All"), HIDE_ALL("Hide all"), diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chroma/ChromaConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chroma/ChromaConfig.java index 6a02e2ed3061..b3f8577f0c0f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chroma/ChromaConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chroma/ChromaConfig.java @@ -20,7 +20,7 @@ public class ChromaConfig { public boolean chromaPreview = false; @Expose - @ConfigOption(name = "Enabled", desc = "Toggle SkyHanni's chroma. §e(Disables Patcher's Optimized Font Renderer while enabled)") + @ConfigOption(name = "Enabled", desc = "Toggle SkyHanni's chroma.") @ConfigEditorBoolean @FeatureToggle public Property enabled = Property.of(false); @@ -80,7 +80,7 @@ public String toString() { public Runnable resetSettings = ChromaManager::resetChromaSettings; @Expose - @ConfigOption(name = "Everything Chroma", desc = "Render §4§l§oALL §r§7text in chroma. §e(Some enchants may appear white with SBA enchant parsing)") + @ConfigOption(name = "Everything Chroma", desc = "Render §4§l§oALL §r§7text in chroma. §e(Disables Patcher's Optimized Font Renderer while enabled)") @ConfigEditorBoolean public boolean allChroma = false; diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java index 4beede62ba18..7042b2fdbdd9 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.config.features.combat; import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.features.combat.broodmother.BroodmotherConfig; import at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig; import at.hannibal2.skyhanni.config.features.combat.ghostcounter.GhostCounterConfig; import com.google.gson.annotations.Expose; @@ -60,6 +61,11 @@ public class CombatConfig { @Accordion public FlareConfig flare = new FlareConfig(); + @Expose + @ConfigOption(name = "Broodmother", desc = "") + @Accordion + public BroodmotherConfig broodmother = new BroodmotherConfig(); + @Expose @ConfigOption(name = "Hide Damage Splash", desc = "Hide all damage splashes anywhere in SkyBlock.") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherConfig.java new file mode 100644 index 000000000000..8acd69c1f400 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherConfig.java @@ -0,0 +1,68 @@ +package at.hannibal2.skyhanni.config.features.combat.broodmother; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.combat.BroodmotherFeatures.StageEntry; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BroodmotherConfig { + + @Expose + @ConfigOption(name = "Countdown", desc = "Display a countdown until the Broodmother will spawn.\n" + + "§cCountdown will not show unless the time until spawn has been established, and may be off by a few seconds.") + @ConfigEditorBoolean + @FeatureToggle + public boolean countdown = true; + + @Expose + @ConfigOption(name = "Spawn Alert", desc = "Send a chat message, title and sound when the Broodmother spawns.") + @ConfigEditorBoolean + @FeatureToggle + public boolean alertOnSpawn = false; + + @Expose + @ConfigOption(name = "Alert Settings", desc = "") + @Accordion + public BroodmotherSpawnAlertConfig spawnAlert = new BroodmotherSpawnAlertConfig(); + + @Expose + @ConfigOption(name = "Imminent Warning", desc = "Warns you when the Broodmother is 1 minute away from spawning.") + @ConfigEditorBoolean + @FeatureToggle + public boolean imminentWarning = false; + + @Expose + @ConfigOption(name = "Chat Messages", desc = "Send a chat message when the Broodmother enters these stages.\n" + + "§cThe 'Alive!' and 'Imminent' stages are overridden by the \"Spawn Alert\" and \"Imminent Warning\" features.") + @ConfigEditorDraggableList + public List stages = new ArrayList<>(Arrays.asList( + StageEntry.SLAIN, + StageEntry.ALIVE + )); + + @Expose + @ConfigOption(name = "Stage on Server Join", desc = "Send a chat message with the Broodmother's current stage upon joining the Spider's Den.") + @ConfigEditorBoolean + @FeatureToggle + public boolean stageOnJoin = false; + + @Expose + @ConfigOption(name = "Hide own kills", desc = "Disable the chat message for the §eSlain §rstage if at the Spider Mound.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideSlainWhenNearby = false; + + @Expose + @ConfigLink(owner = BroodmotherConfig.class, field = "countdown") + public Position countdownPosition = new Position(10, 10, false, true); + +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherSpawnAlertConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherSpawnAlertConfig.java new file mode 100644 index 000000000000..d0c2ccfe9ecd --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherSpawnAlertConfig.java @@ -0,0 +1,41 @@ +package at.hannibal2.skyhanni.config.features.combat.broodmother; + +import at.hannibal2.skyhanni.features.combat.BroodmotherFeatures; +import at.hannibal2.skyhanni.utils.OSUtils; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorButton; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorText; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class BroodmotherSpawnAlertConfig { + + @Expose + @ConfigOption(name = "Alert Sound", desc = "The sound that plays for the alert.") + @ConfigEditorText + public String alertSound = "note.pling"; + + @Expose + @ConfigOption(name = "Pitch", desc = "The pitch of the alert sound.") + @ConfigEditorSlider(minValue = 0.5f, maxValue = 2.0f, minStep = 0.1f) + public float pitch = 1.0f; + + @ConfigOption(name = "Test Sound", desc = "Test current sound settings.") + @ConfigEditorButton(buttonText = "Test") + public Runnable testSound = BroodmotherFeatures::playTestSound; + + @Expose + @ConfigOption(name = "Repeat Sound", desc = "How many times the sound should be repeated.") + @ConfigEditorSlider(minValue = 1, maxValue = 20, minStep = 1) + public int repeatSound = 20; + + @ConfigOption(name = "Sounds", desc = "Click to open the list of available sounds.") + @ConfigEditorButton(buttonText = "OPEN") + public Runnable sounds = () -> OSUtils.openBrowser("https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2213619-1-8-all-playsound-sound-arguments"); + + @Expose + @ConfigOption(name = "Text", desc = "The text with color to be displayed as the title notification.") + @ConfigEditorText + public String text = "&4Broodmother has spawned!"; + +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java index 7010c7d35ff0..ed37c396ccb3 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java @@ -14,6 +14,7 @@ import java.util.List; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.ARACHNE; +import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.BROODMOTHER; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.DIANA_MOBS; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.GARDEN_PESTS; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.INFERNO_DEMONLORD; @@ -96,6 +97,7 @@ public String toString() { DIANA_MOBS, SEA_CREATURES, ARACHNE, + BROODMOTHER, THE_RIFT_BOSSES, RIFTSTALKER_BLOODFIEND, REINDRAKE, @@ -129,6 +131,7 @@ public enum BossCategory implements HasLegacyId { RIFTSTALKER_BLOODFIEND("§bRiftstalker Bloodfiend", 23), REINDRAKE("§6Reindrake", 24), GARDEN_PESTS("§aGarden Pests", 25), + BROODMOTHER("§bBroodmother") ; private final String str; diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java index 46a02e9b21e3..ac9f6e0b210a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java @@ -30,7 +30,7 @@ public class BestiaryFormattingConfig { @ConfigOption(name = "Progress to Max", desc = "Text to show progress when the §eMaxed Bestiary §7option is §aON\n" + "§e%currentKill% §7is replaced with your current total kill.") @ConfigEditorText - public String showMax_progress = "%currentKill%/250k (%percentNumber%%)"; + public String showMax_progress = "%currentKill%/100k (%percentNumber%%)"; @Expose @ConfigOption(name = "Progress", desc = "Text to show progress when the §eMaxed Bestiary §7option is §cOFF\n" + diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/commands/BetterWikiCommandConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/commands/BetterWikiCommandConfig.java index fc6d0be06fc2..df0468226e77 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/commands/BetterWikiCommandConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/commands/BetterWikiCommandConfig.java @@ -53,7 +53,7 @@ public class BetterWikiCommandConfig { public boolean menuOpenWiki = false; @Expose - @ConfigOption(name = "Fandom Wiki Key", desc = "Search for an item on Wiki with this keybind.\n" + + @ConfigOption(name = "Wiki Key", desc = "Search for an item's wiki page with this keybind.\n" + "§cFor an optimal experience, do §lNOT §cbind this to a mouse button.") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) public int wikiKeybind = Keyboard.KEY_NONE; diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/commands/CommandsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/commands/CommandsConfig.java index 1747baee6348..d8626e243b93 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/commands/CommandsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/commands/CommandsConfig.java @@ -47,4 +47,15 @@ public class CommandsConfig { @ConfigEditorBoolean @FeatureToggle public boolean viewRecipeLowerCase = true; + + @Expose + @ConfigOption(name = "Fix Transfer Cooldown", desc = "Waits for the transfer cooldown to complete if you try to warp.") + @ConfigEditorBoolean + @FeatureToggle + public boolean transferCooldown = false; + + @Expose + @ConfigOption(name = "Transfer Cooldown Message", desc = "Sends a message in chat when the transfer cooldown ends.") + @ConfigEditorBoolean + public boolean transferCooldownMessage = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java index b62c88efc61f..6daf37cfda74 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java @@ -108,6 +108,13 @@ public class DevConfig { @ConfigEditorBoolean public boolean fancySbaContributors = false; + @Expose + @ConfigOption( + name = "Number Format Override", + desc = "Forces the number format to use the en_US locale.") + @ConfigEditorBoolean + public boolean numberFormatOverride = false; + @Expose @Category(name = "Minecraft Console", desc = "Minecraft Console Settings") public MinecraftConsoleConfig minecraftConsoles = new MinecraftConsoleConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java index 9a2806f64e01..dda1ddb1e50c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java @@ -4,6 +4,7 @@ import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; import org.lwjgl.input.Keyboard; @@ -31,6 +32,11 @@ public class GraphConfig { @ConfigEditorKeybind(defaultKey = -98) // Middle Mouse public int selectKey = -98; + @Expose + @ConfigOption(name = "Select near look", desc = "Select the node closest to where you are looking.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) + public int selectRaycastKey = Keyboard.KEY_NONE; + @Expose @ConfigOption(name = "Connect Key", desc = "Connect the nearest node with the active node. If the nodes are already connected removes the connection.") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_C) @@ -99,8 +105,24 @@ public class GraphConfig { @ConfigLink(owner = GraphConfig.class, field = "enabled") public Position namedNodesList = new Position(20, 20); + @Expose + @ConfigOption( + name = "Max Node Distance", + desc = "Only render nodes below this distance to the player.") + @ConfigEditorSlider( + minValue = 10, + maxValue = 500, + minStep = 10 + ) + public int maxNodeDistance = 50; + @Expose @ConfigOption(name = "Shows Stats", desc = "Show funny extra statistics on save. May lag the game a bit.") @ConfigEditorBoolean public boolean showsStats = true; + + @Expose + @ConfigOption(name = "Use as Island Area", desc = "When saving, use the current edited graph as temporary island area for the current island.") + @ConfigEditorBoolean + public boolean useAsIslandArea = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java index 385c162c6623..a1c29cd4482f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java @@ -14,13 +14,13 @@ public class ObjectHighlighterConfig { // TODO move some stuff from DungeonConfig into this @Expose - @ConfigOption(name = "Stared", desc = "") + @ConfigOption(name = "Starred Mobs", desc = "") @Accordion public StarredConfig starred = new StarredConfig(); public static class StarredConfig { @Expose - @ConfigOption(name = "Highlight Starred", desc = "Highlights all starred mobs in one colour.") + @ConfigOption(name = "Highlight Starred", desc = "Highlights starred mobs in a color.") @ConfigEditorBoolean @FeatureToggle public Property highlight = Property.of(true); @@ -40,7 +40,7 @@ public static class StarredConfig { public String info; @Expose - @ConfigOption(name = "Colour", desc = "Color in which the stared mobs are highlighted.") + @ConfigOption(name = "Color", desc = "The color used to highlight starred mobs.") @ConfigEditorColour public Property colour = Property.of("0:60:255:255:0"); } @@ -53,18 +53,18 @@ public static class StarredConfig { public static class FelConfig { @Expose - @ConfigOption(name = "Highlight Fels Skull", desc = "Highlights fels that are not yet active.") + @ConfigOption(name = "Highlight Fels Skull", desc = "Highlights fels that are not active.") @ConfigEditorBoolean @FeatureToggle public Property highlight = Property.of(true); @Expose - @ConfigOption(name = "Draw Line", desc = "Draws a line to fels skulls. Works only if the highlight is enabled.") + @ConfigOption(name = "Draw Line", desc = "Draws a line to fels skulls. Requires highlight to be enabled.") @ConfigEditorBoolean public Boolean line = false; @Expose - @ConfigOption(name = "Colour", desc = "Color for the fel skull and line.") + @ConfigOption(name = "Color", desc = "The color used to highlight fel skulls and draw the line.") @ConfigEditorColour public Property colour = Property.of("0:200:255:0:255"); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java index 57d3e0699a30..41d5771ab475 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.config.features.event; import at.hannibal2.skyhanni.config.features.event.bingo.BingoConfig; +import at.hannibal2.skyhanni.config.features.event.carnival.CarnivalConfig; import at.hannibal2.skyhanni.config.features.event.diana.DianaConfig; import at.hannibal2.skyhanni.config.features.event.hoppity.HoppityEggsConfig; import at.hannibal2.skyhanni.config.features.event.waypoints.LobbyWaypointsConfig; @@ -43,6 +44,10 @@ public class EventConfig { @Expose public GreatSpookConfig spook = new GreatSpookConfig(); + @Expose + @Category(name = "The Carnival", desc = "Features for games at §eThe Carnival §7when §bFoxy §7is Mayor.") + public CarnivalConfig carnival = new CarnivalConfig(); + // comment in if the event is needed again // @ConfigOption(name = "300þ Anniversary Celebration", desc = "Features for the 300þ year of SkyBlock") @Accordion @@ -52,5 +57,4 @@ public class EventConfig { @Category(name = "Lobby Waypoints", desc = "Lobby Event Waypoint settings") @Expose public LobbyWaypointsConfig lobbyWaypoints = new LobbyWaypointsConfig(); - } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java new file mode 100644 index 000000000000..cad2b7ea3d72 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java @@ -0,0 +1,39 @@ +package at.hannibal2.skyhanni.config.features.event.carnival; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class CarnivalConfig { + + @Expose + @ConfigOption(name = "Zombie Shootout", desc = "") + @Accordion + public ZombieShootoutConfig zombieShootout = new ZombieShootoutConfig(); + + @Expose + @ConfigOption(name = "Reminder Daily Tickets", desc = "Reminds you when tickets can be claimed from the carnival leader.") + @ConfigEditorBoolean + @FeatureToggle + public boolean reminderDailyTickets = true; + + @Expose + @ConfigOption(name = "Show Goals", desc = "Displays the goals for this carnival event.") + @ConfigEditorBoolean + @FeatureToggle + public boolean showGoals = true; + + @Expose + @ConfigLink(owner = CarnivalConfig.class, field = "showGoals") + public Position goalsPosition = new Position(20, 20); + + @Expose + @ConfigOption(name = "Double Click to Start", desc = "Clicking the npc again after the npc finishes talking to start game.") + @ConfigEditorBoolean + @FeatureToggle + public boolean doubleClickToStart = true; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java new file mode 100644 index 000000000000..e65fc4c8a196 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java @@ -0,0 +1,41 @@ +package at.hannibal2.skyhanni.config.features.event.carnival; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class ZombieShootoutConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "QOL Features for Zombie Shootout.") + @FeatureToggle + @ConfigEditorBoolean + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Colored Hitboxes", desc = "Display colored hitboxes for zombies and lamps.") + @ConfigEditorBoolean + public boolean coloredHitboxes = true; + + @Expose + @ConfigOption(name = "Highest Only", desc = "Only draw colored hitboxes for the highest scoring zombies.") + @ConfigEditorBoolean + public boolean highestOnly = false; + + @Expose + @ConfigOption(name = "Colored Line", desc = "Display a colored line to lamps.") + @ConfigEditorBoolean + public boolean coloredLines = true; + + @Expose + @ConfigOption(name = "Lamp Timer", desc = "Show time until current lamp disappears.") + @ConfigEditorBoolean + public boolean lampTimer = true; + + @Expose + @ConfigLink(owner = ZombieShootoutConfig.class, field = "lampTimer") + public Position lampPosition = new Position(20, 20, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java index c270dae8bbe7..3fd83db69655 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java @@ -50,6 +50,12 @@ public class HoppityEggsConfig { @FeatureToggle public boolean showLine = false; + @Expose + @ConfigOption(name = "Show Path Finder", desc = "Show a pathfind to the next hoppity egg.") + @ConfigEditorBoolean + @FeatureToggle + public boolean showPathFinder = false; + @Expose @ConfigOption(name = "Show All Waypoints", desc = "Show all possible egg waypoints for the current lobby. §e" + "Only works when you don't have an Egglocator in your inventory.") @@ -191,6 +197,11 @@ public String toString() { } } + @Expose + @ConfigOption(name = "Show Duplicate Count", desc = "Show the number of previous finds of a duplicate Hoppity rabbit in chat messages.") + @ConfigEditorBoolean + public boolean showDuplicateNumber = false; + @Expose @ConfigOption( name = "Rabbit Pet Warning", @@ -200,4 +211,15 @@ public String toString() { @ConfigEditorBoolean @FeatureToggle public boolean petWarning = false; + + @Expose + @ConfigOption(name = "Show uniques in Warp Menu", desc = "Shows your unique eggs in the Warp Menu during the hoppity event.") + @ConfigEditorBoolean + @FeatureToggle + public boolean uniquesWarpMenu = true; + + @Expose + @ConfigOption(name = "Hide when maxed", desc = "Stops the above feature from working when the island is complete.") + @ConfigEditorBoolean + public boolean uniquesWarpMenuHideMax = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java index 837f4c7ea811..550ceaeee0ec 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java @@ -46,4 +46,10 @@ public class WinterConfig { @FeatureToggle public boolean newYearCakeReminder = true; + @Expose + @ConfigOption(name = "Reindrake Warp Helper", desc = "Sends a clickable message in chat to warp to the Winter Island spawn when a Reindrake spawns.") + @ConfigEditorBoolean + @FeatureToggle + public boolean reindrakeWarpHelper = true; + } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/ChatMessagesConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/ChatMessagesConfig.java index 0fab8615645c..c5a4dc341307 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/ChatMessagesConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/ChatMessagesConfig.java @@ -82,4 +82,19 @@ public String toString() { @ConfigOption(name = "Silver Duplicates", desc = "Hide duplicate messages for silver Trophy Fishes from chat.") @ConfigEditorBoolean public boolean silverHider = false; + + @Expose + @ConfigOption(name = "Gold Alert", desc = "Send an alert upon catching a gold Trophy Fish.") + @ConfigEditorBoolean + public boolean goldAlert = false; + + @Expose + @ConfigOption(name = "Diamond Alert", desc = "Send an alert upon catching a diamond Trophy Fish.") + @ConfigEditorBoolean + public boolean diamondAlert = false; + + @Expose + @ConfigOption(name = "Play Sound Alert", desc = "Play a sound effect when rare trophy fishes are caught.") + @ConfigEditorBoolean + public boolean playSound = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java index b39f5f01ce63..8aa9aa6a1124 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java @@ -158,12 +158,6 @@ public class GardenConfig { @FeatureToggle public boolean burrowingSporesNotification = true; - @Expose - @ConfigOption(name = "Wild Strawberry", desc = "Show a notification when a Wild Strawberry Dye drops while farming.") - @ConfigEditorBoolean - @FeatureToggle - public boolean wildStrawberryDyeNotification = true; - @Expose @ConfigOption( name = "FF for Contest", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java index 667e3233109d..bb7ea595b94d 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java @@ -2,13 +2,18 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.garden.CropType; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.Accordion; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorInfoText; import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import java.util.ArrayList; +import java.util.List; + public class FarmingLaneConfig { @Expose @@ -37,4 +42,11 @@ public class FarmingLaneConfig { @FeatureToggle public boolean cornerWaypoints = false; + @Expose + @ConfigOption( + name = "Ignored Crops", + desc = "Add the crops you wish to not setup a lane for." + ) + @ConfigEditorDraggableList() + public List ignoredCrops = new ArrayList<>(); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/TimerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/TimerConfig.java index 32bff02debbe..a6b7e509e610 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/TimerConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/TimerConfig.java @@ -34,5 +34,6 @@ public class TimerConfig { @Expose @ConfigLink(owner = TimerConfig.class, field = "enabled") + // TODO rename to position public Position pos = new Position(-200, 40, false, true); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java index 74ab755c9940..37f3d3c42037 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java @@ -36,7 +36,7 @@ public class GUIConfig { @Accordion public ChromaConfig chroma = new ChromaConfig(); - @ConfigOption(name = "Edit GUI Locations", desc = "Change the position of SkyHanni's overlays.") + @ConfigOption(name = "Edit GUI Locations", desc = "Opens the Position Editor, allows changing the position of SkyHanni's overlays.") @ConfigEditorButton(buttonText = "Edit") public Runnable positions = () -> GuiEditManager.openGuiPositionEditor(true); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java index ee77d6664317..f4b16343fef0 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java @@ -25,11 +25,6 @@ public class GetFromSackConfig { @FeatureToggle public boolean superCraftGFS = true; - @Expose - @ConfigOption(name = "Default GfS", desc = "If you don't provide an amount, a default one will be used instead. Queued GfS needs to be on in order for this to work.") - @ConfigEditorBoolean - public boolean defaultGFS = false; - @Expose @ConfigOption(name = "Default Amount GfS", desc = "The default amount of items used when an amount isn't provided.") @ConfigEditorSlider(minValue = 1, maxValue = 64, minStep = 1) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java index 3f7f4c1fd30d..08b8452bb202 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.config.HasLegacyId; import at.hannibal2.skyhanni.config.features.inventory.chocolatefactory.ChocolateFactoryConfig; import at.hannibal2.skyhanni.config.features.inventory.customwardrobe.CustomWardrobeConfig; +import at.hannibal2.skyhanni.config.features.inventory.experimentationtable.ExperimentationTableConfig; import at.hannibal2.skyhanni.config.features.inventory.helper.HelperConfig; import at.hannibal2.skyhanni.config.features.itemability.ItemAbilityConfig; import at.hannibal2.skyhanni.config.features.misc.EstimatedItemValueConfig; @@ -38,6 +39,10 @@ public class InventoryConfig { @Category(name = "Bazaar", desc = "Be smart when buying or selling many items in the Bazaar.") public BazaarConfig bazaar = new BazaarConfig(); + @Expose + @Category(name = "Experimentation Table", desc = "QOL features for the Experimentation Table.") + public ExperimentationTableConfig experimentationTable = new ExperimentationTableConfig(); + @Expose @Category(name = "Enchant Parsing", desc = "Settings for SkyHanni's Enchant Parsing") public EnchantParsingConfig enchantParsing = new EnchantParsingConfig(); @@ -61,6 +66,7 @@ public class InventoryConfig { @Expose @ConfigOption(name = "Item Pickup Log", desc = "Logs all the picked up and dropped items") @Accordion + // TODO remove the suffix "config" public ItemPickupLogConfig itemPickupLogConfig = new ItemPickupLogConfig(); @Expose @@ -230,6 +236,12 @@ public String toString() { @FeatureToggle public boolean itemStars = false; + @Expose + @ConfigOption(name = "Ultimate Enchant Star", desc = "Show a star on Enchanted Books with an Ultimate Enchant.") + @ConfigEditorBoolean + @FeatureToggle + public boolean ultimateEnchantStar = false; + @Expose @ConfigOption(name = "Missing Tasks", desc = "Highlight missing tasks in the SkyBlock Level Guide inventory.") // TODO move( , "inventory.highlightMissingSkyBlockLevelGuide", "inventory.skyblockGuideConfig.highlightMissingSkyBlockLevelGuide") @@ -291,4 +303,10 @@ public String toString() { @ConfigEditorBoolean @FeatureToggle public boolean hexAsColorInLore = true; + + @Expose + @ConfigOption(name = "Highlight Active Beacon Effect", desc = "Highlights the currently selected beacon effect in the beacon inventory.") + @ConfigEditorBoolean + @FeatureToggle + public boolean highlightActiveBeaconEffect = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java index e35bc4d7e790..5d1c63f8d7e1 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java @@ -2,6 +2,7 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats.HighlightRabbitTypes; import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStats.ChocolateFactoryStat; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.Accordion; @@ -174,18 +175,27 @@ public class ChocolateFactoryConfig { public boolean hoppityMenuShortcut = true; @Expose - @ConfigOption(name = "Highlight Requirement Rabbits", desc = "Highlight rabbits that have requirements.\n" + - "§cRed: Requirement not met.\n" + - "§aGreen: Requirement met.") + @ConfigOption(name = "Highlight Found Rabbits", desc = "Highlight rabbits that have already been found.") @ConfigEditorBoolean @FeatureToggle - public boolean highlightRabbitsWithRequirement = false; + public boolean highlightFoundRabbits = false; @Expose - @ConfigOption(name = "Only Requirement Not Met", desc = "Only highlight the rabbits you don't have the requirement for.") + @ConfigOption(name = "Highlight Rabbits", desc = "Highlight specific rabbit types in Hoppity's Collection.") + @ConfigEditorDraggableList + public List highlightRabbits = new ArrayList<>(Arrays.asList( + HighlightRabbitTypes.ABI, + HighlightRabbitTypes.FACTORY, + HighlightRabbitTypes.MET, + HighlightRabbitTypes.NOT_MET, + HighlightRabbitTypes.SHOP, + HighlightRabbitTypes.STRAYS + )); + + @Expose + @ConfigOption(name = "Re-color Missing Rabbit Dyes", desc = "Replace the gray dye in Hoppity's Collection with a color for the rarity of the rabbit.") @ConfigEditorBoolean - @FeatureToggle - public boolean onlyHighlightRequirementNotMet = true; + public boolean rarityDyeRecolor = true; @Expose @ConfigOption( diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java new file mode 100644 index 000000000000..0313498e6829 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java @@ -0,0 +1,50 @@ +package at.hannibal2.skyhanni.config.features.inventory.experimentationtable; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class ExperimentationTableConfig { + + @Expose + @ConfigOption(name = "Profit Tracker", desc = "") + @Accordion + public ExperimentsProfitTrackerConfig experimentsProfitTracker = new ExperimentsProfitTrackerConfig(); + + @Expose + @ConfigOption(name = "Dry-Streak Display", desc = "") + @Accordion + public ExperimentsDryStreakConfig dryStreak = new ExperimentsDryStreakConfig(); + + @Expose + @ConfigOption(name = "Superpair Data", desc = "Displays useful data while doing the Superpair experiment.") + @ConfigEditorBoolean + @FeatureToggle + public boolean superpairDisplay = false; + + @Expose + @ConfigLink(owner = ExperimentationTableConfig.class, field = "superpairDisplay") + public Position superpairDisplayPosition = new Position(-372, 161, false, true); + + @Expose + @ConfigOption(name = "Superpairs Clicks Alert", desc = "Display an alert when you reach the maximum clicks gained from Chronomatron or Ultrasequencer.") + @ConfigEditorBoolean + @FeatureToggle + public boolean superpairsClicksAlert = false; + + @Expose + @ConfigOption(name = "ULTRA-RARE Book Alert", desc = "Send a chat message, title and sound when you find an ULTRA-RARE book.") + @ConfigEditorBoolean + @FeatureToggle + public boolean ultraRareBookAlert = false; + + @Expose + @ConfigOption(name = "Guardian Reminder", desc = "Sends a warning when opening the Experimentation Table without a §9§lGuardian Pet §7equipped.") + @ConfigEditorBoolean + @FeatureToggle + public boolean guardianReminder = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java new file mode 100644 index 000000000000..dfba626a764f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java @@ -0,0 +1,31 @@ +package at.hannibal2.skyhanni.config.features.inventory.experimentationtable; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class ExperimentsDryStreakConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Display attempts and or XP since your last ULTRA-RARE.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Attempts", desc = "Display Attempts since.") + @ConfigEditorBoolean + public boolean attemptsSince = true; + + @Expose + @ConfigOption(name = "XP", desc = "Display XP since.") + @ConfigEditorBoolean + public boolean xpSince = true; + + @Expose + @ConfigLink(owner = ExperimentsDryStreakConfig.class, field = "enabled") + public Position position = new Position(200, -187, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java new file mode 100644 index 000000000000..62ee4f5407ba --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java @@ -0,0 +1,37 @@ +package at.hannibal2.skyhanni.config.features.inventory.experimentationtable; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentMessages; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.List; + +public class ExperimentsProfitTrackerConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Tracker for drops/XP you get from experiments.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Hide Messages", desc = "Change the messages to be hidden after completing Add-on/Main experiments.") + @ConfigEditorDraggableList + public List hideMessages = new ArrayList<>(); + + @Expose + @ConfigOption(name = "Time displayed", desc = "Time displayed after completing an experiment.") + @ConfigEditorSlider(minValue = 5, maxValue = 60, minStep = 1) + public int timeDisplayed = 30; + + @Expose + @ConfigLink(owner = ExperimentsProfitTrackerConfig.class, field = "enabled") + public Position position = new Position(20, 20, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java index 5f54e707d010..717dd76591de 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java @@ -56,30 +56,4 @@ public static class HarpConfig { @ConfigOption(name = "Reforge Helper", desc = "") @Accordion public ReforgeHelperConfig reforge = new ReforgeHelperConfig(); - - @Expose - @ConfigOption(name = "Enchanting", desc = "") - @Accordion - public EnchantingConfig enchanting = new EnchantingConfig(); - - public static class EnchantingConfig { - @Expose - @ConfigOption(name = "Superpairs Clicks Alert", desc = "Display an alert when you reach the maximum clicks gained from Chronomatron or Ultrasequencer.") - @ConfigEditorBoolean - @FeatureToggle - public boolean superpairsClicksAlert = false; - - @Expose - @ConfigOption(name = "ULTRA-RARE Book Alert", desc = "Send a chat message, title and sound when you find an ULTRA-RARE book.") - @ConfigEditorBoolean - @FeatureToggle - public boolean ultraRareBookAlert = false; - - @Expose - @ConfigOption(name = "Guardian Reminder", desc = "Sends a warning when opening the Experimentation Table without a §9§lGuardian Pet §7equipped.") - @ConfigEditorBoolean - @FeatureToggle - public boolean guardianReminder = false; - } - } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java index 61d3b19594a7..229883c83352 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.config.features.mining; +import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; @@ -11,6 +12,7 @@ public class CorpseTrackerConfig { @Expose @ConfigOption(name = "Enabled", desc = "Enable the Corpse Tracker overlay for Glacite Mineshafts.") @ConfigEditorBoolean + @FeatureToggle public boolean enabled = false; @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/ExcavatorTooltipHiderConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/ExcavatorTooltipHiderConfig.java new file mode 100644 index 000000000000..b1489ace876a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/ExcavatorTooltipHiderConfig.java @@ -0,0 +1,21 @@ +package at.hannibal2.skyhanni.config.features.mining; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class ExcavatorTooltipHiderConfig { + + @Expose + @ConfigOption(name = "Hide Dirt", desc = "Hides tooltips of the Dirt inside of the Fossil Excavator.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideDirt = true; + + @Expose + @ConfigOption(name = "Hide Everything", desc = "Hide all tooltips inside of the Fossil Excavator.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideEverything = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java index 176c8f3bda35..8445afe5336a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java @@ -18,6 +18,11 @@ public class FossilExcavatorConfig { @Accordion public ExcavatorProfitTrackerConfig profitTracker = new ExcavatorProfitTrackerConfig(); + @Expose + @ConfigOption(name = "Excavator Tooltip Hider", desc = "") + @Accordion + public ExcavatorTooltipHiderConfig tooltipHider = new ExcavatorTooltipHiderConfig(); + @Expose @ConfigOption( name = "Profit per Excavation", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java index 5f242ecd5f47..08c8ec894a71 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java @@ -96,10 +96,4 @@ public class MiningConfig { @ConfigEditorBoolean @FeatureToggle public boolean highlightYourGoldenGoblin = true; - - @Expose - @ConfigOption(name = "Forge GfS", desc = "Get Forge ingredients of a recipe.") - @ConfigEditorBoolean - @FeatureToggle - public boolean forgeGfs = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/PowderTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/PowderTrackerConfig.java index 1c32cabc2e95..247da9b546d3 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/PowderTrackerConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/PowderTrackerConfig.java @@ -24,7 +24,6 @@ import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.GOLD_ESSENCE; import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.HARD_STONE; import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.JADE; -import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.MITHRIL_POWDER; import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.ROBOTRON; import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.RUBY; import static at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry.SAPPHIRE; @@ -56,7 +55,6 @@ public class PowderTrackerConfig { public Property> textFormat = Property.of(new ArrayList<>(Arrays.asList( TOTAL_CHESTS, DOUBLE_POWDER, - MITHRIL_POWDER, GEMSTONE_POWDER, SPACER_1, DIAMOND_ESSENCE, @@ -78,7 +76,6 @@ public class PowderTrackerConfig { public enum PowderDisplayEntry implements HasLegacyId { TOTAL_CHESTS("§d852 Total chests Picked §7(950/h)", 2), DOUBLE_POWDER("§bx2 Powder: §aActive!", 3), - MITHRIL_POWDER("§b250,420 §aMithril Powder §7(350,000/h)", 4), GEMSTONE_POWDER("§b250,420 §dGemstone Powder §7(350,000/h)", 5), SPACER_1("", 6), DIAMOND_ESSENCE("§b129 §bDiamond Essence §7(600/h)", 7), diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java new file mode 100644 index 000000000000..38a399ed4b20 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java @@ -0,0 +1,32 @@ +package at.hannibal2.skyhanni.config.features.misc; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class AreaNavigationConfig { + + @Expose + @ConfigOption(name = "Area Path Finder", desc = "") + @Accordion + public AreaPathfinderConfig pathfinder = new AreaPathfinderConfig(); + + @Expose + @ConfigOption(name = "In World", desc = "Shows the area names in world") + @ConfigEditorBoolean + @FeatureToggle + public boolean inWorld = false; + + @Expose + @ConfigOption(name = "Small Areas", desc = "Include small areas.") + @ConfigEditorBoolean + public boolean includeSmallAreas = false; + + @Expose + @ConfigOption(name = "Title on Enter", desc = "Sends a titles on screen when entering an area.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enterTitle = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java new file mode 100644 index 000000000000..ed8bda18f4de --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java @@ -0,0 +1,41 @@ +package at.hannibal2.skyhanni.config.features.misc; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; + +public class AreaPathfinderConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "While in your invenotry, show all areas of the island. Click on an area to display the path to this area.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Show Always", desc = "Show the list always, not only while inside the inventory.") + @ConfigEditorBoolean + public boolean showAlways = false; + + @Expose + @ConfigOption(name = "Current Area", desc = "Show the name of the current area at the top of the list") + @ConfigEditorBoolean + public Property includeCurrentArea = Property.of(false); + + @Expose + @ConfigOption( + name = "Path Color", + desc = "Change the color of the path." + ) + @ConfigEditorColour + public Property color = Property.of("0:245:85:255:85"); + + @Expose + @ConfigLink(owner = AreaPathfinderConfig.class, field = "enabled") + public Position position = new Position(-350, 100); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/EstimatedItemValueConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/EstimatedItemValueConfig.java index 0963703088a2..3f5874ac0941 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/EstimatedItemValueConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/EstimatedItemValueConfig.java @@ -39,6 +39,15 @@ public class EstimatedItemValueConfig { ) public Property enchantmentsCap = Property.of(7); + @Expose + @ConfigOption(name = "Star Material Cap", desc = "Only show the top # most expensive parts of star prices.") + @ConfigEditorSlider( + minValue = 1, + maxValue = 15, + minStep = 1 + ) + public Property starMaterialCap = Property.of(3); + @Expose @ConfigOption(name = "Show Exact Price", desc = "Show the exact total price instead of the compact number.") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java index 1464d35ada2d..0869262959c0 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java @@ -15,6 +15,7 @@ import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.annotations.SearchTag; import io.github.notenoughupdates.moulconfig.observer.Property; import java.util.ArrayList; @@ -42,6 +43,10 @@ public class MiscConfig { @Category(name = "Stranded", desc = "Features for the Stranded game mode.") public StrandedConfig stranded = new StrandedConfig(); + @Expose + @Category(name = "Area Navigation", desc = "Helps navigate to different areas on the current island.") + public AreaNavigationConfig areaNavigation = new AreaNavigationConfig(); + @ConfigOption(name = "Hide Armor", desc = "") @Accordion @Expose @@ -140,6 +145,9 @@ public class MiscConfig { @Expose public Position collectionCounterPos = new Position(10, 10, false, true); + @Expose + public Position carryPosition = new Position(10, 10, false, true); + @Expose @ConfigOption(name = "Brewing Stand Overlay", desc = "Display the item names directly inside the Brewing Stand.") @ConfigEditorBoolean @@ -219,6 +227,7 @@ public class MiscConfig { @Expose @ConfigOption(name = "Account Upgrade Reminder", desc = "Remind you to claim community shop account and profile upgrades when complete.") @ConfigEditorBoolean + @SearchTag("Elizabeth Community Center") @FeatureToggle public boolean accountUpgradeReminder = true; @@ -316,9 +325,24 @@ public class MiscConfig { @FeatureToggle public boolean maintainGameVolume = false; + @Expose + @ConfigOption(name = "GFS Piggy Bank", desc = "When your Piggy Bank breaks, send a chat warning to get enchanted pork from sacks.") + @ConfigEditorBoolean + @FeatureToggle + public boolean gfsPiggyBank = true; + @Expose @ConfigOption(name = "SkyHanni User Luck", desc = "Shows SkyHanni User Luck in the SkyBlock Stats.") @ConfigEditorBoolean @FeatureToggle public boolean userluckEnabled = true; + + @Expose + @ConfigOption(name = "Computer Time Offset Warning", + desc = "Sends a Chat Warning if your computer time is not synchronized with the actual time.\n" + + "§cMaking sure your computer time is correct is important for SkyHanni to display times correctly." + ) + @ConfigEditorBoolean + @FeatureToggle + public boolean warnAboutPcTimeOffset = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java index 8cd295249ad5..02c2b2ed45fd 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java @@ -30,6 +30,11 @@ public class PetConfig { @Accordion public PetExperienceToolTipConfig petExperienceToolTip = new PetExperienceToolTipConfig(); + @Expose + @ConfigOption(name = "Pet Nametag", desc = "") + @Accordion + public PetNametagConfig nametag = new PetNametagConfig(); + @Expose @ConfigOption(name = "Hide Autopet Messages", desc = "Hide the autopet messages from chat.\n" + "§eRequires the display to be enabled.") diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetNametagConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetNametagConfig.java new file mode 100644 index 000000000000..4da1b816014e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetNametagConfig.java @@ -0,0 +1,19 @@ +package at.hannibal2.skyhanni.config.features.misc.pets; + +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class PetNametagConfig { + + @Expose + @ConfigOption(name = "Hide Pet Level", desc = "Hide the pet level above the pet.") + @ConfigEditorBoolean + public boolean hidePetLevel = false; + + @Expose + @ConfigOption(name = "Hide Max Pet Level", desc = "Hide the pet level above the pet if it is max level.") + @ConfigEditorBoolean + public boolean hideMaxPetLevel = false; + +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java index 96c721539c1c..69a87bd31660 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java @@ -15,6 +15,11 @@ public class EnigmaSoulConfig { @FeatureToggle public boolean enabled = true; + @Expose + @ConfigOption(name = "Show Path Finder", desc = "Additionally show a pathfind to the Enigma Soul.") + @ConfigEditorBoolean + public boolean showPathFinder = true; + @ConfigOption( name = "§aRift Guide", desc = "Type §e/riftguide §7in chat or navigate through the SkyBlock Menu to open the §aRift Guide§7. " + @@ -26,6 +31,10 @@ public class EnigmaSoulConfig { @Expose @ConfigOption(name = "Color", desc = "Color of the Enigma Souls.") @ConfigEditorColour - public String color = "0:120:13:49:255"; + public String color = "0:245:219:27:198"; + @Expose + @ConfigOption(name = "Buttons Helper", desc = "Help find all 56 wooden buttons required for the Buttons soul when tracking it.") + @ConfigEditorBoolean + public boolean showButtonsHelper = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/dreadfarm/WiltedBerberisConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/dreadfarm/WiltedBerberisConfig.java index eddcb740d96d..2aa89f66ea6d 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/dreadfarm/WiltedBerberisConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/dreadfarm/WiltedBerberisConfig.java @@ -21,7 +21,10 @@ public class WiltedBerberisConfig { @Expose @ConfigOption(name = "Hide Particles", desc = "Hide the Wilted Berberis particles.") @ConfigEditorBoolean - // TODO fix typo - public boolean hideparticles = false; + public boolean hideParticles = false; + @Expose + @ConfigOption(name = "Mute Others Sounds", desc = "Mute nearby Wilted Berberis sounds while not holding a Wand of Farming or not standing on Farmland blocks.") + @ConfigEditorBoolean + public boolean muteOthersSounds = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/livingcave/LivingCaveLivingMetalConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/livingcave/LivingCaveLivingMetalConfig.java index 38f60870f5ac..4053070e3375 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/livingcave/LivingCaveLivingMetalConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/livingcave/LivingCaveLivingMetalConfig.java @@ -3,7 +3,9 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; public class LivingCaveLivingMetalConfig { @@ -19,4 +21,9 @@ public class LivingCaveLivingMetalConfig { @FeatureToggle public boolean hideParticles = false; + @Expose + @ConfigOption(name = "Color", desc = "Set the color to highlight the blocks in.") + @ConfigEditorColour + public Property color = Property.of("0:255:85:255:255"); + } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/GunthersRaceConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/GunthersRaceConfig.java new file mode 100644 index 000000000000..10d18fa85c05 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/GunthersRaceConfig.java @@ -0,0 +1,39 @@ +package at.hannibal2.skyhanni.config.features.rift.area.westvillage; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; + +public class GunthersRaceConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Show the route for Gunther's rift race.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = true; + + @Expose + @ConfigOption(name = "Look Ahead", desc = "Change how many waypoints should be shown in front of you.") + @ConfigEditorSlider(minStep = 1, maxValue = 30, minValue = 1) + public Property lookAhead = Property.of(3); + + @Expose + @ConfigOption(name = "Rainbow Color", desc = "Show the rainbow color effect instead of a boring monochrome.") + @ConfigEditorBoolean + public Property rainbowColor = Property.of(true); + + @Expose + @ConfigOption(name = "Monochrome Color", desc = "Set a boring monochrome color for the guide waypoints.") + @ConfigEditorColour + public Property monochromeColor = Property.of("0:60:0:0:255"); + + @Expose + @ConfigOption(name = "Hide Other Players", desc = "Hide other players while in the race.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hidePlayers = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/WestVillageConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/WestVillageConfig.java index 5dbf1a231eff..fa6db52144b4 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/WestVillageConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/westvillage/WestVillageConfig.java @@ -6,11 +6,6 @@ public class WestVillageConfig { - @ConfigOption(name = "Kloon Hacking", desc = "") - @Accordion - @Expose - public KloonHackingConfig hacking = new KloonHackingConfig(); - @ConfigOption(name = "Vermin Tracker", desc = "Track all vermins collected.") @Accordion @Expose @@ -20,4 +15,14 @@ public class WestVillageConfig { @Accordion @Expose public VerminHighlightConfig verminHighlight = new VerminHighlightConfig(); + + @ConfigOption(name = "Gunther's Race", desc = "") + @Accordion + @Expose + public GunthersRaceConfig gunthersRace = new GunthersRaceConfig(); + + @ConfigOption(name = "Kloon Hacking", desc = "") + @Accordion + @Expose + public KloonHackingConfig hacking = new KloonHackingConfig(); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index 5938eebdb326..4ccb0823d512 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -10,6 +10,7 @@ import at.hannibal2.skyhanni.features.combat.ghostcounter.GhostData; import at.hannibal2.skyhanni.features.dungeon.CroesusChestTracker; import at.hannibal2.skyhanni.features.dungeon.DungeonFloor; +import at.hannibal2.skyhanni.features.event.carnival.CarnivalGoal; import at.hannibal2.skyhanni.features.event.diana.DianaProfitTracker; import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker; import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats; @@ -30,6 +31,7 @@ import at.hannibal2.skyhanni.features.garden.pests.VinylType; import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward; import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker; +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker; import at.hannibal2.skyhanni.features.inventory.wardrobe.WardrobeAPI; import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay; import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker; @@ -64,6 +66,29 @@ private static SimpleTimeMark SimpleTimeMarkFarPast() { @Expose public String currentPet = ""; + @Expose + public ExperimentationStorage experimentation = new ExperimentationStorage(); + + public static class ExperimentationStorage { + + @Expose + public LorenzVec tablePos = new LorenzVec(); + + @Expose + public ExperimentsDryStreakStorage dryStreak = new ExperimentsDryStreakStorage(); + + public static class ExperimentsDryStreakStorage { + @Expose + public int attemptsSince = 0; + + @Expose + public int xpSince = 0; + } + + @Expose + public ExperimentsProfitTracker.Data experimentsProfitTracker = new ExperimentsProfitTracker.Data(); + } + @Expose public ChocolateFactoryStorage chocolateFactory = new ChocolateFactoryStorage(); @@ -77,6 +102,9 @@ public static class ChocolateFactoryStorage { @Expose public long currentChocolate = 0; + @Expose + public long maxChocolate = 0; + @Expose public long chocolateThisPrestige = 0; @@ -159,6 +187,22 @@ public static class PositionChange { public ChocolateFactoryStrayTracker.Data strayTracker = new ChocolateFactoryStrayTracker.Data(); } + @Expose + public CarnivalStorage carnival = new CarnivalStorage(); + + public static class CarnivalStorage { + + @Expose + @Nullable + public java.time.LocalDate lastClaimedDay = null; + + @Expose + public int carnivalYear = 0; + + @Expose + public Map goals = new HashMap<>(); + } + @Expose public MaxwellPowerStorage maxwell = new MaxwellPowerStorage(); diff --git a/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt b/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt index 92a36b62363d..d38b6824b864 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.events.EntityMoveEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWarpEvent @@ -8,22 +9,36 @@ import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.getLorenzVec import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft import net.minecraft.entity.Entity import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @SkyHanniModule object EntityMovementData { private val warpingPattern by RepoPattern.pattern( "data.entity.warping", - "§7(?:Warping|Warping you to your SkyBlock island|Warping using transfer token|Finding player|Sending a visit request)\\.\\.\\." + "§7(?:Warping|Warping you to your SkyBlock island|Warping using transfer token|Finding player|Sending a visit request)\\.\\.\\.", ) + private var nextTeleport: OnNextTeleport? = null + + fun onNextTeleport(island: IslandType, action: () -> Unit) { + nextTeleport = OnNextTeleport(island, action) + } + + class OnNextTeleport(val island: IslandType, val action: () -> Unit) { + val startTime: SimpleTimeMark = SimpleTimeMark.now() + } + private val entityLocation = mutableMapOf() fun addToTrack(entity: Entity) { @@ -32,6 +47,40 @@ object EntityMovementData { } } + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + val nextData = nextTeleport ?: return + if (nextData.island != event.newIsland) return + val passedSince = nextData.startTime.passedSince() + if (passedSince > 5.seconds) { + nextTeleport = null + return + } + + DelayedRun.runDelayed(100.milliseconds) { + nextData.action() + } + nextTeleport = null + } + + @SubscribeEvent + fun onPlayerMove(event: EntityMoveEvent) { + if (!LorenzUtils.inSkyBlock || event.entity != Minecraft.getMinecraft().thePlayer) return + + val nextData = nextTeleport ?: return + + val passedSince = nextData.startTime.passedSince() + if (passedSince > 5.seconds) { + nextTeleport = null + return + } + if (passedSince > 50.milliseconds && nextData.island.isInIsland()) { + nextData.action() + nextTeleport = null + return + } + } + @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!LorenzUtils.inSkyBlock) return diff --git a/src/main/java/at/hannibal2/skyhanni/data/GuiData.kt b/src/main/java/at/hannibal2/skyhanni/data/GuiData.kt index 38ac99d1b3f6..5f2ca510bfef 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/GuiData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/GuiData.kt @@ -36,6 +36,9 @@ object GuiData { @SubscribeEvent(priority = EventPriority.HIGH) fun onGuiClick(event: GuiScreenEvent.MouseInputEvent.Pre) { + + if (CustomWardrobeKeybinds.allowMouseClick()) return + if (preDrawEventCancelled) event.isCanceled = true } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt b/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt index 0392eab25af8..3137458c3bec 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt @@ -26,22 +26,21 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.formatLong +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.indexOfFirstMatch -import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.allLettersFirstUppercase import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.inventory.Slot import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.math.ceil import kotlin.math.pow -private fun calculatePeakOfTheMountainLoot(level: Int): Map = buildMap { +private fun calculateCoreOfTheMountainLoot(level: Int): Map = buildMap { for (i in 1..level) { when (i) { 1, 5, 7 -> addOrPut(HotmReward.EXTRA_TOKENS, 1.0) - 2 -> addOrPut(HotmReward.EXTRA_FORGE_SLOTS, 1.0) + 2 -> addOrPut(HotmReward.ABILITY_LEVEL, 1.0) 3 -> addOrPut(HotmReward.EXTRA_COMMISSION_SLOTS, 1.0) 4 -> addOrPut(HotmReward.MORE_BASE_MITHRIL_POWER, 1.0) 6 -> addOrPut(HotmReward.MORE_BASE_GEMSTONE_POWER, 2.0) @@ -62,20 +61,14 @@ enum class HotmData( MINING_SPEED( "Mining Speed", 50, - { level -> (level + 1.0).pow(3) }, + { level -> (level + 1.0).pow(3.0) }, { level -> mapOf(HotmReward.MINING_SPEED to level * 20.0) }, ), MINING_FORTUNE( "Mining Fortune", 50, { level -> (level + 1.0).pow(3.05) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to level * 5.0) }, - ), - QUICK_FORGE( - "Quick Forge", - 20, - { level -> (level + 1.0).pow(4) }, - { level -> mapOf(HotmReward.FORGE_TIME_DECREASE to if (level >= 20) 30.0 else 10.0 + (level * 0.5)) }, + { level -> mapOf(HotmReward.MINING_FORTUNE to level * 2.0) }, ), TITANIUM_INSANIUM( "Titanium Insanium", @@ -83,40 +76,47 @@ enum class HotmData( { level -> (level + 1.0).pow(3.1) }, { level -> mapOf(HotmReward.TITANIUM_CHANCE to 2.0 + (level * 0.1)) }, ), - DAILY_POWDER( - "Daily Powder", - 100, - { level -> 200 + ((level - 1) * 18.0) }, - { level -> mapOf(HotmReward.DAILY_POWDER to (200.0 + ((level - 1.0) * 18.0)) * 2.0) }, - ), LUCK_OF_THE_CAVE( "Luck of the Cave", 45, { level -> (level + 1.0).pow(3.07) }, { level -> mapOf(HotmReward.EXTRA_CHANCE_TRIGGER_RARE_OCCURRENCES to 5.0 + level) }, ), - CRYSTALLIZED( - "Crystallized", - 30, - { level -> (level + 1.0).pow(3.4) }, - { level -> - mapOf( - HotmReward.MINING_SPEED to 20.0 + ((level - 1.0) * 6.0), - HotmReward.MINING_FORTUNE to 20.0 + ((level - 1.0) * 5.0), - ) - }, - ), EFFICIENT_MINER( "Efficient Miner", 100, { level -> (level + 1.0).pow(2.6) }, - { level -> mapOf(HotmReward.AVERAGE_BLOCK_BREAKS to (10.0 + (level * 0.4)) * (1.0 + (level * 0.05))) }, + { level -> mapOf(HotmReward.MINING_SPREAD to 3.0 * level) }, ), - ORBITER( - "Orbiter", - 80, - { level -> level * 70.0 }, - { level -> mapOf(HotmReward.CHANCE_EXTRA_XP_ORBS to 0.2 + (level * 0.01)) }, + QUICK_FORGE( + "Quick Forge", + 20, + { level -> (level + 1.0).pow(3.2) }, + { level -> mapOf(HotmReward.FORGE_TIME_DECREASE to if (level >= 20) 30.0 else 10.0 + (level * 0.5)) }, + ), + OLD_SCHOOL( + "Old-School", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.ORE_FORTUNE to level * 5.0) }, + ), + PROFESSIONAL( + "Professional", + 140, + { level -> (level + 1.0).pow(2.3) }, + { level -> mapOf(HotmReward.MINING_SPEED to 50.0 + (level * 5.0)) }, + ), + MOLE( + "Mole", + 200, + { level -> (level + 1.0).pow(2.17883) }, + { level -> mapOf(HotmReward.MINING_SPREAD to 50.0 + ((level - 1) * (350 / 199))) }, + ), + GEM_LOVER( + "Gem Lover", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.GEMSTONE_FORTUNE to 20.0 + (level * 4.0)) }, ), SEASONED_MINEMAN( "Seasoned Mineman", @@ -124,18 +124,25 @@ enum class HotmData( { level -> (level + 1.0).pow(2.3) }, { level -> mapOf(HotmReward.MINING_WISDOM to 5.0 + (level * 0.1)) }, ), - MOLE( - "Mole", - 190, - { level -> (level + 1.0).pow(2.2) }, - { level -> mapOf(HotmReward.AVERAGE_BLOCK_BREAKS to 1.0 + ((level + 9.0) * 0.05 * ((level + 8) % 20))) }, + FORTUNATE_MINEMAN( + "Fortunate Mineman", + 50, + { level -> (level + 1.0).pow(3.2) }, + { level -> mapOf(HotmReward.MINING_FORTUNE to level * 3.0) }, ), - PROFESSIONAL( - "Professional", - 140, - { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_SPEED to 50.0 + (level * 5.0)) }, + BLOCKHEAD( + "Blockhead", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.BLOCK_FORTUNE to level * 5.0) }, + ), + KEEP_IT_COOL( + "Keep It Cool", + 50, + { level -> (level + 1.0).pow(3.07) }, + { level -> mapOf(HotmReward.HEAT_RESISTANCE to level * 0.4) }, ), + LONESOME_MINER( "Lonesome Miner", 45, @@ -153,12 +160,7 @@ enum class HotmData( ) }, ), - FORTUNATE( - "Fortunate", - 20, - { level -> (level + 1.0).pow(3.05) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to 20.0 + (level * 4.0)) }, - ), + POWDER_BUFF( "Powder Buff", 50, @@ -170,32 +172,32 @@ enum class HotmData( ) }, ), - MINING_SPEED_II( - "Mining Speed II", + SPEEDY_MINEMAN( + "Speedy Mineman", 50, { level -> (level + 1.0).pow(3.2) }, { level -> mapOf(HotmReward.MINING_SPEED to level * 40.0) }, ), - MINING_FORTUNE_II( - "Mining Fortune II", - 50, - { level -> (level + 1.0).pow(3.2) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to level * 5.0) }, - ), - // Static - MINING_MADNESS( - "Mining Madness", - 1, - { null }, - { + + + SUBTERRANEAN_FISHER( + "Subterranean Fisher", + 40, + { level -> (level + 1.0).pow(3.07) }, + { level -> mapOf( - HotmReward.MINING_SPEED to 50.0, - HotmReward.MINING_FORTUNE to 50.0, + HotmReward.FISHING_SPEED to 5 + (level * 0.5), + HotmReward.SEA_CREATURE_CHANCE to 1 + (level * 0.1), ) }, + ), + + + // Static + SKY_MALL("Sky Mall", 1, { null }, { emptyMap() }), PRECISION_MINING("Precision Mining", 1, { null }, { mapOf(HotmReward.MINING_SPEED_BOOST to 30.0) }), FRONT_LOADED( @@ -204,16 +206,14 @@ enum class HotmData( { null }, { mapOf( - HotmReward.MINING_SPEED to 100.0, - HotmReward.MINING_FORTUNE to 100.0, - HotmReward.MORE_BASE_MITHRIL_POWER to 2.0, - HotmReward.MORE_BASE_GEMSTONE_POWER to 2.0, + HotmReward.MINING_SPEED to 250.0, + HotmReward.GEMSTONE_FORTUNE to 150.0, + HotmReward.MORE_GEMSTONE_POWER to 200.0, ) }, ), - STAR_POWDER("Star Powder", 1, { null }, { mapOf(HotmReward.MORE_MITHRIL_POWER to 300.0) }), - GOBLIN_KILLER("Goblin Killer", 1, { null }, { emptyMap() }), - + DAILY_GRIND("Daily Grind", 1, { null }, { emptyMap() }), + DAILY_POWDER("Daily Powder", 1, { null }, { emptyMap() }), // Abilities PICKOBULUS( @@ -222,8 +222,8 @@ enum class HotmData( { null }, { level -> mapOf( - HotmReward.ABILITY_RADIUS to ceil(level * 0.5) + 1.0, - HotmReward.ABILITY_COOLDOWN to 130.0 - 10.0 * level, + HotmReward.ABILITY_RADIUS to 3.0, + HotmReward.ABILITY_COOLDOWN to 60.0 - 10.0 * (level - 1), ) }, ), @@ -233,66 +233,57 @@ enum class HotmData( { null }, { level -> mapOf( - HotmReward.ABILITY_DURATION to level + 1.0, - HotmReward.ABILITY_COOLDOWN to 10.0 + 5.0 * level, + HotmReward.MINING_SPEED_BOOST to 200.0 + 50.0 * (level - 1), + HotmReward.ABILITY_DURATION to 10.0 + 5 * (level - 1), + HotmReward.ABILITY_COOLDOWN to 120.0, ) }, ), - VEIN_SEEKER( - "Vein Seeker", + MANIAC_MINER( + "Maniac Miner", 3, { null }, { level -> mapOf( - HotmReward.ABILITY_RADIUS to level + 1.0, - HotmReward.ABILITY_DURATION to 10.0 + 2.0 * level, + HotmReward.ABILITY_DURATION to 20.0 + level * 5.0, HotmReward.ABILITY_COOLDOWN to 60.0, + HotmReward.BREAKING_POWER to 1.0, ) }, ), - MANIAC_MINER( - "Maniac Miner", + + SHEER_FORCE( + "Sheer Force", 3, { null }, { level -> mapOf( - HotmReward.ABILITY_DURATION to 5.0 + level * 5.0, - HotmReward.ABILITY_COOLDOWN to 60.0 - level, + HotmReward.ABILITY_DURATION to 20.0 + 5 * (level - 1), + HotmReward.MINING_SPREAD to 200.0, ) }, ), - PEAK_OF_THE_MOUNTAIN( - "Peak of the Mountain", 10, { null }, - { level -> calculatePeakOfTheMountainLoot(level) }, + ANOMALOUS_DESIRE( + "Anomalous Desire", + 3, + { null }, + { level -> + mapOf( + HotmReward.EXTRA_CHANCE_TRIGGER_RARE_OCCURRENCES to 30.0 + (level - 1) * 10.0, + HotmReward.ABILITY_COOLDOWN to 120.0 - (level - 1) * 10.0, + HotmReward.ABILITY_DURATION to 30.0, + ) + }, ), - // Mining V3 - DAILY_GRIND( - "Daily Grind", - 100, - { level -> 218 + (18 * (level - 1.0)) }, - { level -> mapOf(HotmReward.DAILY_POWDER to 50.0 * level) }, - ), - DUST_COLLECTOR( - "Dust Collector", - 20, - { level -> (level + 1.0).pow(4) }, - { level -> mapOf(HotmReward.FOSSIL_DUST to 1.0 * level) }, - ), - WARM_HEARTED( - "Warm Hearted", - 50, - { level -> (level + 1.0).pow(3.1) }, - { level -> mapOf(HotmReward.COLD_RESISTANCE to 0.2 * level) }, + CORE_OF_THE_MOUNTAIN( + "Core of the Mountain", 10, { null }, + { level -> calculateCoreOfTheMountainLoot(level) }, ), - STRONG_ARM( - "Strong Arm", - 100, - { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_SPEED to 5.0 * level) }, - ), + // Mining V3 + NO_STONE_UNTURNED( "No Stone Unturned", 50, @@ -300,63 +291,87 @@ enum class HotmData( { level -> mapOf(HotmReward.UNKNOWN to 0.5 * level) }, ), - SUB_ZERO_MINING( - "SubZero Mining", + STRONG_ARM( + "Strong Arm", 100, { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to 1.0 * level) }, + { level -> mapOf(HotmReward.MINING_SPEED to 5.0 * level) }, + ), + STEADY_HAND( + "Steady Hand", + 100, + { level -> (level + 1.0).pow(2.6) }, + { level -> mapOf(HotmReward.GEMSTONE_SPREAD to 0.1 * level) }, + ), + WARM_HEART( + "Warm Heart", + 50, + { level -> (level + 1.0).pow(3.1) }, + { level -> mapOf(HotmReward.COLD_RESISTANCE to 0.4 * level) }, ), SURVEYOR( "Surveyor", 20, - { level -> (level + 1.0).pow(4) }, + { level -> (level + 1.0).pow(4.0) }, { level -> mapOf(HotmReward.MINESHAFT_CHANCE to 0.75 * level) }, ), + METAL_HEAD( + "Metal Head", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.DWARVEN_METAL_FORTUNE to 5.0 * level) }, + ), + RAGS_TO_RICHES( + "Rags to Riches", + 50, + { level -> (level + 1.0).pow(3.05) }, + { level -> mapOf(HotmReward.MINING_FORTUNE to 4.0 * level) }, + ), EAGER_ADVENTURER( "Eager Adventurer", 100, { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_SPEED to 2.0 * level) }, + { level -> mapOf(HotmReward.MINING_SPEED to 4.0 * level) }, ), - - DEAD_MANS_CHEST( - "Dead Man's Chest", + CRYSTALLINE( + "Crystalline", 50, - { level -> (level + 1.0).pow(3.2) }, - { level -> mapOf(HotmReward.UNKNOWN to 1.0 * level) }, + { level -> (level + 1.0).pow(3.3) }, + { level -> mapOf(HotmReward.UNKNOWN to 0.5 * level) }, ), - GIFTS_FROM_THE_DEPARTED( "Gifts from the Departed", 100, { level -> (level + 1.0).pow(2.45) }, { level -> mapOf(HotmReward.UNKNOWN to 0.2 * level) }, ), - - EXCAVATOR( - "Excavator", + MINING_MASTER( + "Mining Master", + 10, + { level -> (level + 7.0).pow(5.0) }, + { level -> mapOf(HotmReward.PRISTINE to 0.1 * level) }, + ), + DEAD_MANS_CHEST( + "Dead Man's Chest", 50, - { level -> (level + 1.0).pow(3) }, - { level -> mapOf(HotmReward.UNKNOWN to 0.5 * level) }, + { level -> (level + 1.0).pow(3.2) }, + { level -> mapOf(HotmReward.UNKNOWN to 1.0 * level) }, ), - RAGS_TO_RICHES( - "Rags to Riches", + VANGUARD_SEEKER( + "Vanguard Seeker", 50, - { level -> (level + 1.0).pow(3.05) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to 2.0 * level) }, + { level -> (level + 1.0).pow(3.1) }, + { level -> mapOf(HotmReward.UNKNOWN to 1.0 * level) }, ), - KEEN_EYE("Keen Eye", 1, { null }, { emptyMap() }), MINESHAFT_MAYHEM("Mineshaft Mayhem", 1, { null }, { emptyMap() }), - FROZEN_SOLID("Frozen Solid", 1, { null }, { emptyMap() }), GEMSTONE_INFUSION("Gemstone Infusion", 1, { null }, { emptyMap() }), - HAZARDOUS_MINER("Hazardous Miner", 1, { null }, { emptyMap() }), - + MINERS_BLESSING("Miner's Blessing", 1, { null }, { mapOf(HotmReward.MAGIC_FIND to 30.0) }), ; private val guiNamePattern by patternGroup.pattern("perk.name.${name.lowercase().replace("_", "")}", "§.$guiName") - val printName = name.allLettersFirstUppercase() + val printName get() = name.allLettersFirstUppercase() /** Level which are actually paid with powder (does exclude [blueEgg])*/ var rawLevel: Int @@ -367,15 +382,15 @@ enum class HotmData( /** Level for which the effect that is present (considers [enabled] and [blueEgg])*/ val activeLevel: Int - get() = if (enabled) effectivLevel else 0 + get() = if (enabled) effectiveLevel else 0 /** Level that considering [blueEgg]*/ - val effectivLevel: Int get() = storage?.perks?.get(this.name)?.level?.plus(blueEgg()) ?: 0 + val effectiveLevel: Int get() = storage?.perks?.get(this.name)?.level?.plus(blueEgg()) ?: 0 val isMaxLevel: Boolean - get() = effectivLevel >= maxLevel // >= to account for +1 from Blue Cheese + get() = effectiveLevel >= maxLevel // >= to account for +1 from Blue Cheese - private fun blueEgg() = if (this != PEAK_OF_THE_MOUNTAIN && maxLevel != 1 && HotmAPI.isBlueEggActive) 1 else 0 + private fun blueEgg() = if (this != CORE_OF_THE_MOUNTAIN && maxLevel != 1 && HotmAPI.isBlueEggActive) 1 else 0 var enabled: Boolean get() = storage?.perks?.get(this.name)?.enabled ?: false @@ -406,7 +421,8 @@ enum class HotmData( val storage get() = ProfileStorageData.profileSpecific?.mining?.hotmTree - val abilities = listOf(PICKOBULUS, MINING_SPEED_BOOST, VEIN_SEEKER, MANIAC_MINER, HAZARDOUS_MINER, GEMSTONE_INFUSION) + val abilities = + listOf(PICKOBULUS, MINING_SPEED_BOOST, MANIAC_MINER, GEMSTONE_INFUSION, ANOMALOUS_DESIRE, SHEER_FORCE) private val inventoryPattern by patternGroup.pattern( "inventory", @@ -514,10 +530,10 @@ enum class HotmData( HotmAPI.MayhemPerk.entries.forEach { it.chatPattern } - (0..PEAK_OF_THE_MOUNTAIN.maxLevel).forEach { level -> + (0..CORE_OF_THE_MOUNTAIN.maxLevel).forEach { level -> val map = mutableMapOf() if (level >= 1) map.addOrPut(HotmReward.EXTRA_TOKENS, 1.0) - if (level >= 2) map.addOrPut(HotmReward.EXTRA_FORGE_SLOTS, 1.0) + if (level >= 2) map.addOrPut(HotmReward.ABILITY_LEVEL, 1.0) if (level >= 3) map.addOrPut(HotmReward.EXTRA_COMMISSION_SLOTS, 1.0) if (level >= 4) map.addOrPut(HotmReward.MORE_BASE_MITHRIL_POWER, 1.0) if (level >= 5) map.addOrPut(HotmReward.EXTRA_TOKENS, 1.0) @@ -527,7 +543,7 @@ enum class HotmData( if (level >= 9) map.addOrPut(HotmReward.MINESHAFT_CHANCE, 10.0) if (level >= 10) map.addOrPut(HotmReward.EXTRA_TOKENS, 2.0) - peakOfTheMountainPerks[level] = map + coreOfTheMountainPerks[level] = map } } @@ -551,7 +567,7 @@ enum class HotmData( val lore = item.getLore().takeIf { it.isNotEmpty() } ?: return - if (entry != PEAK_OF_THE_MOUNTAIN && notUnlockedPattern.matches(lore.last())) { + if (entry != CORE_OF_THE_MOUNTAIN && notUnlockedPattern.matches(lore.last())) { entry.rawLevel = 0 entry.enabled = false entry.isUnlocked = false @@ -574,7 +590,7 @@ enum class HotmData( ) } - if (entry == PEAK_OF_THE_MOUNTAIN) { + if (entry == CORE_OF_THE_MOUNTAIN) { entry.enabled = entry.rawLevel != 0 return } @@ -663,7 +679,7 @@ enum class HotmData( fun onScoreboardUpdate(event: ScoreboardUpdateEvent) { if (!LorenzUtils.inSkyBlock) return - event.scoreboard.matchFirst(ScoreboardPattern.powderPattern) { + ScoreboardPattern.powderPattern.firstMatcher(event.scoreboard) { val type = HotmAPI.PowderType.entries.firstOrNull { it.displayName == group("type") } ?: return val amount = group("amount").formatLong() val difference = amount - type.getCurrent() @@ -690,7 +706,7 @@ enum class HotmData( DelayedRun.runNextTick { InventoryUtils.getItemsInOpenChest().forEach { it.parse() } abilities.filter { it.isUnlocked }.forEach { - it.rawLevel = if (PEAK_OF_THE_MOUNTAIN.rawLevel >= 1) 2 else 1 + it.rawLevel = if (CORE_OF_THE_MOUNTAIN.rawLevel >= 1) 2 else 1 } } } @@ -791,7 +807,7 @@ enum class HotmData( } } -private val peakOfTheMountainPerks = mutableMapOf>() +private val coreOfTheMountainPerks = mutableMapOf>() private val patternGroup = RepoPattern.group("mining.hotm") @@ -801,7 +817,6 @@ enum class HotmReward { MINING_WISDOM, FORGE_TIME_DECREASE, TITANIUM_CHANCE, - DAILY_POWDER, MORE_BASE_MITHRIL_POWER, MORE_BASE_GEMSTONE_POWER, MORE_BASE_GLACITE_POWER, @@ -811,17 +826,26 @@ enum class HotmReward { CHANCE_OF_TREASURE_CHEST, LOCKS_OF_TREASURE_CHEST, EXTRA_CHANCE_TRIGGER_RARE_OCCURRENCES, - AVERAGE_BLOCK_BREAKS, - CHANCE_EXTRA_XP_ORBS, MINING_SPEED_BOOST, ABILITY_DURATION, ABILITY_RADIUS, ABILITY_COOLDOWN, - FOSSIL_DUST, + ABILITY_LEVEL, MINESHAFT_CHANCE, EXTRA_TOKENS, - EXTRA_FORGE_SLOTS, EXTRA_COMMISSION_SLOTS, UNKNOWN, - COLD_RESISTANCE + COLD_RESISTANCE, + MINING_SPREAD, + GEMSTONE_SPREAD, + ORE_FORTUNE, + BLOCK_FORTUNE, + GEMSTONE_FORTUNE, + DWARVEN_METAL_FORTUNE, + HEAT_RESISTANCE, + MAGIC_FIND, + PRISTINE, + FISHING_SPEED, + SEA_CREATURE_CHANCE, + BREAKING_POWER, } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index 0cd806f577c7..3707d10af0a7 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigManager.Companion.gson import at.hannibal2.skyhanni.data.model.TabWidget +import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.HypixelJoinEvent import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent @@ -13,6 +14,7 @@ import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.events.ScoreboardUpdateEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.minecraft.ClientDisconnectEvent +import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent import at.hannibal2.skyhanni.features.bingo.BingoAPI import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.rift.RiftAPI @@ -118,6 +120,9 @@ object HypixelData { var skyBlock = false var skyBlockIsland = IslandType.UNKNOWN var serverId: String? = null + private var lastSuccessfulServerIdFetchTime = SimpleTimeMark.farPast() + private var lastSuccessfulServerIdFetchType: String? = null + private var failedServerIdFetchCounter = 0 // Ironman, Stranded and Bingo var noTrade = false @@ -158,24 +163,61 @@ object HypixelData { TabWidget.SERVER.matchMatcherFirstLine { serverId = group("serverid") + lastSuccessfulServerIdFetchTime = SimpleTimeMark.now() + lastSuccessfulServerIdFetchType = "tab list" + failedServerIdFetchCounter = 0 return } ScoreboardData.sidebarLinesFormatted.matchFirst(serverIdScoreboardPattern) { val serverType = if (group("servertype") == "M") "mega" else "mini" serverId = "$serverType${group("serverid")}" + lastSuccessfulServerIdFetchTime = SimpleTimeMark.now() + lastSuccessfulServerIdFetchType = "scoreboard" + failedServerIdFetchCounter = 0 return } + failedServerIdFetchCounter++ + if (failedServerIdFetchCounter < 3) return ErrorManager.logErrorWithData( Exception("NoServerId"), "Could not find server id", + "failedServerIdFetchCounter" to failedServerIdFetchCounter, + "lastSuccessfulServerIdFetchTime" to lastSuccessfulServerIdFetchTime, + "lastSuccessfulServerIdFetchType" to lastSuccessfulServerIdFetchType, "islandType" to LorenzUtils.skyBlockIsland, "tablist" to TabListData.getTabList(), "scoreboard" to ScoreboardData.sidebarLinesFormatted, ) } + @SubscribeEvent + fun onDebugDataCollect(event: DebugDataCollectEvent) { + event.title("Server ID") + if (!LorenzUtils.inSkyBlock) { + event.addIrrelevant("not in sb") + return + } + + val id = serverId + if (id == null) { + event.addData { + add("server id is null!") + add("failedServerIdFetchCounter: $failedServerIdFetchCounter") + add("") + add("last successful fetch time: $lastSuccessfulServerIdFetchTime") + add("last successful fetch type: $lastSuccessfulServerIdFetchType") + } + } else { + event.addIrrelevant { + add("Server id: '$id'") + add("fetch time: $lastSuccessfulServerIdFetchTime") + add("fetch type: $lastSuccessfulServerIdFetchType") + } + } + } + fun getPlayersOnCurrentServer(): Int { var amount = 0 val playerPatternList = mutableListOf( @@ -217,7 +259,7 @@ object HypixelData { // This code is modified from NEU, and depends on NEU (or another mod) sending /locraw. private val jsonBracketPattern = "^\\{.+}".toPattern() - //todo convert to proper json object + // todo convert to proper json object fun checkForLocraw(message: String) { jsonBracketPattern.matchMatcher(message.removeColor()) { try { @@ -319,8 +361,13 @@ object HypixelData { loop@ for (line in ScoreboardData.sidebarLinesFormatted) { skyblockAreaPattern.matchMatcher(line) { val originalLocation = group("area").removeColor() - skyBlockArea = LocationFixData.fixLocation(skyBlockIsland) ?: originalLocation + val area = LocationFixData.fixLocation(skyBlockIsland) ?: originalLocation skyBlockAreaWithSymbol = line.trim() + if (area != skyBlockArea) { + val previousArea = skyBlockArea + skyBlockArea = area + ScoreboardAreaChangeEvent(area, previousArea).post() + } break@loop } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt new file mode 100644 index 000000000000..386fb8bbf489 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt @@ -0,0 +1,529 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.data.model.Graph +import at.hannibal2.skyhanni.data.model.GraphNode +import at.hannibal2.skyhanni.data.repo.RepoUtils +import at.hannibal2.skyhanni.events.EntityMoveEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent +import at.hannibal2.skyhanni.features.misc.IslandAreas +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.sorted +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.GraphUtils +import at.hannibal2.skyhanni.utils.LocationUtils +import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer +import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine +import at.hannibal2.skyhanni.utils.RenderUtils.draw3DPathWithWaypoint +import at.hannibal2.skyhanni.utils.chat.Text.asComponent +import at.hannibal2.skyhanni.utils.chat.Text.hover +import at.hannibal2.skyhanni.utils.chat.Text.onClick +import at.hannibal2.skyhanni.utils.chat.Text.send +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.client.Minecraft +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.awt.Color +import java.io.File +import kotlin.time.Duration.Companion.milliseconds + +/** + * TODO + * benefits of every island graphs: + * global: + * NEU's fairy souls + * slayer area (not all there yet) + * NEU's NPC's (auto acitvate when searching via neu) + * races (end, park, winter, dungeon hub) + * jump pads between servers + * ring of love/romeo juliet quest + * death location + * % of island discvovered (every node was most closest node at least once) + * hub: + * 12 starter NPC's + * diana + * farming: + * pelt farming area + * rift: + * eyes + * big quests + * montezuma souls + * blood effigies + * avoid area around enderman + * spider: + * relicts + throw spot + * dwarven mines: + * emissary + * commssion areas + * events: raffle, goblin slayer, donpieresso + * deep + * path to the bottom (Rhys NPC) + * end + * golem spawn + * dragon death spot + * crimson + * vanquisher path + * area mini bosses + * daily quests + * intro tutorials with elle + * fishing spots + * mineshaft + * different types mapped out + * paths to ladder and possible corpse locations, and known corpse locations + * + * Additional global things: + * use custom graphs for your island/garden + * suggest using warp points if closer + * support cross island paths (have a list of all node names in all islands) + * + * Changes in graph editor: + * fix rename not using tick but input event we have (+ create the input event in the first place) + * toggle distance to node by node path lengh, instead of eye of sight lenght + * press test button again to enable "true test mode", with graph math and hiding other stuff + * option to compare two graphs, and store multiple graphs in the edit mode in paralell + */ + +@SkyHanniModule +object IslandGraphs { + var currentIslandGraph: Graph? = null + + val existsForThisIsland get() = currentIslandGraph != null + + private var pathfindClosestNode: GraphNode? = null + var closestNode: GraphNode? = null + private var secondClosestNode: GraphNode? = null + + private var currentTarget: LorenzVec? = null + private var currentTargetNode: GraphNode? = null + private var label = "" + private var lastDistance = 0.0 + private var totalDistance = 0.0 + private var color = Color.WHITE + private var shouldAllowRerouting = false + private var onFound: () -> Unit = {} + private var goal: GraphNode? = null + set(value) { + prevGoal = field + field = value + } + private var prevGoal: GraphNode? = null + + private var fastestPath: Graph? = null + private var condition: () -> Boolean = { true } + private var inGlaciteTunnels: Boolean? = null + + private val patternGroup = RepoPattern.group("data.island.navigation") + + /** + * REGEX-TEST: Dwarven Base Camp + * REGEX-TEST: Forge + * REGEX-TEST: Fossil Research Center + */ + private val glaciteTunnelsPattern by patternGroup.pattern( + "glacitetunnels", + "(Glacite Tunnels|Dwarven Base Camp|Great Glacite Lake|Fossil Research Center)", + ) + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + if (!LorenzUtils.inSkyBlock) return + + loadIsland(LorenzUtils.skyBlockIsland) + } + + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + if (currentIslandGraph != null) return + if (event.newIsland == IslandType.NONE) return + loadIsland(event.newIsland) + } + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + currentIslandGraph = null + if (currentTarget != null) { + "§e[SkyHanni] Navigation stopped because of world switch!".asComponent().send(PATHFIND_ID) + } + reset() + } + + fun isGlaciteTunnelsArea(area: String?): Boolean = glaciteTunnelsPattern.matches(area) + + @HandleEvent + fun onAreaChange(event: ScoreboardAreaChangeEvent) { + if (!IslandType.DWARVEN_MINES.isInIsland()) { + inGlaciteTunnels = null + return + } + + val now = isGlaciteTunnelsArea(LorenzUtils.skyBlockArea) + if (inGlaciteTunnels != now) { + inGlaciteTunnels = now + loadDwarvenMines() + } + } + + private fun loadDwarvenMines() { + if (isGlaciteTunnelsArea(LorenzUtils.skyBlockArea)) { + reloadFromJson("GLACITE_TUNNELS") + } else { + reloadFromJson("DWARVEN_MINES") + } + } + + private fun loadIsland(newIsland: IslandType) { + if (newIsland == IslandType.DWARVEN_MINES) { + loadDwarvenMines() + } else { + reloadFromJson(newIsland.name) + } + } + + private fun reloadFromJson(islandName: String) { + val constant = "island_graphs/$islandName" + val name = "constants/$constant.json" + val jsonFile = File(SkyHanniMod.repo.repoLocation, name) + if (!jsonFile.isFile) { + currentIslandGraph = null + return + } + + val graph = RepoUtils.getConstant(SkyHanniMod.repo.repoLocation, constant, Graph.gson, Graph::class.java) + IslandAreas.display = null + setNewGraph(graph) + } + + fun setNewGraph(graph: Graph) { + reset() + currentIslandGraph = graph + + // calling various update functions to make swtiching between deep caverns and glacite tunnels bareable + handleTick() + IslandAreas.nodeMoved() + DelayedRun.runDelayed(150.milliseconds) { + IslandAreas.updatePosition() + } + } + + private fun reset() { + stop() + pathfindClosestNode = null + closestNode = null + } + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!LorenzUtils.inSkyBlock) return + if (event.isMod(2)) { + handleTick() + checkMoved() + } + } + + private fun handleTick() { + val prevClosest = pathfindClosestNode + + currentTarget?.let { + if (it.distanceToPlayer() < 3) { + onFound() + "§e[SkyHanni] Navigation reached §r$label§e!".asComponent().send(PATHFIND_ID) + reset() + } + if (!condition()) { + reset() + } + } + + val graph = currentIslandGraph ?: return + val sortedNodes = graph.sortedBy { it.position.distanceSqToPlayer() } + val newClosest = sortedNodes.first() + if (pathfindClosestNode == newClosest) return + val newPath = !onCurrentPath() + + closestNode = newClosest + secondClosestNode = sortedNodes.getOrNull(1) + onNewNode() + if (newClosest == prevClosest) return + if (newPath) { + pathfindClosestNode = closestNode + findNewPath() + } + } + + private fun onCurrentPath(): Boolean { + val path = fastestPath ?: return false + if (path.isEmpty()) return false + val closest = path.nodes.minBy { it.position.distanceSqToPlayer() } + val distance = closest.position.distanceToPlayer() + if (distance > 7) return false + + val index = path.nodes.indexOf(closest) + val newNodes = path.drop(index) + val newGraph = Graph(newNodes) + fastestPath = skipIfCloser(newGraph) + newNodes.getOrNull(1)?.let { + secondClosestNode = it + } + setFastestPath(newGraph to newGraph.totalLenght(), setPath = false) + return true + } + + private fun skipIfCloser(graph: Graph): Graph = if (graph.nodes.size > 1) { + val hideNearby = if (Minecraft.getMinecraft().thePlayer.onGround) 3 else 5 + Graph(graph.nodes.takeLastWhile { it.position.distanceToPlayer() > hideNearby }) + } else { + graph + } + + private fun findNewPath() { + val goal = IslandGraphs.goal ?: return + val closest = pathfindClosestNode ?: return + + val (path, distance) = GraphUtils.findShortestPathAsGraphWithDistance(closest, goal) + val first = path.firstOrNull() + val second = path.getOrNull(1) + + val playerPosition = LocationUtils.playerLocation() + val nodeDistance = first?.let { playerPosition.distance(it.position) } ?: 0.0 + if (first != null && second != null) { + val direct = playerPosition.distance(second.position) + val firstPath = first.neighbours[second] ?: 0.0 + val around = nodeDistance + firstPath + if (direct < around) { + setFastestPath(Graph(path.drop(1)) to (distance - firstPath + direct)) + return + } + } + setFastestPath(path to (distance + nodeDistance)) + } + + private fun Graph.totalLenght(): Double = nodes.zipWithNext().sumOf { (a, b) -> a.position.distance(b.position) } + + private fun handlePositionChange() { + updateChat() + } + + private var hasMoved = false + + private fun checkMoved() { + if (hasMoved) { + hasMoved = false + if (goal != null) { + handlePositionChange() + } + } + } + + @SubscribeEvent + fun onPlayerMove(event: EntityMoveEvent) { + if (LorenzUtils.inSkyBlock && event.entity == Minecraft.getMinecraft().thePlayer) { + hasMoved = true + } + } + + private fun setFastestPath(path: Pair, setPath: Boolean = true) { + // TODO cleanup + val (fastestPath, distance) = path.takeIf { it.first.isNotEmpty() } ?: return + val nodes = fastestPath.nodes.toMutableList() + if (Minecraft.getMinecraft().thePlayer.onGround) { + nodes.add(0, GraphNode(0, LocationUtils.playerLocation())) + } + if (setPath) { + this.fastestPath = skipIfCloser(Graph(cutByMaxDistance(nodes, 2.0))) + } + updateChat() + } + + private fun onNewNode() { + // TODO create an event + IslandAreas.nodeMoved() + if (shouldAllowRerouting) { + tryRerouting() + } + } + + private fun tryRerouting() { + val target = currentTargetNode ?: return + val closest = pathfindClosestNode ?: return + val map = GraphUtils.findAllShortestDistances(closest).distances.filter { it.key.sameNameAndTags(target) } + val newTarget = map.sorted().keys.firstOrNull() ?: return + if (newTarget != target) { + ChatUtils.debug("Rerouting navigation..") + newTarget.pathFind(label, color, onFound, allowRerouting = true, condition = condition) + } + } + + fun stop() { + currentTarget = null + goal = null + fastestPath = null + currentTargetNode = null + label = "" + totalDistance = 0.0 + lastDistance = 0.0 + } + + /** + * Activates pathfinding, with this graph node as goal. + * + * @param label The name of the naviation goal in chat. + * @param color The color of the lines in world. + * @param onFound The callback that gets fired when the goal is reached. + * @param allowRerouting When a different node with same name and tags as the origianl goal is closer to the player, starts routing to this instead. + * @param condition The pathfinding stops when the condition is no longer valid. + */ + fun GraphNode.pathFind( + label: String, + color: Color = LorenzColor.WHITE.toColor(), + onFound: () -> Unit = {}, + allowRerouting: Boolean = false, + condition: () -> Boolean, + ) { + reset() + currentTargetNode = this + shouldAllowRerouting = allowRerouting + pathFind0(location = position, label, color, onFound, condition) + } + + /** + * Activates pathfinding to a location in the island. + * + * @param location The goal of the pathfinder. + * @param label The name of the naviation goal in chat. + * @param color The color of the lines in world. + * @param onFound The callback that gets fired when the goal is reached. + * @param condition The pathfinding stops when the condition is no longer valid. + */ + fun pathFind( + location: LorenzVec, + label: String, + color: Color = LorenzColor.WHITE.toColor(), + onFound: () -> Unit = {}, + condition: () -> Boolean, + ) { + reset() + shouldAllowRerouting = false + pathFind0(location, label, color, onFound, condition) + } + + private fun pathFind0( + location: LorenzVec, + label: String, + color: Color = LorenzColor.WHITE.toColor(), + onFound: () -> Unit = {}, + condition: () -> Boolean, + ) { + currentTarget = location + this.label = label + this.color = color + this.onFound = onFound + this.condition = condition + val graph = currentIslandGraph ?: return + goal = graph.minBy { it.position.distance(currentTarget!!) } + updateChat() + } + + private const val PATHFIND_ID = -6457563 + + private fun updateChat() { + if (label == "") return + val path = fastestPath ?: return + var distance = 0.0 + if (path.isNotEmpty()) { + for ((a, b) in path.zipWithNext()) { + distance += a.position.distance(b.position) + } + val distanceToPlayer = path.first().position.distanceToPlayer() + distance += distanceToPlayer + distance = distance.roundTo(1) + } + + if (distance == lastDistance) return + lastDistance = distance + if (distance == 0.0) return + if (totalDistance == 0.0 || distance > totalDistance) { + totalDistance = distance + } + sendChatDistance(distance) + } + + private fun sendChatDistance(distance: Double) { + val percentage = (1 - (distance / totalDistance)) * 100 + val componentText = "§e[SkyHanni] Navigating to §r$label §f[§e$distance§f] §f(§c${percentage.roundTo(1)}%§f)".asComponent() + componentText.onClick( + onClick = { + stop() + "§e[SkyHanni] Navigation manually stopped!".asComponent().send(PATHFIND_ID) + }, + ) + componentText.hover = "§eClick to stop navigating!".asComponent() + componentText.send(PATHFIND_ID) + } + + @SubscribeEvent + fun onRenderWorld(event: LorenzRenderWorldEvent) { + if (!LorenzUtils.inSkyBlock) return + val path = fastestPath ?: return + + // maybe reuse for debuggin +// for ((a, b) in path.nodes.zipWithNext()) { +// val diff = a.position.distance(b.position) +// event.drawString(a.position, "diff: ${diff.roundTo(1)}") +// } + event.draw3DPathWithWaypoint( + path, + color, + 6, + true, + bezierPoint = 0.6, + textSize = 1.0, + ) + + val targetLocation = currentTarget ?: return + val lastNode = path.nodes.lastOrNull()?.position ?: return + event.draw3DLine(lastNode.add(0.5, 0.5, 0.5), targetLocation.add(0.5, 0.5, 0.5), color, 4, true) + } + + // TODO move into new utils class + private fun cutByMaxDistance(nodes: List, maxDistance: Double): List { + var index = nodes.size * 10 + val locations = mutableListOf() + var first = true + for (node in nodes) { + if (first) { + first = false + } else { + var lastPosition = locations.last() + val currentPosition = node.position + val vector = (currentPosition - lastPosition).normalize() + var distance = lastPosition.distance(currentPosition) + while (distance > maxDistance) { + distance -= maxDistance + val nextStepDistance = if (distance < maxDistance / 2) { + (maxDistance + distance) / 2 + break + } else maxDistance + val newPosition = lastPosition + (vector * (nextStepDistance)) + locations.add(newPosition) + lastPosition = newPosition + } + } + locations.add(node.position) + } + + return locations.map { GraphNode(index++, it) } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt b/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt index 129e1cd956ec..20dfbb615722 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt @@ -11,9 +11,9 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object LocationFixData { - private var locationFixes = mutableListOf() + private var locationFixes = mutableMapOf>() - class LocationFix(val island: IslandType, val area: AxisAlignedBB, val realLocation: String) + private data class LocationFix(val area: AxisAlignedBB, val realLocation: String) // priority set to low so that IslandType can load their island names from repo earlier @SubscribeEvent(priority = EventPriority.LOW) @@ -26,11 +26,18 @@ object LocationFixData { val area = fix.a.axisAlignedTo(fix.b) val realLocation = fix.realLocation - locationFixes.add(LocationFix(island, area, realLocation)) + val list = locationFixes[island] + + val locationFix = LocationFix(area, realLocation) + + if (list == null) locationFixes[island] = listOf(locationFix) + else locationFixes[island] = list + locationFix } } - fun fixLocation(skyBlockIsland: IslandType) = locationFixes - .firstOrNull { skyBlockIsland == it.island && it.area.isPlayerInside() } - ?.realLocation + fun fixLocation(skyBlockIsland: IslandType): String? = + locationFixes[skyBlockIsland] + ?.find { it.area.isPlayerInside() } + ?.realLocation + } diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt index b4fb7eaa2dc8..949e33146ce6 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt @@ -16,7 +16,7 @@ import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.SecondPassedEvent import at.hannibal2.skyhanni.features.fame.ReminderUtils import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter import at.hannibal2.skyhanni.utils.CollectionUtils.put @@ -143,6 +143,7 @@ object MayorAPI { ChatUtils.clickableChat( "The Perkpocalypse Mayor is not known! Click here to update the temporary Mayor.", onClick = { HypixelCommands.calendar() }, + replaceSameMessage = true, ) } } @@ -170,7 +171,7 @@ object MayorAPI { } ?: false } ?: return - val perk = stack.getLore().nextAfter({ perkpocalypsePerksPattern.matches(it) }) ?: return + val perk = stack.getLore().nextAfter({ perkpocalypsePerksPattern.matches(it) }, 2) ?: return // This is the first Perk of the Perkpocalypse Mayor val jerryMayor = getMayorFromPerk(getPerkFromName(perk.removeColor()) ?: return)?.addAllPerks() ?: return @@ -216,7 +217,7 @@ object MayorAPI { SkyHanniMod.coroutineScope.launch { val url = "https://api.hypixel.net/v2/resources/skyblock/election" - val jsonObject = withContext(dispatcher) { APIUtil.getJSONResponse(url) } + val jsonObject = withContext(dispatcher) { APIUtils.getJSONResponse(url) } rawMayorData = ConfigManager.gson.fromJson(jsonObject) val data = rawMayorData ?: return@launch val map = mutableMapOf() diff --git a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt index 78647944c9a0..335648dc5116 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt @@ -146,6 +146,7 @@ enum class Mayor( fun Mayor.addPerks(perks: List) { perks.forEach { it.isActive = false } + activePerks.forEach { it.isActive = false } activePerks.clear() for (perk in perks.filter { perks.contains(it) }) { perk.isActive = true diff --git a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt index ecf90172dc79..47133f199a49 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt @@ -1,8 +1,10 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.events.BlockClickEvent import at.hannibal2.skyhanni.events.ColdUpdateEvent import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent @@ -11,8 +13,10 @@ import at.hannibal2.skyhanni.events.ScoreboardUpdateEvent import at.hannibal2.skyhanni.events.ServerBlockChangeEvent import at.hannibal2.skyhanni.events.mining.OreMinedEvent import at.hannibal2.skyhanni.events.player.PlayerDeathEvent +import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern import at.hannibal2.skyhanni.features.mining.OreBlock +import at.hannibal2.skyhanni.features.mining.isTitanium import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.countBy import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer @@ -20,7 +24,9 @@ import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.inAnyIsland import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.TimeUtils.format @@ -37,27 +43,71 @@ import kotlin.time.Duration.Companion.seconds object MiningAPI { private val group = RepoPattern.group("data.miningapi") - private val glaciteAreaPattern by group.pattern("area.glacite", "Glacite Tunnels|Glacite Lake") + private val glaciteAreaPattern by group.pattern("area.glacite", "Glacite Tunnels|Great Glacite Lake") private val dwarvenBaseCampPattern by group.pattern("area.basecamp", "Dwarven Base Camp") - // TODO rename to include suffix "pattern", add regex test - private val coldReset by group.pattern( + // TODO add regex test + private val coldResetPattern by group.pattern( "cold.reset", - "§6The warmth of the campfire reduced your §r§b❄ Cold §r§6to §r§a0§r§6!|§c ☠ §r§7You froze to death§r§7.", + "§6The warmth of the campfire reduced your §r§b❄ Cold §r§6to §r§a0§r§6!|§c ☠ §r§7You froze to death§r§7\\.", ) - private data class MinedBlock(val ore: OreBlock, var confirmed: Boolean, val time: SimpleTimeMark = SimpleTimeMark.now()) + private val pickbobulusGroup = group.group("pickobulus") + + /** + * REGEX-TEST: §aYou used your §r§6Pickobulus §r§aPickaxe Ability! + */ + + private val pickobulusUsePattern by pickbobulusGroup.pattern( + "use", + "§aYou used your §r§6Pickobulus §r§aPickaxe Ability!", + ) + + // TODO add regex test + private val pickobulusEndPattern by pickbobulusGroup.pattern( + "end", + "§7Your §r§aPickobulus §r§7destroyed §r§e(?[\\d,.]+) §r§7blocks!", + ) + + /** + * REGEX-TEST: §7Your §r§aPickobulus §r§7didn't destroy any blocks! + */ + private val pickobulusFailPattern by pickbobulusGroup.pattern( + "fail", + "§7Your §r§aPickobulus §r§7didn't destroy any blocks!", + ) + + private data class MinedBlock(val ore: OreBlock, var confirmed: Boolean) { + val time: SimpleTimeMark = SimpleTimeMark.now() + } + + // normal mining + private val recentClickedBlocks = ConcurrentSet>() + private val surroundingMinedBlocks = ConcurrentLinkedQueue>() private var lastInitSound = SimpleTimeMark.farPast() - private var waitingForInitBlock = false - private var waitingForInitBlockPos: LorenzVec? = null + private var initBlockPos: LorenzVec? = null private var waitingForInitSound = true private var waitingForEffMinerSound = false private var waitingForEffMinerBlock = false + // pickobulus + private var lastPickobulusUse = SimpleTimeMark.farPast() + private var lastPickobulusExplosion = SimpleTimeMark.farPast() + private var pickobulusExplosionPos: LorenzVec? = null + private val pickobulusMinedBlocks = ConcurrentLinkedQueue>() + + private val pickobulusActive get() = lastPickobulusUse.passedSince() < 2.seconds + + private var pickobulusWaitingForSound = false + private var pickobulusWaitingForBlock = false + + // oreblock data var inGlacite = false + var inTunnels = false + var inMineshaft = false var inDwarvenMines = false var inCrystalHollows = false var inCrimsonIsle = false @@ -65,18 +115,19 @@ object MiningAPI { var inSpidersDen = false var currentAreaOreBlocks = setOf() + private set - private var lastSkyblockArea: String? = null - - private val recentClickedBlocks = ConcurrentSet>() - private val surroundingMinedBlocks = ConcurrentLinkedQueue>() - private val allowedSoundNames = listOf("dig.glass", "dig.stone", "dig.gravel", "dig.cloth", "random.orb") + private val allowedSoundNames = setOf("dig.glass", "dig.stone", "dig.gravel", "dig.cloth", "random.orb") var cold: Int = 0 private set var lastColdUpdate = SimpleTimeMark.farPast() + private set var lastColdReset = SimpleTimeMark.farPast() + private set + + private var lastOreMinedTime = SimpleTimeMark.farPast() fun inGlaciteArea() = inGlacialTunnels() || IslandType.MINESHAFT.isInIsland() @@ -123,10 +174,29 @@ object MiningAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (!inColdIsland()) return - if (coldReset.matches(event.message)) { + if (coldResetPattern.matches(event.message)) { updateCold(0) lastColdReset = SimpleTimeMark.now() + return } + if (pickobulusUsePattern.matches(event.message)) { + lastPickobulusUse = SimpleTimeMark.now() + return + } + if (pickobulusFailPattern.matches(event.message)) { + resetPickobulusEvent() + pickobulusMinedBlocks.clear() + return + } + pickobulusEndPattern.matchMatcher(event.message) { + val amount = group("amount").formatInt() + resetPickobulusEvent() + val blocks = pickobulusMinedBlocks.take(amount).countBy { it.second } + if (blocks.isNotEmpty()) OreMinedEvent(null, blocks).post() + pickobulusMinedBlocks.clear() + return + } + } @SubscribeEvent @@ -140,14 +210,25 @@ object MiningAPI { @SubscribeEvent fun onPlaySound(event: PlaySoundEvent) { if (!inCustomMiningIsland()) return + if (event.soundName == "random.explode" && lastPickobulusUse.passedSince() < 5.seconds) { + lastPickobulusExplosion = SimpleTimeMark.now() + pickobulusExplosionPos = event.location + pickobulusWaitingForSound = true + return + } if (event.soundName !in allowedSoundNames) return + if (pickobulusActive && pickobulusWaitingForSound) { + pickobulusWaitingForSound = false + pickobulusWaitingForBlock = true + return + } if (waitingForInitSound) { if (event.soundName != "random.orb" && event.pitch == 0.7936508f) { val pos = event.location.roundLocationToBlock() if (recentClickedBlocks.none { it.first == pos }) return waitingForInitSound = false - waitingForInitBlock = true - waitingForInitBlockPos = event.location.roundLocationToBlock() + waitingForEffMinerBlock = true + initBlockPos = event.location.roundLocationToBlock() lastInitSound = SimpleTimeMark.now() } return @@ -164,21 +245,35 @@ object MiningAPI { @SubscribeEvent fun onBlockChange(event: ServerBlockChangeEvent) { if (!inCustomMiningIsland()) return - if (event.newState.block.let { it != Blocks.air && it != Blocks.bedrock }) return - if (event.oldState.block.let { it == Blocks.air || it == Blocks.bedrock }) return - if (event.oldState.block == Blocks.air) return + val oldState = event.oldState + val newState = event.newState + val oldBlock = oldState.block + val newBlock = newState.block + + if (oldState == newState) return + if (oldBlock == Blocks.air || oldBlock == Blocks.bedrock) return + if (newBlock != Blocks.air && newBlock != Blocks.bedrock && !isTitanium(newState)) return + val pos = event.location - if (pos.distanceToPlayer() > 7) return + if (pickobulusActive && pickobulusWaitingForBlock) { + val explosionPos = pickobulusExplosionPos ?: return + if (explosionPos.distance(pos) > 15) return + val ore = OreBlock.getByStateOrNull(oldState) ?: return + if (pickobulusMinedBlocks.any { it.first == pos }) return + pickobulusMinedBlocks += pos to ore + pickobulusWaitingForBlock = false + pickobulusWaitingForSound = true + return + } if (lastInitSound.passedSince() > 100.milliseconds) return + if (pos.distanceToPlayer() > 7) return - val ore = OreBlock.getByStateOrNull(event.oldState) ?: return + val ore = OreBlock.getByStateOrNull(oldState) ?: return - if (waitingForInitBlock) { - if (waitingForInitBlockPos != pos) return - waitingForInitBlock = false + if (initBlockPos == pos) { surroundingMinedBlocks += MinedBlock(ore, true) to pos - waitingForEffMinerBlock = true + runEvent() return } if (waitingForEffMinerBlock) { @@ -193,19 +288,33 @@ object MiningAPI { @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!inCustomMiningIsland()) return - - if (LorenzUtils.lastWorldSwitch.passedSince() < 4.seconds) return - updateLocation() - if (currentAreaOreBlocks.isEmpty()) return // if somehow you take more than 20 seconds to mine a single block, congrats recentClickedBlocks.removeIf { it.second.passedSince() >= 20.seconds } surroundingMinedBlocks.removeIf { it.first.time.passedSince() >= 20.seconds } - if (waitingForInitSound) return - if (lastInitSound.passedSince() < 200.milliseconds) return + if (!waitingForInitSound && lastInitSound.passedSince() > 200.milliseconds) { + resetOreEvent() + } + if (!lastPickobulusUse.isFarPast() && lastPickobulusUse.passedSince() > 5.seconds) { + resetPickobulusEvent() + pickobulusMinedBlocks.clear() + } + } + @HandleEvent + fun onAreaChange(event: ScoreboardAreaChangeEvent) { + if (!inCustomMiningIsland()) return + updateLocation() + } + + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + updateLocation() + } + + private fun runEvent() { resetOreEvent() if (surroundingMinedBlocks.isEmpty()) return @@ -230,19 +339,34 @@ object MiningAPI { lastColdReset = SimpleTimeMark.now() recentClickedBlocks.clear() surroundingMinedBlocks.clear() + pickobulusMinedBlocks.clear() currentAreaOreBlocks = setOf() resetOreEvent() + resetPickobulusEvent() + lastOreMinedTime = SimpleTimeMark.farPast() } private fun resetOreEvent() { lastInitSound = SimpleTimeMark.farPast() waitingForInitSound = true - waitingForInitBlock = false - waitingForInitBlockPos = null + initBlockPos = null waitingForEffMinerSound = false waitingForEffMinerBlock = false } + private fun resetPickobulusEvent() { + lastPickobulusUse = SimpleTimeMark.farPast() + lastPickobulusExplosion = SimpleTimeMark.farPast() + pickobulusExplosionPos = null + pickobulusWaitingForSound = false + pickobulusWaitingForBlock = false + } + + @HandleEvent(onlyOnSkyblock = true) + fun onOreMined(event: OreMinedEvent) { + lastOreMinedTime = SimpleTimeMark.now() + } + @SubscribeEvent fun onDebugDataCollect(event: DebugDataCollectEvent) { event.title("Mining API") @@ -250,6 +374,10 @@ object MiningAPI { event.addIrrelevant("not in a mining island") return } + if (lastOreMinedTime.passedSince() > 30.seconds) { + event.addIrrelevant("not mined recently") + return + } event.addData { if (lastInitSound.isFarPast()) { @@ -258,8 +386,7 @@ object MiningAPI { add("lastInitSound: ${lastInitSound.passedSince().format()}") } add("waitingForInitSound: $waitingForInitSound") - add("waitingForInitBlock: $waitingForInitBlock") - add("waitingForInitBlockPos: $waitingForInitBlockPos") + add("waitingForInitBlockPos: $initBlockPos") add("waitingForEffMinerSound: $waitingForEffMinerSound") add("waitingForEffMinerBlock: $waitingForEffMinerBlock") add("recentlyClickedBlocks: ${recentClickedBlocks.joinToString { "(${it.first.toCleanString()}" }}") @@ -275,12 +402,9 @@ object MiningAPI { } private fun updateLocation() { - val currentArea = LorenzUtils.skyBlockArea - // TODO add area change event with HypixelData.skyBlockArea instead - if (currentArea == lastSkyblockArea) return - lastSkyblockArea = currentArea - inGlacite = inGlaciteArea() + inTunnels = inGlacialTunnels() + inMineshaft = inMineshaft() inDwarvenMines = inRegularDwarven() inCrystalHollows = inCrystalHollows() inCrimsonIsle = IslandType.CRIMSON_ISLE.isInIsland() diff --git a/src/main/java/at/hannibal2/skyhanni/data/OtherPlayersSlayerAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/OtherPlayersSlayerAPI.kt new file mode 100644 index 000000000000..0401746c4edb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/OtherPlayersSlayerAPI.kt @@ -0,0 +1,36 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.mob.Mob +import at.hannibal2.skyhanni.events.MobEvent +import at.hannibal2.skyhanni.events.entity.slayer.SlayerDeathEvent +import at.hannibal2.skyhanni.features.slayer.SlayerType +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object OtherPlayersSlayerAPI { + + @SubscribeEvent + fun onMobDespawn(event: MobEvent.DeSpawn.SkyblockMob) { + val mob = event.mob + + // no death, rather despawn because too far away + if (mob.baseEntity.health != 0f) return + + if (mob.mobType != Mob.Type.SLAYER) return + + val owner = mob.owner?.ownerName + val tier = mob.levelOrTier + val name = mob.name + val slayerType = SlayerType.getByName(name) ?: run { + ErrorManager.logErrorStateWithData( + "Unknown slayer type found", "unknown slayer", + "name" to name, + ) + return + } + + SlayerDeathEvent(slayerType, tier, owner).post() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt index a5a8eb1847bd..0f029a1f2e2e 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt @@ -19,11 +19,11 @@ object PurseAPI { private val patternGroup = RepoPattern.group("data.purse") val coinsPattern by patternGroup.pattern( "coins", - "(§.)*(Piggy|Purse): §6(?[\\d,.]+)( ?(§.)*\\([+-](?[\\d,.]+)\\)?|.*)?$" + "(§.)*(Piggy|Purse): §6(?[\\d,.]+)( ?(§.)*\\([+-](?[\\d,.]+)\\)?|.*)?$", ) val piggyPattern by patternGroup.pattern( "piggy", - "Piggy: (?.*)" + "Piggy: (?.*)", ) private var inventoryCloseTime = SimpleTimeMark.farPast() @@ -54,6 +54,7 @@ object PurseAPI { return PurseChangeCause.GAIN_TALISMAN_OF_COINS } + // TODO relic of coins support if (diff == 15.million || diff == 100.million) { return PurseChangeCause.GAIN_DICE_ROLL } diff --git a/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt index 88daf40b9520..2f516610ca51 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt @@ -16,10 +16,10 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes @@ -236,7 +236,7 @@ object QuiverAPI { } } - fun Int.asArrowPercentage() = ((this.toFloat() / MAX_ARROW_AMOUNT) * 100).round(1) + fun Int.asArrowPercentage() = ((this.toFloat() / MAX_ARROW_AMOUNT) * 100).roundTo(1) fun hasBowInInventory() = hasBow diff --git a/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt index e392699cdbfe..7581b3b1ec94 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt @@ -412,5 +412,5 @@ enum class SackStatus { MISSING, CORRECT, ALRIGHT, - OUTDATED; + OUTDATED, } diff --git a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt index 378fe03c6953..a8cafcf3d981 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt @@ -51,16 +51,13 @@ object ScoreboardData { val lastColor = start.lastColorCode() ?: "" // Generate the list of color suffixes - val colorSuffixes = generateSequence(lastColor) { it.dropLast(2) } - .takeWhile { it.isNotEmpty() } - .toMutableList() + val colorSuffixes = lastColor.chunked(2).toMutableList() // Iterate through the colorSuffixes to remove matching prefixes from 'end' for (suffix in colorSuffixes.toList()) { if (end.startsWith(suffix)) { end = end.removePrefix(suffix) colorSuffixes.remove(suffix) - break } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt index 29a16944c3d3..7a97fca1d19d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt @@ -2,11 +2,12 @@ package at.hannibal2.skyhanni.data.bazaar import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigManager +import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.features.inventory.bazaar.BazaarData import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzUtils @@ -29,10 +30,29 @@ object HypixelBazaarFetcher { private const val HIDDEN_FAILED_ATTEMPTS = 3 var latestProductInformation = mapOf() + private var lastSuccessfulFetch = SimpleTimeMark.farPast() private var nextFetchTime = SimpleTimeMark.farPast() private var failedAttempts = 0 private var nextFetchIsManual = false + @SubscribeEvent + fun onDebugDataCollect(event: DebugDataCollectEvent) { + event.title("Bazaar Data Fetcher from API") + + val data = listOf( + "failedAttempts: $failedAttempts", + "nextFetchIsManual: $nextFetchIsManual", + "nextFetchTime: ${nextFetchTime.timeUntil()}", + "lastSuccessfulFetch: ${lastSuccessfulFetch.passedSince()}", + ) + + if (failedAttempts == 0) { + event.addIrrelevant(data) + } else { + event.addData(data) + } + } + @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!canFetch()) return @@ -46,11 +66,12 @@ object HypixelBazaarFetcher { val fetchType = if (nextFetchIsManual) "manual" else "automatic" nextFetchIsManual = false try { - val jsonResponse = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(URL) }.asJsonObject + val jsonResponse = withContext(Dispatchers.IO) { APIUtils.getJSONResponse(URL) }.asJsonObject val response = ConfigManager.gson.fromJson(jsonResponse) if (response.success) { latestProductInformation = process(response.products) failedAttempts = 0 + lastSuccessfulFetch = SimpleTimeMark.now() } else { val rawResponse = jsonResponse.toString() onError(fetchType, Exception("success=false, cause=${response.cause}"), rawResponse) @@ -98,13 +119,20 @@ object HypixelBazaarFetcher { e.printStackTrace() } else { nextFetchTime = SimpleTimeMark.now() + 15.minutes - ErrorManager.logErrorWithData( - e, - userMessage, - "fetchType" to fetchType, - "failedAttempts" to failedAttempts, - "rawResponse" to rawResponse, - ) + if (rawResponse == null || rawResponse.toString() == "{}") { + ChatUtils.chat( + "§cFailed loading Bazaar Price data!\n" + + "Please wait until the Hypixel API is sending correct data again! There is nothing else to do at the moment.", + ) + } else { + ErrorManager.logErrorWithData( + e, + userMessage, + "fetchType" to fetchType, + "failedAttempts" to failedAttempts, + "rawResponse" to rawResponse, + ) + } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt index 94bc665b6202..edc4f65b0388 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt @@ -214,7 +214,7 @@ object PlayerNameFormatter { val color = rawColor ?: return null val level = rawLevel?.getText() ?: error("level is null, color is not null") val levelData = "$color$level" - val result = if (config.hideLevelBrackets) levelData else "§8[${levelData}§8]" + val result = if (config.hideLevelBrackets) levelData else "§8[$levelData§8]" return result.applyFormattingFrom(rawLevel) } diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt index a26af584b8a6..e2b9e04ef3ff 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt @@ -1,7 +1,7 @@ package at.hannibal2.skyhanni.data.hypixel.chat.event -import at.hannibal2.skyhanni.utils.StringUtils.cleanPlayerName import at.hannibal2.skyhanni.utils.ComponentSpan +import at.hannibal2.skyhanni.utils.StringUtils.cleanPlayerName import net.minecraft.util.IChatComponent class PartyChatEvent( diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/CarryTrackerJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/CarryTrackerJson.kt new file mode 100644 index 000000000000..1819b36b9517 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/CarryTrackerJson.kt @@ -0,0 +1,8 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +data class CarryTrackerJson( + @Expose @SerializedName("slayer_names") val slayerNames: Map>, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt index 5e601ed32745..ead4eb83c298 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt @@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.data.jsonobjects.repo import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.utils.LorenzVec import com.google.gson.annotations.Expose +import java.util.TreeSet data class HoppityEggLocationsJson( @Expose val eggLocations: Map>, @@ -21,7 +22,14 @@ data class HoppityEggLocationsJson( @Expose val coachRabbitIndex: Int, @Expose val maxRabbits: Int, @Expose val maxPrestige: Int, - @Expose val maxMilestoneChocolate: Long, + @Expose val chocolateMilestones: TreeSet, + @Expose val chocolateShopMilestones: List, + @Expose val chocolateFactoryMilestones: List, @Expose val apiEggLocations: Map>, @Expose val specialRabbits: List, ) + +data class MilestoneJson( + @Expose val amount: Long, + @Expose val rabbit: String, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/RepoErrorData.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/RepoErrorData.kt new file mode 100644 index 000000000000..41d0f701cb15 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/RepoErrorData.kt @@ -0,0 +1,19 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +data class RepoErrorJson( + @Expose @SerializedName("changed_error_messages") val changedErrorMessages: List, +) + +data class RepoErrorData( + @Expose @SerializedName("message_exact") private var rawMessageExact: List?, + @Expose @SerializedName("message_starts_with") private var rawMessageStartsWith: List?, + @Expose @SerializedName("replace_message") var replaceMessage: String?, + @Expose @SerializedName("custom_message") var customMessage: String?, + @Expose @SerializedName("affected_versions") var affectedVersions: List = listOf(), +) { + val messageExact get() = rawMessageExact ?: emptyList() + val messageStartsWith get() = rawMessageStartsWith ?: emptyList() +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/RiftWoodenButtonsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/RiftWoodenButtonsJson.kt new file mode 100644 index 000000000000..fdc4befe785f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/RiftWoodenButtonsJson.kt @@ -0,0 +1,13 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import at.hannibal2.skyhanni.utils.LorenzVec +import com.google.gson.annotations.Expose + +data class RiftWoodenButtonsJson( + @Expose val houses: Map> +) + +data class ButtonSpots( + @Expose val position: LorenzVec, + @Expose val buttons: List +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuEssenceCostJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuEssenceCostJson.kt new file mode 100644 index 000000000000..12aa600ee48f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuEssenceCostJson.kt @@ -0,0 +1,40 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo.neu + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName +import com.google.gson.reflect.TypeToken +import java.lang.reflect.Type + +data class NeuEssenceCostJson( + @Expose @SerializedName("type") val essenceType: String, + @Expose @SerializedName("dungeonize") val essenceForDungeonize: Int?, + @Expose @SerializedName("1") val essenceFor1: Int?, + @Expose @SerializedName("2") val essenceFor2: Int?, + @Expose @SerializedName("3") val essenceFor3: Int?, + @Expose @SerializedName("4") val essenceFor4: Int?, + @Expose @SerializedName("5") val essenceFor5: Int?, + @Expose @SerializedName("6") val essenceFor6: Int?, + @Expose @SerializedName("7") val essenceFor7: Int?, + @Expose @SerializedName("8") val essenceFor8: Int?, + @Expose @SerializedName("9") val essenceFor9: Int?, + @Expose @SerializedName("10") val essenceFor10: Int?, + @Expose @SerializedName("11") val essenceFor11: Int?, + @Expose @SerializedName("12") val essenceFor12: Int?, + @Expose @SerializedName("13") val essenceFor13: Int?, + @Expose @SerializedName("14") val essenceFor14: Int?, + @Expose @SerializedName("15") val essenceFor15: Int?, + @Expose @SerializedName("items") val extraItems: Map>?, + + @Expose @SerializedName("catacombs_requirements") val catacombsRequirements: List, +) { + + companion object { + val TYPE: Type = object : TypeToken>() {}.type + } +} + +data class NeuCatacombsRequirements( + @Expose @SerializedName("type") val type: String, + @Expose @SerializedName("dungeon_type") val dungeonType: String?, + @Expose @SerializedName("level") val level: Int, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt b/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt index 2acbe3546117..eed2d5e70dba 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt @@ -58,26 +58,28 @@ object IslandExceptions { armorStand: EntityArmorStand?, nextEntity: EntityLivingBase?, ) = when { - baseEntity is EntityZombie && armorStand != null && + baseEntity is EntityZombie && + armorStand != null && (armorStand.name == "§e﴾ §c§lThe Watcher§r§r §e﴿" || armorStand.name == "§3§lWatchful Eye§r") -> MobData.MobResult.found( MobFactories.special(baseEntity, armorStand.cleanName(), armorStand), ) - baseEntity is EntityCaveSpider -> MobUtils.getClosedArmorStand(baseEntity, 2.0).takeNonDefault() + baseEntity is EntityCaveSpider -> MobUtils.getClosestArmorStand(baseEntity, 2.0).takeNonDefault() .makeMobResult { MobFactories.dungeon(baseEntity, it) } baseEntity is EntityOtherPlayerMP && baseEntity.isNPC() && baseEntity.name == "Shadow Assassin" -> - MobUtils.getClosedArmorStandWithName(baseEntity, 3.0, "Shadow Assassin") + MobUtils.getClosestArmorStandWithName(baseEntity, 3.0, "Shadow Assassin") .makeMobResult { MobFactories.dungeon(baseEntity, it) } baseEntity is EntityOtherPlayerMP && baseEntity.isNPC() && baseEntity.name == "The Professor" -> MobUtils.getArmorStand(baseEntity, 9) .makeMobResult { MobFactories.boss(baseEntity, it) } - baseEntity is EntityOtherPlayerMP && baseEntity.isNPC() && + baseEntity is EntityOtherPlayerMP && + baseEntity.isNPC() && (nextEntity is EntityGiantZombie || nextEntity == null) && - baseEntity.name.contains("Livid") -> MobUtils.getClosedArmorStandWithName(baseEntity, 6.0, "﴾ Livid") + baseEntity.name.contains("Livid") -> MobUtils.getClosestArmorStandWithName(baseEntity, 6.0, "﴾ Livid") .makeMobResult { MobFactories.boss(baseEntity, it, overriddenName = "Real Livid") } baseEntity is EntityIronGolem && MobFilter.wokeSleepingGolemPattern.matches(armorStand?.name ?: "") -> @@ -174,7 +176,8 @@ object IslandExceptions { baseEntity: EntityLivingBase, armorStand: EntityArmorStand?, ) = when { - baseEntity is EntityMagmaCube && armorStand != null && + baseEntity is EntityMagmaCube && + armorStand != null && armorStand.cleanName() == "[Lv100] Bal ???❤" -> MobData.MobResult.found( Mob(baseEntity, Mob.Type.BOSS, armorStand, "Bal", levelOrTier = 100), @@ -188,7 +191,8 @@ object IslandExceptions { armorStand: EntityArmorStand?, nextEntity: EntityLivingBase?, ) = when { - baseEntity is EntityOcelot && armorStand?.isDefaultValue() == false && + baseEntity is EntityOcelot && + armorStand?.isDefaultValue() == false && armorStand.name.startsWith("§8[§7Lv155§8] §cAzrael§r") -> MobUtils.getArmorStand(baseEntity, 1) .makeMobResult { MobFactories.basic(baseEntity, it) } @@ -203,7 +207,8 @@ object IslandExceptions { MobUtils.getArmorStand(baseEntity, 2) .makeMobResult { MobFactories.basic(baseEntity, it, listOf(armorStand)) } - baseEntity is EntityZombie && armorStand?.isDefaultValue() == true && + baseEntity is EntityZombie && + armorStand?.isDefaultValue() == true && MobUtils.getNextEntity(baseEntity, 4)?.name?.startsWith("§e") == true -> petCareHandler(baseEntity) @@ -250,7 +255,8 @@ object IslandExceptions { .take(RAT_SEARCH_UP_TO - RAT_SEARCH_START + 1) .map { i -> MobUtils.getArmorStand(baseEntity, i) } .firstOrNull { - it != null && it.distanceTo(baseEntity) < 4.0 && + it != null && + it.distanceTo(baseEntity) < 4.0 && it.inventory?.get(4)?.getSkullTexture() == MobFilter.RAT_SKULL }?.let { MobData.MobResult.found(Mob(baseEntity, mobType = Mob.Type.BASIC, armorStand = it, name = "Rat")) diff --git a/src/main/java/at/hannibal2/skyhanni/data/mob/MobDetection.kt b/src/main/java/at/hannibal2/skyhanni/data/mob/MobDetection.kt index b7cc4dfaa13a..34f776308fda 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/mob/MobDetection.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/mob/MobDetection.kt @@ -13,6 +13,7 @@ import at.hannibal2.skyhanni.events.MobEvent import at.hannibal2.skyhanni.events.minecraft.ClientDisconnectEvent import at.hannibal2.skyhanni.events.minecraft.packet.PacketReceivedEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.CollectionUtils.drainForEach import at.hannibal2.skyhanni.utils.CollectionUtils.drainTo import at.hannibal2.skyhanni.utils.CollectionUtils.put @@ -31,6 +32,7 @@ import net.minecraft.entity.player.EntityPlayer import net.minecraft.network.play.server.S01PacketJoinGame import net.minecraft.network.play.server.S0CPacketSpawnPlayer import net.minecraft.network.play.server.S0FPacketSpawnMob +import net.minecraft.world.World import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicBoolean @@ -62,8 +64,42 @@ object MobDetection { MobData.currentMobs.map { it.createDeSpawnEvent() }.forEach { it.postAndCatch() } + MobData.retries.clear() } + // TODO this is a unused debug funciton. maybe connect with a debug commmand or remove + private fun watchdog() { + val world = LorenzUtils.getPlayer()?.worldObj ?: return + if (MobData.retries.any { it.value.entity.worldObj != world }) { + ChatUtils.chat("Watchdog: Retires") + } + if (MobData.currentMobs.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: Current Mobs") + } + if (MobData.players.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: Players") + } + if (MobData.displayNPCs.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: Display NPCs") + } + if (MobData.skyblockMobs.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: SkyBlockMobs") + } + if (MobData.summoningMobs.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: Summoning") + } + if (MobData.special.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: Special") + } + if (MobData.notSeenMobs.any { it.watchdogCheck(world) }) { + ChatUtils.chat("Watchdog: Not Seen Mobs") + } + } + + private fun Mob.watchdogCheck(world: World): Boolean = + this.baseEntity.worldObj != world || (this.armorStand?.let { it.worldObj != world } + ?: false) || this.extraEntities.any { it.worldObj != world } + @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (shouldClear.get()) { // Needs to work outside skyblock since it needs clearing when leaving skyblock and joining limbo @@ -90,7 +126,7 @@ object MobDetection { MobData.currentEntityLiving.clear() // Naturally removing the mobs using the despawn } - (MobData.currentEntityLiving - MobData.previousEntityLiving).forEach { addRetry(it) } // Spawn + (MobData.currentEntityLiving - MobData.previousEntityLiving).forEach { addRetry(it) } // Spawn (MobData.previousEntityLiving - MobData.currentEntityLiving).forEach { entityDeSpawn(it) } // Despawn MobData.notSeenMobs.removeIf(::canBeSeen) @@ -266,13 +302,13 @@ object MobDetection { val entity = retry.entity if (retry.times == MAX_RETRIES) { MobData.logger.log( - "`${retry.entity.name}`${retry.entity.entityId} missed {\n " - + "is already Found: ${MobData.entityToMob[retry.entity] != null})." - + "\n Position: ${retry.entity.getLorenzVec()}\n " - + "DistanceC: ${ - entity.getLorenzVec().distanceChebyshevIgnoreY(LocationUtils.playerLocation()) - }\n" - + "Relative Position: ${entity.getLorenzVec() - LocationUtils.playerLocation()}\n " + + "`${retry.entity.name}`${retry.entity.entityId} missed {\n " + + "is already Found: ${MobData.entityToMob[retry.entity] != null})." + + "\n Position: ${retry.entity.getLorenzVec()}\n " + + "DistanceC: ${ + entity.getLorenzVec().distanceChebyshevIgnoreY(LocationUtils.playerLocation()) + }\n" + + "Relative Position: ${entity.getLorenzVec() - LocationUtils.playerLocation()}\n " + "}", ) // Uncomment this to make it closed a loop diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt index 21440197d8b0..6e1f1d07f0a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt @@ -1,40 +1,41 @@ package at.hannibal2.skyhanni.data.model -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.features.misc.pathfind.NavigationHelper import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.json.SkyHanniTypeAdapters.registerTypeAdapter import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.GsonBuilder import com.google.gson.JsonElement import com.google.gson.annotations.Expose import com.google.gson.stream.JsonToken -import java.util.PriorityQueue +// TODO: This class should be disambiguated into a NodePath and a Graph class @JvmInline value class Graph( - @Expose val graph: List, + @Expose val nodes: List, ) : List { override val size - get() = graph.size + get() = nodes.size - override fun contains(element: GraphNode) = graph.contains(element) + override fun contains(element: GraphNode) = nodes.contains(element) - override fun containsAll(elements: Collection) = graph.containsAll(elements) + override fun containsAll(elements: Collection) = nodes.containsAll(elements) - override fun get(index: Int) = graph.get(index) + override fun get(index: Int) = nodes.get(index) - override fun isEmpty() = graph.isEmpty() + override fun isEmpty() = nodes.isEmpty() - override fun indexOf(element: GraphNode) = graph.indexOf(element) + override fun indexOf(element: GraphNode) = nodes.indexOf(element) - override fun iterator(): Iterator = graph.iterator() - override fun listIterator() = graph.listIterator() + override fun iterator(): Iterator = nodes.iterator() + override fun listIterator() = nodes.listIterator() - override fun listIterator(index: Int) = graph.listIterator(index) + override fun listIterator(index: Int) = nodes.listIterator(index) - override fun subList(fromIndex: Int, toIndex: Int) = graph.subList(fromIndex, toIndex) + override fun subList(fromIndex: Int, toIndex: Int) = nodes.subList(fromIndex, toIndex) - override fun lastIndexOf(element: GraphNode) = graph.lastIndexOf(element) + override fun lastIndexOf(element: GraphNode) = nodes.lastIndexOf(element) companion object { val gson = GsonBuilder().setPrettyPrinting().registerTypeAdapter( @@ -49,7 +50,7 @@ value class Graph( out.name("Name").value(it) } - it.tagNames?.takeIf { it.isNotEmpty() }?.let { + it.tagNames.takeIf { list -> list.isNotEmpty() }?.let { out.name("Tags") out.beginArray() for (tagName in it) { @@ -62,7 +63,7 @@ value class Graph( out.beginObject() for ((node, weight) in it.neighbours) { val id = node.id.toString() - out.name(id).value(weight.round(2)) + out.name(id).value(weight.roundTo(2)) } out.endObject() @@ -79,8 +80,8 @@ value class Graph( reader.beginObject() var position: LorenzVec? = null var name: String? = null - var tags: List? = null - var neighbors = mutableListOf>() + var tags = emptyList() + val neighbors = mutableListOf>() while (reader.hasNext()) { if (reader.peek() != JsonToken.NAME) { reader.skipValue() @@ -137,10 +138,18 @@ value class Graph( fun fromJson(json: String): Graph = gson.fromJson(json) fun fromJson(json: JsonElement): Graph = gson.fromJson(json) } + + fun toPositionsList() = this.map { it.position } + + fun toJson(): String = gson.toJson(this) } // The node object that gets parsed from/to json -class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, val tagNames: List? = null) { +class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, val tagNames: List = emptyList()) { + + val tags: List by lazy { + tagNames.mapNotNull { GraphNodeTag.byId(it) } + } /** Keys are the neighbours and value the edge weight (e.g. Distance) */ lateinit var neighbours: Map @@ -159,53 +168,41 @@ class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, return true } -} - -fun Graph.findShortestPathAsGraph(start: GraphNode, end: GraphNode): Graph = this.findShortestPathAsGraphWithDistance(start, end).first - -fun Graph.findShortestPathAsGraphWithDistance(start: GraphNode, end: GraphNode): Pair { - val distances = mutableMapOf() - val previous = mutableMapOf() - val visited = mutableSetOf() - val queue = PriorityQueue(compareBy { distances.getOrDefault(it, Double.MAX_VALUE) }) - - distances[start] = 0.0 - queue.add(start) - while (queue.isNotEmpty()) { - val current = queue.poll() - if (current == end) break + fun sameNameAndTags(other: GraphNode): Boolean = name == other.name && allowedTags == other.allowedTags - visited.add(current) + private val allowedTags get() = tags.filter { it in NavigationHelper.allowedTags } +} - current.neighbours.forEach { (neighbour, weight) -> - if (neighbour !in visited) { - val newDistance = distances.getValue(current) + weight - if (newDistance < distances.getOrDefault(neighbour, Double.MAX_VALUE)) { - distances[neighbour] = newDistance - previous[neighbour] = current - queue.add(neighbour) - } - } +data class DijkstraTree( + val origin: GraphNode, + /** + * A map of distances between the [origin] and each node in a graph. This distance map is only accurate for nodes closer to the + * origin than the [lastVisitedNode]. In case there is no early bailout, this map will be accurate for all nodes in the graph. + */ + val distances: Map, + /** + * A map of nodes to the neighbouring node that is the quickest path towards the origin (the neighbouring node that has the lowest value + * in [distances]) + */ + val towardsOrigin: Map, + /** + * This is either the furthest away node in the graph, or the node that was bailed out on early because it fulfilled the search + * condition. In case the search condition matches nothing, this will *still* be the furthest away node, so an additional check might be + * necessary. + */ + val lastVisitedNode: GraphNode, +) + +fun DijkstraTree.findPathToDestination(end: GraphNode): Pair { + val distances = this + val reversePath = buildList { + var current = end + while (true) { + add(current) + if (current == distances.origin) break + current = distances.towardsOrigin[current] ?: return Graph(emptyList()) to 0.0 } } - - return Graph( - buildList { - var current = end - while (current != start) { - add(current) - current = previous[current] ?: return Graph(emptyList()) to 0.0 - } - add(start) - }.reversed(), - ) to distances[end]!! + return Graph(reversePath.reversed()) to distances.distances[end]!! } - -fun Graph.findShortestPath(start: GraphNode, end: GraphNode): List = this.findShortestPathAsGraph(start, end).toPositionsList() - -fun Graph.findShortestDistance(start: GraphNode, end: GraphNode): Double = this.findShortestPathAsGraphWithDistance(start, end).second - -fun Graph.toPositionsList() = this.map { it.position } - -fun Graph.toJson(): String = Graph.gson.toJson(this) diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt b/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt index a7349801324a..8efcf4621e37 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt @@ -1,46 +1,88 @@ package at.hannibal2.skyhanni.data.model +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.utils.LorenzColor -enum class GraphNodeTag(val internalName: String?, val color: LorenzColor, val cleanName: String, val description: String) { +enum class GraphNodeTag( + val internalName: String, + val color: LorenzColor, + val cleanName: String, + val description: String, + val onlyIsland: IslandType? = null, +) { DEV("dev", LorenzColor.WHITE, "Dev", "Intentionally marked as dev."), // E.g. Spawn points, todos, etc // Everywhere - NPC("npc", LorenzColor.YELLOW, "NPC", "A NPC entity."), // also take from neu repo + NPC("npc", LorenzColor.YELLOW, "NPC", "A NPC to talk to."), // also take from neu repo AREA("area", LorenzColor.DARK_GREEN, "Area", "A big SkyBlock area."), SMALL_AREA("small_area", LorenzColor.GREEN, "Small Area", "A small SkyBlock area, e.g. a house."), - POI("poi", LorenzColor.WHITE, "PoI", "Point of interest."), - LAUNCH_PAD("launch", LorenzColor.WHITE, "Launch Pad", "Slime blocks sending you to another server."), + POI("poi", LorenzColor.WHITE, "Point of Interest", "A relevant spot or a landmark on the map."), + // LAUNCH_PAD("launch", LorenzColor.WHITE, "Launch Pad", "Slime blocks sending you to another server."), + TELEPORT("teleport", LorenzColor.BLUE, "Teleport", "A spot from/to teleport."), // on multiple islands - ROMEO("romeo", LorenzColor.WHITE, "Romeo & Juliette Quest", "Blocks related to the Romeo and Juliette/Ring of Love quest line."), + ROMEO("romeo", LorenzColor.WHITE, "Romeo & Juliette Quest", "Spots related to the Romeo and Juliette/Ring of Love quest line."), RACE("race", LorenzColor.WHITE, "Race Start/Stop", "A race start or stop point."), - SLAYER("slayer", LorenzColor.WHITE, "Slayer", "A Slayer area"), + SLAYER("slayer", LorenzColor.RED, "Slayer", "A Slayer area."), + HOPPITY("hoppity", LorenzColor.AQUA, "Hoppity Egg", "An egg location in Hoppity's Hunt."), + GRIND_MOBS("grind_mobs", LorenzColor.RED, "Mob Spawn Area", "An area where mobs spawn that can be killed."), + GRIND_ORES("grind_ores", LorenzColor.DARK_AQUA, "Ore Vein", "A regenerating ore vein that can be mined."), + GRIND_CROPS("grind_crops", LorenzColor.DARK_GREEN, "Crop Area", "An area where crops grow that can be farmed."), // hoppity // Hub - HUB_12_STARTER("starter_npc", LorenzColor.WHITE, "Starter NPC", "One of the 12 starter NPC's you need to talk to."), + HUB_12_STARTER( + "starter_npc", LorenzColor.WHITE, "Starter NPC", "One of the 12 starter NPC's you need to talk to.", + onlyIsland = IslandType.HUB, + ), // diana // Farming Islands: Pelts - FARMING_CROP("farming_crop", LorenzColor.WHITE, "Farming Crop", "A spot where you can break crops on farming islands."), +// FARMING_CROP("farming_crop", LorenzColor.WHITE, "Farming Crop", "A spot where you can break crops on farming islands."), // Rift - RIFT_ENIGMA("rift_enigma", LorenzColor.DARK_PURPLE, "Enigma Soul", "Enigma Souls in the rift."), - RIFT_EYE("rift_eye", LorenzColor.DARK_RED, "Eye", "An Eye in the rift to teleport to."), + RIFT_ENIGMA("rift_enigma", LorenzColor.DARK_PURPLE, "Enigma Soul", "Enigma Souls in the Rift.", onlyIsland = IslandType.THE_RIFT), + RIFT_BUTTONS_QUEST("rift_buttons_quest", LorenzColor.LIGHT_PURPLE, "Wooden Buttons", "A spot to hit wooden buttons for the Dreadfarm Enigma Soul.", onlyIsland = IslandType.THE_RIFT), + RIFT_EYE("rift_eye", LorenzColor.DARK_RED, "Rift Eye", "An Eye in the Rift to teleport to.", onlyIsland = IslandType.THE_RIFT), + RIFT_MONTEZUMA( + "rift_montezuma", + LorenzColor.GRAY, + "Montezuma Soul Piece", + "A piece of the Montezuma Soul.", + onlyIsland = IslandType.THE_RIFT, + ), + RIFT_EFFIGY("rift_effigy", LorenzColor.RED, "Blood Effigies", "Locations of the Blood Effigies.", onlyIsland = IslandType.THE_RIFT), // Spider's Den - SPIDER_RELIC("SPIDER_RELIC", LorenzColor.DARK_PURPLE, "Relic", "An relic in the Spider's Den."), + SPIDER_RELIC( + "SPIDER_RELIC", + LorenzColor.DARK_PURPLE, + "Spider's Relic", + "An relic in the Spider's Den.", + onlyIsland = IslandType.SPIDER_DEN, + ), // Dwarven Mines - MINES_EMISSARY("mines_emissary", LorenzColor.GOLD, "Emissary", "A Emissary from the king."), + MINES_EMISSARY("mines_emissary", LorenzColor.GOLD, "Mines Emissary", "An Emissary to the king.", onlyIsland = IslandType.DWARVEN_MINES), // commission areas + // Crimson Isles + CRIMSON_MINIBOSS( + "crimson_miniboss", + LorenzColor.RED, + "Crimson Miniboss", + "A Miniboss in the Crimson Isle.", + onlyIsland = IslandType.CRIMSON_ISLE, + ), + + // The End + END_GOLEM("end_golem", LorenzColor.RED, "Golem Spawn", "A spot where the golem can spawn in the End.", onlyIsland = IslandType.THE_END), + ; val displayName: String = color.getChatColor() + cleanName companion object { - fun byId(internalName: String?): GraphNodeTag? = values().firstOrNull { it.internalName == internalName } + fun byId(internalName: String?): GraphNodeTag? = entries.firstOrNull { it.internalName == internalName } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt b/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt index 6fd65778ecfb..f31c95958659 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt @@ -43,8 +43,18 @@ enum class SkyblockStat(val icon: String) { PRISTINE("§5✧"), FORAGING_FORTUNE("§☘"), FARMING_FORTUNE("§6☘"), + + MINING_SPREAD("§e▚"), MINING_FORTUNE("§6☘"), - FEAR("§a☠") + ORE_FORTUNE("§6☘"), + DWARVEN_METAL_FORTUNE("§6☘"), + BLOCK_FORTUNE("§6☘"), + GEMSTONE_FORTUNE("§6☘"), + + FEAR("§a☠"), + HEAT_RESISTANCE("§c♨"), + + UNKNOWN("§c?") ; val capitalizedName = name.lowercase().allLettersFirstUppercase() @@ -57,6 +67,10 @@ enum class SkyblockStat(val icon: String) { val fontSizeOfLargestIcon by lazy { entries.maxOf { Minecraft.getMinecraft().fontRendererObj.getStringWidth(it.icon) } + 1 } + + fun getValueOrNull(string: String): SkyblockStat? = entries.firstOrNull { it.name == string } + + fun getValue(string: String): SkyblockStat = getValueOrNull(string) ?: UNKNOWN } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt index 523121b3763d..85c50528f4e4 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt @@ -195,7 +195,7 @@ enum class TabWidget( ), BROODMOTHER( // language=RegExp - "Broodmother: (?:§.)*(?