Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 111 additions & 8 deletions src/main/java/org/spongepowered/api/item/recipe/Recipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,66 @@
*/
package org.spongepowered.api.item.recipe;

import org.spongepowered.api.NamedCatalogType;
import org.spongepowered.api.CatalogType;
import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.block.entity.carrier.Campfire;
import org.spongepowered.api.block.entity.carrier.furnace.BlastFurnace;
import org.spongepowered.api.block.entity.carrier.furnace.Furnace;
import org.spongepowered.api.block.entity.carrier.furnace.Smoker;
import org.spongepowered.api.item.ItemTypes;
import org.spongepowered.api.item.inventory.Inventory;
import org.spongepowered.api.item.inventory.ItemStackSnapshot;
import org.spongepowered.api.item.inventory.crafting.CraftingInventory;
import org.spongepowered.api.item.recipe.crafting.CraftingRecipe;
import org.spongepowered.api.item.recipe.crafting.Ingredient;
import org.spongepowered.api.item.recipe.crafting.RecipeResult;
import org.spongepowered.api.item.recipe.crafting.ShapedCraftingRecipe;
import org.spongepowered.api.item.recipe.crafting.ShapelessCraftingRecipe;
import org.spongepowered.api.item.recipe.crafting.SpecialCraftingRecipe;
import org.spongepowered.api.item.recipe.single.StoneCutterRecipe;
import org.spongepowered.api.item.recipe.smelting.SmeltingRecipe;
import org.spongepowered.api.world.World;

import java.util.List;
import java.util.Optional;

/**
* A general interface for recipes. Every direct sub interface
* of this class will require it's own registry module. Depending
* for what purpose a {@link Recipe} is implemented, different
* sub classes will be used.
* <p>The currently supported recipe types are
* {@link CraftingRecipe} and {@link SmeltingRecipe}.
* A general interface for recipes.
* <p>Currently supported recipe types are:</p>
* <p>{@link ShapelessCraftingRecipe} for recipes with simple ingredients/result without pattern in a {@link CraftingInventory}</p>
* <p>{@link ShapedCraftingRecipe} for recipes with simple ingredients/result in a pattern in a {@link CraftingInventory}</p>
* <p>{@link SpecialCraftingRecipe} for recipes with complex ingredients and result in a {@link CraftingInventory}</p>
* <p>{@link SmeltingRecipe} for recipes in {@link Furnace}, {@link BlastFurnace}, {@link Smoker} and {@link Campfire}</p>
* <p>{@link StoneCutterRecipe} for recipes in a {@link BlockTypes#STONECUTTER} block</p>
*/
public interface Recipe extends NamedCatalogType {
public interface Recipe extends CatalogType {

/**
* Checks if the given inventory fits the required constraints to make a valid recipe
*
* @param inventory The inventory to check for validity
* @param world The world this recipe would be used in
*
* @return True if the given input matches this recipe's requirements
*/
boolean isValid(Inventory inventory, World world);

/**
* This method should only be called if {@link #isValid(Inventory, World)} returns {@code true}.
*
* <p>This method is preferred over the
* {@link CraftingRecipe#getExemplaryResult()} method, as it customizes
* the result further depending on the context.</p>
*
* <p>Implementing classes are advised to use the output of
* {@link CraftingRecipe#getExemplaryResult()}, modify it accordingly,
* and {@code return} it.</p>
*
* @param inventory The input inventory
*
* @return An {@link ItemStackSnapshot}
*/
ItemStackSnapshot getResult(Inventory inventory);

/**
* A general result of this recipe. This result may be customized depending
Expand All @@ -47,4 +93,61 @@ public interface Recipe extends NamedCatalogType {
*/
ItemStackSnapshot getExemplaryResult();

/**
* This method should only be called if {@link #isValid(Inventory, World)} returns {@code true}.
*
* <p>A list of items to be added to the inventory of the player when they
* craft the result. For example, if a player crafts a
* {@link ItemTypes#CAKE}, the empty buckets are returned to their
* inventory.</p>
*
* @param inventory The input inventory
* @return The list of items to be added to the inventory of the player
* when the recipe has been fulfilled (possibly empty)
*/
List<ItemStackSnapshot> getRemainingItems(Inventory inventory);

/**
* Returns the {@link RecipeResult} for the given inventory and world.
*
* <p>Returns
* {@link Optional#empty()} if the arguments do not satisfy
* {@link #isValid(Inventory, World)}.</p>
*
* @param inventory The input inventory
* @param world The world this recipe would be used in
*
* @return A {@link RecipeResult} if the arguments satisfy
* {@link #isValid(Inventory, World)}, or
* {@link Optional#empty()} if not
*/
default Optional<RecipeResult> getResult(Inventory inventory, World world) {
if (this.isValid(inventory, world)) {
return Optional.of(new RecipeResult(this.getResult(inventory), this.getRemainingItems(inventory)));
}
return Optional.empty();
}

/**
* Gets the ingredients for this recipe.
*
* @return An unmodifiable list of the ingredients.
*/
List<Ingredient> getIngredients();

/**
* Returns true if the recipe is dynamic.
* <p>Dynamic recipes are not displayed in the recipe book.</p>
*
* @return Whether this recipe is dynamic.
*/
boolean isDynamic();

/**
* Gets the type of recipe
*
* @return The recipe type.
*/
RecipeType getType();

}
142 changes: 141 additions & 1 deletion src/main/java/org/spongepowered/api/item/recipe/RecipeRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,148 @@
*/
package org.spongepowered.api.item.recipe;

import org.spongepowered.api.CatalogKey;
import org.spongepowered.api.event.registry.RegistryEvent;
import org.spongepowered.api.item.inventory.Inventory;
import org.spongepowered.api.item.inventory.ItemStackSnapshot;
import org.spongepowered.api.item.recipe.crafting.RecipeResult;
import org.spongepowered.api.item.recipe.smelting.SmeltingRecipe;
import org.spongepowered.api.world.World;

import java.util.Collection;
import java.util.Optional;
import java.util.function.Supplier;

/**
* A registry holds all registered recipes for a given game.
* Register new Recipes during {@link RegistryEvent.Catalog<Recipe>}.
* To disable a recipe override it with an empty result.
*/
public interface RecipeRegistry<T extends Recipe> {
public interface RecipeRegistry {

/**
* Gets a recipe by its id
*
* @param id the recipe id
*
* @return The recipe if available
*/
Optional<Recipe> getById(CatalogKey id);

/**
* Gets all registered recipes.
*
* @return All registered recipes.
*/
Collection<Recipe> getAll();

/**
* Returns all registered recipes of given type
* @param type The recipe type
*
* @return All recipes of given type
*/
<T extends Recipe> Collection<T> getAllOfType(RecipeType<T> type);

/**
* Returns all registered recipes of given type
* @param supplier The recipe type
*
* @return All recipes of given type
*/
default <T extends Recipe> Collection<T> getAllOfType(Supplier<? extends RecipeType<T>> supplier) {
return this.getAllOfType(supplier.get());
}

/**
* Returns all registered recipes of given type and with given item as a result.
*
* @param type The recipe type
* @param result The recipe result to match
*
* @return The recipes resulting in given item.
*/
<T extends Recipe> Collection<T> findByResult(RecipeType<T> type, ItemStackSnapshot result);

/**
* Gets all recipes with given item as a result.
*
* @param result the recipe result to match
*
* @return All recipes resulting in given item.
*/
default <T extends Recipe> Collection<T> findByResult(Supplier<? extends RecipeType<T>> supplier, ItemStackSnapshot result) {
return this.findByResult(supplier.get(), result);
}

/**
* Finds a matching recipe for given inventory and world.
*
* @param inventory The input inventory
* @param world The world
*
* @return The found {@link Recipe}, or {@link Optional#empty()}
* if no recipe was found for this configuration
*/
Optional<Recipe> findMatchingRecipe(Inventory inventory, World world);

/**
* Finds a matching recipe for given type, inventory and world
*
* @param type The recipe type
* @param inventory The input inventory
* @param world The world
*
* @return The matching recipes.
*/
<T extends Recipe> Optional<T> findMatchingRecipe(RecipeType<T> type, Inventory inventory, World world);

/**
* Finds a matching recipe for given type, inventory and world
*
* @param supplier The recipe type
* @param inventory The input inventory
* @param world The world
*
* @return The matching recipes.
*/
default <T extends Recipe> Optional<T> findMatchingRecipe(Supplier<? extends RecipeType<T>> supplier, Inventory inventory, World world) {
return this.findMatchingRecipe(supplier.get(), inventory, world);
}

/**
* Finds a matching smelting recipe for given type and ingredient
*
* @param type The recipe type
* @param ingredient The ingredient
*
* @return The matching recipe.
*/
<T extends SmeltingRecipe> Optional<T> findSmeltingRecipe(RecipeType<T> type, ItemStackSnapshot ingredient);

/**
* Finds a matching smelting recipe for given type and ingredient
*
* @param supplier The recipe type
* @param ingredient The ingredient
*
* @return The matching recipe.
*/
default <T extends SmeltingRecipe> Optional<T> findSmeltingRecipe(Supplier<? extends RecipeType<T>> supplier, ItemStackSnapshot ingredient) {
return this.findSmeltingRecipe(supplier.get(), ingredient);
}

/**
* Finds the matching recipe and creates the {@link RecipeResult},
* which is then returned.
*
* @param inventory The crafting grid
* @param world The world
* @return The {@link RecipeResult} if a recipe was found, or
* {@link Optional#empty()} if not
*/
default Optional<RecipeResult> getResult(Inventory inventory, World world) {
return this.findMatchingRecipe(inventory, world)
.flatMap(recipe -> recipe.getResult(inventory, world));
}
}
10 changes: 10 additions & 0 deletions src/main/java/org/spongepowered/api/item/recipe/RecipeType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.spongepowered.api.item.recipe;

import org.spongepowered.api.CatalogType;
import org.spongepowered.api.util.annotation.CatalogedBy;

@CatalogedBy(RecipeTypes.class)
public interface RecipeType<T extends Recipe> extends CatalogType {


}
30 changes: 30 additions & 0 deletions src/main/java/org/spongepowered/api/item/recipe/RecipeTypes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.spongepowered.api.item.recipe;

import org.spongepowered.api.Sponge;
import org.spongepowered.api.item.recipe.crafting.CraftingRecipe;
import org.spongepowered.api.item.recipe.single.StoneCutterRecipe;
import org.spongepowered.api.item.recipe.smelting.SmeltingRecipe;

import java.util.function.Supplier;

/**
* An enumeration of all {@link RecipeType}s in vanilla minecraft.
*/
public class RecipeTypes {
// SORTFIELDS:ON

// CRAFTING_SHAPED - CRAFTING_SHAPELESS
public static final Supplier<RecipeType<CraftingRecipe>> CRAFTING = Sponge.getRegistry().getCatalogRegistry().provideSupplier(RecipeType.class, "CRAFTING");
public static final Supplier<RecipeType<SmeltingRecipe>> SMELTING = Sponge.getRegistry().getCatalogRegistry().provideSupplier(RecipeType.class, "SMELTING");
public static final Supplier<RecipeType<SmeltingRecipe>> BLASTING = Sponge.getRegistry().getCatalogRegistry().provideSupplier(RecipeType.class, "BLASTING");
public static final Supplier<RecipeType<SmeltingRecipe>> SMOKING = Sponge.getRegistry().getCatalogRegistry().provideSupplier(RecipeType.class, "SMOKING");
public static final Supplier<RecipeType<SmeltingRecipe>> CAMPFIRE_COOKING = Sponge.getRegistry().getCatalogRegistry().provideSupplier(RecipeType.class, "CAMPFIRE_COOKING");
public static final Supplier<RecipeType<StoneCutterRecipe>> STONECUTTING = Sponge.getRegistry().getCatalogRegistry().provideSupplier(RecipeType.class, "STONECUTTING");

// SORTFIELDS:OFF

// Suppress default constructor to ensure non-instantiability.
private RecipeTypes() {
throw new AssertionError("You should not be attempting to instantiate this class.");
}
}
Loading