How do I make this so that it requires 9 stacks of 64 cobblestone? Despite "count" being set to 64 (meaning 9 full stacks), it works with 1 cobblestone (1 in each of the spots)?
{
"_comment": [
"Craft a diamond using 9 full stacks of cobblestone."
],
"type": "minecraft:crafting_shaped",
"pattern":
[
"WWW",
"WWW",
"WWW"
],
"key":
{
"W":
{
"item": "minecraft:cobblestone",
"count": 64
}
},
"result":
{
"item": "minecraft:diamond",
"count": 1
}
}
You don't have to create a whole new class per say. For shaped recipes, overriding the Ingredient and its apply(ItemStack) method and have that check for count should be enough.
The same may be true for Shapeless recipes, but I had to do a bit more since my objective for my class was an NBTCheck so that I could use potions with certain effects. Potions don't use metadata, but NBTTag data. For that, first, you would need to override the Ingredient like above. Then you would need to create either a new recipe class, a new class that extends ShapelessRecipe or an anonymous ShapelessRecipe class and in that class override the matches(InventoryCrafting, World) method and have that check for the ItemStack nbt. (Side note: I don't fully understand their method, but, from what I can tell, they convert ShapelessRecipes into bytes or something and that gets rid of the nbt data. I assume it is for performance).
I don't have an example on hand.
Rollback Post to RevisionRollBack
My Mods:
Working on updating Little Maid Mod to 1.12 with my own twist. I am a Japanese anime fan :3 Teasers here
Blood Baubles - An addon for BloodMagic that adds related Baubles to the game. (Currently on hold)
Blood Magic Wiki - A Blood Mages Choice Encylopedia (Currently on hold)
LazyModder- A libary that makes modding easier. Currently being developed for 1.12)
Deobfuscator - A program used to deobfuscate obfuscated mods.
You don't have to create a whole new class per say. For shaped recipes, overriding the Ingredient and its apply(ItemStack) method and have that check for count should be enough.
The same may be true for Shapeless recipes, but I had to do a bit more since my objective for my class was an NBTCheck so that I could use potions with certain effects. Potions don't use metadata, but NBTTag data. For that, first, you would need to override the Ingredient like above. Then you would need to create either a new recipe class, a new class that extends ShapelessRecipe or an anonymous ShapelessRecipe class and in that class override the matches(InventoryCrafting, World) method and have that check for the ItemStack nbt. (Side note: I don't fully understand their method, but, from what I can tell, they convert ShapelessRecipes into bytes or something and that gets rid of the nbt data. I assume it is for performance).
I don't have an example on hand.
Judging by the errors I have been getting earlier, a class implementing IRecipeFactory is also required. I have tried both overriding and copying the ShapedRecipes class (and changing what I need). I have most likely isolated it to a single bool being false by default.
Error: "Class 'com.Markyroson.util.CustomShapedRecipe' is not an IRecipeFactory"
The problem is that the only IRecipeFactory examples I have found are for ores, which does not help me for regular items any.
The override (obviously class would be renamed, I am just trying to get it working).
public class R extends ShapedRecipes {
public R(String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result) {
super(group, width, height, ingredients, result);
// TODO Auto-generated constructor stub
}
public static Ingredient deserializeIngredient(@Nullable JsonElement p_193361_0_) {
if (p_193361_0_ != null && !p_193361_0_.isJsonNull())
{
if (p_193361_0_.isJsonObject())
{
return Ingredient.fromStacks(deserializeItem(p_193361_0_.getAsJsonObject(), false));
}
else if (!p_193361_0_.isJsonArray())
{
throw new JsonSyntaxException("Expected item to be object or array of objects");
}
else
{
JsonArray jsonarray = p_193361_0_.getAsJsonArray();
if (jsonarray.size() == 0)
{
throw new JsonSyntaxException("Item array cannot be empty, at least one item must be defined");
}
else
{
ItemStack[] aitemstack = new ItemStack[jsonarray.size()];
for (int i = 0; i < jsonarray.size(); ++i)
{
aitemstack[i] = deserializeItem(JsonUtils.getJsonObject(jsonarray.get(i), "item"), true);
}
return Ingredient.fromStacks(aitemstack);
}
}
}
else
{
throw new JsonSyntaxException("Item cannot be null");
}
}
public static class Factory {//implements IRecipeFactory {
/* @Override
public IRecipe parse(final JsonContext context, final JsonObject json) {
final String group = JsonUtils.getString(json, "group", "");
final CraftingHelper.ShapedPrimer primer = RecipeUtil.parseShaped(context, json);
final ItemStack result = CraftingHelper.getItemStack(JsonUtils.getJsonObject(json, "result"), context);
return new R(group.isEmpty() ? null : group, result, primer);
}*/
}
}
Complete class copy & alter:
package com.Markyroson.util;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.common.crafting.CraftingHelper.ShapedPrimer;
import net.minecraftforge.common.crafting.IRecipeFactory;
import net.minecraftforge.common.crafting.JsonContext;
public class CustomShapedRecipe extends net.minecraftforge.registries.IForgeRegistryEntry.Impl<IRecipe> implements net.minecraftforge.common.crafting.IShapedRecipe {
/** How many horizontal slots this recipe is wide. */
public final int recipeWidth;
/** How many vertical slots this recipe uses. */
public final int recipeHeight;
/** Is a array of ItemStack that composes the recipe. */
public final NonNullList<Ingredient> recipeItems;
/** Is the ItemStack that you get when craft the recipe. */
private final ItemStack recipeOutput;
private final String group;
public CustomShapedRecipe(String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result)
{
this.group = group;
this.recipeWidth = width;
this.recipeHeight = height;
this.recipeItems = ingredients;
this.recipeOutput = result;
}
public String getGroup()
{
return this.group;
}
public ItemStack getRecipeOutput()
{
return this.recipeOutput;
}
public NonNullList<ItemStack> getRemainingItems(InventoryCrafting inv)
{
NonNullList<ItemStack> nonnulllist = NonNullList.<ItemStack>withSize(inv.getSizeInventory(), ItemStack.EMPTY);
for (int i = 0; i < nonnulllist.size(); ++i)
{
ItemStack itemstack = inv.getStackInSlot(i);
nonnulllist.set(i, net.minecraftforge.common.ForgeHooks.getContainerItem(itemstack));
}
return nonnulllist;
}
public NonNullList<Ingredient> getIngredients()
{
return this.recipeItems;
}
/**
* Used to determine if this recipe can fit in a grid of the given width/height
*/
public boolean canFit(int width, int height)
{
return width >= this.recipeWidth && height >= this.recipeHeight;
}
/**
* Used to check if a recipe matches current crafting inventory
*/
public boolean matches(InventoryCrafting inv, World worldIn)
{
for (int i = 0; i <= inv.getWidth() - this.recipeWidth; ++i)
{
for (int j = 0; j <= inv.getHeight() - this.recipeHeight; ++j)
{
if (this.checkMatch(inv, i, j, true))
{
return true;
}
if (this.checkMatch(inv, i, j, false))
{
return true;
}
}
}
return false;
}
/**
* Checks if the region of a crafting inventory is match for the recipe.
*/
private boolean checkMatch(InventoryCrafting p_77573_1_, int p_77573_2_, int p_77573_3_, boolean p_77573_4_)
{
for (int i = 0; i < p_77573_1_.getWidth(); ++i)
{
for (int j = 0; j < p_77573_1_.getHeight(); ++j)
{
int k = i - p_77573_2_;
int l = j - p_77573_3_;
Ingredient ingredient = Ingredient.EMPTY;
if (k >= 0 && l >= 0 && k < this.recipeWidth && l < this.recipeHeight)
{
if (p_77573_4_)
{
ingredient = this.recipeItems.get(this.recipeWidth - k - 1 + l * this.recipeWidth);
}
else
{
ingredient = this.recipeItems.get(k + l * this.recipeWidth);
}
}
if (!ingredient.apply(p_77573_1_.getStackInRowAndColumn(i, j)))
{
return false;
}
}
}
return true;
}
/**
* Returns an Item that is the result of this recipe
*/
public ItemStack getCraftingResult(InventoryCrafting inv)
{
return this.getRecipeOutput().copy();
}
public int getWidth()
{
return this.recipeWidth;
}
public int getHeight()
{
return this.recipeHeight;
}
public static ShapedRecipes deserialize(JsonObject p_193362_0_)
{
String s = JsonUtils.getString(p_193362_0_, "group", "");
Map<String, Ingredient> map = deserializeKey(JsonUtils.getJsonObject(p_193362_0_, "key"));
String[] astring = shrink(patternFromJson(JsonUtils.getJsonArray(p_193362_0_, "pattern")));
int i = astring[0].length();
int j = astring.length;
NonNullList<Ingredient> nonnulllist = deserializeIngredients(astring, map, i, j);
ItemStack itemstack = deserializeItem(JsonUtils.getJsonObject(p_193362_0_, "result"), true);
return new ShapedRecipes(s, i, j, nonnulllist, itemstack);
}
private static NonNullList<Ingredient> deserializeIngredients(String[] p_192402_0_, Map<String, Ingredient> p_192402_1_, int p_192402_2_, int p_192402_3_)
{
NonNullList<Ingredient> nonnulllist = NonNullList.<Ingredient>withSize(p_192402_2_ * p_192402_3_, Ingredient.EMPTY);
Set<String> set = Sets.newHashSet(p_192402_1_.keySet());
set.remove(" ");
for (int i = 0; i < p_192402_0_.length; ++i)
{
for (int j = 0; j < p_192402_0_[i].length(); ++j)
{
String s = p_192402_0_[i].substring(j, j + 1);
Ingredient ingredient = p_192402_1_.get(s);
if (ingredient == null)
{
throw new JsonSyntaxException("Pattern references symbol '" + s + "' but it's not defined in the key");
}
set.remove(s);
nonnulllist.set(j + p_192402_2_ * i, ingredient);
}
}
if (!set.isEmpty())
{
throw new JsonSyntaxException("Key defines symbols that aren't used in pattern: " + set);
}
else
{
return nonnulllist;
}
}
@VisibleForTesting
static String[] shrink(String... p_194134_0_)
{
int i = Integer.MAX_VALUE;
int j = 0;
int k = 0;
int l = 0;
for (int i1 = 0; i1 < p_194134_0_.length; ++i1)
{
String s = p_194134_0_[i1];
i = Math.min(i, firstNonSpace(s));
int j1 = lastNonSpace(s);
j = Math.max(j, j1);
if (j1 < 0)
{
if (k == i1)
{
++k;
}
++l;
}
else
{
l = 0;
}
}
if (p_194134_0_.length == l)
{
return new String[0];
}
else
{
String[] astring = new String[p_194134_0_.length - l - k];
for (int k1 = 0; k1 < astring.length; ++k1)
{
astring[k1] = p_194134_0_[k1 + k].substring(i, j + 1);
}
return astring;
}
}
private static int firstNonSpace(String str)
{
int i;
for (i = 0; i < str.length() && str.charAt(i) == ' '; ++i)
{
;
}
return i;
}
private static int lastNonSpace(String str)
{
int i;
for (i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; --i)
{
;
}
return i;
}
private static String[] patternFromJson(JsonArray p_192407_0_)
{
String[] astring = new String[p_192407_0_.size()];
if (astring.length > 3)
{
throw new JsonSyntaxException("Invalid pattern: too many rows, 3 is maximum");
}
else if (astring.length == 0)
{
throw new JsonSyntaxException("Invalid pattern: empty pattern not allowed");
}
else
{
for (int i = 0; i < astring.length; ++i)
{
String s = JsonUtils.getString(p_192407_0_.get(i), "pattern[" + i + "]");
if (s.length() > 3)
{
throw new JsonSyntaxException("Invalid pattern: too many columns, 3 is maximum");
}
if (i > 0 && astring[0].length() != s.length())
{
throw new JsonSyntaxException("Invalid pattern: each row must be the same width");
}
astring[i] = s;
}
return astring;
}
}
private static Map<String, Ingredient> deserializeKey(JsonObject p_192408_0_)
{
Map<String, Ingredient> map = Maps.<String, Ingredient>newHashMap();
for (Entry<String, JsonElement> entry : p_192408_0_.entrySet())
{
if (((String)entry.getKey()).length() != 1)
{
throw new JsonSyntaxException("Invalid key entry: '" + (String)entry.getKey() + "' is an invalid symbol (must be 1 character only).");
}
if (" ".equals(entry.getKey()))
{
throw new JsonSyntaxException("Invalid key entry: ' ' is a reserved symbol.");
}
map.put(entry.getKey(), deserializeIngredient(entry.getValue()));
}
map.put(" ", Ingredient.EMPTY);
return map;
}
public static Ingredient deserializeIngredient(@Nullable JsonElement p_193361_0_)
{
if (p_193361_0_ != null && !p_193361_0_.isJsonNull())
{
if (p_193361_0_.isJsonObject())
{
return Ingredient.fromStacks(deserializeItem(p_193361_0_.getAsJsonObject(), false));
}
else if (!p_193361_0_.isJsonArray())
{
throw new JsonSyntaxException("Expected item to be object or array of objects");
}
else
{
JsonArray jsonarray = p_193361_0_.getAsJsonArray();
if (jsonarray.size() == 0)
{
throw new JsonSyntaxException("Item array cannot be empty, at least one item must be defined");
}
else
{
ItemStack[] aitemstack = new ItemStack[jsonarray.size()];
for (int i = 0; i < jsonarray.size(); ++i)
{
aitemstack[i] = deserializeItem(JsonUtils.getJsonObject(jsonarray.get(i), "item"), false);
}
return Ingredient.fromStacks(aitemstack);
}
}
}
else
{
throw new JsonSyntaxException("Item cannot be null");
}
}
public static ItemStack deserializeItem(JsonObject p_192405_0_, boolean useCount)
{
String s = JsonUtils.getString(p_192405_0_, "item");
Item item = Item.REGISTRY.getObject(new ResourceLocation(s));
if (item == null)
{
throw new JsonSyntaxException("Unknown item '" + s + "'");
}
else if (item.getHasSubtypes() && !p_192405_0_.has("data"))
{
throw new JsonParseException("Missing data for item '" + s + "'");
}
else
{
int i = JsonUtils.getInt(p_192405_0_, "data", 0);
int j = useCount ? JsonUtils.getInt(p_192405_0_, "count", 1) : 1;
return new ItemStack(item, j, i);
}
}
//================================================ FORGE START ================================================
@Override
public int getRecipeWidth()
{
return this.getWidth();
}
@Override
public int getRecipeHeight()
{
return this.getHeight();
}
}
How do I make this so that it requires 9 stacks of 64 cobblestone? Despite "count" being set to 64 (meaning 9 full stacks), it works with 1 cobblestone (1 in each of the spots)?
I don't believe Minecraft system takes count into account. You will need to code a custom recipe class that checks count itself and register it.
My Mods:
- Happy Coding -
Thanks for the response. Do you know of an example custom recipe class?
You don't have to create a whole new class per say. For shaped recipes, overriding the Ingredient and its apply(ItemStack) method and have that check for count should be enough.
The same may be true for Shapeless recipes, but I had to do a bit more since my objective for my class was an NBTCheck so that I could use potions with certain effects. Potions don't use metadata, but NBTTag data. For that, first, you would need to override the Ingredient like above. Then you would need to create either a new recipe class, a new class that extends ShapelessRecipe or an anonymous ShapelessRecipe class and in that class override the matches(InventoryCrafting, World) method and have that check for the ItemStack nbt. (Side note: I don't fully understand their method, but, from what I can tell, they convert ShapelessRecipes into bytes or something and that gets rid of the nbt data. I assume it is for performance).
I don't have an example on hand.
My Mods:
- Happy Coding -
Judging by the errors I have been getting earlier, a class implementing IRecipeFactory is also required. I have tried both overriding and copying the ShapedRecipes class (and changing what I need). I have most likely isolated it to a single bool being false by default.
Error: "Class 'com.Markyroson.util.CustomShapedRecipe' is not an IRecipeFactory"
The problem is that the only IRecipeFactory examples I have found are for ores, which does not help me for regular items any.
The offending line in both is
Which I have since changed to
[/i]The override (obviously class would be renamed, I am just trying to get it working).
Complete class copy & alter:
[/i][/i][/i][/i]