1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-05-08 10:24:12 +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.turtle.upgrades.TurtleInventoryCrafting;
import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil; import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.List;
public class TurtleCraftCommand implements ITurtleCommand public class TurtleCraftCommand implements ITurtleCommand
{ {
private final int m_limit; private final int limit;
public TurtleCraftCommand( int limit ) public TurtleCraftCommand( int limit )
{ {
m_limit = limit; this.limit = limit;
} }
@Nonnull @Nonnull
@ -34,32 +33,20 @@ public class TurtleCraftCommand implements ITurtleCommand
{ {
// Craft the item // Craft the item
TurtleInventoryCrafting crafting = new TurtleInventoryCrafting( turtle ); TurtleInventoryCrafting crafting = new TurtleInventoryCrafting( turtle );
ArrayList<ItemStack> results = crafting.doCrafting( turtle.getWorld(), m_limit ); List<ItemStack> results = crafting.doCrafting( turtle.getWorld(), limit );
if( results != null ) if( results == null ) return TurtleCommandResult.failure( "No matching recipes" );
// Store or drop any remainders
for( ItemStack stack : results )
{ {
// Store the results ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
for( ItemStack stack : results ) if( !remainder.isEmpty() )
{ {
ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection() );
if( !remainder.isEmpty() )
{
// Drop the remainder
BlockPos position = turtle.getPosition();
WorldUtil.dropItemStack( remainder, turtle.getWorld(), position, turtle.getDirection() );
}
} }
if( !results.isEmpty() )
{
// Animate
turtle.playAnimation( TurtleAnimation.Wait );
}
// Succeed
return TurtleCommandResult.success();
} }
// Fail if( !results.isEmpty() ) turtle.playAnimation( TurtleAnimation.Wait );
return TurtleCommandResult.failure( "No matching recipes" ); return TurtleCommandResult.success();
} }
} }

View File

@ -13,14 +13,20 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.InventoryCrafting; import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.fml.common.FMLCommonHandler;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TurtleInventoryCrafting extends InventoryCrafting public class TurtleInventoryCrafting extends InventoryCrafting
{ {
@ -28,16 +34,19 @@ public class TurtleInventoryCrafting extends InventoryCrafting
private int m_xStart; private int m_xStart;
private int m_yStart; private int m_yStart;
@SuppressWarnings( "ConstantConditions" )
public TurtleInventoryCrafting( ITurtleAccess turtle ) 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 ); super( null, 0, 0 );
m_turtle = turtle; m_turtle = turtle;
m_xStart = 0; m_xStart = 0;
m_yStart = 0; m_yStart = 0;
} }
@Nonnull @Nullable
private ItemStack tryCrafting( int xStart, int yStart ) private IRecipe tryCrafting( int xStart, int yStart )
{ {
m_xStart = xStart; m_xStart = xStart;
m_yStart = yStart; m_yStart = yStart;
@ -52,118 +61,88 @@ public class TurtleInventoryCrafting extends InventoryCrafting
{ {
if( !m_turtle.getInventory().getStackInSlot( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() ) if( !m_turtle.getInventory().getStackInSlot( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() )
{ {
return ItemStack.EMPTY; return null;
} }
} }
} }
} }
// Check the actual crafting // 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) ) if( world.isRemote || !(world instanceof WorldServer) ) return null;
{
return null;
}
// Find out what we can craft // Find out what we can craft
ItemStack result = tryCrafting( 0, 0 ); IRecipe recipe = tryCrafting( 0, 0 );
if( result.isEmpty() ) if( recipe == null ) recipe = tryCrafting( 0, 1 );
{ if( recipe == null ) recipe = tryCrafting( 1, 0 );
result = tryCrafting( 0, 1 ); if( recipe == null ) recipe = tryCrafting( 1, 1 );
} if( recipe == null ) return null;
if( result.isEmpty() )
{
result = tryCrafting( 1, 0 );
}
if( result.isEmpty() )
{
result = tryCrafting( 1, 1 );
}
// Craft it // Special case: craft(0) just returns an empty list if crafting was possible
if( !result.isEmpty() ) 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 ItemStack result = recipe.getCraftingResult( this );
ArrayList<ItemStack> results = new ArrayList<>(); if( result.isEmpty() ) break;
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 );
results.add( result ); results.add( result );
// Consume resources from the inventory result.onCrafting( world, player, result.getCount() );
NonNullList<ItemStack> remainingItems = CraftingManager.getRemainingItems( this, world ); FMLCommonHandler.instance().firePlayerCraftingEvent( player, result, this );
for( int n = 0; n < size; n++ )
{
ItemStack stack = getStackInSlot( n );
if( !stack.isEmpty() )
{
decrStackSize( n, numToCraft );
ItemStack replacement = remainingItems.get( n ); ForgeHooks.setCraftingPlayer( player );
if( !replacement.isEmpty() ) NonNullList<ItemStack> remainders = recipe.getRemainingItems( this );
{ ForgeHooks.setCraftingPlayer( null );
if( !(replacement.isItemStackDamageable() && replacement.getItemDamage() >= replacement.getMaxDamage()) )
{ for( int slot = 0; slot < remainders.size(); slot++ )
replacement.setCount( Math.min( numToCraft, replacement.getMaxStackSize() ) ); {
if( getStackInSlot( n ).isEmpty() ) ItemStack existing = getStackInSlot( slot );
{ ItemStack remainder = remainders.get( slot );
setInventorySlotContents( n, replacement );
} if( !existing.isEmpty() )
else {
{ decrStackSize( slot, 1 );
results.add( replacement ); 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 @Nonnull
@Override @Override
public ItemStack getStackInRowAndColumn( int x, int y ) public ItemStack getStackInRowAndColumn( int x, int y )
{ {
if( x >= 0 && x < getWidth() && y >= 0 && y < getHeight() ) return x >= 0 && x < getWidth() && y >= 0 && y < getHeight()
{ ? getStackInSlot( x + y * getWidth() )
return getStackInSlot( x + y * getWidth() ); : ItemStack.EMPTY;
}
return ItemStack.EMPTY;
} }
@Override @Override
@ -182,12 +161,9 @@ public class TurtleInventoryCrafting extends InventoryCrafting
{ {
int x = m_xStart + index % getWidth(); int x = m_xStart + index % getWidth();
int y = m_yStart + index / getHeight(); int y = m_yStart + index / getHeight();
if( x >= 0 && x < TileTurtle.INVENTORY_WIDTH && return x >= 0 && x < TileTurtle.INVENTORY_WIDTH && y >= 0 && y < TileTurtle.INVENTORY_HEIGHT
y >= 0 && y < TileTurtle.INVENTORY_HEIGHT ) ? x + y * TileTurtle.INVENTORY_WIDTH
{ : -1;
return x + y * TileTurtle.INVENTORY_WIDTH;
}
return -1;
} }
// IInventory implementation // IInventory implementation