1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-13 11:40:29 +00:00

Merge pull request #65 from apemanzilla/fix/drop-consumer-overflow

Prevent stack overflows when using turtle.place() with a full inventory
This commit is contained in:
SquidDev 2018-08-23 08:04:07 +01:00 committed by GitHub
commit 9428bee316
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 43 deletions

View File

@ -98,7 +98,7 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Function;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@ -1125,18 +1125,18 @@ public class ComputerCraft
turtleProxy.addAllUpgradedTurtles( 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 ); 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 ); turtleProxy.setDropConsumer( world, pos, consumer );
} }
public static void clearDropConsumer( ) public static List<ItemStack> clearDropConsumer( )
{ {
turtleProxy.clearDropConsumer(); return turtleProxy.clearDropConsumer();
} }
} }

View File

@ -48,17 +48,19 @@ import net.minecraftforge.registries.IForgeRegistry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Function;
public abstract class CCTurtleProxyCommon implements ICCTurtleProxy public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{ {
private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades; private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades;
private Map<String, ITurtleUpgrade> m_turtleUpgrades; private Map<String, ITurtleUpgrade> m_turtleUpgrades;
private Consumer<ItemStack> dropConsumer; private Function<ItemStack, ItemStack> dropConsumer;
private List<ItemStack> remainingDrops;
private WeakReference<World> dropWorld; private WeakReference<World> dropWorld;
private BlockPos dropPos; private BlockPos dropPos;
private AxisAlignedBB dropBounds; private AxisAlignedBB dropBounds;
@ -200,9 +202,10 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
} }
@Override @Override
public void setDropConsumer( Entity entity, Consumer<ItemStack> consumer ) public void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
{ {
dropConsumer = consumer; dropConsumer = consumer;
remainingDrops = new ArrayList<>();
dropEntity = new WeakReference<>( entity ); dropEntity = new WeakReference<>( entity );
dropWorld = new WeakReference<>( entity.world ); dropWorld = new WeakReference<>( entity.world );
dropPos = null; dropPos = null;
@ -212,9 +215,10 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
} }
@Override @Override
public void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer ) public void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
{ {
dropConsumer = consumer; dropConsumer = consumer;
remainingDrops = new ArrayList<>();
dropEntity = null; dropEntity = null;
dropWorld = new WeakReference<>( world ); dropWorld = new WeakReference<>( world );
dropPos = pos; dropPos = pos;
@ -222,7 +226,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
} }
@Override @Override
public void clearDropConsumer() public List<ItemStack> clearDropConsumer()
{ {
if( dropEntity != null ) if( dropEntity != null )
{ {
@ -232,17 +236,22 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
entity.captureDrops = false; entity.captureDrops = false;
if( entity.capturedDrops != null ) if( entity.capturedDrops != null )
{ {
for( EntityItem entityItem : entity.capturedDrops ) dropConsumer.accept( entityItem.getItem() ); for( EntityItem entityItem : entity.capturedDrops ) handleDrops( entityItem.getItem() );
entity.capturedDrops.clear(); entity.capturedDrops.clear();
} }
} }
} }
List<ItemStack> remainingStacks = remainingDrops;
dropConsumer = null; dropConsumer = null;
remainingDrops = null;
dropEntity = null; dropEntity = null;
dropWorld = null; dropWorld = null;
dropPos = null; dropPos = null;
dropBounds = null; dropBounds = null;
return remainingStacks;
} }
private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade ) private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade )
@ -471,6 +480,12 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
MinecraftForge.EVENT_BUS.register( handlers ); MinecraftForge.EVENT_BUS.register( handlers );
} }
private void handleDrops(ItemStack stack)
{
ItemStack remaining = dropConsumer.apply(stack);
if (!remaining.isEmpty()) remainingDrops.add(remaining);
}
private class ForgeHandlers private class ForgeHandlers
{ {
@SubscribeEvent(priority = EventPriority.LOWEST) @SubscribeEvent(priority = EventPriority.LOWEST)
@ -480,7 +495,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
if( dropEntity != null && event.getEntity() == dropEntity.get() ) if( dropEntity != null && event.getEntity() == dropEntity.get() )
{ {
List<EntityItem> drops = event.getDrops(); List<EntityItem> drops = event.getDrops();
for( EntityItem entityItem : drops ) dropConsumer.accept( entityItem.getItem() ); for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() );
drops.clear(); drops.clear();
} }
} }
@ -494,7 +509,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{ {
for( ItemStack item : event.getDrops() ) 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(); event.getDrops().clear();
} }
@ -507,7 +522,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem
&& dropBounds.contains( event.getEntity().getPositionVector() ) ) && dropBounds.contains( event.getEntity().getPositionVector() ) )
{ {
dropConsumer.accept( ((EntityItem) event.getEntity()).getItem() ); handleDrops( ((EntityItem) event.getEntity()).getItem() );
event.setCanceled( true ); event.setCanceled( true );
} }
} }

View File

@ -14,7 +14,9 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
public interface ICCTurtleProxy public interface ICCTurtleProxy
{ {
@ -27,7 +29,7 @@ public interface ICCTurtleProxy
ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item ); ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item );
void addAllUpgradedTurtles( NonNullList<ItemStack> list ); void addAllUpgradedTurtles( NonNullList<ItemStack> list );
void setDropConsumer( Entity entity, Consumer<ItemStack> consumer ); void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer );
void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer ); void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer );
void clearDropConsumer(); List<ItemStack> clearDropConsumer();
} }

View File

@ -30,7 +30,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
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.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent;
@ -38,6 +37,7 @@ import net.minecraftforge.fml.common.eventhandler.Event;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.List;
public class TurtlePlaceCommand implements ITurtleCommand public class TurtlePlaceCommand implements ITurtleCommand
{ {
@ -241,14 +241,10 @@ public class TurtlePlaceCommand implements ITurtleCommand
// Start claiming entity drops // Start claiming entity drops
Entity hitEntity = hit.getKey(); Entity hitEntity = hit.getKey();
Vec3d hitPos = hit.getValue(); Vec3d hitPos = hit.getValue();
ComputerCraft.setDropConsumer( hitEntity, ( drop ) -> ComputerCraft.setDropConsumer(
{ hitEntity,
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ); drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() )
if( !remainder.isEmpty() ) );
{
WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
}
} );
// Place on the entity // Place on the entity
boolean placed = false; boolean placed = false;
@ -285,7 +281,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
} }
// Stop claiming drops // 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 // Put everything we collected into the turtles inventory, then return
ItemStack remainder = turtlePlayer.unloadInventory( turtle ); ItemStack remainder = turtlePlayer.unloadInventory( turtle );

View File

@ -42,9 +42,8 @@ import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f; import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Function;
public class TurtleTool implements ITurtleUpgrade public class TurtleTool implements ITurtleUpgrade
{ {
@ -187,8 +186,7 @@ public class TurtleTool implements ITurtleUpgrade
} }
// Start claiming entity drops // Start claiming entity drops
List<ItemStack> extra = new ArrayList<>(); ComputerCraft.setDropConsumer( hitEntity, turtleDropConsumer( turtle ) );
ComputerCraft.setDropConsumer( hitEntity, turtleDropConsumer( turtle, extra ) );
// Attack the entity // Attack the entity
boolean attacked = false; boolean attacked = false;
@ -220,7 +218,7 @@ public class TurtleTool implements ITurtleUpgrade
} }
// Stop claiming drops // Stop claiming drops
stopConsuming( turtle, extra ); stopConsuming( turtle );
// Put everything we collected into the turtles inventory, then return // Put everything we collected into the turtles inventory, then return
if( attacked ) if( attacked )
@ -277,8 +275,7 @@ public class TurtleTool implements ITurtleUpgrade
} }
// Consume the items the block drops // Consume the items the block drops
List<ItemStack> extra = new ArrayList<>(); ComputerCraft.setDropConsumer( world, blockPosition, turtleDropConsumer( turtle ) );
ComputerCraft.setDropConsumer( world, blockPosition, turtleDropConsumer( turtle, extra ) );
TileEntity tile = world.getTileEntity( blockPosition ); TileEntity tile = world.getTileEntity( blockPosition );
@ -297,7 +294,7 @@ public class TurtleTool implements ITurtleUpgrade
state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() ); state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() );
} }
stopConsuming( turtle, extra ); stopConsuming( turtle );
// Remember the previous block // Remember the previous block
if( turtle instanceof TurtleBrain ) if( turtle instanceof TurtleBrain )
@ -312,18 +309,14 @@ public class TurtleTool implements ITurtleUpgrade
return TurtleCommandResult.failure( "Nothing to dig here" ); 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 ) -> return drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() ) extra.add( remainder );
};
} }
private void stopConsuming( ITurtleAccess turtle, List<ItemStack> extra ) private void stopConsuming( ITurtleAccess turtle )
{ {
ComputerCraft.clearDropConsumer(); List<ItemStack> extra = ComputerCraft.clearDropConsumer();
for( ItemStack remainder : extra ) for( ItemStack remainder : extra )
{ {
WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() ); WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() );