All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.inventory.ShapedRecipe Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.inventory;

import cn.nukkit.item.Item;
import io.netty.util.collection.CharObjectHashMap;

import java.util.*;

import static cn.nukkit.inventory.Recipe.matchItemList;

/**
 * @author MagicDroidX (Nukkit Project)
 */
public class ShapedRecipe implements CraftingRecipe {

    private String recipeId;
    private final Item primaryResult;
    private final List extraResults = new ArrayList<>();

    private final List ingredientsAggregate;

    private long least,most;

    private final String[] shape;
    private final int priority;

    private final CharObjectHashMap ingredients = new CharObjectHashMap<>();


    public ShapedRecipe(Item primaryResult, String[] shape, Map ingredients, List extraResults) {
        this(null, 1, primaryResult, shape, ingredients, extraResults);
    }

    /**
     * Constructs a ShapedRecipe instance.
     *
     * @param primaryResult    Primary result of the recipe
     * @param shape
Array of 1, 2, or 3 strings representing the rows of the recipe. * This accepts an array of 1, 2 or 3 strings. Each string should be of the same length and must be at most 3 * characters long. Each character represents a unique type of ingredient. Spaces are interpreted as air. * @param ingredients
Char => Item map of items to be set into the shape. * This accepts an array of Items, indexed by character. Every unique character (except space) in the shape * array MUST have a corresponding item in this list. Space character is automatically treated as air. * @param extraResults
List of additional result items to leave in the crafting grid afterwards. Used for things like cake recipe * empty buckets. *

* Note: Recipes **do not** need to be square. Do NOT add padding for empty rows/columns. */ public ShapedRecipe(String recipeId, int priority, Item primaryResult, String[] shape, Map ingredients, List extraResults) { this.recipeId = recipeId; this.priority = priority; int rowCount = shape.length; if (rowCount > 3 || rowCount <= 0) { throw new RuntimeException("Shaped recipes may only have 1, 2 or 3 rows, not " + rowCount); } int columnCount = shape[0].length(); if (columnCount > 3 || columnCount <= 0) { throw new RuntimeException("Shaped recipes may only have 1, 2 or 3 columns, not " + columnCount); } for (int i = 0, shapeLength = shape.length; i < shapeLength; i++) { String row = shape[i]; if (row.length() != columnCount) { throw new RuntimeException("Shaped recipe rows must all have the same length (expected " + columnCount + ", got " + row.length() + ")"); } for (int x = 0; x < columnCount; ++x) { char c = row.charAt(x); if (c != ' ' && !ingredients.containsKey(c)) { throw new RuntimeException("No item specified for symbol '" + c + "'"); } } shape[i] = row.intern(); } this.primaryResult = primaryResult.clone(); this.extraResults.addAll(extraResults); this.shape = shape; for (Map.Entry entry : ingredients.entrySet()) { this.setIngredient(entry.getKey(), entry.getValue()); } this.ingredientsAggregate = new ArrayList<>(); for (char c : String.join("", this.shape).toCharArray()) { if (c == ' ') continue; Item ingredient = this.ingredients.get(c).clone(); for (Item existingIngredient : this.ingredientsAggregate) { if (existingIngredient.equals(ingredient, ingredient.hasMeta(), ingredient.hasCompoundTag())) { existingIngredient.setCount(existingIngredient.getCount() + ingredient.getCount()); ingredient = null; break; } } if (ingredient != null) this.ingredientsAggregate.add(ingredient); } this.ingredientsAggregate.sort(CraftingManager.recipeComparator); } public int getWidth() { return this.shape[0].length(); } public int getHeight() { return this.shape.length; } @Override public Item getResult() { return this.primaryResult; } @Override public String getRecipeId() { return this.recipeId; } @Override public UUID getId() { return new UUID(least, most); } @Override public void setId(UUID uuid) { this.least = uuid.getLeastSignificantBits(); this.most = uuid.getMostSignificantBits(); if (this.recipeId == null) { this.recipeId = getId().toString(); } } public ShapedRecipe setIngredient(String key, Item item) { return this.setIngredient(key.charAt(0), item); } public ShapedRecipe setIngredient(char key, Item item) { if (String.join("", this.shape).indexOf(key) < 0) { throw new RuntimeException("Symbol does not appear in the shape: " + key); } this.ingredients.put(key, item); return this; } public List getIngredientList() { List items = new ArrayList<>(); for (int y = 0, y2 = getHeight(); y < y2; ++y) { for (int x = 0, x2 = getWidth(); x < x2; ++x) { items.add(getIngredient(x, y)); } } return items; } public Map> getIngredientMap() { Map> ingredients = new LinkedHashMap<>(); for (int y = 0, y2 = getHeight(); y < y2; ++y) { Map m = new LinkedHashMap<>(); for (int x = 0, x2 = getWidth(); x < x2; ++x) { m.put(x, getIngredient(x, y)); } ingredients.put(y, m); } return ingredients; } public Item getIngredient(int x, int y) { Item item = this.ingredients.get(this.shape[y].charAt(x)); return item != null ? item.clone() : Item.get(Item.AIR); } public String[] getShape() { return shape; } @Override public void registerToCraftingManager(CraftingManager manager) { manager.registerShapedRecipe(this); } @Override public RecipeType getType() { return RecipeType.SHAPED; } @Override public List getExtraResults() { return extraResults; } @Override public List getAllResults() { List list = new ArrayList<>(); list.add(primaryResult); list.addAll(extraResults); return list; } @Override public int getPriority() { return this.priority; } @Override public boolean matchItems(List inputList, List extraOutputList, int multiplier) { List haveInputs = new ArrayList<>(); for (Item item : inputList) { if (item.isNull()) continue; haveInputs.add(item.clone()); } List needInputs = new ArrayList<>(); if(multiplier != 1){ for (Item item : ingredientsAggregate) { if (item.isNull()) continue; Item itemClone = item.clone(); itemClone.setCount(itemClone.getCount() * multiplier); needInputs.add(itemClone); } } else { for (Item item : ingredientsAggregate) { if (item.isNull()) continue; needInputs.add(item.clone()); } } if (!matchItemList(haveInputs, needInputs)) { return false; } List haveOutputs = new ArrayList<>(); for (Item item : extraOutputList) { if (item.isNull()) continue; haveOutputs.add(item.clone()); } haveOutputs.sort(CraftingManager.recipeComparator); List needOutputs = new ArrayList<>(); if(multiplier != 1){ for (Item item : getExtraResults()) { if (item.isNull()) continue; Item itemClone = item.clone(); itemClone.setCount(itemClone.getCount() * multiplier); needOutputs.add(itemClone); } } else { for (Item item : getExtraResults()) { if (item.isNull()) continue; needOutputs.add(item.clone()); } } needOutputs.sort(CraftingManager.recipeComparator); return matchItemList(haveOutputs, needOutputs); } /** * Returns whether the specified list of crafting grid inputs and outputs matches this recipe. Outputs DO NOT * include the primary result item. * * @param inputList list of items taken from the crafting grid * @param extraOutputList list of items put back into the crafting grid (secondary results) * @return bool */ @Override public boolean matchItems(List inputList, List extraOutputList) { return matchItems(inputList, extraOutputList, 1); } @Override public String toString() { StringJoiner joiner = new StringJoiner(", "); ingredients.forEach((character, item) -> joiner.add(item.getName() + ":" + item.getDamage())); return joiner.toString(); } @Override public boolean requiresCraftingTable() { return this.getHeight() > 2 || this.getWidth() > 2; } @Override public List getIngredientsAggregate() { return ingredientsAggregate; } public static class Entry { public final int x; public final int y; public Entry(int x, int y) { this.x = x; this.y = y; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy