Add class to wrap IItemHandler as IInventory for easier recipe interaction. (#5522)

This commit is contained in:
Brennan Ward authored and LexManos committed 2019-03-25 12:31:54 -07:00
1 parent 5fa732d223
commit 36470f69ad
3 files changed
+190 -5

No files matched your search

@@ -28,6 +28,7 @@ import javax.annotation.Nullable;
import com.google.common.collect.Maps;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.resources.IResourceManager;
@@ -36,24 +37,42 @@ import net.minecraft.util.NonNullList;
import net.minecraft.world.World;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.crafting.RecipeType;
import net.minecraftforge.items.wrapper.RecipeWrapper;
@SuppressWarnings("deprecation")
public abstract class ForgeRecipeManager implements IResourceManagerReloadListener
{
/**
* Master list of sorted recipes.
*/
protected final Map<RecipeType<? extends IRecipe>, List<? extends IRecipe>> sortedRecipes = Maps.newHashMap();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
public void onResourceManagerReload(IResourceManager resourceManager)
{
this.sortedRecipes.clear();
CraftingHelper.reloadConstants(resourceManager);
}
/**
* Returns all the recipes that match this type.
* @param type A recipe type.
* @return All recipes that are of the passed type. This list may be empty.
*/
@SuppressWarnings("unchecked")
public <T extends IRecipe> List<T> getRecipes(RecipeType<T> type)
{
return (List<T>) this.sortedRecipes.computeIfAbsent(type, t -> new ArrayList<>());
}
/**
* Automatically returns a result from the first recipe that matches this inv and type.
* Modders should probably not use this, and instead use {@link #getRecipe(IInventory, World, RecipeType)} since you get the recipe object itself.
* @param input An inventory.
* @param world The world.
* @param type The type of recipe to match against.
* @return The output of the first matching recipe, or {@link ItemStack#EMPTY} if no recipes match.
*/
public ItemStack getResult(IInventory input, World world, RecipeType<?> type)
{
for(IRecipe irecipe : getRecipes(type))
@@ -61,7 +80,16 @@ public abstract class ForgeRecipeManager implements IResourceManagerReloadListen
return ItemStack.EMPTY;
}
@Nullable
/**
* Used to find a matching recipe for the given inv, world, and type.
* Since this requires an IInventory, modders can use {@link RecipeWrapper} to avoid direct implementation.
* For crafting recipes, it is advised to still use {@link InventoryCrafting}. The dynamic vanilla recipes require they be crafted in one.
* @param input An inventory.
* @param world The world.
* @param type The type of recipe to match against.
* @return The first matching recipe.
*/
@Nullable
public <T extends IRecipe> T getRecipe(IInventory input, World world, RecipeType<T> type)
{
for(T irecipe : getRecipes(type))
@@ -71,7 +99,9 @@ public abstract class ForgeRecipeManager implements IResourceManagerReloadListen
/**
* Modders should not use this if possible. In the context that this is used, you should already have the recipe. Do not run extra lookups using this method.
* Use {@link IRecipe#getRemainingItems(IInventory)}.
*/
@Deprecated
public NonNullList<ItemStack> getRemainingItems(IInventory input, World world, RecipeType<?> type)
{
for(IRecipe irecipe : getRecipes(type))
@@ -19,8 +19,6 @@
package net.minecraftforge.common.extensions;
import java.util.Collection;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.common.crafting.RecipeType;
import net.minecraftforge.common.crafting.VanillaRecipeTypes;
@@ -28,7 +26,7 @@ import net.minecraftforge.common.crafting.VanillaRecipeTypes;
public interface IForgeRecipe {
/**
* Used when sorting this recipe into it's category during load, and in the default type matcher below.
* Used when sorting this recipe into it's category during load. This type determines what class the recipe must subclass.
* @return The type of this recipe.
*/
default RecipeType<? extends IRecipe> getType()
@@ -0,0 +1,157 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.items.wrapper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.items.IItemHandlerModifiable;
public class RecipeWrapper implements IInventory {
protected final IItemHandlerModifiable inv;
protected final int width;
protected final int height;
public RecipeWrapper(IItemHandlerModifiable inv, int width, int height)
{
this.inv = inv;
this.width = width;
this.height = height;
}
/**
* Returns the size of this inventory. Must be equivalent to {@link #getHeight()} * {@link #getWidth()}.
*/
@Override
public int getSizeInventory()
{
return getHeight() * getWidth();
}
/**
* Returns the stack in this slot. This stack should be a modifiable reference, not a copy of a stack in your inventory.
*/
@Override
public ItemStack getStackInSlot(int slot)
{
return inv.getStackInSlot(slot);
}
/**
* Attempts to remove n items from the specified slot. Returns the split stack that was removed. Modifies the inventory.
*/
@Override
public ItemStack decrStackSize(int slot, int count)
{
ItemStack stack = inv.getStackInSlot(slot);
return stack.isEmpty() ? ItemStack.EMPTY : stack.split(count);
}
/**
* Sets the contents of this slot to the provided stack.
*/
@Override
public void setInventorySlotContents(int slot, ItemStack stack)
{
inv.setStackInSlot(slot, stack);
}
/**
* Returns the height of this inventory.
*/
@Override
public int getHeight()
{
return height;
}
/**
* Returns the width of this inventory.
*/
@Override
public int getWidth()
{
return width;
}
/**
* Removes the stack contained in this slot from the underlying handler, and returns it.
*/
@Override
public ItemStack removeStackFromSlot(int index)
{
ItemStack s = getStackInSlot(index);
if(s.isEmpty()) return ItemStack.EMPTY;
setInventorySlotContents(index, ItemStack.EMPTY);
return s;
}
@Override
public boolean isEmpty()
{
for(int i = 0; i < inv.getSlots(); i++)
{
if(!inv.getStackInSlot(i).isEmpty()) return false;
}
return true;
}
@Override
public boolean isItemValidForSlot(int slot, ItemStack stack)
{
return inv.isItemValid(slot, stack);
}
@Override
public void clear()
{
for(int i = 0; i < inv.getSlots(); i++)
{
inv.setStackInSlot(i, ItemStack.EMPTY);
}
}
//The following methods are never used by vanilla in crafting. They are defunct as mods need not override them.
@Override
public int getInventoryStackLimit() { return 0; }
@Override
public void markDirty() {}
@Override
public boolean isUsableByPlayer(EntityPlayer player) { return false; }
@Override
public void openInventory(EntityPlayer player) {}
@Override
public void closeInventory(EntityPlayer player) {}
@Override
public int getField(int id) { return 0; }
@Override
public void setField(int id, int value) {}
@Override
public int getFieldCount() { return 0; }
@Override
public ITextComponent getName() { return null; }
@Override
public boolean hasCustomName() { return false; }
@Override
public ITextComponent getCustomName() { return null; }
}