From 4d984dc5ee65367ed7358c91239e3174586486d1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 5 Jul 2018 21:19:04 +0100 Subject: [PATCH] Rewrite turtle block destroying - Try to make drop capturing a little more generic. This now allows for capturing a block's drop at a given position, as well as any drop within a bounding box (for things which don't play nicely). - Use as much of Minecraft's block breaking logic as possible, hopefully simplifying things and making it more consistent with other mods. --- .../dan200/computercraft/ComputerCraft.java | 19 +- .../shared/proxy/CCTurtleProxyCommon.java | 164 +++++++++++------- .../shared/proxy/ICCTurtleProxy.java | 9 +- .../turtle/core/TurtlePlaceCommand.java | 4 +- .../shared/turtle/upgrades/TurtleHoe.java | 25 ++- .../shared/turtle/upgrades/TurtleShovel.java | 35 ++-- .../shared/turtle/upgrades/TurtleSword.java | 26 ++- .../shared/turtle/upgrades/TurtleTool.java | 135 +++++++------- .../shared/util/IEntityDropConsumer.java | 16 -- 9 files changed, 221 insertions(+), 212 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/shared/util/IEntityDropConsumer.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 3b1ce7495f..e622106c39 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -48,7 +48,10 @@ import dan200.computercraft.shared.turtle.blocks.BlockTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.upgrades.*; -import dan200.computercraft.shared.util.*; +import dan200.computercraft.shared.util.CreativeTabMain; +import dan200.computercraft.shared.util.IDAssigner; +import dan200.computercraft.shared.util.InventoryUtil; +import dan200.computercraft.shared.util.WorldUtil; import io.netty.buffer.Unpooled; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; @@ -85,6 +88,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -1015,13 +1019,18 @@ public static void addAllUpgradedTurtles( NonNullList list ) turtleProxy.addAllUpgradedTurtles( list ); } - public static void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer ) + public static void setDropConsumer( Entity entity, Consumer consumer ) { - turtleProxy.setEntityDropConsumer( entity, consumer ); + turtleProxy.setDropConsumer( entity, consumer ); } - public static void clearEntityDropConsumer( Entity entity ) + public static void setDropConsumer( World world, BlockPos pos, Consumer consumer ) { - turtleProxy.clearEntityDropConsumer( entity ); + turtleProxy.setDropConsumer( world, pos, consumer ); + } + + public static void clearDropConsumer( ) + { + turtleProxy.clearDropConsumer(); } } diff --git a/src/main/java/dan200/computercraft/shared/proxy/CCTurtleProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/CCTurtleProxyCommon.java index 53e80563a5..54b346432e 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/CCTurtleProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/CCTurtleProxyCommon.java @@ -20,7 +20,6 @@ import dan200.computercraft.shared.turtle.items.TurtleItemFactory; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.turtle.upgrades.*; -import dan200.computercraft.shared.util.IEntityDropConsumer; import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.block.Block; @@ -32,33 +31,47 @@ import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent; +import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.EntityRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.registries.IForgeRegistry; import javax.annotation.Nonnull; -import java.util.*; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; public abstract class CCTurtleProxyCommon implements ICCTurtleProxy -{ +{ private Map m_legacyTurtleUpgrades; private Map m_turtleUpgrades; - private Map m_dropConsumers; + + private Consumer dropConsumer; + private WeakReference dropWorld; + private BlockPos dropPos; + private AxisAlignedBB dropBounds; + private WeakReference dropEntity; public CCTurtleProxyCommon() { m_legacyTurtleUpgrades = new HashMap<>(); m_turtleUpgrades = new HashMap<>(); - m_dropConsumers = new WeakHashMap<>(); } - + // ICCTurtleProxy implementation - - @Override + + @Override public void preInit() { MinecraftForge.EVENT_BUS.register( this ); @@ -74,8 +87,8 @@ public void preInit() // RecipeSorter.register( "computercraft:turtle", TurtleRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" ); // RecipeSorter.register( "computercraft:turtle_upgrade", TurtleUpgradeRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" ); } - - @Override + + @Override public void init() { registerForgeHandlers(); @@ -93,7 +106,7 @@ public void registerTurtleUpgrade( ITurtleUpgrade upgrade ) ComputerCraft.log.error( message ); throw new RuntimeException( message ); } - + // Register registerTurtleUpgradeInternal( upgrade ); } @@ -109,7 +122,7 @@ public ITurtleUpgrade getTurtleUpgrade( int legacyId ) { return m_legacyTurtleUpgrades.get( legacyId ); } - + @Override public ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack stack ) { @@ -125,7 +138,7 @@ public ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack stack ) } catch( Exception e ) { - ComputerCraft.log.error("Error getting computer upgrade item", e); + ComputerCraft.log.error( "Error getting computer upgrade item", e ); } } return null; @@ -147,7 +160,7 @@ public static boolean isUpgradeSuitableForFamily( ComputerFamily family, ITurtle return true; } } - + private void addAllUpgradedTurtles( ComputerFamily family, NonNullList list ) { ItemStack basicStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ); @@ -168,7 +181,7 @@ private void addAllUpgradedTurtles( ComputerFamily family, NonNullList list ) { - if ( isUpgradeSuitableForFamily( family, upgrade ) ) + if( isUpgradeSuitableForFamily( family, upgrade ) ) { ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null ); if( !stack.isEmpty() ) @@ -177,54 +190,58 @@ private void addUpgradedTurtle( ComputerFamily family, ITurtleUpgrade upgrade, L } } } - + @Override public void addAllUpgradedTurtles( NonNullList list ) { addAllUpgradedTurtles( ComputerFamily.Normal, list ); addAllUpgradedTurtles( ComputerFamily.Advanced, list ); } - + @Override - public void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer ) + public void setDropConsumer( Entity entity, Consumer consumer ) { - if( !m_dropConsumers.containsKey( entity ) ) - { - boolean captured = entity.captureDrops; - - if( !captured ) - { - entity.captureDrops = true; - ArrayList items = entity.capturedDrops; - - if( items == null || items.size() == 0 ) - { - m_dropConsumers.put( entity, consumer ); - } - } - } - } - + dropConsumer = consumer; + dropEntity = new WeakReference<>( entity ); + dropWorld = new WeakReference<>( entity.world ); + dropPos = null; + dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); + + entity.captureDrops = true; + } + @Override - public void clearEntityDropConsumer( Entity entity ) + public void setDropConsumer( World world, BlockPos pos, Consumer consumer ) { - if( m_dropConsumers.containsKey( entity ) ) + dropConsumer = consumer; + dropEntity = null; + dropWorld = new WeakReference<>( world ); + dropPos = pos; + dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 ); + } + + @Override + public void clearDropConsumer() + { + if( dropEntity != null ) { - boolean captured = entity.captureDrops; - - if( captured ) + Entity entity = dropEntity.get(); + if( entity != null ) { entity.captureDrops = false; - ArrayList items = entity.capturedDrops; - - if( items != null ) + if( entity.capturedDrops != null ) { - dispatchEntityDrops( entity, items ); - items.clear(); + for( EntityItem entityItem : entity.capturedDrops ) dropConsumer.accept( entityItem.getItem() ); + entity.capturedDrops.clear(); } } - m_dropConsumers.remove( entity ); } + + dropConsumer = null; + dropEntity = null; + dropWorld = null; + dropPos = null; + dropBounds = null; } private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade ) @@ -288,7 +305,7 @@ public void registerItems( RegistryEvent.Register event ) { IForgeRegistry registry = event.getRegistry(); - registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) ); + registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) ); registry.register( new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ) ); registry.register( new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) ); } @@ -361,7 +378,7 @@ public void registerRecipes( RegistryEvent.Register event ) private void registerUpgrades() { // Upgrades - ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 ); + ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 ); registerTurtleUpgradeInternal( ComputerCraft.Upgrades.wirelessModem ); ComputerCraft.Upgrades.craftingTable = new TurtleCraftingTable( 2 ); @@ -446,38 +463,53 @@ private void registerTileEntities() GameRegistry.registerTileEntity( TileTurtleExpanded.class, ComputerCraft.LOWER_ID + " : " + "turtleex" ); GameRegistry.registerTileEntity( TileTurtleAdvanced.class, ComputerCraft.LOWER_ID + " : " + "turtleadv" ); } - + private void registerForgeHandlers() { ForgeHandlers handlers = new ForgeHandlers(); MinecraftForge.EVENT_BUS.register( handlers ); } - - public class ForgeHandlers + + private class ForgeHandlers { - private ForgeHandlers() + @SubscribeEvent + public void onEntityLivingDrops( LivingDropsEvent event ) { + // Capture any mob drops for the current entity + if( dropEntity != null && event.getEntity() == dropEntity.get() ) + { + List drops = event.getDrops(); + for( EntityItem entityItem : drops ) dropConsumer.accept( entityItem.getItem() ); + drops.clear(); + } } - // Forge event responses - @SubscribeEvent - public void onEntityLivingDrops( LivingDropsEvent event ) + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onHarvestDrops( BlockEvent.HarvestDropsEvent event ) { - dispatchEntityDrops( event.getEntity(), event.getDrops() ); + // Capture block drops for the current entity + if( dropWorld != null && dropWorld.get() == event.getWorld() + && dropPos != null && dropPos.equals( event.getPos() ) ) + { + for( ItemStack item : event.getDrops() ) + { + if( event.getWorld().rand.nextFloat() < event.getDropChance() ) dropConsumer.accept( item ); + } + event.getDrops().clear(); + } } - } - - private void dispatchEntityDrops( Entity entity, java.util.List drops ) - { - IEntityDropConsumer consumer = m_dropConsumers.get( entity ); - if( consumer != null ) + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onEntitySpawn( EntityJoinWorldEvent event ) { - // All checks have passed, lets dispatch the drops - for(EntityItem entityItem : drops) + // Capture any nearby item spawns + if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem + && dropBounds.contains( event.getEntity().getPositionVector() ) ) { - consumer.consumeDrop( entity, entityItem.getItem() ); + dropConsumer.accept( ((EntityItem) event.getEntity()).getItem() ); + event.setCanceled( true ); } - drops.clear(); } } + } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ICCTurtleProxy.java b/src/main/java/dan200/computercraft/shared/proxy/ICCTurtleProxy.java index 3baa8db0ac..f2794f75d7 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ICCTurtleProxy.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ICCTurtleProxy.java @@ -7,12 +7,14 @@ package dan200.computercraft.shared.proxy; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.shared.util.IEntityDropConsumer; import net.minecraft.entity.Entity; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import javax.annotation.Nonnull; +import java.util.function.Consumer; public interface ICCTurtleProxy { @@ -25,6 +27,7 @@ public interface ICCTurtleProxy ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item ); void addAllUpgradedTurtles( NonNullList list ); - void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer ); - void clearEntityDropConsumer( Entity entity ); + void setDropConsumer( Entity entity, Consumer consumer ); + void setDropConsumer( World world, BlockPos pos, Consumer consumer ); + void clearDropConsumer(); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 26b1a47801..4918af2780 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -224,7 +224,7 @@ private static ItemStack deployOnEntity( @Nonnull ItemStack stack, final ITurtle // Start claiming entity drops Entity hitEntity = hit.getKey(); Vec3d hitPos = hit.getValue(); - ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) -> + ComputerCraft.setDropConsumer( hitEntity, ( drop ) -> { ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ); if( !remainder.isEmpty() ) @@ -268,7 +268,7 @@ else if( hitEntity instanceof EntityLivingBase ) } // Stop claiming drops - ComputerCraft.clearEntityDropConsumer( hitEntity ); + ComputerCraft.clearDropConsumer(); // Put everything we collected into the turtles inventory, then return ItemStack remainder = turtlePlayer.unloadInventory( turtle ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index 9acd6545d8..241adf4172 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -11,13 +11,14 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -30,20 +31,16 @@ public TurtleHoe( ResourceLocation id, int legacyId, String adjective, Item item } @Override - protected boolean canBreakBlock( World world, BlockPos pos ) + protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { - if( super.canBreakBlock( world, pos ) ) - { - IBlockState state = world.getBlockState( pos ); - Material material = state.getMaterial( ); - return - material == Material.PLANTS || - material == Material.CACTUS || - material == Material.GOURD || - material == Material.LEAVES || - material == Material.VINE; - } - return false; + if( !super.canBreakBlock( state, world, pos, player ) ) return false; + + Material material = state.getMaterial(); + return material == Material.PLANTS || + material == Material.CACTUS || + material == Material.GOURD || + material == Material.LEAVES || + material == Material.VINE; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index 1d814bbb6d..cc85a4ad60 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -11,6 +11,7 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; @@ -30,26 +31,22 @@ public TurtleShovel( ResourceLocation id, int legacyId, String adjective, Item i } @Override - protected boolean canBreakBlock( World world, BlockPos pos ) + protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { - if( super.canBreakBlock( world, pos ) ) - { - IBlockState state = world.getBlockState( pos ); - Material material = state.getMaterial( ); - return - material == Material.GROUND || - material == Material.SAND || - material == Material.SNOW || - material == Material.CLAY || - material == Material.CRAFTED_SNOW || - material == Material.GRASS || - material == Material.PLANTS || - material == Material.CACTUS || - material == Material.GOURD || - material == Material.LEAVES || - material == Material.VINE; - } - return false; + if( !super.canBreakBlock( state, world, pos, player ) ) return false; + + Material material = state.getMaterial(); + return material == Material.GROUND || + material == Material.SAND || + material == Material.SNOW || + material == Material.CLAY || + material == Material.CRAFTED_SNOW || + material == Material.GRASS || + material == Material.PLANTS || + material == Material.CACTUS || + material == Material.GOURD || + material == Material.LEAVES || + material == Material.VINE; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 8164fedabe..28c1b99e93 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -5,11 +5,13 @@ */ package dan200.computercraft.shared.turtle.upgrades; + +import dan200.computercraft.shared.turtle.core.TurtlePlayer; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class TurtleSword extends TurtleTool @@ -20,20 +22,16 @@ public TurtleSword( ResourceLocation id, int legacyId, String adjective, Item it } @Override - protected boolean canBreakBlock( World world, BlockPos pos ) + protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { - if( super.canBreakBlock( world, pos ) ) - { - IBlockState state = world.getBlockState( pos ); - Material material = state.getMaterial( ); - return - material == Material.PLANTS || - material == Material.LEAVES || - material == Material.VINE || - material == Material.CLOTH || - material == Material.WEB; - } - return false; + if( !super.canBreakBlock( state, world, pos, player ) ) return false; + + Material material = state.getMaterial(); + return material == Material.PLANTS || + material == Material.LEAVES || + material == Material.VINE || + material == Material.CLOTH || + material == Material.WEB; } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 4f8738f54a..87036211cd 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -21,21 +21,17 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.item.EntityArmorStand; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.fml.relauncher.Side; @@ -44,7 +40,9 @@ import javax.annotation.Nonnull; import javax.vecmath.Matrix4f; +import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; public class TurtleTool implements ITurtleUpgrade { @@ -103,7 +101,7 @@ public IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull Tur @Nonnull @Override - @SideOnly( Side.CLIENT ) + @SideOnly(Side.CLIENT) public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { float xOffset = (side == TurtleSide.Left) ? -0.40625f : 0.40625f; @@ -141,26 +139,20 @@ public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull Turt } } - protected boolean canBreakBlock( World world, BlockPos pos ) + protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { - IBlockState state = world.getBlockState( pos ); Block block = state.getBlock(); - return !block.isAir( state, world, pos ) && block != Blocks.BEDROCK && state.getBlockHardness( world, pos ) > -1.0F; + return !block.isAir( state, world, pos ) + && block != Blocks.BEDROCK + && state.getPlayerRelativeBlockHardness( player, world, pos ) > 0 + && block.canEntityDestroy( state, world, pos, player ); } - - protected boolean canHarvestBlock( World world, BlockPos pos ) - { - Block block = world.getBlockState( pos ).getBlock(); - TurtlePlayer turtlePlayer = new TurtlePlayer( (WorldServer)world ); - turtlePlayer.loadInventory( m_item.copy() ); - return ForgeHooks.canHarvestBlock( block, turtlePlayer, world, pos ); - } - + protected float getDamageMultiplier() { return 3.0f; } - + private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direction ) { // Create a fake player, and orient it appropriately @@ -180,21 +172,15 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc // Start claiming entity drops Entity hitEntity = hit.getKey(); - ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) -> - { - ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ); - if( !remainder.isEmpty() ) - { - WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() ); - } - } ); + List extra = new ArrayList<>( ); + ComputerCraft.setDropConsumer( hitEntity, turtleDropConsumer( turtle, extra ) ); // Attack the entity boolean attacked = false; if( hitEntity.canBeAttackedWithItem() && !hitEntity.hitByEntity( turtlePlayer ) && !MinecraftForge.EVENT_BUS.post( new AttackEntityEvent( turtlePlayer, hitEntity ) ) ) { - float damage = (float)turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue(); + float damage = (float) turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue(); damage *= getDamageMultiplier(); if( damage > 0.0f ) { @@ -220,7 +206,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc } // Stop claiming drops - ComputerCraft.clearEntityDropConsumer( hitEntity ); + stopConsuming( turtle, extra ); // Put everything we collected into the turtles inventory, then return if( attacked ) @@ -232,68 +218,71 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc return TurtleCommandResult.failure( "Nothing to attack here" ); } - + private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction ) { // Get ready to dig World world = turtle.getWorld(); - BlockPos position = turtle.getPosition(); - BlockPos newPosition = WorldUtil.moveCoords( position, direction ); + BlockPos turtlePosition = turtle.getPosition(); + BlockPos blockPosition = WorldUtil.moveCoords( turtlePosition, direction ); - if( WorldUtil.isBlockInWorld( world, newPosition ) && - !world.isAirBlock( newPosition ) && - !WorldUtil.isLiquidBlock( world, newPosition ) ) + if( WorldUtil.isBlockInWorld( world, blockPosition ) && + !world.isAirBlock( blockPosition ) && + !WorldUtil.isLiquidBlock( world, blockPosition ) ) { - TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction ); + IBlockState state = world.getBlockState( blockPosition ); + + TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); + turtlePlayer.loadInventory( m_item.copy() ); + if( ComputerCraft.turtlesObeyBlockProtection ) { // Check spawn protection - - if( MinecraftForge.EVENT_BUS.post( new BlockEvent.BreakEvent( world, newPosition, world.getBlockState( newPosition ), turtlePlayer ) ) ) + if( MinecraftForge.EVENT_BUS.post( new BlockEvent.BreakEvent( world, blockPosition, world.getBlockState( blockPosition ), turtlePlayer ) ) ) { return TurtleCommandResult.failure( "Cannot break protected block" ); } - - if( !ComputerCraft.isBlockEditable( world, newPosition, turtlePlayer ) ) + + if( !ComputerCraft.isBlockEditable( world, blockPosition, turtlePlayer ) ) { return TurtleCommandResult.failure( "Cannot break protected block" ); } } // Check if we can break the block - if( !canBreakBlock( world, newPosition ) ) + if( !canBreakBlock( state, world, blockPosition, turtlePlayer ) ) { return TurtleCommandResult.failure( "Unbreakable block detected" ); } // Consume the items the block drops - if( canHarvestBlock( world, newPosition ) ) + List extra = new ArrayList<>( ); + ComputerCraft.setDropConsumer( world, blockPosition, turtleDropConsumer( turtle, extra ) ); + + TileEntity tile = world.getTileEntity( blockPosition ); + + // Much of this logic comes from PlayerInteractionManager#tryHarvestBlock, so it's a good idea + // to consult there before making any changes. + + // Play the destruction sound + world.playEvent( 2001, blockPosition, Block.getStateId( state ) ); + + // Destroy the block + boolean canHarvest = state.getBlock().canHarvestBlock( world, blockPosition, turtlePlayer ); + boolean canBreak = state.getBlock().removedByPlayer( state, world, blockPosition, turtlePlayer, canHarvest ); + if( canBreak ) state.getBlock().onBlockDestroyedByPlayer( world, blockPosition, state ); + if( canHarvest ) { - List items = getBlockDropped( world, newPosition, turtlePlayer ); - if( items != null && items.size() > 0 ) - { - for( ItemStack stack : items ) - { - ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); - if( !remainder.isEmpty() ) - { - // If there's no room for the items, drop them - WorldUtil.dropItemStack( remainder, world, position, direction ); - } - } - } + state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() ); } - // Destroy the block - IBlockState previousState = world.getBlockState( newPosition ); - world.playEvent(2001, newPosition, Block.getStateId(previousState)); - world.setBlockToAir( newPosition ); + stopConsuming( turtle, extra ); // Remember the previous block if( turtle instanceof TurtleBrain ) { - TurtleBrain brain = (TurtleBrain)turtle; - brain.saveBlockChange( newPosition, previousState ); + TurtleBrain brain = (TurtleBrain) turtle; + brain.saveBlockChange( blockPosition, state ); } return TurtleCommandResult.success(); @@ -302,21 +291,21 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction ) return TurtleCommandResult.failure( "Nothing to dig here" ); } - private List getBlockDropped( World world, BlockPos pos, EntityPlayer player ) + private Consumer turtleDropConsumer( ITurtleAccess turtle, List extra ) { - IBlockState state = world.getBlockState( pos ); - Block block = state.getBlock(); - NonNullList drops = NonNullList.create(); - block.getDrops( drops, world, pos, world.getBlockState( pos ), 0 ); - double chance = ForgeEventFactory.fireBlockHarvesting( drops, world, pos, state, 0, 1, false, player ); + return ( drop ) -> + { + ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ); + if( !remainder.isEmpty() ) extra.add( remainder ); + }; + } - for( int i = drops.size() - 1; i >= 0; i-- ) + private void stopConsuming( ITurtleAccess turtle, List extra ) + { + ComputerCraft.clearDropConsumer(); + for( ItemStack remainder : extra ) { - if( world.rand.nextFloat() > chance ) - { - drops.remove( i ); - } + WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() ); } - return drops; } } diff --git a/src/main/java/dan200/computercraft/shared/util/IEntityDropConsumer.java b/src/main/java/dan200/computercraft/shared/util/IEntityDropConsumer.java deleted file mode 100644 index f29c9e8fcd..0000000000 --- a/src/main/java/dan200/computercraft/shared/util/IEntityDropConsumer.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.util; -import net.minecraft.entity.Entity; -import net.minecraft.item.ItemStack; - -import javax.annotation.Nonnull; - -public interface IEntityDropConsumer -{ - void consumeDrop( Entity dropper, @Nonnull ItemStack drop ); -}