Fixes #3040: Cache recipe and revalidate it (#3042)

* Fixes #3040: Cache recipe and revalidate it

This caches the last used recipe instead of only the result. Which
allows to revalidate the crafting grid against the recipe itself before
hitting the CraftingManager again. Therefore avoiding a high performance
hit for recipe lookups, just find the potential same recipe again.

* Remove old recipe lookup as forge provides it now.

* Further optimizations.

These are a bit quick'n'dirty and need a better solution with a full
container/gui refactoring. But for now they provide some great benefits
in terms of performance.
This commit is contained in:
yueh 2017-08-20 21:31:30 +02:00 committed by GitHub
parent d84500c5b7
commit b8e685b1b6
7 changed files with 75 additions and 26 deletions

View file

@ -24,6 +24,7 @@ import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.PlayerInvWrapper;
@ -46,6 +47,7 @@ public class ContainerCraftingTerm extends ContainerMEMonitorable implements IAE
private final AppEngInternalInventory output = new AppEngInternalInventory( this, 1 );
private final SlotCraftingMatrix[] craftingSlots = new SlotCraftingMatrix[9];
private final SlotCraftingTerm outputSlot;
private IRecipe currentRecipe;
public ContainerCraftingTerm( final InventoryPlayer ip, final ITerminalHost monitorable )
{
@ -85,7 +87,21 @@ public class ContainerCraftingTerm extends ContainerMEMonitorable implements IAE
ic.setInventorySlotContents( x, this.craftingSlots[x].getStack() );
}
this.outputSlot.putStack( CraftingManager.findMatchingResult( ic, this.getPlayerInv().player.world ) );
if( this.currentRecipe == null || !this.currentRecipe.matches( ic, this.getPlayerInv().player.world ) )
{
this.currentRecipe = CraftingManager.findMatchingRecipe( ic, this.getPlayerInv().player.world );
}
if( this.currentRecipe == null )
{
this.outputSlot.putStack( ItemStack.EMPTY );
}
else
{
final ItemStack craftingResult = this.currentRecipe.getCraftingResult( ic );
this.outputSlot.putStack( craftingResult );
}
}
@Override
@ -115,4 +131,9 @@ public class ContainerCraftingTerm extends ContainerMEMonitorable implements IAE
{
return true;
}
public IRecipe getCurrentRecipe()
{
return this.currentRecipe;
}
}

View file

@ -391,7 +391,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
ic.setInventorySlotContents( x, packetPatternSlot.pattern[x] == null ? ItemStack.EMPTY : packetPatternSlot.pattern[x].getItemStack() );
}
final IRecipe r = Platform.findMatchingRecipe( ic, p.world );
final IRecipe r = CraftingManager.findMatchingRecipe( ic, p.world );
if( r == null )
{
@ -413,7 +413,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
}
}
final IRecipe rr = Platform.findMatchingRecipe( real, p.world );
final IRecipe rr = CraftingManager.findMatchingRecipe( real, p.world );
if( rr == r && Platform.itemComparisons().isSameItem( rr.getCraftingResult( real ), is ) )
{

View file

@ -24,6 +24,7 @@ import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
import appeng.util.helpers.ItemHandlerUtil;
@ -149,7 +150,7 @@ public class AppEngCraftingSlot extends AppEngSlot
ic.setInventorySlotContents( x, this.craftMatrix.getStackInSlot( x ) );
}
final NonNullList<ItemStack> aitemstack = CraftingManager.getRemainingItems( ic, playerIn.world );
final NonNullList<ItemStack> aitemstack = this.getRemainingItems( ic, playerIn.world );
ItemHandlerUtil.copy( ic, this.craftMatrix, false );
@ -195,4 +196,10 @@ public class AppEngCraftingSlot extends AppEngSlot
return super.decrStackSize( par1 );
}
// TODO: This is really hacky and NEEDS to be solved with a full container/gui refactoring.
protected NonNullList<ItemStack> getRemainingItems( InventoryCrafting ic, World world )
{
return CraftingManager.getRemainingItems( ic, world );
}
}

View file

@ -27,8 +27,11 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
import appeng.api.config.Actionable;
@ -39,6 +42,7 @@ import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.container.ContainerNull;
import appeng.container.implementations.ContainerCraftingTerm;
import appeng.helpers.IContainerCraftingPacket;
import appeng.helpers.InventoryAction;
import appeng.items.storage.ItemViewCell;
@ -153,6 +157,41 @@ public class SlotCraftingTerm extends AppEngCraftingSlot
}
}
// TODO: This is really hacky and NEEDS to be solved with a full container/gui refactoring.
protected IRecipe findRecipe( InventoryCrafting ic, World world )
{
if( this.container instanceof ContainerCraftingTerm )
{
final ContainerCraftingTerm containerTerminal = (ContainerCraftingTerm) this.container;
final IRecipe recipe = containerTerminal.getCurrentRecipe();
if( recipe != null && recipe.matches( ic, world ) )
{
return containerTerminal.getCurrentRecipe();
}
}
return CraftingManager.findMatchingRecipe( ic, world );
}
// TODO: This is really hacky and NEEDS to be solved with a full container/gui refactoring.
@Override
protected NonNullList<ItemStack> getRemainingItems( InventoryCrafting ic, World world )
{
if( this.container instanceof ContainerCraftingTerm )
{
final ContainerCraftingTerm containerTerminal = (ContainerCraftingTerm) this.container;
final IRecipe recipe = containerTerminal.getCurrentRecipe();
if( recipe != null && recipe.matches( ic, world ) )
{
return containerTerminal.getCurrentRecipe().getRemainingItems( ic );
}
}
return CraftingManager.getRemainingItems( ic, world );
}
private int capCraftingAttempts( final int maxTimesToCraft )
{
return maxTimesToCraft;
@ -178,7 +217,7 @@ public class SlotCraftingTerm extends AppEngCraftingSlot
ic.setInventorySlotContents( x, this.getPattern().getStackInSlot( x ) );
}
final IRecipe r = Platform.findMatchingRecipe( ic, p.world );
final IRecipe r = this.findRecipe( ic, p.world );
if( r == null )
{

View file

@ -32,6 +32,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
@ -145,7 +146,7 @@ public class PacketJEIRecipe extends AppEngPacket
}
}
final IRecipe r = Platform.findMatchingRecipe( testInv, pmp.world );
final IRecipe r = CraftingManager.findMatchingRecipe( testInv, pmp.world );
if( r != null && security.hasPermission( player, SecurityPermissions.EXTRACT ) )
{

View file

@ -106,7 +106,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
if( this.isCrafting )
{
this.standardRecipe = Platform.findMatchingRecipe( this.crafting, w );
this.standardRecipe = CraftingManager.findMatchingRecipe( this.crafting, w );
if( this.standardRecipe != null )
{

View file

@ -432,25 +432,6 @@ public class Platform
}
}
/*
* The usual version of this returns an ItemStack, this version returns the recipe.
*/
public static IRecipe findMatchingRecipe( final InventoryCrafting inventoryCrafting, final World par2World )
{
IForgeRegistry<IRecipe> recipes = ForgeRegistries.RECIPES;
final List<IRecipe> rl = recipes.getValues();
for( final IRecipe r : rl )
{
if( r.matches( inventoryCrafting, par2World ) )
{
return r;
}
}
return null;
}
public static ItemStack[] getBlockDrops( final World w, final BlockPos pos )
{
List<ItemStack> out = new ArrayList<>();