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:
parent
173ea72001
commit
9bf586b018
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user