mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-13 03:30:29 +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.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 class TurtleCraftCommand implements ITurtleCommand
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,20 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
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 @@ public class TurtleInventoryCrafting extends InventoryCrafting
|
||||
{
|
||||
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 @@ public class TurtleInventoryCrafting extends InventoryCrafting
|
||||
{
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user