Skip to content

Commit 766a87c

Browse files
committed
Revamp crafting API
1 parent faee072 commit 766a87c

55 files changed

Lines changed: 1636 additions & 476 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.cloudburstmc.api.crafting;
2+
3+
/**
4+
* Marker interface for recipes whose output is computed dynamically at runtime
5+
* rather than being a fixed item stack.
6+
*/
7+
public interface ComplexRecipe extends Recipe {
8+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.cloudburstmc.api.crafting;
2+
3+
import org.cloudburstmc.api.item.ItemStack;
4+
5+
/**
6+
* A recipe processed by a cooking station (furnace, blast furnace, smoker, campfire).
7+
* The specific station is identified by {@link #getBlock()}.
8+
*/
9+
public interface CookingRecipe extends Recipe {
10+
11+
/**
12+
* Returns the ingredient descriptor for the input slot.
13+
* Can be a tag-based ingredient for recipes that accept a category of items.
14+
*/
15+
RecipeIngredient getInput();
16+
17+
/**
18+
* Returns a representative {@link ItemStack} for the input slot.
19+
* Useful for display and item-based recipe matching.
20+
* For tag-based inputs this returns a representative concrete item that satisfies the tag.
21+
*/
22+
ItemStack getInputItem();
23+
24+
/**
25+
* Returns the priority used to order this recipe in the recipe book display.
26+
* Lower values are preferred over higher values when multiple cooking recipes match the same input.
27+
*/
28+
int getPriority();
29+
}

api/src/main/java/org/cloudburstmc/api/crafting/CraftingRecipe.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,41 @@
55
import java.util.List;
66

77
/**
8-
* @author CreeperFace
8+
* A recipe crafted in a crafting grid, either the 2x2 inventory grid or a 3x3 crafting table.
9+
* Subtypes include {@link ShapedRecipe}, {@link ShapelessRecipe}, and {@link ShulkerBoxRecipe}.
910
*/
1011
public interface CraftingRecipe extends Recipe {
1112

13+
/**
14+
* Returns {@code true} if this recipe requires a 3x3 crafting grid (crafting table).
15+
* Returns {@code false} if it can be crafted in the 2x2 inventory grid.
16+
*/
1217
boolean requiresCraftingTable();
1318

19+
/**
20+
* Returns the secondary output items produced alongside the primary result.
21+
* Does not include the primary result ({@link #getResult()}).
22+
* Returns an empty list if there are no secondary outputs.
23+
*/
1424
List<? extends ItemStack> getExtraResults();
1525

26+
/**
27+
* Returns all output items: the primary result followed by any secondary outputs.
28+
* Equivalent to prepending {@link #getResult()} to {@link #getExtraResults()}.
29+
*/
1630
List<? extends ItemStack> getAllResults();
1731

32+
/**
33+
* Returns the priority used to order this recipe in the recipe book display.
34+
* Lower values are preferred over higher values when multiple recipes share the same inputs.
35+
*/
1836
int getPriority();
1937

2038
/**
21-
* Returns whether the specified list of crafting grid inputs and outputs matches this recipe. Outputs DO NOT
22-
* include the primary result item.
23-
*
24-
* @param input 2D array of items taken from the crafting grid
25-
* @param output 2D array of items put back into the crafting grid (secondary results)
26-
* @return bool
39+
* Returns the context under which this recipe is automatically unlocked in the recipe book.
40+
* Defaults to {@link RecipeUnlockContext#ALWAYS_UNLOCKED}.
2741
*/
28-
boolean matchItems(ItemStack[][] input, ItemStack[][] output);
42+
default RecipeUnlockContext getUnlockContext() {
43+
return RecipeUnlockContext.ALWAYS_UNLOCKED;
44+
}
2945
}
Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,29 @@
11
package org.cloudburstmc.api.crafting;
22

3-
import lombok.ToString;
43
import org.cloudburstmc.api.item.ItemStack;
5-
import org.cloudburstmc.api.util.Identifier;
64

7-
@ToString
8-
public abstract class MixRecipe implements Recipe {
9-
10-
private final ItemStack input;
11-
private final ItemStack ingredient;
12-
private final ItemStack output;
13-
private final Identifier recipeId;
14-
15-
public MixRecipe(Identifier id, ItemStack input, ItemStack ingredient, ItemStack output) {
16-
this.recipeId = id;
17-
this.input = input;
18-
this.ingredient = ingredient;
19-
this.output = output;
20-
}
21-
22-
@Override
23-
public Identifier getId() {
24-
return this.recipeId;
25-
}
26-
27-
public ItemStack getIngredient() {
28-
return ingredient;
29-
}
30-
31-
public ItemStack getInput() {
32-
return input;
33-
}
34-
35-
public ItemStack getResult() {
36-
return output;
37-
}
38-
39-
@Override
40-
public RecipeType getType() {
41-
throw new UnsupportedOperationException();
42-
}
43-
44-
@Override
45-
public Identifier getBlock() {
46-
throw new UnsupportedOperationException();
47-
}
48-
}
5+
/**
6+
* A brewing stand recipe where one input item and one reagent combine to produce one output item.
7+
*
8+
* <p>Used for two distinct recipe categories, distinguished by {@link #getType()}:
9+
* <ul>
10+
* <li>{@link RecipeType#POTION}: potion brewing, combining a base potion with a reagent item.
11+
* <li>{@link RecipeType#POTION_CONTAINER}: container transformation, changing the container type of the potion
12+
* (e.g. converting a regular potion into a splash potion).
13+
* </ul>
14+
* Both use the brewing stand as their station.
15+
*/
16+
public interface MixRecipe extends Recipe {
17+
18+
/**
19+
* Returns the base input item for this recipe.
20+
* Always a specific item stack rather than a tag-based ingredient.
21+
*/
22+
ItemStack getInput();
23+
24+
/**
25+
* Returns the reagent item placed in the top slot of the brewing stand.
26+
* Always a specific item stack rather than a tag-based ingredient.
27+
*/
28+
ItemStack getIngredient();
29+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,45 @@
11
package org.cloudburstmc.api.crafting;
22

3+
import org.cloudburstmc.api.block.BlockIds;
34
import org.cloudburstmc.api.item.ItemStack;
45
import org.cloudburstmc.api.util.Identifier;
56

7+
/**
8+
* Base interface for all recipes. Every recipe has a unique identifier, a result item,
9+
* a type that categorizes it, and an associated crafting station.
10+
*/
611
public interface Recipe {
12+
13+
/**
14+
* Returns the unique identifier for this recipe.
15+
*/
716
Identifier getId();
817

18+
/**
19+
* Returns the item produced when this recipe is completed.
20+
*/
921
ItemStack getResult();
1022

23+
/**
24+
* Returns the type of this recipe, indicating which crafting mechanic it belongs to.
25+
*/
1126
RecipeType getType();
1227

28+
/**
29+
* Returns the identifier of the crafting station this recipe belongs to, or {@code null}
30+
* if no station is associated.
31+
*
32+
* <p>Common values by recipe category:
33+
* <ul>
34+
* <li>Crafting recipes ({@link ShapedRecipe}, {@link ShapelessRecipe}): {@code minecraft:crafting_table}
35+
* for 3x3 recipes, or a specific block identifier for station-specific recipes.
36+
* <li>Cooking recipes ({@link CookingRecipe}): {@code minecraft:furnace}, {@code minecraft:blast_furnace},
37+
* {@code minecraft:smoker}, or {@code minecraft:campfire}.
38+
* <li>Smithing recipes ({@link SmithingRecipe}): {@code minecraft:smithing_table}.
39+
* <li>Stonecutting recipes ({@link StonecuttingRecipe}): {@code minecraft:stonecutter}.
40+
* <li>Brewing recipes ({@link MixRecipe}): {@code minecraft:brewing_stand}.
41+
* <li>Complex recipes ({@link ComplexRecipe}): {@link BlockIds#AIR}, no physical station.
42+
* </ul>
43+
*/
1344
Identifier getBlock();
1445
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.cloudburstmc.api.crafting;
2+
3+
import org.cloudburstmc.api.item.ItemStack;
4+
import org.cloudburstmc.api.util.Identifier;
5+
6+
import java.util.function.Predicate;
7+
8+
/**
9+
* An ingredient slot in a recipe.
10+
*
11+
* <p>Use pattern matching to branch on the concrete type:
12+
* <pre>{@code
13+
* switch (ingredient) {
14+
* case RecipeIngredient.Exact(var item) -> // one specific item
15+
* case RecipeIngredient.Tag(var tag) -> // any item carrying the given tag
16+
* }
17+
* }</pre>
18+
*
19+
* <p>{@code test(ItemStack)} works on {@code Exact} variants. On a {@code Tag} variant it
20+
* always returns {@code false} because tag membership requires registry access that is not
21+
* available through this interface.
22+
*/
23+
public sealed interface RecipeIngredient extends Predicate<ItemStack> permits RecipeIngredient.Exact, RecipeIngredient.Tag {
24+
25+
/**
26+
* An ingredient that requires one specific item type.
27+
*/
28+
record Exact(Identifier item) implements RecipeIngredient {
29+
@Override
30+
public boolean test(ItemStack stack) {
31+
return !stack.isEmpty() && stack.getType().getId().equals(item);
32+
}
33+
}
34+
35+
/**
36+
* An ingredient satisfied by any item carrying the given tag.
37+
* {@code test} always returns {@code false} for this variant.
38+
*/
39+
record Tag(Identifier tag) implements RecipeIngredient {
40+
@Override
41+
public boolean test(ItemStack stack) {
42+
return false;
43+
}
44+
}
45+
}
Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,55 @@
11
package org.cloudburstmc.api.crafting;
22

3+
/**
4+
* Identifies the crafting mechanic a recipe belongs to.
5+
*/
36
public enum RecipeType {
7+
/**
8+
* A recipe with unordered ingredients placed anywhere in the crafting grid.
9+
*/
410
SHAPELESS,
11+
/**
12+
* A recipe where ingredients must be placed in a specific grid arrangement.
13+
*/
514
SHAPED,
6-
FURNACE,
7-
FURNACE_DATA,
8-
MULTI,
15+
/**
16+
* A recipe processed by a cooking station: furnace, blast furnace, smoker, or campfire.
17+
*/
18+
COOKING,
19+
/**
20+
* A recipe whose output is computed at runtime rather than being a fixed item, such as firework crafting.
21+
*/
22+
COMPLEX,
23+
/**
24+
* A shapeless recipe that recolors a shulker box by combining it with a dye.
25+
*/
926
SHULKER_BOX,
27+
/**
28+
* A shapeless recipe used for chemistry-based crafting. Behaves identically to {@link #SHAPELESS}.
29+
*/
1030
SHAPELESS_CHEMISTRY,
31+
/**
32+
* A shaped recipe used for chemistry-based crafting. Behaves identically to {@link #SHAPED}.
33+
*/
1134
SHAPED_CHEMISTRY,
35+
/**
36+
* A smithing table recipe that transforms a base item into a new item using a template and an addition material.
37+
*/
1238
SMITHING_TRANSFORM,
39+
/**
40+
* A smithing table recipe that applies a decorative trim pattern to a piece of armor.
41+
*/
1342
SMITHING_TRIM,
14-
15-
//Internal Use
43+
/**
44+
* A recipe processed by the stonecutter, producing one specific cut output from a stone-type input.
45+
*/
46+
STONECUTTING,
47+
/**
48+
* A brewing stand recipe that combines a base potion with a reagent to produce a new potion.
49+
*/
1650
POTION,
17-
CONTAINER
51+
/**
52+
* A brewing stand recipe that changes the container type of the potion, such as converting a regular potion to a splash potion.
53+
*/
54+
POTION_CONTAINER
1855
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.cloudburstmc.api.crafting;
2+
3+
/**
4+
* Controls when a crafting recipe is made visible to players in the recipe book.
5+
*
6+
* <p>The default for all built-in recipes is {@link #ALWAYS_UNLOCKED}. Use
7+
* {@link #PLAYER_IN_WATER} or {@link #PLAYER_HAS_MANY_ITEMS} for recipes that should only
8+
* appear when specific conditions are met, or {@link #NONE} to suppress automatic unlocking
9+
* entirely and handle discovery manually.
10+
*/
11+
public enum RecipeUnlockContext {
12+
/**
13+
* The recipe is never automatically unlocked. Discovery must be handled explicitly.
14+
*/
15+
NONE,
16+
/**
17+
* The recipe is always visible in the recipe book without any condition.
18+
*/
19+
ALWAYS_UNLOCKED,
20+
/**
21+
* The recipe becomes visible when the player enters water.
22+
*/
23+
PLAYER_IN_WATER,
24+
/**
25+
* The recipe becomes visible when the player has collected many different item types.
26+
*/
27+
PLAYER_HAS_MANY_ITEMS
28+
}

0 commit comments

Comments
 (0)