Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recipe Remainder API #158

Merged
merged 34 commits into from
Oct 8, 2022
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ad74dce
Beginning of the recipe remainder api, impl take 2
OroArmor Mar 4, 2022
0e73972
Use a bit more of my brain to make things work better now, still need…
OroArmor Mar 4, 2022
379f1f0
did some reworking and everything works that doesnt have a todo.
OroArmor Mar 5, 2022
10fdb76
cant remember
OroArmor Apr 20, 2022
398622b
Merge remote-tracking branch 'QuiltMC/1.19' into recipe-remainder-api
Platymemo Jul 30, 2022
dbe696c
prevent crash on craft in furnace with pre-existing fuel time
Platymemo Jul 31, 2022
2422f53
properly re-ordered recipe remainder logic
Platymemo Jul 31, 2022
6ba5a9c
apply suggestions
Platymemo Jul 31, 2022
2aaead1
add fuel test
Platymemo Jul 31, 2022
399a6b6
allow partial returns
Platymemo Jul 31, 2022
4d7bd39
Merge remote-tracking branch 'QuiltMC/1.19' into recipe-remainder-api
Platymemo Aug 3, 2022
4eaff80
Merge remote-tracking branch 'QuiltMC/1.19' into recipe-remainder-api
Platymemo Aug 6, 2022
d15e2fe
remove SharedConstantsMixin
Platymemo Aug 6, 2022
7291e8c
apply suggestions
Platymemo Aug 6, 2022
52de650
Merge remote-tracking branch 'QuiltMC/1.19' into recipe-remainder-api
Platymemo Sep 2, 2022
bf320f4
small fixes
Platymemo Sep 2, 2022
67d4531
brewing remainder test
Platymemo Sep 2, 2022
dc5ebd7
update package-info and apply licences
Platymemo Sep 3, 2022
40da666
code cleanup
Platymemo Sep 3, 2022
25a2dbd
remove invalid contracts
Platymemo Sep 4, 2022
ac991ea
move recipe remainder tests
Platymemo Sep 4, 2022
293bb3b
fix recipe remainder order of operations
Platymemo Sep 4, 2022
e0e617c
apply licenses
Platymemo Sep 4, 2022
c02450a
refactoring and docs
Platymemo Sep 8, 2022
011635a
Merge remote-tracking branch 'QuiltMC/1.19' into recipe-remainder-api
Platymemo Sep 8, 2022
0a957b2
ApiStatus annotations
Platymemo Sep 8, 2022
a73ff10
apply suggestion
Platymemo Sep 8, 2022
6e11ae8
apply suggestions
Platymemo Sep 12, 2022
b82c9a1
Merge branch '1.19' into recipe-remainder-api
EnnuiL Sep 28, 2022
63632bc
checkstyle pass
Platymemo Sep 29, 2022
a287b68
revert bad checkstyle
Platymemo Sep 29, 2022
f6f0f40
Apply suggestions
Platymemo Oct 5, 2022
1ace64d
update recipe remainder names
Platymemo Oct 5, 2022
83ad373
Merge branch '1.19' into recipe-remainder-api
EnnuiL Oct 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions library/item/item_setting/build.gradle
Expand Up @@ -12,6 +12,14 @@ qslModule {
core {
api("qsl_base")
testmodOnly("resource_loader")
testmodOnly("lifecycle_events")
testmodOnly("networking")
}
data {
testmodOnly("tags")
}
item {
testmodOnly("item_content_registry")
}
}
}
Expand Up @@ -19,18 +19,34 @@
import org.quiltmc.qsl.item.setting.impl.CustomItemSettingImpl;

/**
* A list of the {@link CustomItemSetting}s that are provided by Quilt
* A list of the {@link CustomItemSetting}s that are provided by Quilt.
*/
public final class QuiltCustomItemSettings {
private QuiltCustomItemSettings() {
}
private QuiltCustomItemSettings() {}
Platymemo marked this conversation as resolved.
Show resolved Hide resolved

/**
* The {@link CustomItemSetting} in charge of handing {@link EquipmentSlotProvider}s
* The {@link CustomItemSetting} in charge of handing {@link EquipmentSlotProvider}s.
*/
public static final CustomItemSetting<EquipmentSlotProvider> EQUIPMENT_SLOT_PROVIDER = CustomItemSettingImpl.EQUIPMENT_SLOT_PROVIDER;

/**
* The {@link CustomItemSetting} in charge of handing {@link CustomDamageHandler}s
* The {@link CustomItemSetting} in charge of handing {@link CustomDamageHandler}s.
*/
public static final CustomItemSetting<CustomDamageHandler> CUSTOM_DAMAGE_HANDLER = CustomItemSettingImpl.CUSTOM_DAMAGE_HANDLER;

/**
Leo40Git marked this conversation as resolved.
Show resolved Hide resolved
* The {@link CustomItemSetting} in charge of handing {@link RecipeRemainderProvider}s. This setting should be used when implementing custom crafting systems to properly handle remainders.
* <p>
* The setting is currently used in the following places:
* <ul>
* <li>Crafting Table</li>
* <li>Furnace Fuel</li>
* <li>Furnace Ingredient</li>
* <li>Loom Dye Input</li>
* <li>Brewing Stand Ingredient</li>
* <li>Smithing Table Addition</li>
* <li>Stone Cutter Ingredient</li>
* </ul>
*/
public static final CustomItemSetting<RecipeRemainderProvider> RECIPE_REMAINDER_PROVIDER = CustomItemSettingImpl.RECIPE_REMAINDER_PROVIDER;
}
Expand Up @@ -17,6 +17,8 @@

package org.quiltmc.qsl.item.setting.api;

import org.jetbrains.annotations.Contract;

import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.FoodComponent;
import net.minecraft.item.Item;
Expand Down Expand Up @@ -65,6 +67,55 @@ public QuiltItemSettings customDamage(CustomDamageHandler handler) {
return this.customSetting(QuiltCustomItemSettings.CUSTOM_DAMAGE_HANDLER, handler);
}

/**
* Sets the stack-aware recipe remainder provider of the item.
*/
public QuiltItemSettings recipeRemainder(RecipeRemainderProvider provider) {
return this.customSetting(QuiltCustomItemSettings.RECIPE_REMAINDER_PROVIDER, provider);
}

/**
* Sets the stack-aware recipe remainder to damage the item by 1 every time it is used in crafting.
*/
public QuiltItemSettings recipeDamageRemainder() {
return this.recipeDamageRemainder(1);
}

/**
* Sets the stack-aware recipe remainder to return the item itself.
*/
public QuiltItemSettings recipeSelfRemainder() {
return this.recipeDamageRemainder(0);
}

/**
* 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
*/
public QuiltItemSettings recipeDamageRemainder(int by) {
if (by == 0) {
return this.recipeRemainder((original, recipe) -> original.copy());
}

return this.recipeRemainder((original, recipe) -> {
if (!original.isDamageable()) {
return original.copy();
}

ItemStack copy = original.copy();

copy.setDamage(copy.getDamage() + by);

if (copy.getDamage() >= copy.getMaxDamage()) {
copy.setCount(0);
return ItemStack.EMPTY;
}

return copy;
});
}

/**
* Sets a custom setting of the item.
*
Expand All @@ -84,6 +135,7 @@ public <T> QuiltItemSettings customSetting(CustomItemSetting<T> setting, T value
// Overrides of vanilla methods

@Override
@Contract("_->this")
public QuiltItemSettings food(FoodComponent foodComponent) {
super.food(foodComponent);
return this;
Expand All @@ -102,30 +154,35 @@ public QuiltItemSettings maxDamageIfAbsent(int maxDamage) {
}

@Override
@Contract("_->this")
public QuiltItemSettings maxDamage(int maxDamage) {
super.maxDamage(maxDamage);
return this;
}

@Override
@Contract("_->this")
public QuiltItemSettings recipeRemainder(Item recipeRemainder) {
super.recipeRemainder(recipeRemainder);
return this;
}

@Override
@Contract("_->this")
public QuiltItemSettings group(ItemGroup group) {
super.group(group);
return this;
}

@Override
@Contract("_->this")
public QuiltItemSettings rarity(Rarity rarity) {
super.rarity(rarity);
return this;
}

@Override
@Contract("->this")
public QuiltItemSettings fireproof() {
super.fireproof();
return this;
Expand Down
@@ -0,0 +1,84 @@
/*
* Copyright 2022 QuiltMC
*
* 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 org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
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 org.quiltmc.qsl.item.setting.impl.CustomItemSettingImpl;
import org.quiltmc.qsl.item.setting.impl.RecipeRemainderLogicHandlerImpl;

/**
* Handles most logic for stack-aware recipe remainders.
* This can be used by custom {@link Recipe} crafting systems.
*/
@ApiStatus.NonExtendable
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
* @return the recipe remainder
*/
static ItemStack getRemainder(ItemStack original, @Nullable Recipe<?> recipe) {
ItemStack remainder = CustomItemSettingImpl.RECIPE_REMAINDER_PROVIDER.get(original.getItem()).getRecipeRemainder(
original,
recipe
);

return remainder.isEmpty() ? ItemStack.EMPTY : remainder;
}

/**
* 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 recipe the recipe being used
* @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
*/
@Contract(mutates = "param1, param3, param5")
static void handleRemainderForNonPlayerCraft(ItemStack input, @Nullable Recipe<?> recipe, DefaultedList<ItemStack> inventory, int index, World world, BlockPos location) {
RecipeRemainderLogicHandlerImpl.handleRemainderForNonPlayerCraft(input, recipe, inventory, index, world, location);
}

/**
* 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 recipe the recipe being used
* @param player the player performing the craft
*/
@Contract(mutates = "param1, param3")
static void handleRemainderForScreenHandler(Slot slot, @Nullable Recipe<?> recipe, PlayerEntity player) {
RecipeRemainderLogicHandlerImpl.handleRemainderForScreenHandler(slot, recipe, player);
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2022 QuiltMC
*
* 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 org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

import net.minecraft.inventory.Inventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Recipe;
import net.minecraft.util.collection.DefaultedList;

/**
* Allows an item to conditionally specify the recipe remainder.
* 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.
* <p>
* Recipe remainder providers can be set with {@link QuiltItemSettings#recipeRemainder(RecipeRemainderProvider)}.
*/
@FunctionalInterface
public interface RecipeRemainderProvider {
/**
* An {@link ItemStack} aware version of {@link Item#getRecipeRemainder()}.
*
* @param original the input item stack
* @param recipe the recipe being used
* @return the recipe remainder
*/
@Contract(value = "_, _ -> new")
ItemStack getRecipeRemainder(ItemStack original, @Nullable Recipe<?> recipe);

static DefaultedList<ItemStack> getRemainingStacks(Inventory inventory, Recipe<?> recipe, DefaultedList<ItemStack> defaultedList) {
for (int i = 0; i < defaultedList.size(); ++i) {
ItemStack stack = inventory.getStack(i);
ItemStack remainder = RecipeRemainderLogicHandler.getRemainder(stack, recipe);

if (!remainder.isEmpty()) {
defaultedList.set(i, remainder);
}
}

return defaultedList;
}
}
@@ -1,12 +1,14 @@
/**
* <h2>The Quilt Item Settings API.</h2>
*
* <p>
* <h3>What are {@link net.minecraft.item.Item.Settings}?</h3>
* {@link net.minecraft.item.Item.Settings} are ways to add specific traits to {@link net.minecraft.item.Item}s without creating a subclass.
* In addition, these traits are applicable to all {@link net.minecraft.item.Item}s, not just a specific subclass.
* <p>
* This API adds two new settings for items, {@link org.quiltmc.qsl.item.setting.api.QuiltCustomItemSettings#CUSTOM_DAMAGE_HANDLER} and {@link org.quiltmc.qsl.item.setting.api.QuiltCustomItemSettings#EQUIPMENT_SLOT_PROVIDER}.
* This API adds three new settings for items,
* {@link org.quiltmc.qsl.item.setting.api.QuiltItemSettings#customDamage(org.quiltmc.qsl.item.setting.api.CustomDamageHandler)},
* {@link org.quiltmc.qsl.item.setting.api.QuiltItemSettings#equipmentSlot(org.quiltmc.qsl.item.setting.api.EquipmentSlotProvider)}, and
* {@link org.quiltmc.qsl.item.setting.api.QuiltItemSettings#recipeRemainder(org.quiltmc.qsl.item.setting.api.RecipeRemainderProvider)}.
* <p>
* These custom settings make use of the {@link org.quiltmc.qsl.item.setting.api.CustomItemSetting} API provided.
* This API allows mods to specify their own custom settings in an API.
Expand Down
Expand Up @@ -25,16 +25,33 @@
import java.util.WeakHashMap;
import java.util.function.Supplier;

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.RecipeRemainderProvider;

@ApiStatus.Internal
public class CustomItemSettingImpl<T> implements CustomItemSetting<T> {
public static final CustomItemSetting<EquipmentSlotProvider> EQUIPMENT_SLOT_PROVIDER = CustomItemSetting.create(() -> null);
public static final CustomItemSetting<CustomDamageHandler> CUSTOM_DAMAGE_HANDLER = CustomItemSetting.create(() -> null);

@SuppressWarnings("ConstantConditions")
public static final CustomItemSetting<RecipeRemainderProvider> RECIPE_REMAINDER_PROVIDER = new CustomItemSettingImpl<>(() -> (original, recipe) -> original.getItem().hasRecipeRemainder() ? original.getItem().getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY) {
@Override
public void apply(Item.Settings settings, Item item) {
if (item.hasRecipeRemainder()) {
throw new IllegalArgumentException("Item cannot have a standard recipe remainder and a custom recipe remainder");
}

super.apply(settings, item);
}
};

private static final Map<Item.Settings, Collection<CustomItemSettingImpl<?>>> CUSTOM_SETTINGS = new WeakHashMap<>();

private final Map<Item.Settings, T> customSettings = new WeakHashMap<>();
Expand Down