Permalink
Browse files

Prevent stack overflows when using turtle.place() with a full inventory

  • Loading branch information...
apemanzilla authored and SquidDev committed Aug 22, 2018
1 parent 4d984dc commit 5f57733ee76ab6d51ebea577f6bdbba62911ef31
@@ -88,7 +88,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -1019,18 +1019,18 @@ public static void addAllUpgradedTurtles( NonNullList<ItemStack> list )
turtleProxy.addAllUpgradedTurtles( list );
}
public static void setDropConsumer( Entity entity, Consumer<ItemStack> consumer )
public static void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
{
turtleProxy.setDropConsumer( entity, consumer );
}
public static void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer )
public static void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
{
turtleProxy.setDropConsumer( world, pos, consumer );
}
public static void clearDropConsumer( )
public static List<ItemStack> clearDropConsumer( )
{
turtleProxy.clearDropConsumer();
return turtleProxy.clearDropConsumer();
}
}
@@ -47,17 +47,19 @@
import javax.annotation.Nonnull;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades;
private Map<String, ITurtleUpgrade> m_turtleUpgrades;
private Consumer<ItemStack> dropConsumer;
private Function<ItemStack, ItemStack> dropConsumer;
private List<ItemStack> remainingDrops;
private WeakReference<World> dropWorld;
private BlockPos dropPos;
private AxisAlignedBB dropBounds;
@@ -199,9 +201,10 @@ public void addAllUpgradedTurtles( NonNullList<ItemStack> list )
}
@Override
public void setDropConsumer( Entity entity, Consumer<ItemStack> consumer )
public void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
{
dropConsumer = consumer;
remainingDrops = new ArrayList<>();
dropEntity = new WeakReference<>( entity );
dropWorld = new WeakReference<>( entity.world );
dropPos = null;
@@ -211,17 +214,18 @@ public void setDropConsumer( Entity entity, Consumer<ItemStack> consumer )
}
@Override
public void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer )
public void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
{
dropConsumer = consumer;
remainingDrops = new ArrayList<>();
dropEntity = null;
dropWorld = new WeakReference<>( world );
dropPos = pos;
dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 );
}
@Override
public void clearDropConsumer()
public List<ItemStack> clearDropConsumer()
{
if( dropEntity != null )
{
@@ -231,17 +235,22 @@ public void clearDropConsumer()
entity.captureDrops = false;
if( entity.capturedDrops != null )
{
for( EntityItem entityItem : entity.capturedDrops ) dropConsumer.accept( entityItem.getItem() );
for( EntityItem entityItem : entity.capturedDrops ) handleDrops( entityItem.getItem() );
entity.capturedDrops.clear();
}
}
}
List<ItemStack> remainingStacks = remainingDrops;
dropConsumer = null;
remainingDrops = null;
dropEntity = null;
dropWorld = null;
dropPos = null;
dropBounds = null;
return remainingStacks;
}
private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade )
@@ -470,6 +479,12 @@ private void registerForgeHandlers()
MinecraftForge.EVENT_BUS.register( handlers );
}
private void handleDrops(ItemStack stack)
{
ItemStack remaining = dropConsumer.apply(stack);
if (!remaining.isEmpty()) remainingDrops.add(remaining);
}
private class ForgeHandlers
{
@SubscribeEvent
@@ -479,7 +494,7 @@ public void onEntityLivingDrops( LivingDropsEvent event )
if( dropEntity != null && event.getEntity() == dropEntity.get() )
{
List<EntityItem> drops = event.getDrops();
for( EntityItem entityItem : drops ) dropConsumer.accept( entityItem.getItem() );
for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() );
drops.clear();
}
}
@@ -493,7 +508,7 @@ public void onHarvestDrops( BlockEvent.HarvestDropsEvent event )
{
for( ItemStack item : event.getDrops() )
{
if( event.getWorld().rand.nextFloat() < event.getDropChance() ) dropConsumer.accept( item );
if( event.getWorld().rand.nextFloat() < event.getDropChance() ) handleDrops( item );
}
event.getDrops().clear();
}
@@ -506,7 +521,7 @@ public void onEntitySpawn( EntityJoinWorldEvent event )
if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem
&& dropBounds.contains( event.getEntity().getPositionVector() ) )
{
dropConsumer.accept( ((EntityItem) event.getEntity()).getItem() );
handleDrops( ((EntityItem) event.getEntity()).getItem() );
event.setCanceled( true );
}
}
@@ -14,7 +14,8 @@
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.function.Consumer;
import java.util.List;
import java.util.function.Function;
public interface ICCTurtleProxy
{
@@ -27,7 +28,7 @@
ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item );
void addAllUpgradedTurtles( NonNullList<ItemStack> list );
void setDropConsumer( Entity entity, Consumer<ItemStack> consumer );
void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer );
void clearDropConsumer();
void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer );
void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer );
List<ItemStack> clearDropConsumer();
}
@@ -36,6 +36,7 @@
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import java.util.List;
public class TurtlePlaceCommand implements ITurtleCommand
{
@@ -224,14 +225,10 @@ private static ItemStack deployOnEntity( @Nonnull ItemStack stack, final ITurtle
// Start claiming entity drops
Entity hitEntity = hit.getKey();
Vec3d hitPos = hit.getValue();
ComputerCraft.setDropConsumer( hitEntity, ( drop ) ->
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
{
WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
}
} );
ComputerCraft.setDropConsumer(
hitEntity,
drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() )
);
// Place on the entity
boolean placed = false;
@@ -268,7 +265,11 @@ else if( hitEntity instanceof EntityLivingBase )
}
// Stop claiming drops
ComputerCraft.clearDropConsumer();
List<ItemStack> remainingDrops = ComputerCraft.clearDropConsumer();
for( ItemStack remaining : remainingDrops )
{
WorldUtil.dropItemStack( remaining, world, position, turtle.getDirection().getOpposite() );
}
// Put everything we collected into the turtles inventory, then return
ItemStack remainder = turtlePlayer.unloadInventory( turtle );
@@ -40,9 +40,8 @@
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
public class TurtleTool implements ITurtleUpgrade
{
@@ -172,8 +171,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc
// Start claiming entity drops
Entity hitEntity = hit.getKey();
List<ItemStack> extra = new ArrayList<>( );
ComputerCraft.setDropConsumer( hitEntity, turtleDropConsumer( turtle, extra ) );
ComputerCraft.setDropConsumer( hitEntity, turtleDropConsumer( turtle ) );
// Attack the entity
boolean attacked = false;
@@ -206,7 +204,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc
}
// Stop claiming drops
stopConsuming( turtle, extra );
stopConsuming( turtle );
// Put everything we collected into the turtles inventory, then return
if( attacked )
@@ -256,8 +254,7 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction )
}
// Consume the items the block drops
List<ItemStack> extra = new ArrayList<>( );
ComputerCraft.setDropConsumer( world, blockPosition, turtleDropConsumer( turtle, extra ) );
ComputerCraft.setDropConsumer( world, blockPosition, turtleDropConsumer( turtle ) );
TileEntity tile = world.getTileEntity( blockPosition );
@@ -276,7 +273,7 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction )
state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() );
}
stopConsuming( turtle, extra );
stopConsuming( turtle );
// Remember the previous block
if( turtle instanceof TurtleBrain )
@@ -291,18 +288,14 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction )
return TurtleCommandResult.failure( "Nothing to dig here" );
}
private Consumer<ItemStack> turtleDropConsumer( ITurtleAccess turtle, List<ItemStack> extra )
private Function<ItemStack, ItemStack> turtleDropConsumer( ITurtleAccess turtle )
{
return ( drop ) ->
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() ) extra.add( remainder );
};
return drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
}
private void stopConsuming( ITurtleAccess turtle, List<ItemStack> extra )
private void stopConsuming( ITurtleAccess turtle )
{
ComputerCraft.clearDropConsumer();
List<ItemStack> extra = ComputerCraft.clearDropConsumer();
for( ItemStack remainder : extra )
{
WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() );

0 comments on commit 5f57733

Please sign in to comment.