diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f494caa5b7..601dd6a723 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,16 +1,18 @@ name: Release on: [workflow_dispatch] # Manual trigger + jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: "temurin" java-version: 17 + - uses: gradle/actions/setup-gradle@v3 - run: ./gradlew checkLicenses generateQmj --parallel --stacktrace env: MAVEN_URL: ${{ secrets.MAVEN_URL }} diff --git a/.github/workflows/publish_snapshot.yml b/.github/workflows/publish_snapshot.yml index b0f7a35f0f..75b0dcf3b0 100644 --- a/.github/workflows/publish_snapshot.yml +++ b/.github/workflows/publish_snapshot.yml @@ -6,32 +6,29 @@ jobs: strategy: matrix: java: [17] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: "temurin" java-version: ${{ matrix.java }} - cache: 'gradle' - - name: Check Licenses and Generate QMJs - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 with: - arguments: checkLicenses generateQmj --parallel --stacktrace cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') && !startsWith(github.ref, 'refs/tags/v') }} + - name: Check Licenses and Generate QMJs + run: ./gradlew checkLicenses generateQmj --stacktrace - name: Publish to Snapshot maven - uses: gradle/gradle-build-action@v2 - with: - arguments: build publish --stacktrace --parallel - cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') && !startsWith(github.ref, 'refs/tags/v') }} + run: ./gradlew build publish --stacktrace env: SNAPSHOTS_URL: ${{ secrets.SNAPSHOTS_URL }} SNAPSHOTS_USERNAME: ${{ secrets.SNAPSHOTS_USERNAME }} SNAPSHOTS_PASSWORD: ${{ secrets.SNAPSHOTS_PASSWORD }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - name: Artifacts + name: Artifacts (Java ${{ matrix.java }}) path: ./*/build/libs/ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a32e796fef..b02c945721 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,41 +5,37 @@ jobs: build: strategy: matrix: - java: [17, 20] - runs-on: ubuntu-22.04 + java: [17, 21] + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: "temurin" java-version: ${{ matrix.java }} - - name: Check Licenses and Generate QMJs - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 with: - arguments: checkLicenses generateQmj --parallel --stacktrace cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') && !startsWith(github.ref, 'refs/tags/v') }} + - name: Check Licenses and Generate QMJs + run: ./gradlew checkLicenses generateQmj --stacktrace - name: Build - uses: gradle/gradle-build-action@v2 - with: - arguments: build publishToMavenLocal --stacktrace --parallel -Porg.gradle.parallel.threads=4 - cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') && !startsWith(github.ref, 'refs/tags/v') }} + run: ./gradlew build publishToMavenLocal --stacktrace -Porg.gradle.parallel.threads=4 - run: mkdir run && echo "eula=true" >> run/eula.txt - name: Run auto-test server - uses: gradle/gradle-build-action@v2 - with: - arguments: :runAutoAllTestServer --stacktrace - - uses: actions/upload-artifact@v3 + run: ./gradlew :runAutoAllTestServer --stacktrace + - uses: actions/upload-artifact@v4 with: - name: Production Mods + name: Production Mods (Java ${{ matrix.java }}) path: | ./**/build/libs/ !./build-logic/** !./**/build/libs/*-javadoc.jar !./**/build/libs/*-sources.jar !./**/build/libs/*-testmod.jar - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - name: Test Mods + name: Test Mods (Java ${{ matrix.java }}) path: ./**/build/libs/*-testmod.jar diff --git a/build-logic/gradle/libs.versions.toml b/build-logic/gradle/libs.versions.toml index f9f7a78969..a20c0950e7 100644 --- a/build-logic/gradle/libs.versions.toml +++ b/build-logic/gradle/libs.versions.toml @@ -1,9 +1,9 @@ [versions] -asm = "9.5" -indra_git = "3.1.2" -quilt_gradle_licenser = "2.+" -quilt_parsers = "0.2.1" -quilt_loom = "1.3.+" +asm = "9.7" +indra_git = "3.1.3" +quilt_gradle_licenser = "2.0.1" +quilt_parsers = "0.3.0" +quilt_loom = "1.5.8" [libraries] asm = { module = "org.ow2.asm:asm", version.ref = "asm" } diff --git a/build-logic/src/main/groovy/qsl.library.gradle b/build-logic/src/main/groovy/qsl.library.gradle index 8f28b0a4ff..b882a58011 100644 --- a/build-logic/src/main/groovy/qsl.library.gradle +++ b/build-logic/src/main/groovy/qsl.library.gradle @@ -107,10 +107,6 @@ jar { enabled = false } -prepareRemapJar { - enabled = false -} - remapJar { enabled = false } diff --git a/build-logic/src/main/groovy/qsl.module.gradle b/build-logic/src/main/groovy/qsl.module.gradle index 2e77e2f541..2499e64ae3 100644 --- a/build-logic/src/main/groovy/qsl.module.gradle +++ b/build-logic/src/main/groovy/qsl.module.gradle @@ -146,7 +146,7 @@ loom { // Enable the game test runner. property("quilt.game_test", "true") - property("quilt.game_test.report_file", "${project.buildDir}/game_test/report.xml") + property("quilt.game_test.report_file", layout.buildDirectory.file("game_test/report.xml").get().asFile.path) runDir("build/game_test") } } @@ -173,8 +173,7 @@ javadoc { "https://guava.dev/releases/31.0.1-jre/api/docs/", "https://asm.ow2.io/javadoc/", "https://docs.oracle.com/en/java/javase/17/docs/api/", - "https://jenkins.liteloader.com/job/Mixin/javadoc/", - "https://logging.apache.org/log4j/2.x/log4j-api/apidocs/" + "https://jenkins.liteloader.com/job/Mixin/javadoc/" ) // Disable the overzealous doclint tool in Java 8 diff --git a/build-logic/src/main/java/qsl/internal/Versions.java b/build-logic/src/main/java/qsl/internal/Versions.java index 50b95d2032..13861a2a8b 100644 --- a/build-logic/src/main/java/qsl/internal/Versions.java +++ b/build-logic/src/main/java/qsl/internal/Versions.java @@ -43,7 +43,7 @@ public final class Versions { /** * The version of Quilt Loader to use. */ - public static final String LOADER_VERSION = "0.20.2"; + public static final String LOADER_VERSION = "0.25.0"; /** * The target Java version. diff --git a/build-logic/src/main/java/qsl/internal/extension/QslExtension.java b/build-logic/src/main/java/qsl/internal/extension/QslExtension.java index 4370348eec..3e55657af1 100644 --- a/build-logic/src/main/java/qsl/internal/extension/QslExtension.java +++ b/build-logic/src/main/java/qsl/internal/extension/QslExtension.java @@ -1,12 +1,16 @@ package qsl.internal.extension; import org.gradle.api.Project; +import org.gradle.api.Task; import qsl.internal.Versions; public class QslExtension { - private static final String RESOLVE_VINEFLOWER_TASK = "resolveVineflower"; - private static final String GEN_SOURCES_WITH_VINEFLOWER_TASK = "genSourcesWithVineflower"; - private static final String[] TASKS_TO_DISABLE = {RESOLVE_VINEFLOWER_TASK, "genSourcesWithFernFlower"}; + private static final String[] TASKS_TO_DISABLE = { + "genSourcesWithFernFlower", + "genSourcesWithVineflower", + "genSourcesWithCfr", + "genSources" + }; protected final Project project; public QslExtension(Project project) { @@ -14,10 +18,11 @@ public QslExtension(Project project) { this.project.afterEvaluate(p -> { for (var task : TASKS_TO_DISABLE) { - p.getTasks().findByName(task).setEnabled(false); + Task disabled = p.getTasks().findByName(task); + if (disabled != null) { + disabled.setEnabled(false); + } } - - p.getTasks().findByName(GEN_SOURCES_WITH_VINEFLOWER_TASK).dependsOn(p.getRootProject().getTasks().findByName(RESOLVE_VINEFLOWER_TASK)); }); } diff --git a/build.gradle b/build.gradle index 12c1c84502..e730159948 100644 --- a/build.gradle +++ b/build.gradle @@ -34,10 +34,6 @@ sourceSets { // The root project simply just publishes all artifacts. // For that reason, do not generate a remapped jar. -prepareRemapJar { - enabled = false -} - remapJar { enabled = false } @@ -58,8 +54,9 @@ task fatJavadoc(type: Javadoc) { "https://guava.dev/releases/31.1-jre/api/docs/", "https://asm.ow2.io/javadoc/", "https://docs.oracle.com/en/java/javase/17/docs/api/", - "https://jenkins.liteloader.com/job/Mixin/javadoc/", - "https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-mappings/${Versions.MINECRAFT_VERSION.version()}+build.${Versions.MAPPINGS_BUILD}/quilt-mappings-${Versions.MINECRAFT_VERSION.version()}+build.${Versions.MAPPINGS_BUILD}-javadoc.jar/" + "https://jenkins.liteloader.com/job/Mixin/javadoc/" + // TODO: Fix maven javadocs + // "https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-mappings/${Versions.MINECRAFT_VERSION.version()}+build.${Versions.MAPPINGS_BUILD}/quilt-mappings-${Versions.MINECRAFT_VERSION.version()}+build.${Versions.MAPPINGS_BUILD}-javadoc.jar/" ) // Disable the overzealous doclint tool in Java 8 @@ -77,21 +74,24 @@ task fatJavadoc(type: Javadoc) { } afterEvaluate { - subprojects.stream().filter { it.path.count(':') == 2 }.each { subproject -> - subproject.tasks.withType(Javadoc).each { javadocTask -> - source += javadocTask.source - classpath += javadocTask.classpath - // TODO: find a proper fix for this - // What does this do? Well, turns out transitive access wideners aren't applied properly, - // which fails the fat javadoc task! Since Quilt Block Entity adds a transitive access widener to a private interface. - // So what do we do? We simply removed the Vanilla JAR and hope that the correct transformed JAR shows up first. - // The proper fix is to get the root project to generate a new MC JAR that contains all the transitive transformations of the modules - // applied and pass that to the fat javadoc task instead. - .filter { !it.name.startsWith("minecraft") || it.name.contains("@block@block_entity") } + subprojects.stream() + .filter { it.path.count(':') == 2 } + .filter { it.name != "block_entity"} + .each { subproject -> + subproject.tasks.withType(Javadoc).each { javadocTask -> + source += javadocTask.source + classpath += javadocTask.classpath + // TODO: find a proper fix for this + // What does this do? Well, turns out transitive access wideners aren't applied properly, + // which fails the fat javadoc task! Since Quilt Block Entity adds a transitive access widener to a private interface. + // So what do we do? We simply removed the Vanilla JAR and hope that the correct transformed JAR shows up first. + // The proper fix is to get the root project to generate a new MC JAR that contains all the transitive transformations of the modules + // applied and pass that to the fat javadoc task instead. +// .filter { !it.name.startsWith("minecraft") } } } } - destinationDir = file("${buildDir}/docs/fat-javadoc") + destinationDir = layout.buildDirectory.file("docs/fat-javadoc").get().asFile } @@ -170,7 +170,7 @@ loom { configName = "Game test server" property("quilt.game_test", "true") - property("quilt.game_test.report_file", "${project.buildDir}/game_test/report.xml") + property("quilt.game_test.report_file", project.layout.buildDirectory.file("game_test/report.xml").get().asFile.path) runDir("build/game_test") } } diff --git a/gradle.properties b/gradle.properties index a3eec90d7b..e0b556de0a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,3 @@ # though needing more might be a sign that something is wrong in the build tool. org.gradle.jvmargs=-Xmx3072m org.gradle.parallel=true -fabric.loom.multiProjectOptimisation=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49..e6441136f3 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34e8a..a4413138c9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ 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.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1a53..b740cf1339 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f13..25da30dbde 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/library/block/block_extensions/build.gradle b/library/block/block_extensions/build.gradle index 8dbb667e1c..5fd64442f6 100644 --- a/library/block/block_extensions/build.gradle +++ b/library/block/block_extensions/build.gradle @@ -63,7 +63,7 @@ def checkBlockSettings = tasks.register('checkBlockSettings') { dependsOn jar doLast { - def moduleJar = project.buildDir.toPath().resolve("devlibs/${qslModule.moduleName.get()}-${version}-dev.jar") + def moduleJar = project.layout.buildDirectory.file("devlibs/${qslModule.moduleName.get()}-${version}-dev.jar").get().asFile.toPath() try (def moduleFs = FileSystems.newFileSystem(URI.create("jar:${moduleJar.toUri()}"), [create: false])) { def mcFs = ClassAnalysisUtils.loadMinecraftJar(project) diff --git a/library/item/item_setting/build.gradle b/library/item/item_setting/build.gradle index 4fcfd0ab1e..c846b88b7d 100644 --- a/library/item/item_setting/build.gradle +++ b/library/item/item_setting/build.gradle @@ -32,7 +32,7 @@ tasks.register('checkItemSettings') { dependsOn jar doLast { - def moduleJar = project.buildDir.toPath().resolve("devlibs/${qslModule.moduleName.get()}-${version}-dev.jar") + def moduleJar = project.layout.buildDirectory.file("devlibs/${qslModule.moduleName.get()}-${version}-dev.jar").get().asFile.toPath() try (def moduleFs = FileSystems.newFileSystem(URI.create("jar:${moduleJar.toUri()}"), [create: false])) { try (def mcFs = ClassAnalysisUtils.loadMinecraftJar(project)) { diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltCustomItemSettings.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltCustomItemSettings.java index ad03948db7..c2184dfe2e 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltCustomItemSettings.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltCustomItemSettings.java @@ -16,6 +16,8 @@ package org.quiltmc.qsl.item.setting.api; +import java.util.Map; + import org.quiltmc.qsl.item.setting.impl.CustomItemSettingImpl; /** @@ -36,17 +38,20 @@ private QuiltCustomItemSettings() {} /** * The {@link CustomItemSetting} in charge of handing {@link RecipeRemainderProvider}s. This setting should be used when implementing custom crafting systems to properly handle remainders. + * *

* The setting is currently used in the following places: *

*/ - public static final CustomItemSetting RECIPE_REMAINDER_PROVIDER = CustomItemSettingImpl.RECIPE_REMAINDER_PROVIDER; + public static final CustomItemSetting> RECIPE_REMAINDER_PROVIDER = CustomItemSettingImpl.RECIPE_REMAINDER_PROVIDER; } diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltItemSettings.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltItemSettings.java index f11b9d2783..907ec338cf 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltItemSettings.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/QuiltItemSettings.java @@ -17,6 +17,8 @@ package org.quiltmc.qsl.item.setting.api; +import java.util.Map; + import org.jetbrains.annotations.Contract; import net.minecraft.entity.EquipmentSlot; @@ -31,6 +33,7 @@ /** * Quilt's version of {@link Item.Settings}. * Adds additional methods and hooks not found in the original class. + * *

* To use it, simply replace {@code new Item.Settings()} with {@code new QuiltItemSettings()}. */ @@ -69,33 +72,83 @@ public QuiltItemSettings customDamage(CustomDamageHandler handler) { /** * Sets the stack-aware recipe remainder provider of the item. + * Defaults to setting both crafting, furnace fuel remainder, and brewing stand addition, like vanilla. + * + * @param provider the {@link RecipeRemainderProvider} for the item */ public QuiltItemSettings recipeRemainder(RecipeRemainderProvider provider) { - return this.customSetting(QuiltCustomItemSettings.RECIPE_REMAINDER_PROVIDER, provider); + return this.recipeRemainder(provider, RecipeRemainderLocation.DEFAULT_LOCATIONS); } /** * Sets the stack-aware recipe remainder to damage the item by 1 every time it is used in crafting. + * Defaults to setting both crafting, furnace fuel remainder, and brewing stand addition, like vanilla. */ public QuiltItemSettings recipeDamageRemainder() { - return this.recipeDamageRemainder(1); + return this.recipeDamageRemainder(1, RecipeRemainderLocation.DEFAULT_LOCATIONS); } /** * Sets the stack-aware recipe remainder to return the item itself. + * Defaults to setting both crafting, furnace fuel remainder, and brewing stand addition, like vanilla. */ public QuiltItemSettings recipeSelfRemainder() { - return this.recipeDamageRemainder(0); + return this.recipeDamageRemainder(0, RecipeRemainderLocation.DEFAULT_LOCATIONS); } /** * Sets the stack-aware recipe remainder to damage the item by a certain amount every time it is used in crafting. + * Defaults to setting both crafting, furnace fuel remainder, and brewing stand addition, like vanilla. * * @param by the amount */ public QuiltItemSettings recipeDamageRemainder(int by) { + return this.recipeDamageRemainder(by, RecipeRemainderLocation.DEFAULT_LOCATIONS); + } + + /** + * Sets the stack-aware recipe remainder provider of the item. + * + * @param provider the {@link RecipeRemainderProvider} for the item + * @param locations the {@link RecipeRemainderLocation locations} for the remainder + */ + public QuiltItemSettings recipeRemainder(RecipeRemainderProvider provider, RecipeRemainderLocation... locations) { + for (var location : locations) { + ((CustomItemSettingImpl>) QuiltCustomItemSettings.RECIPE_REMAINDER_PROVIDER) + .get(this) + .put(location, provider); + } + + return this; + } + + /** + * Sets the stack-aware recipe remainder to damage the item by 1 every time it is used in crafting. + * + * @param locations the {@link RecipeRemainderLocation locations} for the remainder + */ + public QuiltItemSettings recipeDamageRemainder(RecipeRemainderLocation... locations) { + return this.recipeDamageRemainder(1, locations); + } + + /** + * Sets the stack-aware recipe remainder to return the item itself. + * + * @param locations the {@link RecipeRemainderLocation locations} for the remainder + */ + public QuiltItemSettings recipeSelfRemainder(RecipeRemainderLocation... locations) { + return this.recipeDamageRemainder(0, locations); + } + + /** + * Sets the stack-aware recipe remainder to damage the item by a certain amount every time it is used in crafting. + * + * @param by the amount + * @param locations the {@link RecipeRemainderLocation location} for the remainder + */ + public QuiltItemSettings recipeDamageRemainder(int by, RecipeRemainderLocation... locations) { if (by == 0) { - return this.recipeRemainder((original, recipe) -> original.copy()); + return this.recipeRemainder((original, recipe) -> original.copy(), locations); } return this.recipeRemainder((original, recipe) -> { @@ -113,7 +166,7 @@ public QuiltItemSettings recipeDamageRemainder(int by) { } return copy; - }); + }, locations); } /** diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLocation.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLocation.java new file mode 100644 index 0000000000..92e760da04 --- /dev/null +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLocation.java @@ -0,0 +1,123 @@ +/* + * Copyright 2024 The Quilt Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.item.setting.api; + +import java.util.Objects; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; + +import net.minecraft.util.Identifier; + +import org.quiltmc.qsl.item.setting.impl.RecipeRemainderLogicHandlerImpl; + +/** + * Contains the different recipe remainder locations that QSL supports. + * Calling {@link #getOrCreate(Identifier)} allows mods to create their own remainder locations or get remainder locations without needing to compile against the other mod. + * The hierarchy of recipe remainder locations is: {@link #DEFAULT_LOCATIONS} < any location < {@link #ALL_LOCATIONS}. + * + *

This class should not be extended. + */ +@ApiStatus.NonExtendable +public interface RecipeRemainderLocation { + /** + * Remainder location for Vanilla crafting. Used in Crafting Tables and the inventory crafting screen. + */ + RecipeRemainderLocation CRAFTING = addToDefaultLocations(getOrCreate(new Identifier("minecraft:crafting"))); + + /** + * Remainder location for the furnace fuel slot in the different furnace types. + */ + RecipeRemainderLocation FURNACE_FUEL = addToDefaultLocations(getOrCreate(new Identifier("minecraft:furnace_fuel"))); + + /** + * Remainder location for the furnace ingredient slot in the different furnace types. + */ + RecipeRemainderLocation FURNACE_INGREDIENT = getOrCreate(new Identifier("minecraft:furnace_ingredient")); + + /** + * Remainder location for the dye slot in looms. + */ + RecipeRemainderLocation LOOM_DYE = getOrCreate(new Identifier("minecraft:loom_dye")); + + /** + * Remainder location for the potion addition in brewing stands. + */ + RecipeRemainderLocation POTION_ADDITION = addToDefaultLocations(getOrCreate(new Identifier("minecraft:potion_addition"))); + + /** + * Remainder location for the input to the stonecutter. + */ + RecipeRemainderLocation STONECUTTER_INPUT = getOrCreate(new Identifier("minecraft:stonecutter_input")); + + /** + * Remainder location for the smithing template slot. + */ + RecipeRemainderLocation SMITHING_TEMPLATE = getOrCreate(new Identifier("minecraft:smithing_template")); + + /** + * Remainder location for the smithing base slot. + */ + RecipeRemainderLocation SMITHING_BASE = getOrCreate(new Identifier("minecraft:smithing_base")); + + /** + * Remainder location for the smithing ingredient slot. + */ + RecipeRemainderLocation SMITHING_INGREDIENT = getOrCreate(new Identifier("minecraft:smithing_ingredient")); + + /** + * Remainder location for the default locations. This starts with {@link #CRAFTING}, {@link #FURNACE_FUEL}, and {@link #POTION_ADDITION}. + */ + RecipeRemainderLocation DEFAULT_LOCATIONS = getOrCreate(new Identifier("quilt:default")); + + /** + * Remainder location for all locations. Using this will override any other locations that is specified. + */ + RecipeRemainderLocation ALL_LOCATIONS = getOrCreate(new Identifier("quilt:all")); + + /** + * Gets a new remainder location if it already exists, creating it otherwise. + * @param id the id for the location + * @return the remainder location + */ + @Contract("null -> fail; _ -> new") + static RecipeRemainderLocation getOrCreate(Identifier id) { + record RecipeRemainderLocationImpl(Identifier id) implements RecipeRemainderLocation { + } + + Objects.requireNonNull(id, "`id` must not be null."); + + return RecipeRemainderLogicHandlerImpl.LOCATIONS.computeIfAbsent(id, RecipeRemainderLocationImpl::new); + } + + /** + * @param location the location to add to the default locations + */ + @Contract("null -> fail") + static RecipeRemainderLocation addToDefaultLocations(RecipeRemainderLocation location) { + Objects.requireNonNull(location, "`location` must not be null"); + + RecipeRemainderLogicHandlerImpl.DEFAULT_LOCATIONS.add(location); + return location; + } + + /** + * + * @return the id for the location. + */ + Identifier id(); +} diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLogicHandler.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLogicHandler.java index 7782e800a3..afecf3ae36 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLogicHandler.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderLogicHandler.java @@ -16,6 +16,7 @@ package org.quiltmc.qsl.item.setting.api; +import java.util.Map; import java.util.function.Consumer; import org.jetbrains.annotations.ApiStatus; @@ -44,14 +45,32 @@ public interface RecipeRemainderLogicHandler { * Gets the stack-aware remainder of the provided {@link ItemStack} for the provided {@link Recipe}. * * @param original the stack to decrement - * @param recipe the recipe being used + * @param recipe the recipe being used + * @param location the remainder location * @return the recipe remainder */ - static ItemStack getRemainder(ItemStack original, @Nullable Recipe recipe) { - ItemStack remainder = CustomItemSettingImpl.RECIPE_REMAINDER_PROVIDER.get(original.getItem()).getRecipeRemainder( - original, - recipe - ); + static ItemStack getRemainder(ItemStack original, @Nullable Recipe recipe, RecipeRemainderLocation location) { + Map providers = CustomItemSettingImpl.RECIPE_REMAINDER_PROVIDER + .get(original.getItem()); + + RecipeRemainderProvider provider = (_original, _recipe) -> _original.getItem().hasRecipeRemainder() ? _original.getItem().getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY; + + if (RecipeRemainderLogicHandlerImpl.DEFAULT_LOCATIONS.contains(location) && providers.containsKey(RecipeRemainderLocation.DEFAULT_LOCATIONS)) { + provider = providers.get(RecipeRemainderLocation.DEFAULT_LOCATIONS); + } + + if (providers.containsKey(location)) { + provider = providers.get(location); + } + + if (providers.containsKey(RecipeRemainderLocation.ALL_LOCATIONS)) { + provider = providers.get(RecipeRemainderLocation.ALL_LOCATIONS); + } + + ItemStack remainder = provider.getRecipeRemainder( + original, + recipe + ); return remainder.isEmpty() ? ItemStack.EMPTY : remainder; } @@ -60,62 +79,65 @@ static ItemStack getRemainder(ItemStack original, @Nullable Recipe recipe) { * Handles the recipe remainder logic for crafts without a {@link PlayerEntity player} present. * Excess items that cannot be returned to a slot are dropped in the world. * - * @param input the original item stack - * @param amount the amount by which to decrease the stack - * @param recipe the recipe being used + * @param input the original item stack + * @param amount the amount by which to decrease the stack + * @param recipe the recipe being used + * @param location the remainder location * @param inventory the inventory - * @param index the index of the original stack in the inventory - * @param world the world - * @param location the location to drop excess remainders + * @param index the index of the original stack in the inventory + * @param world the world + * @param pos the location to drop excess remainders */ - @Contract(mutates = "param1, param4, param6") - static void handleRemainderForNonPlayerCraft(ItemStack input, int amount, @Nullable Recipe recipe, DefaultedList inventory, int index, World world, BlockPos location) { - handleRemainderForNonPlayerCraft(input, amount, recipe, inventory, index, remainder -> ItemScatterer.spawn(world, location.getX(), location.getY(), location.getZ(), remainder)); + @Contract(mutates = "param1, param5, param7") + static void handleRemainderForNonPlayerCraft(ItemStack input, int amount, @Nullable Recipe recipe, RecipeRemainderLocation location, DefaultedList inventory, int index, World world, BlockPos pos) { + handleRemainderForNonPlayerCraft(input, amount, recipe, location, inventory, index, remainder -> ItemScatterer.spawn(world, pos.getX(), pos.getY(), pos.getZ(), remainder)); } /** * Handles the recipe remainder logic for crafts without a {@link PlayerEntity player} present. * Excess items that cannot be returned to a slot are handled by the provided {@link Consumer consumer}. * - * @param input the original item stack - * @param amount the amount by which to decrease the stack - * @param recipe the recipe being used + * @param input the original item stack + * @param amount the amount by which to decrease the stack + * @param recipe the recipe being used + * @param location the remainder location * @param inventory the inventory - * @param index the index of the original stack in the inventory - * @param failure callback that is run if excess items could not be returned to a slot + * @param index the index of the original stack in the inventory + * @param failure callback that is run if excess items could not be returned to a slot */ - @Contract(mutates = "param1, param4, param6") - static void handleRemainderForNonPlayerCraft(ItemStack input, int amount, @Nullable Recipe recipe, DefaultedList inventory, int index, Consumer failure) { - RecipeRemainderLogicHandlerImpl.handleRemainderForNonPlayerCraft(input, amount, recipe, inventory, index, failure); + @Contract(mutates = "param1, param5, param7") + static void handleRemainderForNonPlayerCraft(ItemStack input, int amount, @Nullable Recipe recipe, RecipeRemainderLocation location, DefaultedList inventory, int index, Consumer failure) { + RecipeRemainderLogicHandlerImpl.handleRemainderForNonPlayerCraft(input, amount, recipe, location, inventory, index, failure); } /** - * @see RecipeRemainderLogicHandler#handleRemainderForNonPlayerCraft(ItemStack, int, Recipe, DefaultedList, int, World, BlockPos) + * @see RecipeRemainderLogicHandler#handleRemainderForNonPlayerCraft(ItemStack, int, Recipe, RecipeRemainderLocation, DefaultedList, int, World, BlockPos) */ - @Contract(mutates = "param1, param3, param5") - static void handleRemainderForNonPlayerCraft(ItemStack input, @Nullable Recipe recipe, DefaultedList inventory, int index, World world, BlockPos location) { - handleRemainderForNonPlayerCraft(input, 1, recipe, inventory, index, world, location); + @Contract(mutates = "param1, param4, param6") + static void handleRemainderForNonPlayerCraft(ItemStack input, @Nullable Recipe recipe, RecipeRemainderLocation location, DefaultedList inventory, int index, World world, BlockPos pos) { + handleRemainderForNonPlayerCraft(input, 1, recipe, location, inventory, index, world, pos); } /** * Handles the recipe remainder logic for crafts within a {@link net.minecraft.screen.ScreenHandler screen handler}. * Excess items that cannot be returned to a slot are {@linkplain net.minecraft.entity.player.PlayerInventory#offerOrDrop(ItemStack) offered to the player or dropped}. * - * @param slot the slot of the original stack - * @param amount the amount by which to decrease the stack - * @param recipe the recipe being used - * @param player the player performing the craft + * @param slot the slot of the original stack + * @param amount the amount by which to decrease the stack + * @param recipe the recipe being used + * @param location the remainder location + * @param player the player performing the craft */ - @Contract(mutates = "param1, param4") - static void handleRemainderForScreenHandler(Slot slot, int amount, @Nullable Recipe recipe, PlayerEntity player) { - RecipeRemainderLogicHandlerImpl.handleRemainderForScreenHandler(slot, amount, recipe, player); + @Contract(mutates = "param1, param5") + static void handleRemainderForScreenHandler(Slot slot, int amount, @Nullable Recipe recipe, RecipeRemainderLocation location, PlayerEntity player) { + RecipeRemainderLogicHandlerImpl.handleRemainderForScreenHandler(slot, amount, recipe, location, player); } /** - * @see RecipeRemainderLogicHandler#handleRemainderForScreenHandler(Slot, int, Recipe, PlayerEntity) + * @see RecipeRemainderLogicHandler#handleRemainderForScreenHandler(Slot, int, Recipe, RecipeRemainderLocation, PlayerEntity) */ - @Contract(mutates = "param1, param3") - static void handleRemainderForScreenHandler(Slot slot, @Nullable Recipe recipe, PlayerEntity player) { - handleRemainderForScreenHandler(slot, 1, recipe, player); + @Contract(mutates = "param1, param4") + static void handleRemainderForScreenHandler(Slot slot, @Nullable Recipe recipe, RecipeRemainderLocation location, PlayerEntity player) { + handleRemainderForScreenHandler(slot, 1, recipe, location, player); } } diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderProvider.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderProvider.java index 5dfe6630f5..00333eaa23 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderProvider.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/api/RecipeRemainderProvider.java @@ -30,6 +30,7 @@ * The recipe remainder is an {@link ItemStack} instead of an {@link Item}. * This can be used to allow your item to get damaged instead of * getting removed when used in crafting. + * *

* Recipe remainder providers can be set with {@link QuiltItemSettings#recipeRemainder(RecipeRemainderProvider)}. */ @@ -45,10 +46,10 @@ public interface RecipeRemainderProvider { @Contract(value = "_, _ -> new") ItemStack getRecipeRemainder(ItemStack original, @Nullable Recipe recipe); - static DefaultedList getRemainingStacks(Inventory inventory, Recipe recipe, DefaultedList defaultedList) { + static DefaultedList getRemainingStacks(Inventory inventory, Recipe recipe, RecipeRemainderLocation location, DefaultedList defaultedList) { for (int i = 0; i < defaultedList.size(); ++i) { ItemStack stack = inventory.getStack(i); - ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(stack, recipe); + ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(stack, recipe, location); if (!remainder.isEmpty()) { defaultedList.set(i, remainder); diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/CustomItemSettingImpl.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/CustomItemSettingImpl.java index d44b80e988..a23eb30c88 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/CustomItemSettingImpl.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/CustomItemSettingImpl.java @@ -28,11 +28,11 @@ import org.jetbrains.annotations.ApiStatus; import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; import org.quiltmc.qsl.item.setting.api.CustomDamageHandler; import org.quiltmc.qsl.item.setting.api.CustomItemSetting; import org.quiltmc.qsl.item.setting.api.EquipmentSlotProvider; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderProvider; @ApiStatus.Internal @@ -41,7 +41,7 @@ public class CustomItemSettingImpl implements CustomItemSetting { public static final CustomItemSetting CUSTOM_DAMAGE_HANDLER = CustomItemSetting.create(() -> null); @SuppressWarnings("ConstantConditions") - public static final CustomItemSetting RECIPE_REMAINDER_PROVIDER = new CustomItemSettingImpl<>(() -> (original, recipe) -> original.getItem().hasRecipeRemainder() ? original.getItem().getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY) { + public static final CustomItemSetting> RECIPE_REMAINDER_PROVIDER = new CustomItemSettingImpl<>(HashMap::new) { @Override public void apply(Item.Settings settings, Item item) { if (item.hasRecipeRemainder()) { @@ -78,6 +78,13 @@ public void set(Item.Settings settings, T value) { CUSTOM_SETTINGS.computeIfAbsent(settings, s -> new HashSet<>()).add(this); } + public T get(Item.Settings settings) { + Objects.requireNonNull(settings); + + CUSTOM_SETTINGS.computeIfAbsent(settings, s -> new HashSet<>()).add(this); + return this.customSettings.computeIfAbsent(settings, _setting -> this.defaultValue.get()); + } + public void apply(Item.Settings settings, Item item) { Objects.requireNonNull(settings); diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/RecipeRemainderLogicHandlerImpl.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/RecipeRemainderLogicHandlerImpl.java index 6783f7bb8c..77499c6b00 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/RecipeRemainderLogicHandlerImpl.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/impl/RecipeRemainderLogicHandlerImpl.java @@ -16,6 +16,10 @@ package org.quiltmc.qsl.item.setting.impl; +import java.util.HashMap; +import java.util.Map; +import java.util.HashSet; +import java.util.Set; import java.util.function.Consumer; import org.jetbrains.annotations.ApiStatus; @@ -27,15 +31,18 @@ import net.minecraft.recipe.Recipe; import net.minecraft.screen.slot.Slot; import net.minecraft.util.collection.DefaultedList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.util.Identifier; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderLogicHandler; @ApiStatus.Internal public final class RecipeRemainderLogicHandlerImpl implements RecipeRemainderLogicHandler { + public static final Map LOCATIONS = new HashMap<>(); + public static final Set DEFAULT_LOCATIONS = new HashSet<>(); + /** - * {@return {@code true} if returning the item to the inventory was successful, or {@code false} if additional handling for the remainder is needed} + * @return {@code true} if returning the item to the inventory was successful, or {@code false} if additional handling for the remainder is needed */ @Contract(mutates = "param1, param2") private static boolean tryReturnItemToInventory(ItemStack remainder, DefaultedList inventory, int index) { @@ -49,7 +56,7 @@ private static boolean tryReturnItemToInventory(ItemStack remainder, DefaultedLi } /** - * {@return {@code true} if returning the item to the slot was successful, or {@code false} if additional handling for the remainder is needed} + * @return {@code true} if returning the item to the slot was successful, or {@code false} if additional handling for the remainder is needed */ @Contract(mutates = "param1, param2") private static boolean tryReturnItemToSlot(ItemStack remainder, Slot slot) { @@ -63,7 +70,7 @@ private static boolean tryReturnItemToSlot(ItemStack remainder, Slot slot) { } /** - * {@return {@code true} if the remainder stack was fully merged into the base stack, or {@code false} otherwise} + * @return {@code true} if the remainder stack was fully merged into the base stack, or {@code false} otherwise */ @Contract(mutates = "param1, param2") private static boolean tryMergeStacks(ItemStack base, ItemStack remainder) { @@ -80,30 +87,30 @@ private static boolean tryMergeStacks(ItemStack base, ItemStack remainder) { } @Contract(mutates = "param1") - private static ItemStack decrementWithRemainder(ItemStack original, int amount, @Nullable Recipe recipe) { + private static ItemStack decrementWithRemainder(ItemStack original, int amount, @Nullable Recipe recipe, RecipeRemainderLocation location) { if (original.isEmpty()) { return ItemStack.EMPTY; } - ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(original, recipe); + ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(original, recipe, location); original.decrement(amount); return remainder; } - @Contract(mutates = "param1, param4, param6") - public static void handleRemainderForNonPlayerCraft(ItemStack input, int amount, @Nullable Recipe recipe, DefaultedList inventory, int index, Consumer failure) { - ItemStack remainder = decrementWithRemainder(input, amount, recipe); + @Contract(mutates = "param1, param5, param7") + public static void handleRemainderForNonPlayerCraft(ItemStack input, int amount, @Nullable Recipe recipe, RecipeRemainderLocation location, DefaultedList inventory, int index, Consumer failure) { + ItemStack remainder = decrementWithRemainder(input, amount, recipe, location); if (!tryReturnItemToInventory(remainder, inventory, index)) { failure.accept(remainder); } } - @Contract(mutates = "param1, param4") - public static void handleRemainderForScreenHandler(Slot slot, int amount, @Nullable Recipe recipe, PlayerEntity player) { - ItemStack remainder = decrementWithRemainder(slot.getStack(), amount, recipe); + @Contract(mutates = "param1, param5") + public static void handleRemainderForScreenHandler(Slot slot, int amount, @Nullable Recipe recipe, RecipeRemainderLocation location, PlayerEntity player) { + ItemStack remainder = decrementWithRemainder(slot.getStack(), amount, recipe, location); if (!tryReturnItemToSlot(remainder, slot)) { player.getInventory().offerOrDrop(remainder); diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/AbstractFurnaceBlockEntityMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/AbstractFurnaceBlockEntityMixin.java index 0484b6d2a2..de7dba54fc 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/AbstractFurnaceBlockEntityMixin.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/AbstractFurnaceBlockEntityMixin.java @@ -43,6 +43,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderLogicHandler; @Mixin(AbstractFurnaceBlockEntity.class) @@ -80,7 +81,7 @@ private static void checkMismatchedRemaindersCanDrop(DynamicRegistryManager regi ItemStack original = inventory.get(INPUT_SLOT).copy(); if (!original.isEmpty()) { - ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(original, recipe).copy(); + ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(original, recipe, RecipeRemainderLocation.FURNACE_INGREDIENT).copy(); original.decrement(1); if (!remainder.isEmpty() && ItemStack.canCombine(original, remainder)) { @@ -111,6 +112,7 @@ private static void setFuelRemainder(ItemStack fuelStack, int amount, World worl fuelStack, amount, recipe, + RecipeRemainderLocation.FURNACE_FUEL, cast.inventory, FUEL_SLOT, blockEntity.getWorld(), @@ -129,6 +131,7 @@ private static void setInputRemainder(ItemStack inputStack, int amount, DynamicR inputStack, amount, recipe, + RecipeRemainderLocation.FURNACE_INGREDIENT, inventory, INPUT_SLOT, remainder -> { // consumer only called when there are excess remainder items that can be dropped into the world diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BannerDuplicateRecipeMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BannerDuplicateRecipeMixin.java new file mode 100644 index 0000000000..86e12ca13a --- /dev/null +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BannerDuplicateRecipeMixin.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 The Quilt Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.item.setting.mixin.recipe_remainder; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.inventory.RecipeInputInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.BannerDuplicateRecipe; +import net.minecraft.recipe.Recipe; +import net.minecraft.util.collection.DefaultedList; + +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderProvider; + +@Mixin(BannerDuplicateRecipe.class) +public abstract class BannerDuplicateRecipeMixin implements Recipe { + @Inject(method = "getRemainder(Lnet/minecraft/inventory/RecipeInputInventory;)Lnet/minecraft/util/collection/DefaultedList;", at = @At(value = "RETURN", ordinal = 0), cancellable = true) + private void interceptGetRemainingStacks(RecipeInputInventory inventory, CallbackInfoReturnable> cir) { + cir.setReturnValue( + RecipeRemainderProvider.getRemainingStacks(inventory, this, RecipeRemainderLocation.CRAFTING, cir.getReturnValue()) + ); + } +} diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BookCloningRecipeMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BookCloningRecipeMixin.java new file mode 100644 index 0000000000..6a93e8e034 --- /dev/null +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BookCloningRecipeMixin.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 The Quilt Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.item.setting.mixin.recipe_remainder; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.inventory.RecipeInputInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.BookCloningRecipe; +import net.minecraft.recipe.Recipe; +import net.minecraft.util.collection.DefaultedList; + +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderProvider; + +@Mixin(BookCloningRecipe.class) +public abstract class BookCloningRecipeMixin implements Recipe { + @Inject(method = "getRemainder(Lnet/minecraft/inventory/RecipeInputInventory;)Lnet/minecraft/util/collection/DefaultedList;", at = @At(value = "RETURN", ordinal = 0), cancellable = true) + private void interceptGetRemainingStacks(RecipeInputInventory inventory, CallbackInfoReturnable> cir) { + cir.setReturnValue( + RecipeRemainderProvider.getRemainingStacks(inventory, this, RecipeRemainderLocation.CRAFTING, cir.getReturnValue()) + ); + } +} diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BrewingStandBlockEntityMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BrewingStandBlockEntityMixin.java index 6ba60b2032..54ecedad5d 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BrewingStandBlockEntityMixin.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/BrewingStandBlockEntityMixin.java @@ -28,6 +28,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderLogicHandler; @Mixin(BrewingStandBlockEntity.class) @@ -44,6 +45,7 @@ private static void applyRecipeRemainder(ItemStack ingredient, int amount, World ingredient, amount, null, + RecipeRemainderLocation.POTION_ADDITION, inventory, INGREDIENT_SLOT, world, diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/ItemsMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/ItemsMixin.java new file mode 100644 index 0000000000..1e4abe14d8 --- /dev/null +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/ItemsMixin.java @@ -0,0 +1,52 @@ +/* + * Copyright 2024 The Quilt Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.item.setting.mixin.recipe_remainder; + +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; + +import org.quiltmc.qsl.item.setting.api.QuiltItemSettings; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; + +@Mixin(Items.class) +public class ItemsMixin { + @Redirect( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/Item$Settings;recipeRemainder(Lnet/minecraft/item/Item;)Lnet/minecraft/item/Item$Settings;" + ), + slice = @Slice( + from = @At(value = "FIELD", target = "Lnet/minecraft/item/Items;BEETROOT_SOUP:Lnet/minecraft/item/Item;", opcode = Opcodes.PUTSTATIC), + to = @At(value = "FIELD", target = "Lnet/minecraft/item/Items;DRAGON_BREATH:Lnet/minecraft/item/Item;", opcode = Opcodes.PUTSTATIC) + ) + ) + private static Item.Settings changeDragonBreathRecipeRemainder(Item.Settings instance, Item recipeRemainder) { + // See: https://github.com/FabricMC/fabric/issues/2873 + // https://bugs.mojang.com/browse/MC-259583 + return new QuiltItemSettings() + .recipeRemainder((_original, _recipe) -> recipeRemainder.getDefaultStack()) + .recipeRemainder((original, recipe) -> original.getCount() >= 2 ? recipeRemainder.getDefaultStack() : ItemStack.EMPTY, RecipeRemainderLocation.POTION_ADDITION); + } +} diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/LoomOutputSlotMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/LoomOutputSlotMixin.java index 9402476334..6cdf35fba0 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/LoomOutputSlotMixin.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/LoomOutputSlotMixin.java @@ -25,6 +25,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderLogicHandler; @Mixin(targets = {"net.minecraft.screen.LoomScreenHandler$C_ntobwfpp"}) @@ -39,6 +40,7 @@ public ItemStack getRecipeRemainder(Slot slot, int amount, PlayerEntity player, slot, amount, null, + RecipeRemainderLocation.LOOM_DYE, player ); diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/RecipeManagerMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/RecipeMixin.java similarity index 58% rename from library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/RecipeManagerMixin.java rename to library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/RecipeMixin.java index 3d7eb49e3e..ad8bc8fde6 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/RecipeManagerMixin.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/RecipeMixin.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Quilt Project + * Copyright 2024 The Quilt Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,30 +16,25 @@ package org.quiltmc.qsl.item.setting.mixin.recipe_remainder; -import java.util.Optional; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; import net.minecraft.recipe.Recipe; -import net.minecraft.recipe.RecipeManager; -import net.minecraft.recipe.RecipeType; import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderProvider; -@Mixin(RecipeManager.class) -public class RecipeManagerMixin { - @Inject(method = "getRemainingStacks", at = @At(value = "RETURN", ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - public > void interceptGetRemainingStacks(RecipeType recipeType, C inventory, World world, CallbackInfoReturnable> cir, Optional> optionalRecipe) { +@Mixin(Recipe.class) +public interface RecipeMixin { + @Inject(method = "getRemainder", at = @At(value = "RETURN", ordinal = 0), cancellable = true) + private void interceptGetRemainingStacks(C inventory, CallbackInfoReturnable> cir) { cir.setReturnValue( - RecipeRemainderProvider.getRemainingStacks(inventory, optionalRecipe.get(), cir.getReturnValue()) + RecipeRemainderProvider.getRemainingStacks(inventory, (Recipe) this, RecipeRemainderLocation.CRAFTING, cir.getReturnValue()) ); } } diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/SmithingScreenHandlerMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/SmithingScreenHandlerMixin.java index 34467af907..421b28bec2 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/SmithingScreenHandlerMixin.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/SmithingScreenHandlerMixin.java @@ -33,6 +33,7 @@ import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.SmithingScreenHandler; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderLogicHandler; @Mixin(SmithingScreenHandler.class) @@ -47,12 +48,18 @@ public SmithingScreenHandlerMixin(@Nullable ScreenHandlerType screenHandlerTy super(screenHandlerType, i, playerInventory, screenHandlerContext); } - @Redirect(method = "decrementStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;decrement(I)V")) - private void applyRecipeRemainder(ItemStack instance, int amount, int slot) { + @Redirect(method = "onTakeOutput", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/SmithingScreenHandler;decrementStack(I)V")) + private void applyRecipeRemainderToIngredient(SmithingScreenHandler instance, int slot) { RecipeRemainderLogicHandler.handleRemainderForScreenHandler( this.getSlot(slot), - amount, + 1, this.currentRecipe, + switch (slot) { + case SmithingScreenHandler.TEMPLATE_SLOT -> RecipeRemainderLocation.SMITHING_TEMPLATE; + case SmithingScreenHandler.BASE_SLOT -> RecipeRemainderLocation.SMITHING_BASE; + case SmithingScreenHandler.ADDITIONAL_SLOT -> RecipeRemainderLocation.SMITHING_INGREDIENT; + default -> throw new IllegalStateException("Unexpected value: " + slot); + }, this.player ); } diff --git a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/StonecutterOutputSlotMixin.java b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/StonecutterOutputSlotMixin.java index fdf442e532..30297cb323 100644 --- a/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/StonecutterOutputSlotMixin.java +++ b/library/item/item_setting/src/main/java/org/quiltmc/qsl/item/setting/mixin/recipe_remainder/StonecutterOutputSlotMixin.java @@ -30,6 +30,7 @@ import net.minecraft.screen.StonecutterScreenHandler; import net.minecraft.screen.slot.Slot; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; import org.quiltmc.qsl.item.setting.api.RecipeRemainderLogicHandler; @Mixin(targets = {"net.minecraft.screen.StonecutterScreenHandler$C_biccipxg"}) @@ -53,6 +54,7 @@ public ItemStack getRecipeRemainder(Slot slot, int amount, PlayerEntity player, slot, amount, recipe, + RecipeRemainderLocation.STONECUTTER_INPUT, player ); diff --git a/library/item/item_setting/src/main/resources/quilt_item_setting.mixins.json b/library/item/item_setting/src/main/resources/quilt_item_setting.mixins.json index 04bc0049bd..7854e39cf5 100644 --- a/library/item/item_setting/src/main/resources/quilt_item_setting.mixins.json +++ b/library/item/item_setting/src/main/resources/quilt_item_setting.mixins.json @@ -7,9 +7,12 @@ "ItemStackMixin", "LivingEntityMixin", "recipe_remainder.AbstractFurnaceBlockEntityMixin", + "recipe_remainder.BannerDuplicateRecipeMixin", + "recipe_remainder.BookCloningRecipeMixin", "recipe_remainder.BrewingStandBlockEntityMixin", + "recipe_remainder.ItemsMixin", "recipe_remainder.LoomOutputSlotMixin", - "recipe_remainder.RecipeManagerMixin", + "recipe_remainder.RecipeMixin", "recipe_remainder.SmithingScreenHandlerMixin", "recipe_remainder.StonecutterOutputSlotMixin" ], diff --git a/library/item/item_setting/src/testmod/java/org/quiltmc/qsl/item/test/RecipeRemainderTests.java b/library/item/item_setting/src/testmod/java/org/quiltmc/qsl/item/test/RecipeRemainderTests.java index 762f80abdf..83b6709dd7 100644 --- a/library/item/item_setting/src/testmod/java/org/quiltmc/qsl/item/test/RecipeRemainderTests.java +++ b/library/item/item_setting/src/testmod/java/org/quiltmc/qsl/item/test/RecipeRemainderTests.java @@ -29,6 +29,7 @@ import org.quiltmc.loader.api.ModContainer; import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; import org.quiltmc.qsl.item.setting.api.QuiltItemSettings; +import org.quiltmc.qsl.item.setting.api.RecipeRemainderLocation; public class RecipeRemainderTests implements ModInitializer { // Static field so we can use it in BrewingRecipeRegistryMixin @@ -37,73 +38,56 @@ public class RecipeRemainderTests implements ModInitializer { new Identifier(QuiltItemSettingsTests.NAMESPACE, "potion_ingredient_remainder"), new Item( new QuiltItemSettings().recipeRemainder( - (original, recipe) -> new ItemStack(Items.BLAZE_POWDER) + (original, recipe) -> new ItemStack(Items.BLAZE_POWDER), RecipeRemainderLocation.POTION_ADDITION ) ) ); @Override public void onInitialize(ModContainer mod) { + // TODO: figure out a way to test these better. Maybe a gametest? Item hammerItem = new Item(new QuiltItemSettings().maxDamage(16).recipeDamageRemainder()); Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "hammer"), hammerItem); - Item furnaceInputRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> { - if (recipe != null && recipe.getType() == RecipeType.SMELTING) { - return Items.DIAMOND.getDefaultStack(); - } - - return ItemStack.EMPTY; - })); + Item furnaceInputRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> Items.DIAMOND.getDefaultStack(), RecipeRemainderLocation.FURNACE_INGREDIENT)); Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "weird_ore"), furnaceInputRemainder); Item furnaceInputSelfRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> { - if (recipe != null && recipe.getType() == RecipeType.SMELTING) { - var remainder = original.copy(); - remainder.setCount(2); - return remainder; - } - - return ItemStack.EMPTY; - })); + var remainder = original.copy(); + remainder.setCount(2); + return remainder; + }, RecipeRemainderLocation.FURNACE_INGREDIENT)); Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "infinite_ore"), furnaceInputSelfRemainder); Item furnaceFuelSelfRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> { var remainder = original.copy(); - if (recipe != null) { - if (recipe.getType() == RecipeType.SMELTING) { - remainder.setCount(1); - } else if (recipe.getType() == RecipeType.SMOKING) { - remainder.setCount(2); - } else if (recipe.getType() == RecipeType.BLASTING) { - remainder.setCount(3); - } - - return remainder; + if (recipe == null) { + // noop + } else if (recipe.getType() == RecipeType.SMELTING) { + remainder.setCount(1); + } else if (recipe.getType() == RecipeType.SMOKING) { + remainder.setCount(2); + } else if (recipe.getType() == RecipeType.BLASTING) { + remainder.setCount(3); } - return ItemStack.EMPTY; - })); + return remainder; + }, RecipeRemainderLocation.FURNACE_FUEL)); Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "infinite_fuel"), furnaceFuelSelfRemainder); - Item smithingInputRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> { - if (recipe != null && recipe.getType() == RecipeType.SMITHING) { - return original.getItem().getDefaultStack(); - } - - return Items.NETHERITE_SCRAP.getDefaultStack(); - })); + Item smithingInputRemainder = new Item(new QuiltItemSettings().recipeSelfRemainder(RecipeRemainderLocation.SMITHING_INGREDIENT)); Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "infinite_netherite"), smithingInputRemainder); - Item loomInputRemainder = new DyeItem(DyeColor.RED, new QuiltItemSettings().maxDamage(100).recipeDamageRemainder()); - Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "infinite_dye"), loomInputRemainder); + Item smithingTemplateRemainder = new Item(new QuiltItemSettings().maxDamage(100).recipeDamageRemainder(1, RecipeRemainderLocation.SMITHING_TEMPLATE)); + Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "infinite_netherite_template"), smithingTemplateRemainder); - Item cuttingInputRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> { - if (recipe != null && recipe.getType() == RecipeType.STONECUTTING) { - return Items.STONE.getDefaultStack(); - } + Item smithingBaseRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> new ItemStack(Items.LEATHER), RecipeRemainderLocation.SMITHING_BASE)); + Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "leaving_leather_base"), smithingBaseRemainder); + + Item loomInputRemainder = new DyeItem(DyeColor.RED, new QuiltItemSettings().maxDamage(100).recipeDamageRemainder(RecipeRemainderLocation.LOOM_DYE)); + Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "reusable_dye"), loomInputRemainder); - return ItemStack.EMPTY; - })); + Item cuttingInputRemainder = new Item(new QuiltItemSettings().recipeRemainder((original, recipe) -> Items.STONE.getDefaultStack(), RecipeRemainderLocation.STONECUTTER_INPUT)); Registry.register(Registries.ITEM, new Identifier(QuiltItemSettingsTests.NAMESPACE, "infinite_stone"), cuttingInputRemainder); } } diff --git a/library/item/item_setting/src/testmod/resources/data/quilt_item_content_registry/attachments/minecraft/item/fuel_time.json b/library/item/item_setting/src/testmod/resources/data/quilt/attachments/minecraft/item/fuel_times.json similarity index 100% rename from library/item/item_setting/src/testmod/resources/data/quilt_item_content_registry/attachments/minecraft/item/fuel_time.json rename to library/item/item_setting/src/testmod/resources/data/quilt/attachments/minecraft/item/fuel_times.json diff --git a/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_base_test.json b/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_base_test.json new file mode 100644 index 0000000000..f25c6aacb7 --- /dev/null +++ b/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_base_test.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:smithing_transform", + "base": { + "item": "quilt_item_setting_testmod:leaving_leather_base" + }, + "addition": { + "item": "minecraft:netherite_ingot" + }, + "result": { + "item": "minecraft:netherite_chestplate" + }, + "template": { + "item": "minecraft:netherite_upgrade_smithing_template" + } +} diff --git a/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_test.json b/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_ingredient_test.json similarity index 100% rename from library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_test.json rename to library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_ingredient_test.json diff --git a/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_template_test.json b/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_template_test.json new file mode 100644 index 0000000000..61f89a9e05 --- /dev/null +++ b/library/item/item_setting/src/testmod/resources/data/quilt_item_setting_testmod/recipes/smithing_template_test.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:smithing_transform", + "base": { + "item": "minecraft:gold_block" + }, + "addition": { + "item": "minecraft:netherite_ingot" + }, + "result": { + "item": "minecraft:netherite_block" + }, + "template": { + "item": "quilt_item_setting_testmod:infinite_netherite_template" + } +}