1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-23 13:43:22 +00:00

Make turtle crafting more consistent with vanilla

- Fire all the appropriate Forge hooks
 - Crafting will now attempt to craft one item at a time in a loop,
   instead of multiplying the resulting stack by the number of crafts.
   This means we function as expected on recipes which consume
   durability instead.
 - Cache the recipe between crafting and getting the remainder (and each
   craft loop). This should reduce any performance hit we would
   otherwise get.
This commit is contained in:
SquidDev 2019-03-30 16:12:49 +00:00
parent 173ea72001
commit 9bf586b018
2 changed files with 83 additions and 120 deletions

View File

@ -14,18 +14,17 @@
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
public class TurtleCraftCommand implements ITurtleCommand
{
private final int m_limit;
private final int limit;
public TurtleCraftCommand( int limit )
{
m_limit = limit;
this.limit = limit;
}
@Nonnull
@ -34,32 +33,20 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
{
// Craft the item
TurtleInventoryCrafting crafting = new TurtleInventoryCrafting( turtle );
ArrayList<ItemStack> results = crafting.doCrafting( turtle.getWorld(), m_limit );
if( results != null )
List<ItemStack> results = crafting.doCrafting( turtle.getWorld(), limit );
if( results == null ) return TurtleCommandResult.failure( "No matching recipes" );
// Store or drop any remainders
for( ItemStack stack : results )
{
// Store the results
for( ItemStack stack : results )
ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
{
ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
{
// Drop the remainder
BlockPos position = turtle.getPosition();
WorldUtil.dropItemStack( remainder, turtle.getWorld(), position, turtle.getDirection() );
}
WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection() );
}
if( !results.isEmpty() )
{
// Animate
turtle.playAnimation( TurtleAnimation.Wait );
}
// Succeed
return TurtleCommandResult.success();
}
// Fail
return TurtleCommandResult.failure( "No matching recipes" );
if( !results.isEmpty() ) turtle.playAnimation( TurtleAnimation.Wait );
return TurtleCommandResult.success();
}
}

View File

@ -13,14 +13,20 @@
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.util.NonNullList;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.fml.common.FMLCommonHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TurtleInventoryCrafting extends InventoryCrafting
{
@ -28,16 +34,19 @@ public class TurtleInventoryCrafting extends InventoryCrafting
private int m_xStart;
private int m_yStart;
@SuppressWarnings( "ConstantConditions" )
public TurtleInventoryCrafting( ITurtleAccess turtle )
{
// Passing null in here is evil, but we don't have a container present. We override most methods in order to
// avoid throwing any NPEs.
super( null, 0, 0 );
m_turtle = turtle;
m_xStart = 0;
m_yStart = 0;
}
@Nonnull
private ItemStack tryCrafting( int xStart, int yStart )
@Nullable
private IRecipe tryCrafting( int xStart, int yStart )
{
m_xStart = xStart;
m_yStart = yStart;
@ -52,118 +61,88 @@ private ItemStack tryCrafting( int xStart, int yStart )
{
if( !m_turtle.getInventory().getStackInSlot( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() )
{
return ItemStack.EMPTY;
return null;
}
}
}
}
// Check the actual crafting
return CraftingManager.findMatchingResult( this, m_turtle.getWorld() );
return CraftingManager.findMatchingRecipe( this, m_turtle.getWorld() );
}
public ArrayList<ItemStack> doCrafting( World world, int maxCount )
@Nullable
public List<ItemStack> doCrafting( World world, int maxCount )
{
if( world.isRemote || !(world instanceof WorldServer) )
{
return null;
}
if( world.isRemote || !(world instanceof WorldServer) ) return null;
// Find out what we can craft
ItemStack result = tryCrafting( 0, 0 );
if( result.isEmpty() )
{
result = tryCrafting( 0, 1 );
}
if( result.isEmpty() )
{
result = tryCrafting( 1, 0 );
}
if( result.isEmpty() )
{
result = tryCrafting( 1, 1 );
}
IRecipe recipe = tryCrafting( 0, 0 );
if( recipe == null ) recipe = tryCrafting( 0, 1 );
if( recipe == null ) recipe = tryCrafting( 1, 0 );
if( recipe == null ) recipe = tryCrafting( 1, 1 );
if( recipe == null ) return null;
// Craft it
if( !result.isEmpty() )
// Special case: craft(0) just returns an empty list if crafting was possible
if( maxCount == 0 ) return Collections.emptyList();
TurtlePlayer player = TurtlePlayer.get( m_turtle );
ArrayList<ItemStack> results = new ArrayList<>();
for( int i = 0; i < maxCount && recipe.matches( this, world ); i++ )
{
// Special case: craft(0) just returns an empty list if crafting was possible
ArrayList<ItemStack> results = new ArrayList<>();
if( maxCount == 0 )
{
return results;
}
// Find out how many we can craft
int numToCraft = 1;
int size = getSizeInventory();
if( maxCount > 1 )
{
int minStackSize = 0;
for( int n = 0; n < size; n++ )
{
ItemStack stack = getStackInSlot( n );
if( !stack.isEmpty() && (minStackSize == 0 || minStackSize > stack.getCount()) )
{
minStackSize = stack.getCount();
}
}
if( minStackSize > 1 )
{
numToCraft = Math.min( minStackSize, result.getMaxStackSize() / result.getCount() );
numToCraft = Math.min( numToCraft, maxCount );
result.setCount( result.getCount() * numToCraft );
}
}
// Do post-pickup stuff
TurtlePlayer turtlePlayer = TurtlePlayer.get( m_turtle );
result.onCrafting( world, turtlePlayer, numToCraft );
ItemStack result = recipe.getCraftingResult( this );
if( result.isEmpty() ) break;
results.add( result );
// Consume resources from the inventory
NonNullList<ItemStack> remainingItems = CraftingManager.getRemainingItems( this, world );
for( int n = 0; n < size; n++ )
{
ItemStack stack = getStackInSlot( n );
if( !stack.isEmpty() )
{
decrStackSize( n, numToCraft );
result.onCrafting( world, player, result.getCount() );
FMLCommonHandler.instance().firePlayerCraftingEvent( player, result, this );
ItemStack replacement = remainingItems.get( n );
if( !replacement.isEmpty() )
{
if( !(replacement.isItemStackDamageable() && replacement.getItemDamage() >= replacement.getMaxDamage()) )
{
replacement.setCount( Math.min( numToCraft, replacement.getMaxStackSize() ) );
if( getStackInSlot( n ).isEmpty() )
{
setInventorySlotContents( n, replacement );
}
else
{
results.add( replacement );
}
}
}
ForgeHooks.setCraftingPlayer( player );
NonNullList<ItemStack> remainders = recipe.getRemainingItems( this );
ForgeHooks.setCraftingPlayer( null );
for( int slot = 0; slot < remainders.size(); slot++ )
{
ItemStack existing = getStackInSlot( slot );
ItemStack remainder = remainders.get( slot );
if( !existing.isEmpty() )
{
decrStackSize( slot, 1 );
existing = getStackInSlot( slot );
}
if( remainder.isEmpty() ) continue;
// Either update the current stack or add it to the remainder list (to be inserted into the inventory
// afterwards).
if( existing.isEmpty() )
{
setInventorySlotContents( slot, remainder );
}
else if( ItemStack.areItemsEqual( existing, remainder ) && ItemStack.areItemStackTagsEqual( existing, remainder ) )
{
remainder.grow( existing.getCount() );
setInventorySlotContents( slot, remainder );
}
else
{
results.add( remainder );
}
}
return results;
}
return null;
return results;
}
@Nonnull
@Override
public ItemStack getStackInRowAndColumn( int x, int y )
{
if( x >= 0 && x < getWidth() && y >= 0 && y < getHeight() )
{
return getStackInSlot( x + y * getWidth() );
}
return ItemStack.EMPTY;
return x >= 0 && x < getWidth() && y >= 0 && y < getHeight()
? getStackInSlot( x + y * getWidth() )
: ItemStack.EMPTY;
}
@Override
@ -182,12 +161,9 @@ private int modifyIndex( int index )
{
int x = m_xStart + index % getWidth();
int y = m_yStart + index / getHeight();
if( x >= 0 && x < TileTurtle.INVENTORY_WIDTH &&
y >= 0 && y < TileTurtle.INVENTORY_HEIGHT )
{
return x + y * TileTurtle.INVENTORY_WIDTH;
}
return -1;
return x >= 0 && x < TileTurtle.INVENTORY_WIDTH && y >= 0 && y < TileTurtle.INVENTORY_HEIGHT
? x + y * TileTurtle.INVENTORY_WIDTH
: -1;
}
// IInventory implementation