mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	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.
This commit is contained in:
		| @@ -48,7 +48,10 @@ import dan200.computercraft.shared.proxy.IComputerCraftProxy; | ||||
| 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.ArrayList; | ||||
| 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 class ComputerCraft | ||||
|         turtleProxy.addAllUpgradedTurtles( list ); | ||||
|     } | ||||
|  | ||||
|     public static void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer ) | ||||
|     public static void setDropConsumer( Entity entity, Consumer<ItemStack> consumer ) | ||||
|     { | ||||
|         turtleProxy.setEntityDropConsumer( entity, consumer ); | ||||
|         turtleProxy.setDropConsumer( entity, consumer ); | ||||
|     } | ||||
|  | ||||
|     public static void clearEntityDropConsumer( Entity entity ) | ||||
|     public static void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer ) | ||||
|     { | ||||
|         turtleProxy.clearEntityDropConsumer( entity ); | ||||
|         turtleProxy.setDropConsumer( world, pos, consumer ); | ||||
|     } | ||||
|  | ||||
|     public static void clearDropConsumer( ) | ||||
|     { | ||||
|         turtleProxy.clearDropConsumer(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,6 @@ import dan200.computercraft.shared.turtle.items.ItemTurtleNormal; | ||||
| 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,28 +31,42 @@ import net.minecraft.item.ItemStack; | ||||
| 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<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades; | ||||
|     private Map<String, ITurtleUpgrade> m_turtleUpgrades; | ||||
|     private Map<Entity, IEntityDropConsumer> m_dropConsumers; | ||||
|  | ||||
|     private Consumer<ItemStack> dropConsumer; | ||||
|     private WeakReference<World> dropWorld; | ||||
|     private BlockPos dropPos; | ||||
|     private AxisAlignedBB dropBounds; | ||||
|     private WeakReference<Entity> dropEntity; | ||||
|  | ||||
|     public CCTurtleProxyCommon() | ||||
|     { | ||||
|         m_legacyTurtleUpgrades = new HashMap<>(); | ||||
|         m_turtleUpgrades = new HashMap<>(); | ||||
|         m_dropConsumers = new WeakHashMap<>(); | ||||
|     } | ||||
|  | ||||
|     // ICCTurtleProxy implementation | ||||
| @@ -125,7 +138,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy | ||||
|             } | ||||
|             catch( Exception e ) | ||||
|             { | ||||
|                 ComputerCraft.log.error("Error getting computer upgrade item", e); | ||||
|                 ComputerCraft.log.error( "Error getting computer upgrade item", e ); | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
| @@ -168,7 +181,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy | ||||
|  | ||||
|     private void addUpgradedTurtle( ComputerFamily family, ITurtleUpgrade upgrade, List<ItemStack> list ) | ||||
|     { | ||||
|         if ( isUpgradeSuitableForFamily( family, upgrade ) ) | ||||
|         if( isUpgradeSuitableForFamily( family, upgrade ) ) | ||||
|         { | ||||
|             ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null ); | ||||
|             if( !stack.isEmpty() ) | ||||
| @@ -186,45 +199,49 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer ) | ||||
|     public void setDropConsumer( Entity entity, Consumer<ItemStack> consumer ) | ||||
|     { | ||||
|         if( !m_dropConsumers.containsKey( entity ) ) | ||||
|         { | ||||
|             boolean captured = entity.captureDrops; | ||||
|         dropConsumer = consumer; | ||||
|         dropEntity = new WeakReference<>( entity ); | ||||
|         dropWorld = new WeakReference<>( entity.world ); | ||||
|         dropPos = null; | ||||
|         dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); | ||||
|  | ||||
|             if( !captured ) | ||||
|             { | ||||
|         entity.captureDrops = true; | ||||
|                 ArrayList<EntityItem> items = entity.capturedDrops; | ||||
|                  | ||||
|                 if( items == null || items.size() == 0 ) | ||||
|                 { | ||||
|                     m_dropConsumers.put( entity, consumer ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void clearEntityDropConsumer( Entity entity ) | ||||
|     public void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer ) | ||||
|     { | ||||
|         if( m_dropConsumers.containsKey( entity ) ) | ||||
|         { | ||||
|             boolean captured = entity.captureDrops; | ||||
|         dropConsumer = consumer; | ||||
|         dropEntity = null; | ||||
|         dropWorld = new WeakReference<>( world ); | ||||
|         dropPos = pos; | ||||
|         dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 ); | ||||
|     } | ||||
|  | ||||
|             if( captured ) | ||||
|     @Override | ||||
|     public void clearDropConsumer() | ||||
|     { | ||||
|         if( dropEntity != null ) | ||||
|         { | ||||
|             Entity entity = dropEntity.get(); | ||||
|             if( entity != null ) | ||||
|             { | ||||
|                 entity.captureDrops = false; | ||||
|                 ArrayList<EntityItem> 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 abstract class CCTurtleProxyCommon implements ICCTurtleProxy | ||||
|     { | ||||
|         IForgeRegistry<Item> 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" ) ) ); | ||||
|     } | ||||
| @@ -453,31 +470,46 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy | ||||
|         MinecraftForge.EVENT_BUS.register( handlers ); | ||||
|     } | ||||
|  | ||||
|     public class ForgeHandlers | ||||
|     private class ForgeHandlers | ||||
|     { | ||||
|         private ForgeHandlers() | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         // Forge event responses  | ||||
|         @SubscribeEvent | ||||
|         public void onEntityLivingDrops( LivingDropsEvent event ) | ||||
|         { | ||||
|             dispatchEntityDrops( event.getEntity(), event.getDrops() ); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private void dispatchEntityDrops( Entity entity, java.util.List<EntityItem> drops ) | ||||
|             // Capture any mob drops for the current entity | ||||
|             if( dropEntity != null && event.getEntity() == dropEntity.get() ) | ||||
|             { | ||||
|         IEntityDropConsumer consumer = m_dropConsumers.get( entity ); | ||||
|         if( consumer != null ) | ||||
|         { | ||||
|             // All checks have passed, lets dispatch the drops | ||||
|             for(EntityItem entityItem : drops) | ||||
|             { | ||||
|                 consumer.consumeDrop( entity, entityItem.getItem() ); | ||||
|             } | ||||
|                 List<EntityItem> drops = event.getDrops(); | ||||
|                 for( EntityItem entityItem : drops ) dropConsumer.accept( entityItem.getItem() ); | ||||
|                 drops.clear(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @SubscribeEvent(priority = EventPriority.LOWEST) | ||||
|         public void onHarvestDrops( BlockEvent.HarvestDropsEvent event ) | ||||
|         { | ||||
|             // 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(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @SubscribeEvent(priority = EventPriority.LOWEST) | ||||
|         public void onEntitySpawn( EntityJoinWorldEvent event ) | ||||
|         { | ||||
|             // Capture any nearby item spawns | ||||
|             if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem | ||||
|                 && dropBounds.contains( event.getEntity().getPositionVector() ) ) | ||||
|             { | ||||
|                 dropConsumer.accept( ((EntityItem) event.getEntity()).getItem() ); | ||||
|                 event.setCanceled( true ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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<ItemStack> list ); | ||||
|  | ||||
|     void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer ); | ||||
|     void clearEntityDropConsumer( Entity entity ); | ||||
|     void setDropConsumer( Entity entity, Consumer<ItemStack> consumer ); | ||||
|     void setDropConsumer( World world, BlockPos pos, Consumer<ItemStack> consumer ); | ||||
|     void clearDropConsumer(); | ||||
| } | ||||
|   | ||||
| @@ -224,7 +224,7 @@ public class TurtlePlaceCommand implements ITurtleCommand | ||||
|         // 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 @@ public class TurtlePlaceCommand implements ITurtleCommand | ||||
|         } | ||||
|  | ||||
|         // Stop claiming drops | ||||
|         ComputerCraft.clearEntityDropConsumer( hitEntity ); | ||||
|         ComputerCraft.clearDropConsumer(); | ||||
|  | ||||
|         // Put everything we collected into the turtles inventory, then return | ||||
|         ItemStack remainder = turtlePlayer.unloadInventory( turtle ); | ||||
|   | ||||
| @@ -11,13 +11,14 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; | ||||
| 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,21 +31,17 @@ public class TurtleHoe extends TurtleTool | ||||
|     } | ||||
|  | ||||
|     @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 || | ||||
|         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; | ||||
|     } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; | ||||
| 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,14 +31,12 @@ public class TurtleShovel extends TurtleTool | ||||
|     } | ||||
|  | ||||
|     @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 || | ||||
|         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 || | ||||
| @@ -49,8 +48,6 @@ public class TurtleShovel extends TurtleTool | ||||
|             material == Material.LEAVES || | ||||
|             material == Material.VINE; | ||||
|     } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|   | ||||
| @@ -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,21 +22,17 @@ public class TurtleSword extends TurtleTool | ||||
|     } | ||||
|  | ||||
|     @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 || | ||||
|         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; | ||||
|     } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected float getDamageMultiplier() | ||||
|   | ||||
| @@ -21,21 +21,17 @@ import net.minecraft.client.renderer.block.model.IBakedModel; | ||||
| 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 org.apache.commons.lang3.tuple.Pair; | ||||
|  | ||||
| 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 class TurtleTool implements ITurtleUpgrade | ||||
|  | ||||
|     @Nonnull | ||||
|     @Override | ||||
|     @SideOnly( Side.CLIENT ) | ||||
|     @SideOnly(Side.CLIENT) | ||||
|     public Pair<IBakedModel, Matrix4f> getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) | ||||
|     { | ||||
|         float xOffset = (side == TurtleSide.Left) ? -0.40625f : 0.40625f; | ||||
| @@ -141,19 +139,13 @@ public class TurtleTool implements ITurtleUpgrade | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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; | ||||
|     } | ||||
|      | ||||
|     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 ); | ||||
|         return !block.isAir( state, world, pos ) | ||||
|             && block != Blocks.BEDROCK | ||||
|             && state.getPlayerRelativeBlockHardness( player, world, pos ) > 0 | ||||
|             && block.canEntityDestroy( state, world, pos, player ); | ||||
|     } | ||||
|  | ||||
|     protected float getDamageMultiplier() | ||||
| @@ -180,21 +172,15 @@ public class TurtleTool implements ITurtleUpgrade | ||||
|  | ||||
|             // 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<ItemStack> 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 @@ public class TurtleTool implements ITurtleUpgrade | ||||
|             } | ||||
|  | ||||
|             // Stop claiming drops | ||||
|             ComputerCraft.clearEntityDropConsumer( hitEntity ); | ||||
|             stopConsuming( turtle, extra ); | ||||
|  | ||||
|             // Put everything we collected into the turtles inventory, then return | ||||
|             if( attacked ) | ||||
| @@ -237,63 +223,66 @@ public class TurtleTool implements ITurtleUpgrade | ||||
|     { | ||||
|         // 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<ItemStack> 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 ); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             List<ItemStack> 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 | ||||
|             IBlockState previousState = world.getBlockState( newPosition ); | ||||
|             world.playEvent(2001, newPosition, Block.getStateId(previousState)); | ||||
|             world.setBlockToAir( newPosition ); | ||||
|             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 ) | ||||
|             { | ||||
|                 state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() ); | ||||
|             } | ||||
|  | ||||
|             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 @@ public class TurtleTool implements ITurtleUpgrade | ||||
|         return TurtleCommandResult.failure( "Nothing to dig here" ); | ||||
|     } | ||||
|  | ||||
|     private List<ItemStack> getBlockDropped( World world, BlockPos pos, EntityPlayer player ) | ||||
|     private Consumer<ItemStack> turtleDropConsumer( ITurtleAccess turtle, List<ItemStack> extra ) | ||||
|     { | ||||
|         IBlockState state = world.getBlockState( pos ); | ||||
|         Block block = state.getBlock(); | ||||
|         NonNullList<ItemStack> 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<ItemStack> extra ) | ||||
|     { | ||||
|             if( world.rand.nextFloat() > chance ) | ||||
|         ComputerCraft.clearDropConsumer(); | ||||
|         for( ItemStack remainder : extra ) | ||||
|         { | ||||
|                 drops.remove( i ); | ||||
|             WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() ); | ||||
|         } | ||||
|     } | ||||
|         return drops; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 ); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 SquidDev
					SquidDev