diff --git a/.github/scripts/checkDependencies.mjs b/.github/scripts/checkDependencies.mjs new file mode 100644 index 000000000000..2e351bbe6daa --- /dev/null +++ b/.github/scripts/checkDependencies.mjs @@ -0,0 +1,71 @@ +import {Octokit} from "@octokit/rest"; +import fetch from "node-fetch"; + +const labelName = "Waiting on Dependency PR"; + +async function run() { + const octokit = new Octokit({ + auth: process.env.GITHUB_TOKEN, + request: { + fetch: fetch, + }, + }); + + const context = JSON.parse(process.env.GITHUB_CONTEXT); + + const pull_request = context.event.pull_request; + + const owner = context.repository_owner; + const name = context.repository.split("/")[1]; + + const prNumber = pull_request.number; + const prBody = pull_request.body || ""; + + const dependencyRegex = /## Dependencies/; + const match = prBody.match(dependencyRegex); + + if (match) { + const prLinks = prBody.match(/- https:\/\/github\.com\/[\w-]+\/[\w-]+\/pull\/\d+/g); + + if (prLinks && prLinks.length > 0) { + let hasOpenDependencies = false; + + for (const link of prLinks) { + const [, depOwner, depRepo, depNumber] = link.match(/github\.com\/([\w-]+)\/([\w-]+)\/pull\/(\d+)/); + const {data: dependencyPr} = await octokit.pulls.get({ + owner: depOwner, + repo: depRepo, + pull_number: depNumber, + }); + + if (dependencyPr.state === "open") { + hasOpenDependencies = true; + break; + } + } + + const labels = pull_request.labels.map(label => label.name); + + if (hasOpenDependencies && !labels.includes(labelName)) { + await octokit.issues.addLabels({ + owner, + repo: name, + issue_number: prNumber, + labels: [labelName], + }); + } else if (!hasOpenDependencies && labels.includes(labelName)) { + await octokit.issues.removeLabel({ + owner, + repo: name, + issue_number: prNumber, + name: labelName, + }); + } + } + } +} + +run().catch(error => { + console.error(error); + process.exit(1); +}); diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 379f842d8e19..8275ac8b0740 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,44 +1,63 @@ name: Build on: - push: - branches: - - "*" - paths-ignore: - - ".gitignore" - pull_request: - branches: - - "*" - paths-ignore: - - ".gitignore" - workflow_dispatch: + push: + branches: + - "*" + paths-ignore: + - ".gitignore" + pull_request: + branches: + - "*" + paths-ignore: + - ".gitignore" + workflow_dispatch: permissions: write-all jobs: - build: - runs-on: ubuntu-latest - name: "Build and test" - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: temurin - cache: gradle - - name: Setup gradle - uses: gradle/gradle-build-action@v2 - - name: Build with Gradle - run: ./gradlew build -x test --stacktrace - - uses: actions/upload-artifact@v3 - name: Upload development build - with: - name: "Development Build" - path: build/libs/*.jar - - name: Test with Gradle - run: ./gradlew test - - uses: actions/upload-artifact@v3 - name: "Upload test report" - if: ${{ !cancelled() }} - with: - name: "Test Results" - path: build/reports/tests/test/ + build: + 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: Build with Gradle + run: ./gradlew assemble -x test --stacktrace + - uses: actions/upload-artifact@v3 + name: Upload development build + with: + name: "Development Build" + path: versions/1.8.9/build/libs/*.jar + - name: Test with Gradle + run: ./gradlew test + - uses: actions/upload-artifact@v3 + name: "Upload test report" + if: ${{ !cancelled() }} + with: + name: "Test Results" + path: versions/1.8.9/build/reports/tests/test/ + 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: Enable preprocessor + run: | + mkdir -p .gradle + echo skyhanni.multi-version=preprocess-only > .gradle/private.properties + - name: Build with Gradle + run: ./gradlew build --stacktrace diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml new file mode 100644 index 000000000000..50f3641ae03c --- /dev/null +++ b/.github/workflows/check_dependencies.yml @@ -0,0 +1,29 @@ +name: Check PR Dependencies + +on: + pull_request_target: + types: [ opened, edited ] + push: + branches: + - beta + +jobs: + check-dependencies: + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '16' + + - name: Install dependencies + run: npm install @octokit/rest node-fetch + + - name: Run dependency check script + run: node .github/scripts/checkDependencies.mjs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_CONTEXT: ${{ toJson(github) }} diff --git a/.github/workflows/generate-constants.yaml b/.github/workflows/generate-constants.yaml index 505a035b2ada..c589676d0e2f 100644 --- a/.github/workflows/generate-constants.yaml +++ b/.github/workflows/generate-constants.yaml @@ -18,10 +18,10 @@ jobs: name: "Generate regexes" steps: - uses: actions/checkout@v3 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: 17 + java-version: 21 distribution: temurin cache: gradle - name: Setup gradle @@ -33,7 +33,7 @@ jobs: name: Upload generated repo regexes with: name: Repo Regexes - path: build/regexes/constants.json + path: versions/1.8.9/build/regexes/constants.json publish-regexes: runs-on: ubuntu-latest needs: regexes diff --git a/.gitignore b/.gitignore index c303fd98c5bf..d77f4bd8b6f0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ gradle.properties .devauth/* !.devauth/config.toml +.kotlin diff --git a/.idea/dictionaries/default_user.xml b/.idea/dictionaries/default_user.xml index 29903e6587fb..b166e60d38fd 100644 --- a/.idea/dictionaries/default_user.xml +++ b/.idea/dictionaries/default_user.xml @@ -243,6 +243,7 @@ statspocalypse stillgore stonk + stonks superboom supercraft supercrafting diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62ffd979ea84..57f22f2e2583 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -180,3 +180,194 @@ Plugin [HotSwap Agent](https://plugins.jetbrains.com/plugin/9552-hotswapagent) t Follow [this](https://forums.Minecraftforge.net/topic/82228-1152-3110-intellij-and-gradlew-forge-hotswap-and-dcevm-tutorial/) tutorial. + +## 1.21 / Modern version development + +You might have noticed that while the SkyHanni source code is found in `src/`, the actual tasks for compiling, building and running the mod +are located in a subproject called `1.8.9`. This is because SkyHanni is preparing for the eventual fall of 1.8.9 (via the foraging update or +otherwise). + +To do so (while not disrupting regular development) we use [preprocessor](https://github.com/Deftu/RM-Preprocessor). Preprocessor +automatically transforms code based on mappings as well as comment directives to create multiple variants of your source code for +different Minecraft versions. + +Note also that the only targets we consider are 1.8.9 and 1.21 (or whatever the latest version we may target). The other versions are only there +to make mappings translate more easily (more on that later). + +### Goals + +It is the explicit goal of this operation to passively generate a 1.21 version of SH using preprocessor. To this end, contributors are +encouraged to add mappings and preprocessing directives to their features to make them compile on 1.21. *However*, this is considered a very +low priority. Due to the confusing nature (and the slower initial setup time due to decompiling four versions of Minecraft), this feature +is disabled by default. Similarly, it is up to each contributor to decide if they want to learn how to use preprocessor mappings and +directives. An explicit non-goal is to maintain two SH versions continuously; instead, we only want to make the eventual transition to 1.21 a task +that can be slowly worked on over a long span of time. + +### Set Up + +The modern version variants can be set using `skyhanni.multi-version` in `.gradle/private.properties` to three levels. + +`off` completely disables any preprocessor action or alternative versions. There will be only one project (although still at the `:1.8.9` +subproject path), and alternative version sources will not be generated (although old generated sources **will not be deleted**). To make +setting up a dev environment as fast and discernible as possible, this is the default option. + +`preprocess-only` adds the `preprocessCode` task as well as all the version subprojects. Compiling or running newer versions is not +possible, but the `preprocessCode` task can be run manually to inspect the generated source code. This mode is what should most often be +used when making alterations to the mappings or modifying preprocessor directives. Note that while this setting generally ignores any failed +renaming attempts, if something is so badly mangled that it cannot even guess a name for a function, it will still break the build. Those +situations should be rare, however. (In the entire SH codebase prior to me introducing this system I only found <10 such cases). You can +specifically compile 1.8.9 using `./gradlew :1.8.9:build`. This does not affect the regular execution of the client which will only compile +1.8.9. + +`compile` enables compilation for the `:1.21` subproject. This means that a `build` or `assemble` task will try (and fail) to compile a +1.21 (as well as 1.8.9) JAR. This mode may be useful for someone seeking out issues to fix, but is generally not useful in day to day +operations since the compile will never succeed and will block things like hotswap compilations (via CTRL+F9) from completing. + +### Improving mappings + +The different project versions are set up in such a way that each version depends on a slightly older version from which it is then adapted. +There are two main versions (1.8.9 and 1.21), but there are also a few bridge versions. These exist to make remapping easier since automatic +name mappings between 1.8.9 and 1.21 do not really exist. This is the current layout for our remaps: First, we remap to 1.12. This still +largely uses the old rendering system and has a lot of similar names to 1.8.9. As such, only very little needs to be adapted in terms of +behaviour, and at best, a couple of names need to be updated manually. The big jump is from 1.12 to 1.16. We use 1.16 since we don't want to +make too large of a jump (which could lead to a lot more missing names), but we still want to jump to a version with Fabric (and specifically +with Fabric intermediary mappings). We also can't really jump to an earlier version since 1.14 and 1.15 have a really poor Fabric API and +still have some of the old rendering code, meaning we would need to adapt to two slightly different rendering engines instead of just one +big rendering change. Despite the preprocessor's best efforts, this version will likely have the most manual mapping changes. Note that we +actually have two projects on 1.16. There is the Forge project, which is the one we remap to first. Then we remap to the corresponding +Fabric/Yarn mappings. This is because remapping between Searge and Yarn is very inconsistent unless it is done on one and the same version. +Finally, we remap from 1.16 to 1.21. This is a fairly small change, especially since Fabric intermediary mappings make different names +between versions very rare. The only real changes that need to be done in this jump are behavioural ones. + +The preprocessor does some built-in remapping (changing names), based on obfuscated names, but sometimes the automatic matching fails. If it +cannot find a new name (or the name it automatically determines was wrong), you can change the corresponding mapping. In order to make +this as smooth as possible, it is generally recommended to find the earliest spot at which the mappings deviate. So fixing a mapping on the +hop from 1.16 to 1.21 is generally not recommended. This is because, while we do not care about 1.12 or 1.16 compiling for its own merit, +we do care about the automatically inferred name changes from 1.12 to 1.16 and so on, which only work if those versions already have the +correct names available. + +#### A missing/incorrect name + +This is the easiest part. If a name for a function simply could not be automatically remapped, all you need to do is to add an entry in the +corresponding mapping.txt file. These can be found at `versions/mapping--.txt`. + +``` +# You can use # to comment lines + +# You can rename a class simply by writing the two names +# The first name is the name on the newer version (the first one in the file name); the second one is the name in the old version. +net.minecraft.util.math.MathHelper net.minecraft.util.MathHelper +# If you want to rename an inner class, remember to use $s +net.minecraft.world.scores.Team$Visibility net.minecraft.scoreboard.Team$EnumVisible + +# You can rename a field by writing the name of the containing class in the new version, and then the new and old name of the field. +# Again, the first field name is the one in the newer version (first in the file name). +net.minecraft.world.entity.Entity xOld prevPosX + +# Finally, you can also rename methods. To do so, you need to first specify the name of the containing class in the new version, then +# the name of the new and old method name. The first method name is the newer version name (first in the file name). +net.minecraft.util.text.Style getHoverEvent() getChatHoverEvent() +``` + +Adding a mapping like this is the easiest way to fix a broken method call, field access, or class reference. It will also apply to all +files, so you might be fixing issues in files you didn't even look at. It will even work in mixin targets, as long as they are unambiguous +(consider using the method descriptor instead of just the method name for your mixin). However, if something aside from the name changed, +this will not suffice. + +#### Conditional compilation + +In addition to the built-in remapping, there is also the more complicated art of preprocessor directives. Directives allow you to comment or +uncomment sections of the code depending on the version you are on. Uncommented sections are renamed as usual, so even within those directives, +you only need to write code for the *lowest* version that your comment is active in. As such, I once again highly recommend to target your +directive to the lowest version in which it applies, so that other sections that call into that code as well as your code can make use of +as many automatic renames as possible. + +There is only really one directive, which is `if`. Take this function, for example: + +```kt +private fun WorldClient.getAllEntities(): Iterable = +//#if MC < 1.16 + loadedEntityList +//#else +//$$ entitiesForRendering() +//#endif +``` + +The first `#if` instructs the preprocessor to only uncomment the following code if the Minecraft version is less than 1.16. Then, the `#else` +uncomments the other section on versions 1.16 and above. Finally, the `#endif` ends the else block and lets the following functions always remain +active. To distinguish regular comments from preprocessor comments, preprocessor only works with comments that start with `//$$`. So let's +walk through what is happening here. + +In 1.8.9, the code remains unchanged. **Note that this means the programmer is responsible for commenting out the unused parts. +The preprocessor will never change the `src/` directory**. + +Next, the preprocessor converts the code to 1.12. 1.12 still has the `loadedEntityList` as well as the same name for the `WorldClient` and +`Entity` classes, so nothing is changed. + +Next, the code gets converted to 1.16 Forge. Since 1.16 is not less than 1.16, it will comment out the first line and uncomment the second line. +1.16 Forge also uses a different name for `WorldClient` and a different package for `Entity`, so those are also changed (the package change +is only visible in the imports): + +```kt +private fun ClientLevel.getAllEntities(): Iterable = +//#if MC < 1.14 +//$$ loadedEntityList +//#else + entitiesForRendering() +//#endif +``` + +Now the code gets converted to 1.16 Fabric. Since those two targets are on the same Minecraft version name changes almost never fail to be +done automatically. Notice the different names for `ClientWorld` as well as `entities`. The method is called `getEntities()` on Fabric, but +since this is Kotlin code, the preprocessor automatically cleans up `getEntities()` using +[Kotlin property access syntax](https://kotlinlang.org/docs/java-interop.html#getters-and-setters). + +```kt +private fun ClientWorld.getAllEntities(): Iterable = +//#if MC < 1.14 +//$$ loadedEntityList +//#else + entities +//#endif +``` + +Finally, the code gets converted to 1.21 using intermediary mappings. This last step does not bring any new challenges, so we end up with: + +```kt +private fun ClientWorld.getAllEntities(): Iterable = +//#if MC < 1.14 +//$$ loadedEntityList +//#else + entities +//#endif +``` + +#### If expressions + +Let's look at the syntax of those `#if` expressions. + +First of all, the `#else` block is optional. If you just want code on some versions (for example for adding a method call that is implicitly +done on newer versions, or simply because the corresponding code for newer versions has to be done in some other place), you can just omit +the `#else` section and you will simply not compile any code at that spot. + +There is also an `#elseif` in case you want to switch behaviour based on multiple version brackets. Again, while we don't actually target +1.12 or 1.16, making those versions compile will help other parts of the code to upgrade to 1.21 more cleanly and easily. So, making those +versions work (or at least providing a stub like `error("Not implemented on this version") as List` to make types infer correctly) +should be something you look out for. + +`#if` and `#elseif` also do not support complicated expressions. The only operations supported are `!=`, `==`, `>=`, `<=`, `<` and `>`. You +cannot join two checks using `&&` or similar, instead needing to use nested `#if`s. + +The actual versions being worked with here are not actually semantically compared Minecraft versions, but instead integers in the form +`major * 10000 + minor * 100 + patch`. So, for example, `1.12` turns into `11200`. Both `11200` and `1.12` can be used in directives, but +`1.12` style values are generally easier to understand. + +You can also check if you are on Forge using the `FORGE` variable. It is set to either 1 or 0. Similarly, there is also a `JAVA` variable to +check the Java version this Minecraft version is on. For the `FORGE` variable there is an implicit `!= 0` to check added if you just check +for the variable using `#if FORGE`. + +#### Helpers + +Sadly, `#if` expressions cannot be applied globally (unlike name changes), so it is often very helpful to create a helper method and call +that method from various places in the codebase. This is generally already policy in SH for a lot of things. For more complex types that +change beyond just their name (for example different generics), a `typealias` can be used in combination with `#if` expressions. diff --git a/build.gradle.kts b/build.gradle.kts index 9081713ef050..e8464ada27e8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,52 +1,40 @@ -import org.apache.commons.lang3.SystemUtils +import at.skyhanni.sharedvariables.MinecraftVersion +import at.skyhanni.sharedvariables.MultiVersionStage +import at.skyhanni.sharedvariables.ProjectTarget +import at.skyhanni.sharedvariables.SHVersionInfo +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 java.io.ByteArrayOutputStream plugins { idea java - id("gg.essential.loom") version "0.10.0.+" - id("dev.architectury.architectury-pack200") version "0.1.3" id("com.github.johnrengelman.shadow") version "7.1.2" - kotlin("jvm") version "1.9.0" - id("com.bnorm.power.kotlin-power-assert") version "0.13.0" + id("gg.essential.loom") + id("dev.deftu.gradle.preprocess") + kotlin("jvm") + id("com.google.devtools.ksp") + kotlin("plugin.power-assert") `maven-publish` - id("com.google.devtools.ksp") version "1.9.0-1.0.13" id("moe.nea.shot") version "1.0.0" } -group = "at.hannibal2.skyhanni" -version = "0.26.Beta.20" - -val gitHash by lazy { - val baos = ByteArrayOutputStream() - exec { - standardOutput = baos - commandLine("git", "rev-parse", "--short", "HEAD") - isIgnoreExitValue = true - } - baos.toByteArray().decodeToString().trim() -} - -// Toolchains: -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(8)) -} - -sourceSets.main { - output.setResourcesDir(sourceSets.main.flatMap { it.java.classesDirectory }) - java.srcDir(layout.projectDirectory.dir("src/main/kotlin")) - kotlin.destinationDirectory.set(java.destinationDirectory) -} +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\\.github\\..*") + includeGroupByRegex("(com|io)\\.github\\..*") } } maven("https://repo.nea.moe/releases") // libautoupdate @@ -55,6 +43,53 @@ repositories { maven("https://maven.teamresourceful.com/repository/thatgravyboat/") // DiscordIPC } +// Toolchains: +java { + toolchain.languageVersion.set(target.minecraftVersion.javaLanguageVersion) + // We specifically request ADOPTIUM because if we do not restrict the vendor DCEVM is a + // possible candidate. Some DCEVMs are however incompatible with some things gradle is doing, + // causing crashes during tests. You can still manually select DCEVM in the Minecraft Client + // IntelliJ run configuration. + toolchain.vendor.set(JvmVendorSpec.ADOPTIUM) +} +val runDirectory = rootProject.file("run") +runDirectory.mkdirs() +// Minecraft configuration: +loom { + if (this.isForgeLike) + forge { + pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter()) + mixinConfig("mixins.skyhanni.json") + } + mixin { + useLegacyMixinAp.set(true) + defaultRefmapName.set("mixins.skyhanni.refmap.json") + } + runs { + named("client") { + if (target == ProjectTarget.MAIN) { + isIdeConfigGenerated = true + appendProjectPathToConfigName.set(false) + } + this.runDir(runDirectory.relativeTo(projectDir).toString()) + property("mixin.debug", "true") + if (System.getenv("repo_action") != "true") { + property("devauth.configDir", rootProject.file(".devauth").absolutePath) + } + vmArgs("-Xmx4G") + programArgs("--tweakClass", "at.hannibal2.skyhanni.tweaker.SkyHanniTweaker") + programArgs("--tweakClass", "io.github.notenoughupdates.moulconfig.tweaker.DevelopmentResourceTweaker") + } + removeIf { it.name == "server" } + } +} + +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) } @@ -72,13 +107,22 @@ val headlessLwjgl by configurations.creating { isTransitive = false isVisible = false } - -val shot = shots.shot("minecraft", project.file("shots.txt")) +tasks.runClient { + this.javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(target.minecraftVersion.javaLanguageVersion) + }) +} +val shot = shots.shot("minecraft", rootProject.file("shots.txt")) dependencies { - minecraft("com.mojang:minecraft:1.8.9") - mappings("de.oceanlabs.mcp:mcp_stable:22-1.8.9") - forge("net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9") + minecraft("com.mojang:minecraft:${target.minecraftVersion.versionName}") + if (target.mappingDependency == "official") { + mappings(loom.officialMojangMappings()) + } else { + mappings(target.mappingDependency) + } + if (target.forgeDep != null) + "forge"(target.forgeDep!!) // Discord RPC client shadowImpl("com.jagrosh:DiscordIPC:0.5.3") { @@ -93,10 +137,16 @@ dependencies { compileOnly(ksp(project(":annotation-processors"))!!) - shadowImpl("org.spongepowered:mixin:0.7.11-SNAPSHOT") { - isTransitive = false + val mixinVersion = if (target.minecraftVersion >= MinecraftVersion.MC11200) "0.8.2" else "0.7.11-SNAPSHOT" + + if (!target.isFabric) { + shadowImpl("org.spongepowered:mixin:$mixinVersion") { + isTransitive = false + } + annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT") + annotationProcessor("com.google.code.gson:gson:2.10.1") + annotationProcessor("com.google.guava:guava:17.0") } - annotationProcessor("org.spongepowered:mixin:0.8.4-SNAPSHOT") implementation(kotlin("stdlib-jdk8")) shadowImpl("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") { @@ -133,14 +183,16 @@ dependencies { implementation("net.hypixel:mod-api:0.3.1") } -configurations.getByName("minecraftNamed").dependencies.forEach { - shot.applyTo(it as HasConfigurableAttributes<*>) +afterEvaluate { + loom.runs.named("client") { + programArgs("--mods", devenvMod.resolve().joinToString(",") { it.relativeTo(runDirectory).path }) + } } tasks.withType(Test::class) { useJUnitPlatform() javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) - workingDir(file("run")) + workingDir(file(runDirectory)) systemProperty("junit.jupiter.extensions.autodetection.enabled", "true") } @@ -151,46 +203,6 @@ kotlin { enableLanguageFeature("BreakContinueInInlineLambdas") } } - sourceSets.main { - kotlin.srcDir("build/generated/ksp/main/kotlin") - } - sourceSets.test { - kotlin.srcDir("build/generated/ksp/test/kotlin") - } -} - -// Minecraft configuration: -loom { - launchConfigs { - "client" { - property("mixin.debug", "true") - if (System.getenv("repo_action") != "true") { - property("devauth.configDir", rootProject.file(".devauth").absolutePath) - } - arg("--tweakClass", "at.hannibal2.skyhanni.tweaker.SkyHanniTweaker") - arg("--tweakClass", "io.github.notenoughupdates.moulconfig.tweaker.DevelopmentResourceTweaker") - arg("--mods", devenvMod.resolve().joinToString(",") { it.relativeTo(file("run")).path }) - } - } - forge { - pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter()) - mixinConfig("mixins.skyhanni.json") - } - @Suppress("UnstableApiUsage") - mixin { - defaultRefmapName.set("mixins.skyhanni.refmap.json") - } - runConfigs { - "client" { - if (SystemUtils.IS_OS_MAC_OSX) { - vmArgs.remove("-XstartOnFirstThread") - } - vmArgs.add("-Xmx4G") - } - "server" { - isIdeConfigGenerated = false - } - } } // Tasks: @@ -199,51 +211,64 @@ tasks.processResources { filesMatching(listOf("mcmod.info", "fabric.mod.json")) { expand("version" to version) } + if (target.isFabric) { + exclude("mcmod.info") + } // else do NOT exclude fabric.mod.json. We use fabric.mod.json in order to show a logo in prism launcher. } -val generateRepoPatterns by tasks.creating(JavaExec::class) { - javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) - mainClass.set("net.fabricmc.devlaunchinjector.Main") - workingDir(project.file("run")) - classpath(sourceSets.main.map { it.runtimeClasspath }, sourceSets.main.map { it.output }) - jvmArgs( - "-Dfabric.dli.config=${project.file(".gradle/loom-cache/launch.cfg").absolutePath}", - "-Dfabric.dli.env=client", - "-Dfabric.dli.main=net.minecraft.launchwrapper.Launch", - "-Dorg.lwjgl.opengl.Display.allowSoftwareOpenGL=true", - "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006", - "-javaagent:${headlessLwjgl.singleFile.absolutePath}" - ) - val outputFile = project.file("build/regexes/constants.json") - environment("SKYHANNI_DUMP_REGEXES", "${gitHash}:${outputFile.absolutePath}") - environment("SKYHANNI_DUMP_REGEXES_EXIT", "true") +if (target == ProjectTarget.MAIN) { + tasks.create("generateRepoPatterns", RunGameTask::class, loom.runs.named("client").get()).apply { + javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) + dependsOn(tasks.configureLaunch) + jvmArgs( + "-Dorg.lwjgl.opengl.Display.allowSoftwareOpenGL=true", + "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006", + "-javaagent:${headlessLwjgl.singleFile.absolutePath}", + ) + val outputFile = project.file("build/regexes/constants.json") + environment("SKYHANNI_DUMP_REGEXES", "${SHVersionInfo.gitHash}:${outputFile.absolutePath}") + environment("SKYHANNI_DUMP_REGEXES_EXIT", "true") + } } -tasks.compileJava { - dependsOn(tasks.processResources) +if (target == ProjectTarget.MAIN) + tasks.compileJava { + dependsOn(tasks.processResources) + } + +if (target.parent == ProjectTarget.MAIN) { + val mainRes = project(ProjectTarget.MAIN.projectPath).tasks.getAt("processResources") + tasks.named("processResources") { + dependsOn(mainRes) + } + tasks.named("preprocessCode") { + dependsOn(mainRes) + } } tasks.withType(JavaCompile::class) { options.encoding = "UTF-8" } -tasks.withType(Jar::class) { +tasks.withType(org.gradle.jvm.tasks.Jar::class) { archiveBaseName.set("SkyHanni") - duplicatesStrategy = DuplicatesStrategy.EXCLUDE + duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Why do we have this here? This only *hides* errors. manifest.attributes.run { - this["FMLCorePluginContainsFMLMod"] = "true" - this["ForceLoadAsMod"] = "true" this["Main-Class"] = "SkyHanniInstallerFrame" - - this["TweakClass"] = "at.hannibal2.skyhanni.tweaker.SkyHanniTweaker" - this["MixinConfigs"] = "mixins.skyhanni.json" + if (target == ProjectTarget.MAIN) { + this["FMLCorePluginContainsFMLMod"] = "true" + this["ForceLoadAsMod"] = "true" + this["TweakClass"] = "at.hannibal2.skyhanni.tweaker.SkyHanniTweaker" + this["MixinConfigs"] = "mixins.skyhanni.json" + } } } val remapJar by tasks.named("remapJar") { archiveClassifier.set("") - from(tasks.shadowJar) - input.set(tasks.shadowJar.get().archiveFile) + dependsOn(tasks.shadowJar) + inputFile.set(tasks.shadowJar.get().archiveFile) + destinationDirectory.set(rootProject.layout.buildDirectory.dir("libs")) } tasks.shadowJar { @@ -267,13 +292,31 @@ tasks.jar { } tasks.assemble.get().dependsOn(tasks.remapJar) -val compileKotlin: KotlinCompile by tasks -compileKotlin.kotlinOptions { - jvmTarget = "1.8" +tasks.withType(KotlinCompile::class) { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(target.minecraftVersion.javaLanguageVersion.versionString())) + } +} + +if (!MultiVersionStage.activeState.shouldCompile(target)) { + tasks.withType { + onlyIf { false } + } + tasks.withType { + onlyIf { false } + } + tasks.withType { + onlyIf { false } + } + tasks.withType { + onlyIf { false } + } } -val compileTestKotlin: KotlinCompile by tasks -compileTestKotlin.kotlinOptions { - jvmTarget = "1.8" +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") } val sourcesJar by tasks.creating(Jar::class) { destinationDirectory.set(layout.buildDirectory.dir("badjars")) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 35b272a88530..bc1311f37b70 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -27,6 +27,8 @@ Paloys (https://github.com/hannibal002/SkyHanni/pull/1891) + Added crop last farmed waypoint. - appable (https://github.com/hannibal002/SkyHanni/pull/1335) + Accessible in the Crop Start Locations section. ++ Added Farming Personal Best FF Gain. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2332) + + Displays in chat how much additional FF you earn from the farming contest personal best bonus after beating your previous record. #### Dungeon Features @@ -113,6 +115,8 @@ + Show Bestiary Level as Stack Size. - saga (https://github.com/hannibal002/SkyHanni/pull/1945) + Can be enabled/disabled on the Item Number list. + Added Item Pickup Log. - catgirlseraid (https://github.com/hannibal002/SkyHanni/pull/1937) ++ Added Tactical Insertion Ability Cooldown feature. - DungeonHub (https://github.com/hannibal002/SkyHanni/pull/2278) ++ Display the price per Stonk when taking the minimum bid in the Stonks Auction (Richard Menu). - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2195) #### Fishing Features @@ -131,6 +135,7 @@ + Punchcard Artifact Highlighter & Overlay. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/1089) + Highlights unpunched players in the Rift. ++ Added Splatter Hearts Highlight for the Rift. - Empa (https://github.com/hannibal002/SkyHanni/pull/2318) #### Misc Features @@ -141,7 +146,7 @@ + Added Beacon Power Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/1901) + Added Hide Useless Armor Stands. - Empa (https://github.com/hannibal002/SkyHanni/pull/1962) + Hides armor stands that briefly appear on Hypixel. -+ Added Custom Wardrobe, a new look for the wardrobe. - j10an15, Empa (https://github.com/hannibal002/SkyHanni/pull/2039) ++ Added Custom Wardrobe, a new look for the wardrobe. - j10a1n15, Empa (https://github.com/hannibal002/SkyHanni/pull/2039) + Highly customizable: Colors, display sizes. + Estimated Price Integration. + Favorite slots; option to only display favorite slots. @@ -181,6 +186,8 @@ + Added a "Compact" option to the Rancher Boots Optimal Speed GUI. - Empa (https://github.com/hannibal002/SkyHanni/pull/2137) + The Rancher Boots Optimal Speed GUI now highlights the crop corresponding to the last held tool. - Empa (https://github.com/hannibal002/SkyHanni/pull/2137) + Added Slug pet to the FF Guide. - maxime-bodifee (https://github.com/hannibal002/SkyHanni/pull/2249) ++ Added Copper dye to the list of blocked visitor rewards. - not-a-cow (https://github.com/hannibal002/SkyHanni/pull/2329) ++ Added Copper Dye to Visitor Drop Statistics. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2346) #### Hoppity Event Improvements @@ -258,6 +265,10 @@ + Added reset buttons for colors and spacing in the Custom Wardrobe config. - raven (https://github.com/hannibal002/SkyHanni/pull/2120) + Added an option for the Estimated Chest Value display to also work in your own inventory. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2218) + Added SkyBlock Level number in SB Menu to Item Number config. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2172) ++ Added Divan's Powder Coating to the Estimated Item Value feature. - jani (https://github.com/hannibal002/SkyHanni/pull/2317) ++ Added support for Chocolate Milestones in Custom Reminder. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2334) ++ Clicking on the chat message when you try to open /cf without a rabbit pet will now open /pets. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2333) ++ Improved Wardrobe Keybinds when using favorite mode. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2331) #### Fishing Improvements @@ -307,6 +318,10 @@ + Reverted item source names to shorter format. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2233) + Rounded corner smoothness now applies to custom Scoreboard textures. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2228) + Reduced the frequency of "tab list not found" error messages. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2266) ++ Hide Beacon Power display while on a Bingo profile. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2286) ++ Added the current Minister's name and perks to the Mayor Display on the Custom Scoreboard. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2313) ++ Hide repo errors in chat. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2338) + + Errors will be displayed directly in the GUI when necessary, making them less intrusive. ### Fixes @@ -341,6 +356,13 @@ + Fixed TunnelMaps not resetting on lobby swap. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2275) + Fixed a rare error when detecting corpses in the Mineshaft. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2268) + Fixed incorrect maximum Powder value on HotM perks when disabled. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2269) ++ Fixed HOTM levels being saved incorrectly if the menu was opened with a Blue Egg Cheese Drill in hand. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2295) ++ Fixed Flawless Gemstones not being formatted correctly when the Powder Mining filter is enabled. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2281) ++ Fixed Peak of the Mountain always being disabled. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2282) ++ Fixed an issue where TunnelMaps could stop functioning. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2277) ++ Fixed blocks mined by Efficient Miner not being detected in the Pity Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/2307) ++ Fixed empty lines not being blocked by the Powder Mining filter. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2309) ++ Fixed a rare crash occurring on a mining island. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2354) #### Garden Fixes @@ -369,6 +391,11 @@ + Fixed Dicer Tracker Reset Button misalignment. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2248) + Fixed errors when selecting Fine Flour with the Sprayonator. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2251) + Fixed typos in the FF guide. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2273) ++ Fixed command sent in chat for Farming Weight Display. - not-a-cow (https://github.com/hannibal002/SkyHanni/pull/2303) ++ Fixed visitor shopping list with AH items. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2297) ++ Fixed Zorro's Cape not working with Green Thumb in the FF stats breakdown in item lore. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2299) ++ Fixed Composter Overlay calculating incorrectly while Composter Display is disabled. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2294) ++ Fixed own garden not being detected when swapping islands from a guesting server. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2355) #### Chocolate Factory & Hoppity Hunt Fixes @@ -399,6 +426,9 @@ + Fixed buying items sometimes triggering compact Hoppity messages. - sayomaki (https://github.com/hannibal002/SkyHanni/pull/2201) + Fixed Hoppity Chat Compact not working outside of Hoppity's event for Abiphone users who have Hoppity as a contact. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2250) + Fixed stray rabbit production time tooltip display. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2239) ++ Fixed Hoppity custom goals being off by one level. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2280) ++ Fixed Custom Reminder not working in the Chocolate Shop. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2334) ++ Fixed a warning about space in the Chocolate Factory appearing even when the barn was already large enough to store all rabbits. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2356) #### Custom Scoreboard Fixes @@ -419,6 +449,9 @@ + Fixed 2 Custom Scoreboard Errors while in Kuudra. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2236) + Fixed Scoreboard Reset not updating the draggable list. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2252) + Fixed a scoreboard error message when a Hypixel bug shows a negative number of magma cubes remaining in the scoreboard. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2267) ++ Fixed Custom Scoreboard Error when having more than 1000 medals. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2319) ++ Fixed a Custom Scoreboard error during the Winter Event. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2345) ++ Fixed getting mayor/minister information for Custom Scoreboard. - Luna (https://github.com/hannibal002/SkyHanni/pull/2343) #### Dungeon Fixes @@ -428,12 +461,14 @@ + Fixed Dungeons in DiscordRPC not showing the elapsed time. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2089) + Fixed multiple empty lines appearing in Custom Scoreboard while in Dungeons. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2082) + Fixed Livid Finder not working with Magenta Livid. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2086) ++ Fixed the dungeon finder item lore displaying on other items in the inventory. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2298) #### Commands Fixes + Fixed typo in /shclearkismet command. - fahr-plan (https://github.com/hannibal002/SkyHanni/pull/1912) + Fixed 'viewrecipe' lowercase not working. - Obsidian + hannibal2 (https://github.com/hannibal002/SkyHanni/pull/1939) + Fixed rare cases where queued /gfs didn't work. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/1999) ++ Fixed an additional empty /shcommands page from appearing. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2287) #### Fishing Fixes @@ -445,6 +480,7 @@ + Fixed a rare double hook detection issue. - appable (https://github.com/hannibal002/SkyHanni/pull/2125) + Fixed Commission Mob Highlighter incorrectly highlighting Deep Sea Protectors as Automatons. - Luna (https://github.com/hannibal002/SkyHanni/pull/2130) + Fixed Squid Pet counting towards the Fishing Timer. - Empa (https://github.com/hannibal002/SkyHanni/pull/1960) ++ Fixed an error during fishing. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2350) #### Performance Fixes @@ -461,6 +497,7 @@ + Fixed rift slayer warning showing while hitting Oubliette Guard. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/1950) ++ Fixed an error when killing Splatter Cruxes in the Rift. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2349) #### Inventory Fixes @@ -480,6 +517,16 @@ + Fixed price source inconsistencies (Bazaar sell/buy and NPC prices). - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2221) + Fixed Carnival Masks not being detected by Reforge Helper. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2244) + Fixed a typo in the Item Pickup Log config. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2271) ++ Fixed a bug in SkyHanni's Time Held in Lore with Coca Truffle when using Odin. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2300) ++ Fixed sack changes appearing with a delay in the Item Pickup Log. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2292) ++ Fixed Item Pickup Log error with Wisp Potion. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2291) ++ Fixed Carnival Masks not being clickable in `/equipment`. - Luna (https://github.com/hannibal002/SkyHanni/pull/2293) ++ Fixed Bobbin' Time not being detected correctly. - Vixid (https://github.com/hannibal002/SkyHanni/pull/2301) ++ Fixed lore not showing on enchanted books with compressed format. - Vixid (https://github.com/hannibal002/SkyHanni/pull/2301) ++ Fixed the incorrect "This item has no attributes" message appearing in the Attribute Fusion menu for some items. - Luna (https://github.com/hannibal002/SkyHanni/pull/2304) ++ Fixed shift-clicking items in GUIs triggering the Item Pickup Log. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2305) ++ Fixed the Master Mode Dungeon stack size display in the party finder menu. - fazfoxy (https://github.com/hannibal002/SkyHanni/pull/2316) ++ Fixed the Item Pickup Log detecting "Magical Map" in dungeons when using Skytils. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2351) #### Combat Fixes @@ -493,6 +540,11 @@ + Fixed stash getting detected as a private message. - sayomaki (https://github.com/hannibal002/SkyHanni/pull/2060) + Fix Guild Rank formatting having an extra space. - Empa (https://github.com/hannibal002/SkyHanni/pull/2191) +#### Crimson Fixes + ++ Fixed Pablo Helper not functioning when called via Abiphone. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2288) ++ Fixed reputation helper keybind activating while inside GUIs. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2284) + #### Misc Fixes + Fixed LorenzToolTipEvent triggering when not actually hovering over an item. - @@ -523,6 +575,14 @@ + Fixed a typo in /shcommands. - Obsidian (https://github.com/hannibal002/SkyHanni/pull/2223) + Fixed multiple features not showing a duration when it was less than one second. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2261) + Fixed some incorrect boxes in the GUI editor. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2260) ++ Fixed chroma preview always being white. - Vixid (https://github.com/hannibal002/SkyHanni/pull/2302) ++ Fixed Contributor name tag flickering when using Patcher. - nea (https://github.com/hannibal002/SkyHanni/pull/2296) ++ Fixed Discord Rich Presence dynamic fallback. - NetheriteMiner (https://github.com/hannibal002/SkyHanni/pull/2279) + + Placeholder messages that should not be visible will no longer appear. ++ Fixed pet detection with newer NEU versions. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2358) ++ Fixed Item Trackers displaying the incorrect NPC price. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2352) ++ Fixed players with similar names to friends being incorrectly marked as friends in the tab list. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2353) ++ Fixed color codes in Discord RPC pet status. - NetheriteMiner (https://github.com/hannibal002/SkyHanni/pull/2344) ### Technical Details @@ -540,7 +600,7 @@ + Just add the @SkyHanniModule annotation to an object to auto load it. + Modified removeColor for visual formatting consistency. - appable (https://github.com/hannibal002/SkyHanni/pull/1824) + Keeps formatting consistency in the presence of color codes acting as implicit reset codes. -+ Added RepoPattern.list. - !nea (https://github.com/hannibal002/SkyHanni/pull/1733) ++ Added RepoPattern.list. - nea (https://github.com/hannibal002/SkyHanni/pull/1733) + A way to store x amount of patterns. + Added unit test for repo pattern lists. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/1733) + Added RepoPattern.exclusiveGroup. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/1733) @@ -636,6 +696,20 @@ + Added renderRenderableDouble. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2260) + A direct replacement for renderStringsAndItems. + Changed detecting active mayor to no longer use the number of votes. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2227) ++ Fixed wrong color for Jasper gemstone in OreBlock API. - Luna (https://github.com/hannibal002/SkyHanni/pull/2257) ++ Added DYE to Item Category. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2315) ++ Added /shdebugprice command. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2289) ++ Cache rewardPatterns in the powder chat filter. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2276) ++ Added Minister data to the MayorAPI. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2313) ++ Added ItemPriceUtils and moved all item price functions into it. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2290) ++ Added a preprocessor to prepare for 1.21. - nea (https://github.com/hannibal002/SkyHanni/pull/2283) + + This will require a minor adjustment in how the Minecraft client is launched. ++ Deleted an unnecessary function in Garden Crop Milestone. - notafrogo (https://github.com/hannibal002/SkyHanni/pull/2339) ++ Removed repository item errors. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2338) + + Instead of stack traces for "no item name for internal name", "no item stack for internal name", and "no internal name for item stack", we now return the internal name in red, the internal name `MISSING_ITEM`, or a barrier item instead. + + Command /shdebug lists all failed item names. + + Debug chat still logs the errors. + + Shows a popup (currently disabled). ### Removed Features diff --git a/docs/DISCORD_FAQ.md b/docs/DISCORD_FAQ.md index 9edc758672ce..75e520692b39 100644 --- a/docs/DISCORD_FAQ.md +++ b/docs/DISCORD_FAQ.md @@ -26,8 +26,8 @@ _Frequently Asked Questions_ > **8: How can I get bigger crop hit boxes?** > Use Patcher or PolyPatcher to have 1.12 hit boxes in 1.8.9. -> - [Sk1erLLC's Patcher]() -> - [Polyfrost's PolyPatcher]() (a fork of Patcher with OneConfig, slightly different features, and bug fixes) +> - [Sk1erLLC's Patcher]() (Versions 1.8.8 and after will have broken cactus hitboxes) +> - [Polyfrost's PolyPatcher]() (a fork of Patcher with OneConfig, slightly different features, and bug fixes. Fixes cactus hitboxes.) > **9: Why does my Item Tracker feature not track this item?** > 1. Check if the item goes directly into your sacks. @@ -57,10 +57,11 @@ _Frequently Asked Questions_ > **12: Why can I still see the normal Scoreboard when using Custom Scoreboard?** > Most of the time, this is a mod conflict. > If you are using [Sidebar Mod](https://github.com/Alexdoru/SidebarMod), please remove this mod. -> If you are using [VanillaHUD](https://modrinth.com/mod/vanillahud), please update to 2.2.8 or newer to resolve this issue. +> If you are using [VanillaHUD](https://modrinth.com/mod/vanillahud), please update to 2.2.9 or newer to resolve this issue. > If you are using [Apec](https://github.com/BananaFructa/Apec/) and want to remove their Scoreboard, you need to remove Apec since they don't have an option to disable their Scoreboard. +> If you are using [Patcher](https://sk1er.club/mods/patcher) or [PolyPatcher](https://modrinth.com/mod/patcher) and the vanilla scoreboard is flickering, disable the "HUD Caching" option. > If you don't use any of these mods, make sure the option to "Hide Vanilla Scoreboard" is actually enabled. -*This FAQ was last updated on July 1st, 2024. +*This FAQ was last updated on August 10th, 2024. If you believe there's something that should be added to this list, please tell us, so we can add it.* diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 139d30b41c7e..dd4e6ea41bc0 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -217,7 +217,8 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Optionally show the different stat values compared to the current reforge. + Show Bestiary Level as Stack Size. - saga (https://github.com/hannibal002/SkyHanni/pull/1945) + Can be enabled/disabled on the Item Number list. -+ Added Item Pickup Log. - catgirlseraid (https://github.com/hannibal002/SkyHanni/pull/1937) ++ 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)
@@ -234,6 +235,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Lesser Orb of Healing Hider. - jani + Wand of Strength cooldown is now displayed. - saga (https://github.com/hannibal002/SkyHanni/pull/1948) + The cooldown displayed is for the buff, not the item usage. ++ Added Tactical Insertion Ability Cooldown feature. - DungeonHub (https://github.com/hannibal002/SkyHanni/pull/2278)
@@ -731,6 +733,8 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Overflow Garden crop milestones. - Luna & HiZe (https://github.com/hannibal002/SkyHanni/pull/997) + New "Craftable!" message when Visitor Items Needed are craftable. - Paloys (https://github.com/hannibal002/SkyHanni/pull/1891) + Added toggle for compacting Garden visitor summary messages. - DavidArthurCole (https://github.com/hannibal002/SkyHanni/pull/2026) ++ Added Farming Personal Best FF Gain. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2332) + + Displays in chat how much additional FF you earn from the farming contest personal best bonus after beating your previous record.
@@ -811,6 +815,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Change Highlight color. + Punchcard Artifact Highlighter & Overlay. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/1089) + Highlights unpunched players in the Rift. ++ Added Splatter Hearts Highlight for the Rift. - Empa (https://github.com/hannibal002/SkyHanni/pull/2318)
diff --git a/docs/INSTALLING.md b/docs/INSTALLING.md index 091b064f87ca..3dc059a428ac 100644 --- a/docs/INSTALLING.md +++ b/docs/INSTALLING.md @@ -122,7 +122,7 @@ select new installation, under version you need to find Forge for 1.8.9 (most li 10. Recommended additional mods (optional) [OptiFine](https://optifine.net/adloadx?f=preview_OptiFine_1.8.9_HD_U_M6_pre2.jar) -and either [Sk1erLLC's Patcher](https://sk1er.club/mods/patcher) or [Polyfrost's PolyPatcher]() (a fork of Patcher with OneConfig, slightly different features, and bug fixes) +and either [Sk1erLLC's Patcher](https://sk1er.club/mods/patcher) or [Polyfrost's PolyPatcher]() (a fork of Patcher with OneConfig, slightly different features, and bug fixes, including fixed cactus hitboxes) Those two mods help you get more FPS in game and let you change many more performance settings. diff --git a/gradle.properties b/gradle.properties index 16cc55dfa11b..f5b8c6325fed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,3 @@ -loom.platform=forge org.gradle.jvmargs=-Xmx2g org.gradle.parallel=true org.gradle.caching=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index db9a6b825d7f..19cfad969baf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/root.gradle.kts b/root.gradle.kts new file mode 100644 index 000000000000..9a15c2d0b555 --- /dev/null +++ b/root.gradle.kts @@ -0,0 +1,42 @@ +import at.skyhanni.sharedvariables.ProjectTarget +import com.replaymod.gradle.preprocess.Node + +plugins { + id("dev.deftu.gradle.preprocess") version "0.6.1" + 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" +} + +allprojects { + group = "at.hannibal2.skyhanni" + version = "0.26.Beta.24" +} + +preprocess { + val nodes = mutableMapOf() + ProjectTarget.activeVersions().forEach { target -> + nodes[target] = createNode(target.projectName, target.minecraftVersion.versionNumber, target.mappingStyle.identifier) + val p = project(target.projectPath) + if (target.isForge) + p.extra.set("loom.platform", "forge") + } + ProjectTarget.activeVersions().forEach { child -> + val parent = child.linkTo ?: return@forEach + val pNode = nodes[parent] + if (pNode == null) { + println("Parent target to ${child.projectName} not available in this multi version stage. Not setting parent.") + return@forEach + } + val mappingFile = file("versions/mapping-${parent.projectName}-${child.projectName}.txt") + if (mappingFile.exists()) { + pNode.link(nodes[child]!!, mappingFile) + println("Loading mappings from $mappingFile") + } else { + pNode.link(nodes[child]!!) + println("Skipped loading mappings from $mappingFile") + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 8bd4de72fb14..2de2760b266d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,8 @@ +import at.skyhanni.sharedvariables.MultiVersionStage +import at.skyhanni.sharedvariables.ProjectTarget + pluginManagement { + includeBuild("sharedVariables") repositories { mavenCentral() gradlePluginPortal() @@ -9,6 +13,12 @@ pluginManagement { maven("https://repo.spongepowered.org/maven/") maven("https://repo.nea.moe/releases") maven("https://repo.sk1er.club/repository/maven-releases/") + maven("https://maven.deftu.xyz/releases") + maven("https://jitpack.io") { + content { + includeGroupByRegex("(com|io)\\.github\\..*") + } + } } resolutionStrategy { eachPlugin { @@ -20,8 +30,20 @@ pluginManagement { } plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version("0.6.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("0.8.0") + id("at.skyhanni.shared-variables") } +MultiVersionStage.initFrom(file(".gradle/private.properties")) + include("annotation-processors") rootProject.name = "SkyHanni" +rootProject.buildFileName = "root.gradle.kts" + +ProjectTarget.activeVersions().forEach { target -> + include(target.projectPath) + val p = project(target.projectPath) + p.projectDir = file("versions/${target.projectName}") + p.buildFileName = "../../build.gradle.kts" +} + diff --git a/sharedVariables/build.gradle.kts b/sharedVariables/build.gradle.kts new file mode 100644 index 000000000000..27799fb860dc --- /dev/null +++ b/sharedVariables/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + `kotlin-dsl` + `java-gradle-plugin` +} + +repositories { + this.mavenCentral() + this.mavenLocal() +} +dependencies { + this.implementation("com.google.code.gson:gson:2.10.1") + this.implementation("com.google.guava:guava:33.2.1-jre") +} + +sourceSets.main { + this.kotlin.srcDir(file("src")) +} +gradlePlugin { + this.plugins { + this.create("simplePlugin") { + this.id = "at.skyhanni.shared-variables" + this.implementationClass = "at.skyhanni.sharedvariables.NoOp" + } + } +} diff --git a/sharedVariables/settings.gradle.kts b/sharedVariables/settings.gradle.kts new file mode 100644 index 000000000000..e3b5e48960b8 --- /dev/null +++ b/sharedVariables/settings.gradle.kts @@ -0,0 +1,2 @@ +// This space has been intentionally left blank +// It serves such that this folder is a new gradle workspace rather than being a subproject diff --git a/sharedVariables/src/MappingStyle.kt b/sharedVariables/src/MappingStyle.kt new file mode 100644 index 000000000000..604495ce1457 --- /dev/null +++ b/sharedVariables/src/MappingStyle.kt @@ -0,0 +1,6 @@ +package at.skyhanni.sharedvariables + +enum class MappingStyle(val identifier: String) { + SEARGE("srg"), + YARN("yarn"), +} diff --git a/sharedVariables/src/MinecraftVersion.kt b/sharedVariables/src/MinecraftVersion.kt new file mode 100644 index 000000000000..7384c8fbd49b --- /dev/null +++ b/sharedVariables/src/MinecraftVersion.kt @@ -0,0 +1,25 @@ +package at.skyhanni.sharedvariables + +import org.gradle.jvm.toolchain.JavaLanguageVersion + +enum class MinecraftVersion( + val versionName: String, + val javaVersion: Int, +) { + MC189("1.8.9", 8), + MC11200("1.12", 8), + MC11202("1.12.2", 8), + MC1144("1.14.4", 8), + MC11605("1.16.5", 8), + MC121("1.21", 21), + ; + + val javaLanguageVersion = JavaLanguageVersion.of(javaVersion) + + val versionNumber = run { + val parts = versionName.split('.').mapTo(mutableListOf()) { it.toInt() } + if (parts.size == 2) parts.add(0) + require(parts.size == 3) + parts[0] * 10000 + parts[1] * 100 + parts[2] + } +} diff --git a/sharedVariables/src/MultiVersionStage.kt b/sharedVariables/src/MultiVersionStage.kt new file mode 100644 index 000000000000..78914a91dba8 --- /dev/null +++ b/sharedVariables/src/MultiVersionStage.kt @@ -0,0 +1,43 @@ +package at.skyhanni.sharedvariables + +import java.io.File +import java.util.Properties + +enum class MultiVersionStage(val label: String) { + OFF("off"), + PREPROCESS_ONLY("preprocess-only"), + FULL("compile") + ; + + fun shouldCompile(projectTarget: ProjectTarget): Boolean { + if (projectTarget == ProjectTarget.MAIN) return true + return when (this) { + OFF -> false + PREPROCESS_ONLY -> false + FULL -> projectTarget == ProjectTarget.MODERN + } + } + + fun shouldCreateProject(projectTarget: ProjectTarget): Boolean { + if (projectTarget == ProjectTarget.MAIN) return true + return when (this) { + OFF -> false + PREPROCESS_ONLY -> true + FULL -> true + } + } + + + companion object { + lateinit var activeState: MultiVersionStage + fun initFrom(file: File) { + val prop = Properties() + if (file.exists()) { + file.inputStream().use(prop::load) + } + val multiVersion = prop["skyhanni.multi-version"] + activeState = MultiVersionStage.values().find { it.label == multiVersion } ?: OFF + println("SkyHanni multi version stage loaded: $activeState") + } + } +} diff --git a/sharedVariables/src/NoOp.kt b/sharedVariables/src/NoOp.kt new file mode 100644 index 000000000000..d0103a956c2f --- /dev/null +++ b/sharedVariables/src/NoOp.kt @@ -0,0 +1,11 @@ +package at.skyhanni.sharedvariables + +import org.gradle.api.Plugin +/** + * This class is a no op plugin. It can be applied to any project or gradle workspace and serves only as a marker + * for gradle to pull in the other classes in the sharedVariables project. We use a subproject rather than buildSrc + * since buildSrc is not available during settings configuration time (and also buildSrc tends to be slower). + */ +class NoOp : Plugin { + override fun apply(target: Any) {} +} diff --git a/sharedVariables/src/ProjectTarget.kt b/sharedVariables/src/ProjectTarget.kt new file mode 100644 index 000000000000..9bf46c781110 --- /dev/null +++ b/sharedVariables/src/ProjectTarget.kt @@ -0,0 +1,74 @@ +package at.skyhanni.sharedvariables + +private fun yarn(version: String): String = "net.fabricmc:yarn:${version}:v2" + +enum class ProjectTarget( + val projectName: String, + val minecraftVersion: MinecraftVersion, + val mappingDependency: String, + val mappingStyle: MappingStyle, + val forgeDep: String?, + linkTo: String?, +) { + MAIN( + "1.8.9", + MinecraftVersion.MC189, + "de.oceanlabs.mcp:mcp_stable:22-1.8.9@zip", + MappingStyle.SEARGE, + "net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9", + "BRIDGE112", + ), + BRIDGE112( + "1.12.2", + MinecraftVersion.MC11202, + "de.oceanlabs.mcp:mcp_stable:39-1.12@zip", + MappingStyle.SEARGE, + "net.minecraftforge:forge:1.12.2-14.23.5.2847", + "BRIDGE116FORGE", + ), + BRIDGE116FORGE( + "1.16.5-forge", + MinecraftVersion.MC11605, + "official", + MappingStyle.SEARGE, + "net.minecraftforge:forge:1.16.5-36.2.39", + "BRIDGE116FABRIC", + ), + BRIDGE116FABRIC( + "1.16.5", + MinecraftVersion.MC11605, + yarn("1.16.5+build.10"), + MappingStyle.YARN, + null, + "MODERN", + ), + MODERN( + "1.21", + MinecraftVersion.MC121, + yarn("1.21+build.9"), + MappingStyle.YARN, + null, + null, + ) + ; + + val isBridge get() = name.contains("bridge") + + val linkTo by lazy { + if (linkTo == null) null + else { + ProjectTarget.values().find { it.name == linkTo }!! + } + } + val parent by lazy { + values().find { it.linkTo == this } + } + val isForge get() = forgeDep != null + val isFabric get() = forgeDep == null + + val projectPath get() = ":$projectName" + + companion object { + fun activeVersions() = values().filter { MultiVersionStage.activeState.shouldCreateProject(it) } + } +} diff --git a/sharedVariables/src/SHVersionInfo.kt b/sharedVariables/src/SHVersionInfo.kt new file mode 100644 index 000000000000..2f948897e984 --- /dev/null +++ b/sharedVariables/src/SHVersionInfo.kt @@ -0,0 +1,12 @@ +package at.skyhanni.sharedvariables + +object SHVersionInfo { + val gitHash by lazy { + val proc = ProcessBuilder("git", "rev-parse", "--short", "HEAD") + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectInput(ProcessBuilder.Redirect.PIPE) + .start() + proc.waitFor() + proc.inputStream.readBytes().decodeToString().trim() + } +} diff --git a/sharedVariables/src/Util.kt b/sharedVariables/src/Util.kt new file mode 100644 index 000000000000..750a73cbe978 --- /dev/null +++ b/sharedVariables/src/Util.kt @@ -0,0 +1,7 @@ +package at.skyhanni.sharedvariables + +import org.gradle.jvm.toolchain.JavaLanguageVersion + +fun JavaLanguageVersion.versionString() = + if (asInt() < 9) "1." + asInt() + else asInt().toString() diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index bd7f743ad3db..1e19bfcbabd4 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.26.Beta.20", + version = "0.26.Beta.24", ) class SkyHanniMod { diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index d42dfbbbf670..25cab54fbec5 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 = 52 + const val CONFIG_VERSION = 54 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 2d4947d51ae6..354748a668a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -60,7 +60,6 @@ import at.hannibal2.skyhanni.features.minion.MinionFeatures import at.hannibal2.skyhanni.features.misc.CollectionTracker import at.hannibal2.skyhanni.features.misc.LockMouseLook import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager -import at.hannibal2.skyhanni.features.misc.MiscFeatures import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager import at.hannibal2.skyhanni.features.misc.limbo.LimboTimeTracker import at.hannibal2.skyhanni.features.misc.massconfiguration.DefaultConfigFeatures @@ -88,6 +87,7 @@ import at.hannibal2.skyhanni.test.command.TrackSoundsCommand import at.hannibal2.skyhanni.utils.APIUtil import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ExtendedChatColor +import at.hannibal2.skyhanni.utils.ItemPriceUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.SoundUtils import at.hannibal2.skyhanni.utils.TabListData @@ -457,6 +457,7 @@ object Commands { "shtestisland", "Sets the current skyblock island for testing purposes.", ) { SkyBlockIslandTest.onCommand(it) } + registerCommand("shdebugprice", "Debug different price sources for an item.") { ItemPriceUtils.debugItemPrice(it) } } private fun developersCodingHelp() { 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 e0e8c28a5d60..3e64d5f5abff 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 @@ -28,8 +28,9 @@ 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.compat.GuiScreenUtils +import at.hannibal2.skyhanni.utils.compat.SkyhanniBaseScreen import net.minecraft.client.Minecraft -import net.minecraft.client.gui.GuiScreen import net.minecraft.client.gui.ScaledResolution import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager @@ -40,8 +41,8 @@ import java.io.IOException class GuiPositionEditor( private val positions: List, private val border: Int, - private val oldScreen: GuiContainer? = null -) : GuiScreen() { + private val oldScreen: GuiContainer? = null, +) : SkyhanniBaseScreen() { private var grabbedX = 0 private var grabbedY = 0 @@ -86,18 +87,14 @@ class GuiPositionEditor( // When the mouse isn't currently hovering over a gui element if (displayPos == -1) { GuiRenderUtils.drawStringCentered( - "§eTo edit hidden GUI elements set a key in /sh edit", getScaledWidth() / 2, - 20 - + 20, ) GuiRenderUtils.drawStringCentered( - "§ethen click that key while the GUI element is visible", getScaledWidth() / 2, - 32 - + 32, ) return } @@ -110,7 +107,7 @@ class GuiPositionEditor( GuiRenderUtils.drawStringCentered( "§aRight-Click to open associated config options", getScaledWidth() / 2, - 38 + 38, ) } @@ -136,16 +133,13 @@ class GuiPositionEditor( drawRect(x - border, y - border, x + elementWidth + border * 2, y + elementHeight + border * 2, -0x7fbfbfc0) if (GuiRenderUtils.isPointInRect( - mouseX, mouseY, x - border, y - border, elementWidth + border * 2, - elementHeight + border * 2 - + elementHeight + border * 2, ) - ) { hoveredPos = index } @@ -154,8 +148,8 @@ class GuiPositionEditor( return hoveredPos } - private fun getScaledHeight() = ScaledResolution(Minecraft.getMinecraft()).scaledHeight - private fun getScaledWidth() = ScaledResolution(Minecraft.getMinecraft()).scaledWidth + private fun getScaledHeight() = GuiScreenUtils.scaledWindowHeight + private fun getScaledWidth() = GuiScreenUtils.scaledWindowWidth @Throws(IOException::class) override fun mouseClicked(originalX: Int, priginalY: Int, mouseButton: Int) { @@ -175,7 +169,7 @@ class GuiPositionEditor( x - border, y - border, elementWidth + border * 2, - elementHeight + border * 2 + elementHeight + border * 2, ) if (!isHovered) continue if (mouseButton == 1) { @@ -251,7 +245,7 @@ class GuiPositionEditor( GuiRenderUtils.isPointInRect( mx, my, it.getAbsX() - border, it.getAbsY() - border, - size.x + border * 2, size.y + border * 2 + size.x + border * 2, size.y + border * 2, ) } ?: return if (mw < 0) 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 7eb2f19b8a0f..42a53f8dd3bf 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,6 +111,7 @@ public String toString() { @Expose @ConfigOption(name = "Gemstones", desc = "") @Accordion + // TODO remove config 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 2b4936af1ecf..3a44738ca6e8 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 @@ -15,38 +15,39 @@ public class PowderMiningGemstoneFilterConfig { @Expose @ConfigOption(name = "Ruby", desc = "Hide Ruby gemstones under a certain quality.") @ConfigEditorDropdown - public GemstoneFilterEntry rubyGemstones = GemstoneFilterEntry.FINE_ONLY; + public GemstoneFilterEntry rubyGemstones = GemstoneFilterEntry.FINE_UP; @Expose @ConfigOption(name = "Sapphire", desc = "Hide Sapphire gemstones under a certain quality.") @ConfigEditorDropdown - public GemstoneFilterEntry sapphireGemstones = GemstoneFilterEntry.FINE_ONLY; + public GemstoneFilterEntry sapphireGemstones = GemstoneFilterEntry.FINE_UP; @Expose @ConfigOption(name = "Amber", desc = "Hide Amber gemstones under a certain quality.") @ConfigEditorDropdown - public GemstoneFilterEntry amberGemstones = GemstoneFilterEntry.FINE_ONLY; + public GemstoneFilterEntry amberGemstones = GemstoneFilterEntry.FINE_UP; @Expose @ConfigOption(name = "Amethyst", desc = "Hide Amethyst gemstones under a certain quality.") @ConfigEditorDropdown - public GemstoneFilterEntry amethystGemstones = GemstoneFilterEntry.FINE_ONLY; + public GemstoneFilterEntry amethystGemstones = GemstoneFilterEntry.FINE_UP; @Expose @ConfigOption(name = "Jade", desc = "Hide Jade gemstones under a certain quality.") @ConfigEditorDropdown - public GemstoneFilterEntry jadeGemstones = GemstoneFilterEntry.FINE_ONLY; + public GemstoneFilterEntry jadeGemstones = GemstoneFilterEntry.FINE_UP; @Expose @ConfigOption(name = "Topaz", desc = "Hide Topaz gemstones under a certain quality.") @ConfigEditorDropdown - public GemstoneFilterEntry topazGemstones = GemstoneFilterEntry.FINE_ONLY; + public GemstoneFilterEntry topazGemstones = GemstoneFilterEntry.FINE_UP; public enum GemstoneFilterEntry { SHOW_ALL("Show All"), HIDE_ALL("Hide all"), FLAWED_UP("Show §aFlawed §7or higher"), - FINE_ONLY("Show §9Fine §7only"); + FINE_UP("Show §9Fine §7or higher"), + FLAWLESS_ONLY("Show §5Flawless §7only"); private final String str; 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 c4bbfacf34b0..b39f5f01ce63 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 @@ -217,6 +217,15 @@ public class GardenConfig { @FeatureToggle public boolean jacobContestSummary = true; + @Expose + @ConfigOption( + name = "Personal Best Increase FF", + desc = "Show in chat how much more FF you get from farming contest personal best bonus after beating the previous record." + ) + @ConfigEditorBoolean + @FeatureToggle + public boolean contestPersonalBestIncreaseFF = true; + // Does not have a config element! @Expose public Position cropSpeedMeterPos = new Position(278, -236, false, true); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/DropsStatisticsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/DropsStatisticsConfig.java index 078f82c5d99d..aecedf0b07d3 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/DropsStatisticsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/DropsStatisticsConfig.java @@ -16,6 +16,7 @@ import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.ACCEPTED; import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.COINS_SPENT; import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.COPPER; +import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.COPPER_DYE; import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.DEDICATION_IV; import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.DENIED; import static at.hannibal2.skyhanni.config.features.garden.visitor.DropsStatisticsConfig.DropsStatisticsTextEntry.FARMING_EXP; @@ -55,7 +56,8 @@ public class DropsStatisticsConfig { COINS_SPENT, OVERGROWN_GRASS, GREEN_BANDANA, - DEDICATION_IV + DEDICATION_IV, + COPPER_DYE )); /** @@ -89,6 +91,7 @@ public enum DropsStatisticsTextEntry implements HasLegacyId { CULTIVATING_I("§b1 §9Cultivating I", 15), REPLENISH_I("§b1 §9Replenish I", 16), DELICATE("§b1 §9Delicate V"), + COPPER_DYE("§b1 §8Copper Dye"), ; private final String str; diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java index 4b70d5230439..7e464d426d18 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java @@ -53,7 +53,8 @@ public class RewardWarningConfig { VisitorReward.MUSIC_RUNE, VisitorReward.SPACE_HELMET, VisitorReward.CULTIVATING, - VisitorReward.REPLENISH + VisitorReward.REPLENISH, + VisitorReward.COPPER_DYE )); @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java index a704efc42e9d..5621d7571a62 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java @@ -16,8 +16,7 @@ public class MayorConfig { public boolean showTimeTillNextMayor = true; @Expose - // TODO: Same Toggle toggles ministers - @ConfigOption(name = "Show Extra Mayor", desc = "Show the Perkpocalypse Mayor without their perks.") + @ConfigOption(name = "Show Extra Mayor", desc = "Show the Perkpocalypse Mayor without their perks and the minister with their perk.") @ConfigEditorBoolean public boolean showExtraMayor = true; } 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 730fb5764548..e7e90f51dd82 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 @@ -263,4 +263,10 @@ public String toString() { @ConfigEditorBoolean @FeatureToggle public boolean timeHeldInLore = false; + + @Expose + @ConfigOption(name = "Stonk of Stonk Price", desc = "Show Price per Stonk when taking the minimum bid in Stonks Auction (Richard).") + @ConfigEditorBoolean + @FeatureToggle + public boolean stonkOfStonkPrice = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/stillgorechateau/StillgoreChateauConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/stillgorechateau/StillgoreChateauConfig.java index eee9e2c6933d..2ea71f610f6e 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/stillgorechateau/StillgoreChateauConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/stillgorechateau/StillgoreChateauConfig.java @@ -2,6 +2,7 @@ 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 StillgoreChateauConfig { @@ -11,4 +12,9 @@ public class StillgoreChateauConfig { @Accordion public EffigiesConfig bloodEffigies = new EffigiesConfig(); + @Expose + @ConfigOption(name = "Highlight Splatter Hearts", desc = "Highlight heart particles of hearts removed by Splatter Cruxes.") + @ConfigEditorBoolean + public boolean highlightSplatterHearts = true; + } 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 f1e77ee75d72..4931a3b13db3 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -30,7 +30,6 @@ import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward; import at.hannibal2.skyhanni.features.inventory.caketracker.CakeTracker; import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker; -import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryUpgrade; import at.hannibal2.skyhanni.features.inventory.wardrobe.WardrobeAPI; import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay; import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker; @@ -276,6 +275,10 @@ public static class GardenStorage { @Expose public Map latestTrueFarmingFortune = new HashMap<>(); + // TODO use in /ff guide + @Expose + public Map personalBestFF = new HashMap<>(); + @Expose @Nullable public CropAccessory savedCropAccessory = CropAccessory.NONE; diff --git a/src/main/java/at/hannibal2/skyhanni/data/EntityData.kt b/src/main/java/at/hannibal2/skyhanni/data/EntityData.kt index c8e90fd279f7..c4e5fd7e76db 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/EntityData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/EntityData.kt @@ -23,16 +23,15 @@ import net.minecraft.entity.item.EntityItem import net.minecraft.entity.item.EntityItemFrame import net.minecraft.entity.item.EntityXPOrb import net.minecraft.network.play.server.S1CPacketEntityMetadata -import net.minecraft.util.IChatComponent +import net.minecraft.util.ChatComponentText import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable import kotlin.time.Duration.Companion.milliseconds @SkyHanniModule object EntityData { private val maxHealthMap = mutableMapOf() - private val nametagCache = TimeLimitedCache(50.milliseconds) + private val nametagCache = TimeLimitedCache(50.milliseconds) @SubscribeEvent fun onTick(event: LorenzTickEvent) { @@ -95,11 +94,11 @@ object EntityData { } @JvmStatic - fun getDisplayName(entity: Entity, ci: CallbackInfoReturnable) { - ci.returnValue = postRenderNametag(entity, ci.returnValue) + fun getDisplayName(entity: Entity, oldValue: ChatComponentText): ChatComponentText { + return postRenderNametag(entity, oldValue) } - private fun postRenderNametag(entity: Entity, chatComponent: IChatComponent) = nametagCache.getOrPut(entity) { + private fun postRenderNametag(entity: Entity, chatComponent: ChatComponentText) = nametagCache.getOrPut(entity) { val event = EntityDisplayNameEvent(entity, chatComponent) event.postAndCatch() event.chatComponent diff --git a/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt b/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt index 1d9ca38271e0..e82ddd4aebea 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt @@ -357,16 +357,16 @@ enum class HotmData( val printName = name.allLettersFirstUppercase() - /** Level which are actually paid with powder (does exclude [blueEgg]*/ - val rawLevel: Int + /** Level which are actually paid with powder (does exclude [blueEgg])*/ + var rawLevel: Int get() = storage?.perks?.get(this.name)?.level ?: 0 + private set(value) { + storage?.perks?.computeIfAbsent(this.name) { HotmTree.HotmPerk() }?.level = value + } /** Level for which the effect that is present (considers [enabled] and [blueEgg])*/ - var activeLevel: Int + val activeLevel: Int get() = if (enabled) effectivLevel else 0 - private set(value) { - storage?.perks?.computeIfAbsent(this.name) { HotmTree.HotmPerk() }?.level = value.minus(blueEgg()) - } /** Level that considering [blueEgg]*/ val effectivLevel: Int get() = storage?.perks?.get(this.name)?.level?.plus(blueEgg()) ?: 0 @@ -524,7 +524,7 @@ enum class HotmData( fun getPerkByNameOrNull(name: String): HotmData? = entries.find { it.guiName == name } private fun resetTree() = entries.forEach { - it.activeLevel = 0 + it.rawLevel = 0 it.enabled = false it.isUnlocked = false HotmAPI.Powder.entries.forEach { it.setCurrent(it.getTotal()) } @@ -542,7 +542,7 @@ enum class HotmData( val lore = item.getLore().takeIf { it.isNotEmpty() } ?: return if (entry != PEAK_OF_THE_MOUNTAIN && notUnlockedPattern.matches(lore.last())) { - entry.activeLevel = 0 + entry.rawLevel = 0 entry.enabled = false entry.isUnlocked = false return @@ -550,7 +550,7 @@ enum class HotmData( entry.isUnlocked = true - entry.activeLevel = levelPattern.matchMatcher(lore.first()) { + entry.rawLevel = levelPattern.matchMatcher(lore.first()) { group("level").toInt().transformIf({ group("color") == "b" }, { this.minus(1) }) } ?: entry.maxLevel @@ -565,7 +565,7 @@ enum class HotmData( } if (entry == PEAK_OF_THE_MOUNTAIN) { - entry.enabled = entry.activeLevel != 0 + entry.enabled = entry.rawLevel != 0 return } entry.enabled = lore.any { enabledPattern.matches(it) } @@ -681,7 +681,7 @@ enum class HotmData( DelayedRun.runNextTick { InventoryUtils.getItemsInOpenChest().forEach { it.parse() } abilities.filter { it.isUnlocked }.forEach { - it.activeLevel = if (PEAK_OF_THE_MOUNTAIN.rawLevel >= 1) 2 else 1 + it.rawLevel = if (PEAK_OF_THE_MOUNTAIN.rawLevel >= 1) 2 else 1 } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index bc43a807e02e..14aa579cae1a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -290,10 +290,10 @@ object HypixelData { } if (message.startsWith("you are playing on profile:")) { val newProfile = message.replace("you are playing on profile:", "").replace("(co-op)", "").trim() + ProfileStorageData.profileJoinMessage() if (profileName == newProfile) return profileName = newProfile ProfileJoinEvent(newProfile).postAndCatch() - ProfileStorageData.profileJoinMessage() } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt index c484f40714e3..555fdb7f8ff0 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt @@ -86,6 +86,8 @@ object MayorAPI { var currentMayor: Mayor? = null private set + var currentMinister: Mayor? = null + private set private var lastMayor: Mayor? = null var jerryExtraMayor: Pair = null to SimpleTimeMark.farPast() private set @@ -216,6 +218,7 @@ object MayorAPI { val currentMayorName = data.mayor.name if (lastMayor?.name != currentMayorName) { currentMayor = setAssumeMayorJson(currentMayorName, data.mayor.perks) + currentMinister = setAssumeMayorJson(data.mayor.minister.name, listOf(data.mayor.minister.perk)) } } } @@ -246,6 +249,8 @@ object MayorAPI { add("Active Perks: ${currentMayor?.activePerks}") add("Last Update: $lastUpdate (${lastUpdate.passedSince()} ago)") add("Time Till Next Mayor: ${nextMayorTimestamp.timeUntil()}") + add("Current Minister: ${currentMinister?.name ?: "Unknown"}") + add("Current Minister Perk: ${currentMinister?.activePerks}") if (jerryExtraMayor.first != null) { add("Jerry Mayor: ${jerryExtraMayor.first?.name} expiring at: ${jerryExtraMayor.second.timeUntil()}") } diff --git a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt index 975282a3abc0..53ebae1dd534 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt @@ -45,10 +45,10 @@ enum class Mayor( FINNEGAN( "Finnegan", "§c", - Perk.FARMING_SIMULATOR, Perk.PELT_POCALYPSE, Perk.GOATED, Perk.BLOOMING_BUSINESS, + Perk.PEST_ERADICATOR, ), FOXY( "Foxy", @@ -189,10 +189,10 @@ enum class Perk(val perkName: String) { LONG_TERM_INVESTMENT("Long Term Investment"), // Finnegan - FARMING_SIMULATOR("Farming Simulator"), PELT_POCALYPSE("Pelt-pocalypse"), GOATED("GOATed"), BLOOMING_BUSINESS("Blooming Business"), + PEST_ERADICATOR("Pest Eradicator"), // Foxy SWEET_BENEVOLENCE("Sweet Benevolence"), @@ -224,9 +224,7 @@ enum class Perk(val perkName: String) { // Derpy TURBO_MINIONS("TURBO MINIONS!!!"), - AH_TAX("MOAR TAX!!!"), - - // I don't know what the perk is actually gonna be named + AH_TAX("MOAR TAX!!!"), // TODO: Change to actual perk name when known DOUBLE_MOBS_HP("DOUBLE MOBS HP!!!"), MOAR_SKILLZ("MOAR SKILLZ!!!"), ; diff --git a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt index be36bc11b61a..e97d25c52516 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt @@ -20,13 +20,15 @@ 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.RegexUtils.matchFirst +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import io.netty.util.internal.ConcurrentSet import net.minecraft.init.Blocks import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.concurrent.ConcurrentLinkedQueue import kotlin.math.absoluteValue import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -37,14 +39,12 @@ object MiningAPI { private val group = RepoPattern.group("data.miningapi") private val glaciteAreaPattern by group.pattern("area.glacite", "Glacite Tunnels|Glacite Lake") private val dwarvenBaseCampPattern by group.pattern("area.basecamp", "Dwarven Base Camp") - val coldReset by group.pattern( + + // TODO rename to include suffix "pattern", add regex test + private val coldReset 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.", ) - private val coldResetDeath by group.pattern( - "cold.deathreset", - "§c ☠ §r§7§r§.(?.+)§r§7 (?.+)", - ) private data class MinedBlock(val ore: OreBlock, var confirmed: Boolean, val time: SimpleTimeMark = SimpleTimeMark.now()) @@ -68,8 +68,8 @@ object MiningAPI { private var lastSkyblockArea: String? = null - private var recentClickedBlocks = mutableMapOf() - private var surroundingMinedBlocks = mutableMapOf() + private val recentClickedBlocks = ConcurrentSet>() + private val surroundingMinedBlocks = ConcurrentLinkedQueue>() private val allowedSoundNames = listOf("dig.glass", "dig.stone", "dig.gravel", "dig.cloth", "random.orb") var cold: Int = 0 @@ -103,7 +103,7 @@ object MiningAPI { @SubscribeEvent fun onScoreboardChange(event: ScoreboardUpdateEvent) { - val newCold = event.scoreboard.matchFirst(ScoreboardPattern.coldPattern) { + val newCold = ScoreboardPattern.coldPattern.firstMatcher(event.scoreboard) { group("cold").toInt().absoluteValue } ?: return @@ -116,10 +116,8 @@ object MiningAPI { fun onBlockClick(event: BlockClickEvent) { if (!inCustomMiningIsland()) return if (event.clickType != ClickType.LEFT_CLICK) return - val position = event.position - val blockState = event.getBlockState - val ore = OreBlock.getByStateOrNull(blockState) ?: return - recentClickedBlocks[position] = MinedBlock(ore, false) + if (OreBlock.getByStateOrNull(event.getBlockState) == null) return + recentClickedBlocks += event.position to SimpleTimeMark.now() } @SubscribeEvent @@ -146,7 +144,7 @@ object MiningAPI { if (waitingForInitSound) { if (event.soundName != "random.orb" && event.pitch == 0.7936508f) { val pos = event.location.roundLocationToBlock() - if (pos !in recentClickedBlocks) return + if (recentClickedBlocks.none { it.first == pos }) return waitingForInitSound = false waitingForInitBlock = true waitingForInitBlockPos = event.location.roundLocationToBlock() @@ -155,8 +153,7 @@ object MiningAPI { return } if (waitingForEffMinerSound) { - if (surroundingMinedBlocks.isEmpty()) return - val lastBlock = surroundingMinedBlocks.values.minByOrNull { it.time.passedSince() } ?: return + val lastBlock = surroundingMinedBlocks.lastOrNull()?.first ?: return if (lastBlock.confirmed) return waitingForEffMinerSound = false lastBlock.confirmed = true @@ -169,23 +166,24 @@ object MiningAPI { if (!inCustomMiningIsland()) return if (event.newState.block != Blocks.air) return if (event.oldState.block == Blocks.air) return - if (event.location.distanceToPlayer() > 7) return + val pos = event.location + if (pos.distanceToPlayer() > 7) return if (lastInitSound.passedSince() > 100.milliseconds) return val ore = OreBlock.getByStateOrNull(event.oldState) ?: return if (waitingForInitBlock) { - if (waitingForInitBlockPos != event.location) return + if (waitingForInitBlockPos != pos) return waitingForInitBlock = false - surroundingMinedBlocks[event.location] = MinedBlock(ore, true) + surroundingMinedBlocks += MinedBlock(ore, true) to pos waitingForEffMinerBlock = true return } if (waitingForEffMinerBlock) { - if (event.location in surroundingMinedBlocks) return + if (surroundingMinedBlocks.any { it.second == pos }) return waitingForEffMinerBlock = false - surroundingMinedBlocks[event.location] = MinedBlock(ore, false) + surroundingMinedBlocks += MinedBlock(ore, false) to pos waitingForEffMinerSound = true return } @@ -201,8 +199,8 @@ object MiningAPI { if (currentAreaOreBlocks.isEmpty()) return // if somehow you take more than 20 seconds to mine a single block, congrats - recentClickedBlocks = recentClickedBlocks.filter { it.value.time.passedSince() <= 20.seconds }.toMutableMap() - surroundingMinedBlocks = surroundingMinedBlocks.filter { it.value.time.passedSince() <= 20.seconds }.toMutableMap() + recentClickedBlocks.removeIf { it.second.passedSince() >= 20.seconds } + surroundingMinedBlocks.removeIf { it.first.time.passedSince() >= 20.seconds } if (waitingForInitSound) return if (lastInitSound.passedSince() < 200.milliseconds) return @@ -211,19 +209,18 @@ object MiningAPI { if (surroundingMinedBlocks.isEmpty()) return - val originalBlock = surroundingMinedBlocks.maxByOrNull { it.value.time.passedSince() }?.takeIf { it.value.confirmed }?.value - ?: run { - surroundingMinedBlocks.clear() - recentClickedBlocks.clear() - return - } + val originalBlock = surroundingMinedBlocks.firstOrNull { it.first.confirmed }?.first ?: run { + surroundingMinedBlocks.clear() + recentClickedBlocks.clear() + return + } - val extraBlocks = surroundingMinedBlocks.values.filter { it.confirmed }.countBy { it.ore } + val extraBlocks = surroundingMinedBlocks.filter { it.first.confirmed }.countBy { it.first.ore } OreMinedEvent(originalBlock.ore, extraBlocks).post() surroundingMinedBlocks.clear() - recentClickedBlocks = recentClickedBlocks.filter { it.value.time.passedSince() < originalBlock.time.passedSince() }.toMutableMap() + recentClickedBlocks.removeIf { it.second.passedSince() >= originalBlock.time.passedSince() } } @SubscribeEvent @@ -264,7 +261,7 @@ object MiningAPI { add("waitingForInitBlockPos: $waitingForInitBlockPos") add("waitingForEffMinerSound: $waitingForEffMinerSound") add("waitingForEffMinerBlock: $waitingForEffMinerBlock") - add("recentClickedBlocks: ${recentClickedBlocks.entries.joinToString { it.key.toCleanString() }}") + add("recentlyClickedBlocks: ${recentClickedBlocks.joinToString { "(${it.first.toCleanString()}" }}") } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index dfe57cc5cb0f..d79320603e76 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -23,7 +23,7 @@ object PetAPI { ) private val neuRepoPetItemName by patternGroup.pattern( "item.name.neu.format", - "(?:§f§f)?§7\\[Lvl 1➡(?:100|200)] (?.*)", + "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", ) private val ignoredPetStrings = listOf( diff --git a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt index 0ade6a946036..26915faf357b 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt @@ -22,7 +22,13 @@ object ScoreboardData { private var sidebarLines: List = emptyList() // TODO rename to raw var sidebarLinesRaw: List = emptyList() // TODO delete - var objectiveTitle = "" + val objectiveTitle: String get() = grabObjectiveTitle() + + fun grabObjectiveTitle(): String { + val scoreboard = Minecraft.getMinecraft().theWorld?.scoreboard ?: return "" + val objective = scoreboard.getObjectiveInDisplaySlot(1) ?: return "" + return objective.displayName + } private var dirty = false @@ -35,8 +41,14 @@ object ScoreboardData { val lastColor = start.lastColorCode() ?: "" - if (end.startsWith(lastColor)) { - end = end.removePrefix(lastColor) + // Determine the longest prefix of "end" that matches any suffix of "lastColor" + val colorSuffixes = generateSequence(lastColor) { it.dropLast(2) } + .takeWhile { it.isNotEmpty() } + .toList() + + val matchingPrefix = colorSuffixes.find { end.startsWith(it) } ?: "" + if (matchingPrefix.isNotEmpty()) { + end = end.removePrefix(matchingPrefix) } add(start + end) @@ -84,7 +96,6 @@ object ScoreboardData { private fun fetchScoreboardLines(): List { val scoreboard = Minecraft.getMinecraft().theWorld?.scoreboard ?: return emptyList() val objective = scoreboard.getObjectiveInDisplaySlot(1) ?: return emptyList() - objectiveTitle = objective.displayName var scores = scoreboard.getSortedScores(objective) val list = scores.filter { input: Score? -> input != null && input.playerName != null && !input.playerName.startsWith("#") diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/other/MayorJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/other/MayorJson.kt index d8f0df279a25..912a6f8c6476 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/other/MayorJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/other/MayorJson.kt @@ -11,6 +11,7 @@ data class MayorInfo( @Expose val key: String, @Expose val name: String, @Expose val perks: List, + @Expose val minister: Minister, @Expose val election: MayorElection, ) @@ -26,7 +27,14 @@ data class MayorCandidate( @Expose val votes: Int, ) +data class Minister( + @Expose val key: String, + @Expose val name: String, + @Expose val perk: MayorPerk, +) + data class MayorPerk( @Expose val name: String, @Expose val description: String, + @Expose val minister: Boolean = false, ) 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 9d922f93d60a..cd72264f31b1 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt @@ -55,7 +55,7 @@ enum class TabWidget( ), PROFILE( // language=RegExp - "(?:§.)*Profile: (?:§.)*(?\\S+).*", + "(?:§.)+Profile: §r§a(?[\\w\\s]+[^ §]).*", ), SB_LEVEL( // language=RegExp diff --git a/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt index f5566e278415..c895b1058d7c 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt @@ -13,7 +13,7 @@ import net.minecraftforge.common.MinecraftForge import net.minecraftforge.fml.common.eventhandler.Event import net.minecraftforge.fml.common.eventhandler.IEventListener -@Deprecated("Use SkyHanniEvent instead", ReplaceWith("")) +@Deprecated("Use SkyHanniEvent instead") abstract class LorenzEvent : Event() { private val eventName by lazy { diff --git a/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt index 1a987e6f9032..4f6269c81745 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt @@ -8,7 +8,7 @@ import net.minecraftforge.fml.common.eventhandler.Cancelable class LorenzToolTipEvent(val slot: Slot, val itemStack: ItemStack, private val toolTip0: MutableList) : LorenzEvent() { - var toolTip + var toolTip: MutableList set(value) { toolTip0.clear() toolTip0.addAll(value) diff --git a/src/main/java/at/hannibal2/skyhanni/events/entity/EntityDisplayNameEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/entity/EntityDisplayNameEvent.kt index 1a3bcfed4280..c4d24eb0a2c9 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/entity/EntityDisplayNameEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/entity/EntityDisplayNameEvent.kt @@ -2,6 +2,6 @@ package at.hannibal2.skyhanni.events.entity import at.hannibal2.skyhanni.events.LorenzEvent import net.minecraft.entity.Entity -import net.minecraft.util.IChatComponent +import net.minecraft.util.ChatComponentText -class EntityDisplayNameEvent(val entity: Entity, var chatComponent: IChatComponent) : LorenzEvent() +class EntityDisplayNameEvent(val entity: Entity, var chatComponent: ChatComponentText) : LorenzEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt index 3f2897aaede0..303f8de371a7 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt @@ -483,7 +483,10 @@ object ChatFilter { config.others && isOthers(message) -> othersMsg config.winterGift && message.isPresent("winter_gift") -> "winter_gift" - config.eventLevelUp && (message.isPresent("event") || StringUtils.isEmpty(message)) -> "event" + + // TODO need proper solution to hide empty messages in event text + config.eventLevelUp && (message.isPresent("event")) -> "event" + config.fireSale && (fireSalePattern.matches(message) || message.isPresent("fire_sale")) -> "fire_sale" config.factoryUpgrade && message.isPresent("factory_upgrade") -> "factory_upgrade" config.sacrifice && message.isPresent("sacrifice") -> "sacrifice" @@ -576,5 +579,12 @@ object ChatFilter { event.move(3, "chat.profileJoin", "chat.filterType.profileJoin") event.move(3, "chat.others", "chat.filterType.others") event.move(52, "chat.filterType.powderMining", "chat.filterType.powderMiningFilter.enabled") + event.transform(53, "chat.filterType.powderMiningFilter.gemstoneFilterConfig") { element -> + element.asJsonObject.apply { + entrySet().forEach { (key, value) -> + if (value.asString == "FINE_ONLY") addProperty(key, "FINE_UP") + } + } + } } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt index 1d414cea484b..9c100ef47ead 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt @@ -13,12 +13,17 @@ import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.Simpl import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.WISHING_COMPASS import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.YOGGIE import at.hannibal2.skyhanni.config.features.chat.PowderMiningGemstoneFilterConfig.GemstoneFilterEntry +import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Pattern @SkyHanniModule object PowderMiningChatFilter { @@ -46,6 +51,14 @@ object PowderMiningChatFilter { "§6You have successfully picked the lock on this chest!", ) + /** + * REGEX-TEST: §cThis chest has already been looted. + */ + private val alreadyLootedPattern by patternGroup.pattern( + "warning.alreadylooted", + "§cThis chest has already been looted\\.", + ) + /** * REGEX-TEST: §cYou need a tool with a §r§aBreaking Power §r§cof §r§66§r§c to mine Ruby Gemstone Block§r§c! Speak to §r§dFragilis §r§cby the entrance to the Crystal Hollows to learn more! */ @@ -232,16 +245,18 @@ object PowderMiningChatFilter { * REGEX-TEST: §r§f❈ Rough Amethyst Gemstone §r§8x24 * REGEX-TEST: §r§a❈ Flawed Amethyst Gemstone §r§8x4 * REGEX-TEST: §r§9⸕ Fine Amber Gemstone + * REGEX-TEST: §r§5⸕ Flawless Amber Gemstone */ private val gemstonePattern by patternGroup.pattern( "reward.gemstone", - "§r§[fa9][❤❈☘⸕✎✧] (?Rough|Flawed|Fine) (?Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone( §r§8x(?[\\d,]+))?", + "§r§[fa9][❤❈☘⸕✎✧] (?Rough|Flawed|Fine|Flawless) (?Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone( §r§8x(?[\\d,]+))?", ) fun block(message: String): String? { // Generic "you uncovered a chest" message if (uncoverChestPattern.matches(message)) return "powder_mining_chest" if (successfulPickPattern.matches(message)) return "powder_mining_picked" + if (alreadyLootedPattern.matches(message)) return "powder_mining_dupe" // Breaking power warning if (breakingPowerPattern.matches(message) && gemstoneConfig.strongerToolMessages) return "stronger_tool" // Closing or opening a reward 'loop' with the spam of ▬ @@ -251,6 +266,7 @@ object PowderMiningChatFilter { } if (!unclosedRewards) return null + if (StringUtils.isEmpty(message)) return "powder_mining_empty" if (lockPickedPattern.matches(message)) return "powder_chest_lockpicked" if (lootChestCollectedPattern.matches(message)) return "loot_chest_opened" if (rewardHeaderPattern.matches((message))) return "powder_reward_header" @@ -289,8 +305,11 @@ object PowderMiningChatFilter { return null } - private fun blockSimpleRewards(ssMessage: String): String? { - val rewardPatterns = mapOf( + var rewardPatterns: Map, String> = emptyMap() + + @SubscribeEvent(priority = EventPriority.HIGHEST) + fun onRepoReload(event: RepositoryReloadEvent) { + rewardPatterns = mapOf( ascensionRopeRewardPattern to ASCENSION_ROPE to "powder_mining_ascension_rope", wishingCompassRewardPattern to WISHING_COMPASS to "powder_mining_wishing_compass", oilBarrelRewardPattern to OIL_BARREL to "powder_mining_oil_barrel", @@ -302,6 +321,9 @@ object PowderMiningChatFilter { robotPartsPattern to ROBOT_PARTS to "powder_mining_robot_parts", treasuritePattern to TREASURITE to "powder_mining_treasurite", ) + } + + private fun blockSimpleRewards(ssMessage: String): String? { for ((patternToReward, returnReason) in rewardPatterns) { if (patternToReward.first.matches(ssMessage)) { return if (config.simplePowderMiningTypes.contains(patternToReward.second)) returnReason @@ -316,8 +338,7 @@ object PowderMiningChatFilter { if (config.goblinEggs == PowderMiningFilterConfig.GoblinEggFilterEntry.SHOW_ALL) return "no_filter" if (config.goblinEggs == PowderMiningFilterConfig.GoblinEggFilterEntry.HIDE_ALL) return "powder_mining_goblin_eggs" - val colorStr = groupOrNull("color")?.lowercase() - return when (colorStr) { + return when (val colorStr = groupOrNull("color")?.lowercase()) { //'Colorless', base goblin eggs will never be shown in this code path null -> "powder_mining_goblin_eggs" "green" -> if (config.goblinEggs > PowderMiningFilterConfig.GoblinEggFilterEntry.GREEN_UP) { @@ -372,9 +393,13 @@ object PowderMiningChatFilter { "flawed" -> if (gemSpecificFilterEntry > GemstoneFilterEntry.FLAWED_UP) { "powder_mining_gemstones" } else "no_filter" - // FINE_ONLY enum not explicitly used in comparison, as the only + + "fine" -> if (gemSpecificFilterEntry > GemstoneFilterEntry.FINE_UP) { + "powder_mining_gemstones" + } else "no_filter" + // FLAWLESS_ONLY enum not explicitly used in comparison, as the only // case that will block it is HIDE_ALL, which is covered above - "fine" -> "no_filter" + "flawless" -> "no_filter" // This should not be reachable else -> "no_filter" } diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/endernodetracker/EnderNodeTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/endernodetracker/EnderNodeTracker.kt index 9012f0223073..12bd69658880 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/endernodetracker/EnderNodeTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/endernodetracker/EnderNodeTracker.kt @@ -19,10 +19,10 @@ import at.hannibal2.skyhanni.utils.ConfigUtils import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemCategory import at.hannibal2.skyhanni.utils.ItemCategory.Companion.containsItem +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getNpcPriceOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland -import at.hannibal2.skyhanni.utils.NEUItems.getNpcPriceOrNull import at.hannibal2.skyhanni.utils.NEUItems.getPriceOrNull import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt index 9bd3afce48f9..1890c62930d1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt @@ -13,6 +13,7 @@ import at.hannibal2.skyhanni.utils.chat.Text.style import at.hannibal2.skyhanni.utils.chat.Text.suggest import net.minecraft.util.EnumChatFormatting import net.minecraft.util.IChatComponent +import kotlin.math.ceil object HelpCommand { @@ -36,7 +37,7 @@ object HelpCommand { if (description.isNotEmpty()) description.prependIndent(" ") else null, "", "$color§l${category.categoryName}", - categoryDescription.prependIndent(" ") + categoryDescription.prependIndent(" "), ) this.suggest = "/${command.name}" } @@ -45,12 +46,15 @@ object HelpCommand { private fun showPage( page: Int, search: String, - commands: List + commands: List, ) { val filtered = commands.filter { it.name.contains(search, ignoreCase = true) || it.description.contains(search, ignoreCase = true) } - val maxPage = filtered.size / COMMANDS_PER_PAGE + 1 + + val maxPage = if (filtered.isNotEmpty()) { + ceil(filtered.size.toDouble() / COMMANDS_PER_PAGE).toInt() + } else 1 val page = page.coerceIn(1, maxPage) val title = if (search.isEmpty()) "§6SkyHanni Commands" else "§6SkyHanni Commands matching '$search'" @@ -58,19 +62,21 @@ object HelpCommand { text.add(createDivider()) text.add(title.asComponent().center()) - text.add(Text.join( - if (page > 1) "§6§l<<".asComponent { - this.hover = "§eClick to view page ${page - 1}".asComponent() - this.onClick { showPage(page - 1, search, commands) } - } else null, - " ", - "§6(Page $page of $maxPage)", - " ", - if (page < maxPage) "§6§l>>".asComponent { - this.hover = "§eClick to view page ${page + 1}".asComponent() - this.onClick { showPage(page + 1, search, commands) } - } else null - ).center()) + text.add( + Text.join( + if (page > 1) "§6§l<<".asComponent { + this.hover = "§eClick to view page ${page - 1}".asComponent() + this.onClick { showPage(page - 1, search, commands) } + } else null, + " ", + "§6(Page $page of $maxPage)", + " ", + if (page < maxPage) "§6§l>>".asComponent { + this.hover = "§eClick to view page ${page + 1}".asComponent() + this.onClick { showPage(page + 1, search, commands) } + } else null, + ).center(), + ) text.add(createDivider()) if (filtered.isEmpty()) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonCleanEnd.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonCleanEnd.kt index 3b9f023d2e98..eca75bc7014b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonCleanEnd.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonCleanEnd.kt @@ -23,9 +23,15 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object DungeonCleanEnd { private val config get() = SkyHanniMod.feature.dungeon.cleanEnd + + /** + * REGEX-TEST: §f §r§cMaster Mode The Catacombs §r§8- §r§eFloor III + * REGEX-TEST: §f §r§cThe Catacombs §r§8- §r§eFloor VI + * REGEX-TEST: §f §r§cMaster Mode Catacombs §r§8- §r§eFloor II + */ private val catacombsPattern by RepoPattern.pattern( "dungeon.end.chests.spawned", - "(?:§f)?( *)§r§c(The|Master Mode) Catacombs §r§8- §r§eFloor (.*)" + "(?:§f)?( *)§r§c(Master Mode )?The Catacombs §r§8- §r§eFloor (.*)", ) private var bossDone = false diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt index d3a3692019f7..93efa204fd7b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt @@ -57,9 +57,14 @@ object DungeonFinderFeatures { "note", "§7§7Note: §f(?.*)" ) + + /** + * REGEX-TEST: The Catacombs + * REGEX-TEST: Master Mode The Catacombs + */ private val floorTypePattern by patternGroup.pattern( "floor.type", - "(The Catacombs).*|.*(MM Catacombs).*" + "(The Catacombs).*|.*(Master Mode The Catacombs).*", ) private val checkIfPartyPattern by patternGroup.pattern( "check.if.party", @@ -87,11 +92,16 @@ object DungeonFinderFeatures { ) private val anyFloorPattern by patternGroup.pattern( "floor.any", - "(Any)" + "(Any)", ) + + /** + * REGEX-TEST: Master Mode The Catacombs + * REGEX-TEST: The Catacombs + */ private val masterModeFloorPattern by patternGroup.pattern( "floor.mastermode", - "(MM )|(.*Master Mode Catacombs)" + "(MM )|(.*Master Mode The Catacombs)" ) private val dungeonFloorPattern by patternGroup.pattern( "floor.dungeon", @@ -297,7 +307,7 @@ object DungeonFinderFeatures { fun onTooltip(event: LorenzToolTipEvent) { if (!isEnabled()) return if (!inInventory) return - val toolTip = toolTipMap[event.slot.slotIndex] + val toolTip = toolTipMap[event.slot.slotNumber] if (toolTip.isNullOrEmpty()) return // TODO @Thunderblade73 fix that to "event.toolTip = toolTip" val oldToolTip = event.toolTip diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt index f9a25f3d596b..91316dbfcdab 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt @@ -75,7 +75,7 @@ object HoppityEggsCompactChat { val timeStr = if (config.showDuplicateTime) ", §a+§b$timeFormatted§7" else "" "$mealNameFormatted! §7Duplicate $lastName §7(§6+$format Chocolate§7$timeStr)" } else if (newRabbit) { - "$mealNameFormatted! §d§lNEW $lastName §7(${lastProfit}§7)" + "$mealNameFormatted! §d§lNEW $lastRarity $lastName §7(${lastProfit}§7)" } else "?" } diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingTimer.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingTimer.kt index 74cf9294da64..5be021fbb8a1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingTimer.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingTimer.kt @@ -125,7 +125,7 @@ object FishingTimer { private fun handle() { if (lastSeaCreatureFished.passedSince() > 2.seconds) return val name = lastNameFished ?: return - val mobs = recentMobs.filter { it.name == name && it !in mobDespawnTime } + val mobs = recentMobs.toSet().filter { it.name == name && it !in mobDespawnTime } .sortedBy { it.baseEntity.distanceToPlayer() } .take(mobsToFind).ifEmpty { return } mobsToFind -= mobs.size @@ -165,9 +165,7 @@ object FishingTimer { } private fun updateInfo() { - currentCount = mobDespawnTime.entries.sumOf { - 1 + it.key.extraEntities.size - } + currentCount = mobDespawnTime.size startTime = mobDespawnTime.maxByOrNull { it.value.passedSince() }?.value ?: SimpleTimeMark.farPast() display = createDisplay() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt index 9f3e83f4ed3c..4b91b6240243 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt @@ -7,7 +7,6 @@ import at.hannibal2.skyhanni.data.jsonobjects.repo.TrophyFishJson import at.hannibal2.skyhanni.events.NeuProfileDataLoadedEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import net.minecraft.event.HoverEvent import net.minecraft.util.ChatComponentText @@ -65,8 +64,8 @@ object TrophyFishManager { } private fun updateFromNeuPv( - savedFishes: MutableMap>, - neuData: MutableList>, + savedFishes: Map>, + neuData: List>, ) { for ((name, rarity, newValue) in neuData) { val saved = savedFishes[name] ?: continue diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt index edc5f17ee137..29b92f24afd8 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt @@ -44,33 +44,33 @@ object FarmingFortuneDisplay { private val patternGroup = RepoPattern.group("garden.fortunedisplay") private val universalTabFortunePattern by patternGroup.pattern( "tablist.universal", - " Farming Fortune: §r§6☘(?\\d+)" + " Farming Fortune: §r§6☘(?\\d+)", ) private val cropSpecificTabFortunePattern by patternGroup.pattern( "tablist.cropspecific", - " (?Wheat|Carrot|Potato|Pumpkin|Sugar Cane|Melon|Cactus|Cocoa Beans|Mushroom|Nether Wart) Fortune: §r§6☘(?\\d+)" + " (?Wheat|Carrot|Potato|Pumpkin|Sugar Cane|Melon|Cactus|Cocoa Beans|Mushroom|Nether Wart) Fortune: §r§6☘(?\\d+)", ) private val collectionPattern by patternGroup.pattern( "collection", - "§7You have §6\\+(?\\d{1,3})☘ .*" + "§7You have §6\\+(?\\d{1,3})☘ .*", ) private val tooltipFortunePattern by patternGroup.pattern( "tooltip.new", - "^§7Farming Fortune: §a\\+(?[\\d.]+)(?: §2\\(\\+\\d\\))?(?: §9\\(\\+(?\\d+)\\))?(?: §d\\(\\+(?\\d+)\\))?\$" + "^§7Farming Fortune: §a\\+(?[\\d.]+)(?: §2\\(\\+\\d\\))?(?: §9\\(\\+(?\\d+)\\))?(?: §d\\(\\+(?\\d+)\\))?\$", ) private val armorAbilityPattern by patternGroup.pattern( "armorability", - "Tiered Bonus: .* [(](?.*)/4[)]" + "Tiered Bonus: .* [(](?.*)/4[)]", ) private val lotusAbilityPattern by patternGroup.pattern( "lotusability", - "§7Piece Bonus: §6+(?.*)☘" + "§7Piece Bonus: §6+(?.*)☘", ) // todo make pattern work on Melon and Cropie armor private val armorAbilityFortunePattern by patternGroup.pattern( "armorabilityfortune", - "§7.*§7Grants §6(?.*)☘.*" + "§7.*§7Grants §6(?.*)☘.*", ) private var display = emptyList() @@ -168,8 +168,8 @@ object FarmingFortuneDisplay { Renderable.string( "§6Farming Fortune§7: §e" + if (!recentlySwitchedTool && farmingFortune != -1.0) { farmingFortune.round(0).addSeparators() - } else "§7" + (displayCrop.getLatestTrueFarmingFortune()?.addSeparators() ?: "?") - ) + } else "§7" + (displayCrop.getLatestTrueFarmingFortune()?.addSeparators() ?: "?"), + ), ) add(Renderable.horizontalContainer(list)) @@ -189,27 +189,31 @@ object FarmingFortuneDisplay { private fun drawMissingFortuneDisplay(cropFortune: Boolean) = buildList { if (cropFortune) { - add(Renderable.clickAndHover( - "§cNo Crop Fortune Found! Enable The Stats Widget", - listOf( - "§cEnable the Stats widget and enable", - "§cshowing latest Crop Fortune." + add( + Renderable.clickAndHover( + "§cNo Crop Fortune Found! Enable The Stats Widget", + listOf( + "§cEnable the Stats widget and enable", + "§cshowing latest Crop Fortune.", + ), + onClick = { + HypixelCommands.widget() + }, ), - onClick = { - HypixelCommands.widget() - } - )) + ) } else { - add(Renderable.clickAndHover( - "§cNo Farming Fortune Found! Enable The Stats Widget", - listOf( - "§cEnable the Stats widget and enable", - "§cshowing the Farming Fortune stat." + add( + Renderable.clickAndHover( + "§cNo Farming Fortune Found! Enable The Stats Widget", + listOf( + "§cEnable the Stats widget and enable", + "§cshowing the Farming Fortune stat.", + ), + onClick = { + HypixelCommands.widget() + }, ), - onClick = { - HypixelCommands.widget() - } - )) + ) } } @@ -300,7 +304,7 @@ object FarmingFortuneDisplay { val dedicationLevel = tool?.getEnchantments()?.get("dedication") ?: 0 val dedicationMultiplier = listOf(0.0, 0.5, 0.75, 1.0, 2.0)[dedicationLevel] val cropMilestone = GardenCropMilestones.getTierForCropCount( - cropType.getCounter(), cropType + cropType.getCounter(), cropType, ) return dedicationMultiplier * cropMilestone } @@ -355,11 +359,14 @@ object FarmingFortuneDisplay { itemBaseFortune = if (tool.getInternalName().contains("LOTUS")) { 5.0 + } else if (tool.getInternalName().equals("ZORROS_CAPE")) { + 10.0 } else { val dummiesFF = (tool.getFarmingForDummiesCount() ?: 0) * 1.0 displayedFortune - reforgeFortune - gemstoneFortune - pesterminatorFortune - enchantmentFortune - dummiesFF } - greenThumbFortune = if (tool.getInternalName().contains("LOTUS")) { + + greenThumbFortune = if (tool.getInternalName().let { it.contains("LOTUS") || it.equals("ZORROS_CAPE") }) { displayedFortune - reforgeFortune - itemBaseFortune } else 0.0 } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt index 7c88acfca264..a08acac9146e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt @@ -55,7 +55,7 @@ object ComposterDisplay { @SubscribeEvent fun onTabListUpdate(event: WidgetUpdateEvent) { - if (!(config.displayEnabled && GardenAPI.inGarden())) return + if (!GardenAPI.inGarden()) return if (!event.isWidget(TabWidget.COMPOSTER)) return readData(event.lines) @@ -68,6 +68,7 @@ object ComposterDisplay { } private fun updateDisplay() { + if (!config.displayEnabled) return val newDisplay = mutableListOf>() newDisplay.addAsSingletonList("§bComposter") diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt index 8ed772ea30a2..aee2a93f428f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.config.features.garden.composter.ComposterConfig.Re import at.hannibal2.skyhanni.data.SackAPI.getAmountInSacksOrNull import at.hannibal2.skyhanni.data.jsonobjects.repo.GardenJson import at.hannibal2.skyhanni.data.model.ComposterUpgrade +import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent @@ -170,23 +171,19 @@ object ComposterOverlay { return } if (organicMatterFactors.isEmpty()) { - organicMatterDisplay = - Collections.singletonList( - listOf( - "§cSkyHanni composter error:", "§cRepo data not loaded!", - "§7(organicMatterFactors is empty)" - ) - ) + organicMatterDisplay = listOf( + Collections.singletonList("§cSkyHanni composter error:"), + Collections.singletonList("§cRepo data not loaded!"), + Collections.singletonList("§7(organicMatterFactors is empty)"), + ) return } if (fuelFactors.isEmpty()) { - organicMatterDisplay = - Collections.singletonList( - listOf( - "§cSkyHanni composter error:", "§cRepo data not loaded!", - "§7(fuelFactors is empty)" - ) - ) + organicMatterDisplay = listOf( + Collections.singletonList("§cSkyHanni composter error:"), + Collections.singletonList("§cRepo data not loaded!"), + Collections.singletonList("§7(fuelFactors is empty)"), + ) return } if (currentOrganicMatterItem.let { it !in organicMatterFactors.keys && it != NONE }) { @@ -310,7 +307,7 @@ object ComposterOverlay { onChange = { currentTimeType = it update() - } + }, ) val list = mutableListOf() @@ -405,10 +402,12 @@ object ComposterOverlay { val first: NEUInternalName? = calculateFirst(map, testOffset, factors, missing, onClick, bigList) if (testOffset != 0) { - bigList.addAsSingletonList(Renderable.link("testOffset = $testOffset") { - ComposterOverlay.testOffset = 0 - update() - }) + bigList.addAsSingletonList( + Renderable.link("testOffset = $testOffset") { + ComposterOverlay.testOffset = 0 + update() + }, + ) } return first ?: error("First is empty!") @@ -475,7 +474,7 @@ object ComposterOverlay { lastAttemptTime = SimpleTimeMark.now() retrieveMaterials(internalName, itemName, itemsNeeded.toInt()) } - } + }, ) } @@ -524,7 +523,8 @@ object ComposterOverlay { if (LorenzUtils.noTradeMode) { ChatUtils.chat("You're out of $itemName §ein your sacks!") } else { - ChatUtils.clickableChat( // TODO Add this as a separate feature, and then don't send any msg if the feature is disabled + ChatUtils.clickableChat( + // TODO Add this as a separate feature, and then don't send any msg if the feature is disabled "You're out of $itemName §ein your sacks! Click here to buy more on the Bazaar!", onClick = { HypixelCommands.bazaar(itemName.removeColor()) }, "§eClick find on the bazaar!", @@ -559,7 +559,7 @@ object ComposterOverlay { } catch (e: Exception) { ErrorManager.logErrorWithData( e, "Failed to calculate composter overlay data", - "organicMatter" to organicMatter + "organicMatter" to organicMatter, ) } } @@ -597,11 +597,11 @@ object ComposterOverlay { if (inInventory) { config.overlayOrganicMatterPos.renderStringsAndItems( organicMatterDisplay, - posLabel = "Composter Overlay Organic Matter" + posLabel = "Composter Overlay Organic Matter", ) config.overlayFuelExtrasPos.renderStringsAndItems( fuelExtraDisplay, - posLabel = "Composter Overlay Fuel Extras" + posLabel = "Composter Overlay Fuel Extras", ) } } @@ -624,4 +624,30 @@ object ComposterOverlay { ConfigUtils.migrateIntToEnum(element, RetrieveFromEntry::class.java) } } + + @SubscribeEvent + fun onDebugDataCollect(event: DebugDataCollectEvent) { + event.title("Garden Composter") + + event.addIrrelevant { + add("currentOrganicMatterItem: $currentOrganicMatterItem") + add("currentFuelItem: $currentFuelItem") + + println(" ") + val composterUpgrades = ComposterAPI.composterUpgrades + if (composterUpgrades == null) { + println("composterUpgrades is null") + } else { + for ((a, b) in composterUpgrades) { + println("upgrade $a: $b") + } + } + + println(" ") + val tabListData = ComposterAPI.tabListData + for ((a, b) in tabListData) { + println("tabListData $a: $b") + } + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/GardenComposterInventoryFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/GardenComposterInventoryFeatures.kt index eb6dc41e04ba..a4510af8b4e6 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/GardenComposterInventoryFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/GardenComposterInventoryFeatures.kt @@ -57,14 +57,7 @@ object GardenComposterInventoryFeatures { ) continue } - val internalName = NEUInternalName.fromItemNameOrNull(itemName) ?: run { - ErrorManager.logErrorStateWithData( - "Error reading internal name for item: $itemName", - "could not find internal name for", - "itemName" to itemName - ) - continue - } + val internalName = NEUInternalName.fromItemName(itemName) val lowestBin = internalName.getPrice() val price = lowestBin * amount fullPrice += price diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt new file mode 100644 index 000000000000..7d009629b7c9 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt @@ -0,0 +1,95 @@ +package at.hannibal2.skyhanni.features.garden.contest + +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object FarmingPersonalBestGain { + private val config get() = GardenAPI.config + private val patternGroup = RepoPattern.group("garden.contest.personal.best") + + /** + * REGEX-TEST: §e[NPC] Jacob§f: §rYou collected §e1,400,694 §fitems! §d§lPERSONAL BEST§f! + */ + private val newPattern by patternGroup.pattern( + "collection.new", + "§e\\[NPC] Jacob§f: §rYou collected §e(?.*) §fitems! §d§lPERSONAL BEST§f!", + ) + + /** + * REGEX-TEST: §e[NPC] Jacob§f: §rYour previous Personal Best was §e1,176,372§f. + */ + private val oldPattern by patternGroup.pattern( + "collection.old", + "§e\\[NPC] Jacob§f: §rYour previous Personal Best was §e(?.*)§f.", + ) + + /** + * REGEX-TEST: §e[NPC] Jacob§f: §rYour §6Personal Bests §fperk is now granting you §6+46.69☘ Potato Fortune§f! + * + */ + private val newFFPattern by patternGroup.pattern( + "ff.new", + "§e\\[NPC] Jacob§f: §rYour §6Personal Bests §fperk is now granting you §6\\+(?.*)☘ (?.*) Fortune§f!", + ) + + var newCollected: Double? = null + var oldCollected: Double? = null + var newFF: Double? = null + var crop: String? = null + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + + newPattern.matchMatcher(event.message) { + newCollected = group("collected").formatDouble() + checkDelayed() + } + oldPattern.matchMatcher(event.message) { + oldCollected = group("collected").formatDouble() + checkDelayed() + } + newFFPattern.matchMatcher(event.message) { + val cropName = group("crop") + newFF = group("ff").formatDouble() + crop = cropName + val cropType = CropType.getByName(cropName) + GardenAPI.storage?.let { + it.personalBestFF[cropType] = newFF + } + checkDelayed() + } + } + + private fun checkDelayed() = DelayedRun.runNextTick { check() } + + private fun check() { + val newCollected = newCollected ?: return + val oldCollected = oldCollected ?: return + val newFF = newFF ?: return + val crop = crop ?: return + + this.newCollected = null + this.oldCollected = null + this.newFF = null + this.crop = null + + val collectionPerFF = newCollected / newFF + val oldFF = oldCollected / collectionPerFF + val ffDiff = newFF - oldFF + + ChatUtils.chat("This is §6${ffDiff.round(2)}☘ $crop Fortune §emore than previously!") + } + + fun isEnabled() = GardenAPI.inGarden() && config.contestPersonalBestIncreaseFF +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt index bea005d76dc6..217da97359ac 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt @@ -24,6 +24,7 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.moveEntryToTop import at.hannibal2.skyhanni.utils.CollectionUtils.sortedDesc import at.hannibal2.skyhanni.utils.ConfigUtils import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getNpcPrice import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.itemNameWithoutColor import at.hannibal2.skyhanni.utils.LorenzUtils @@ -31,7 +32,6 @@ import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.NEUItems.getItemStack -import at.hannibal2.skyhanni.utils.NEUItems.getNpcPrice import at.hannibal2.skyhanni.utils.NEUItems.getNpcPriceOrNull import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt index ffd778aa36bc..7133cf1fb301 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt @@ -362,7 +362,7 @@ object FarmingWeightDisplay { "§eClick to open your Farming Weight", "§eprofile on §celitebot.dev", ), - "shfarmingprofile ${LorenzUtils.getPlayerName()}", + "/shfarmingprofile ${LorenzUtils.getPlayerName()}", ) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt index 69e12796e75b..c37eb41b7cdf 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt @@ -120,13 +120,7 @@ object GardenCropMilestoneDisplay { val addedCounter = (counter - old).toInt() FarmingWeightDisplay.addCrop(crop, addedCounter) update() - // Farming Simulator: There is a 25% chance for Mathematical Hoes and the Cultivating Enchantment to count twice. - // 0.8 = 1 / 1.25 - crop.setCounter( - crop.getCounter() + if (GardenCropSpeed.finneganPerkActive()) { - (addedCounter.toDouble() * 0.8).toInt() - } else addedCounter - ) + crop.setCounter(crop.getCounter() + addedCounter) } cultivatingData[crop] = counter } catch (e: Throwable) { @@ -245,15 +239,6 @@ object GardenCropMilestoneDisplay { } } - if (overflowConfig.chat) { - if (currentTier > 46 && currentTier == previousNext && - nextRealTier == currentTier + 1 && lastWarnedLevel != currentTier - ) { - GardenCropMilestones.onOverflowLevelUp(crop, currentTier - 1, nextRealTier - 1) - lastWarnedLevel = currentTier - } - } - if (GardenAPI.mushroomCowPet && crop != CropType.MUSHROOM) { addMushroomCowData() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropSpeed.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropSpeed.kt index f4d9542293e4..141c93ff102c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropSpeed.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropSpeed.kt @@ -177,8 +177,6 @@ object GardenCropSpeed { secondsStopped = 0 } - fun finneganPerkActive() = Perk.FARMING_SIMULATOR.isActive - fun isEnabled() = GardenAPI.inGarden() fun CropType.getSpeed() = cropsPerSecond?.get(this) diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FarmingItems.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FarmingItems.kt index b46d6ebe4066..bdfe98abfff2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FarmingItems.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FarmingItems.kt @@ -142,10 +142,10 @@ enum class FarmingItems( fun getArmorDisplay(clickEnabled: Boolean = false): List = armor.map { it.getDisplay(clickEnabled) } - fun getEquipmentDisplay(clickEnabled: Boolean = false): List = - equip.map { it.getDisplay(clickEnabled) } + fun getEquipmentDisplay(clickEnabled: Boolean = false): List = equip.map { it.getDisplay(clickEnabled) } fun getPetsDisplay(clickEnabled: Boolean = false): List = pets.map { it.getDisplay(clickEnabled) } + fun resetClickState() { entries.filterNot { pets.contains(it) }.forEach { it.selectedState = false } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/AnitaExtraFarmingFortune.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/AnitaExtraFarmingFortune.kt index afebbda4dc8f..af4e4b31f45a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/AnitaExtraFarmingFortune.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/AnitaExtraFarmingFortune.kt @@ -9,8 +9,8 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.indexOfFirst import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName -import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt index 3372c2abd0f7..fef28450f719 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt @@ -23,6 +23,7 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getSpeed import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.blockReason import at.hannibal2.skyhanni.features.inventory.bazaar.BazaarApi +import at.hannibal2.skyhanni.features.inventory.bazaar.BazaarApi.isBazaarItem import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager @@ -201,7 +202,11 @@ object GardenVisitorFeatures { if (Minecraft.getMinecraft().currentScreen is GuiEditSign) { LorenzUtils.setTextIntoSign("$amount") } else { - BazaarApi.searchForBazaarItem(name, amount) + if (internalName.isBazaarItem()) { + BazaarApi.searchForBazaarItem(name, amount) + } else { + HypixelCommands.auctionSearch(name.removeColor()) + } } }, ) { GardenAPI.inGarden() && !NEUItems.neuHasFocus() }, @@ -724,6 +729,14 @@ object GardenVisitorFeatures { drops } + event.transform(54, "garden.visitors.rewardWarning.drops") { element -> + val drops = JsonArray() + for (entry in element.asJsonArray) { + drops.add(JsonPrimitive(entry.asString)) + } + drops.add(JsonPrimitive(VisitorReward.COPPER_DYE.name)) + drops + } event.transform(15, "garden.visitors.highlightStatus") { element -> ConfigUtils.migrateIntToEnum(element, HighlightMode::class.java) diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorReward.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorReward.kt index 76ef142372c8..e20102299d17 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorReward.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorReward.kt @@ -8,8 +8,7 @@ import at.hannibal2.skyhanni.utils.NEUItems.getItemStack enum class VisitorReward( private val rawInternalName: String, val displayName: String, - private val legacyId: - Int = -1 + private val legacyId: Int = -1, ) : HasLegacyId { FLOWERING_BOUQUET("FLOWERING_BOUQUET", "§9Flowering Bouquet", legacyId = 0), OVERGROWN_GRASS("OVERGROWN_GRASS", "§9Overgrown Grass", legacyId = 1), @@ -20,6 +19,7 @@ enum class VisitorReward( CULTIVATING("CULTIVATING;1", "§9Cultivating I", legacyId = 6), REPLENISH("REPLENISH;1", "§9Replenish I", legacyId = 7), DELICATE("DELICATE;5", "§9Delicate V"), + COPPER_DYE("DYE_COPPER", "§8Copper Dye"), ; private val internalName by lazy { rawInternalName.asInternalName() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/BeaconPower.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/BeaconPower.kt index 0eb596afceb0..76990b37ad98 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/BeaconPower.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/BeaconPower.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryUpdatedEvent +import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.events.SecondPassedEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ItemUtils.getLore @@ -28,19 +29,19 @@ object BeaconPower { // TODO add regex tests private val deactivatedPattern by group.pattern( "deactivated", - "§7Beacon Deactivated §8- §cNo Power Remaining" + "§7Beacon Deactivated §8- §cNo Power Remaining", ) private val timeRemainingPattern by group.pattern( "time", - "§7Power Remaining: §e(?