--- ../src-base/minecraft/net/minecraft/block/Block.java +++ ../src-work/minecraft/net/minecraft/block/Block.java @@ -52,11 +52,12 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class Block +public class Block extends net.minecraftforge.fml.common.registry.IForgeRegistryEntry.Impl { private static final ResourceLocation field_176230_a = new ResourceLocation("air"); - public static final RegistryNamespacedDefaultedByKey field_149771_c = new RegistryNamespacedDefaultedByKey(field_176230_a); - public static final ObjectIntIdentityMap field_176229_d = new ObjectIntIdentityMap(); + public static final RegistryNamespacedDefaultedByKey field_149771_c = net.minecraftforge.fml.common.registry.GameData.getBlockRegistry(); + @Deprecated //Modders: DO NOT use this! Use GameRegistry + public static final ObjectIntIdentityMap field_176229_d = net.minecraftforge.fml.common.registry.GameData.getBlockStateIDMap(); public static final AxisAlignedBB field_185505_j = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D); @Nullable public static final AxisAlignedBB field_185506_k = null; @@ -319,7 +320,7 @@ public boolean func_176200_f(IBlockAccess p_176200_1_, BlockPos p_176200_2_) { - return false; + return p_176200_1_.func_180495_p(p_176200_2_).func_185904_a().func_76222_j(); } public Block func_149711_c(float p_149711_1_) @@ -357,9 +358,10 @@ return this.field_149789_z; } + @Deprecated //Forge: New State sensitive version. public boolean func_149716_u() { - return this.field_149758_A; + return hasTileEntity(func_176223_P()); } @Deprecated @@ -372,13 +374,13 @@ @SideOnly(Side.CLIENT) public int func_185484_c(IBlockState p_185484_1_, IBlockAccess p_185484_2_, BlockPos p_185484_3_) { - int i = p_185484_2_.func_175626_b(p_185484_3_, p_185484_1_.func_185906_d()); + int i = p_185484_2_.func_175626_b(p_185484_3_, p_185484_1_.getLightValue(p_185484_2_, p_185484_3_)); if (i == 0 && p_185484_1_.func_177230_c() instanceof BlockSlab) { p_185484_3_ = p_185484_3_.func_177977_b(); p_185484_1_ = p_185484_2_.func_180495_p(p_185484_3_); - return p_185484_2_.func_175626_b(p_185484_3_, p_185484_1_.func_185906_d()); + return p_185484_2_.func_175626_b(p_185484_3_, p_185484_1_.getLightValue(p_185484_2_, p_185484_3_)); } else { @@ -442,7 +444,7 @@ } } - return !p_176225_2_.func_180495_p(p_176225_3_.func_177972_a(p_176225_4_)).func_185914_p(); + return !p_176225_2_.func_180495_p(p_176225_3_.func_177972_a(p_176225_4_)).doesSideBlockRendering(p_176225_2_, p_176225_3_.func_177972_a(p_176225_4_), p_176225_4_.func_176734_d()); } @Deprecated @@ -534,6 +536,10 @@ public void func_180663_b(World p_180663_1_, BlockPos p_180663_2_, IBlockState p_180663_3_) { + if (hasTileEntity(p_180663_3_) && !(this instanceof BlockContainer)) + { + p_180663_1_.func_175713_t(p_180663_2_); + } } public int func_149745_a(Random p_149745_1_) @@ -549,16 +555,7 @@ @Deprecated public float func_180647_a(IBlockState p_180647_1_, EntityPlayer p_180647_2_, World p_180647_3_, BlockPos p_180647_4_) { - float f = p_180647_1_.func_185887_b(p_180647_3_, p_180647_4_); - - if (f < 0.0F) - { - return 0.0F; - } - else - { - return !p_180647_2_.func_184823_b(p_180647_1_) ? p_180647_2_.func_184813_a(p_180647_1_) / f / 100.0F : p_180647_2_.func_184813_a(p_180647_1_) / f / 30.0F; - } + return net.minecraftforge.common.ForgeHooks.blockStrength(p_180647_1_, p_180647_2_, p_180647_3_, p_180647_4_); } public final void func_176226_b(World p_176226_1_, BlockPos p_176226_2_, IBlockState p_176226_3_, int p_176226_4_) @@ -568,20 +565,17 @@ public void func_180653_a(World p_180653_1_, BlockPos p_180653_2_, IBlockState p_180653_3_, float p_180653_4_, int p_180653_5_) { - if (!p_180653_1_.field_72995_K) + if (!p_180653_1_.field_72995_K && !p_180653_1_.restoringBlockSnapshots) // do not drop items while restoring blockstates, prevents item dupe { - int i = this.func_149679_a(p_180653_5_, p_180653_1_.field_73012_v); + List items = NonNullList.func_191196_a(); + items.addAll(getDrops(p_180653_1_, p_180653_2_, p_180653_3_, p_180653_5_)); + p_180653_4_ = net.minecraftforge.event.ForgeEventFactory.fireBlockHarvesting(items, p_180653_1_, p_180653_2_, p_180653_3_, p_180653_5_, p_180653_4_, false, harvesters.get()); - for (int j = 0; j < i; ++j) + for (ItemStack item : items) { if (p_180653_1_.field_73012_v.nextFloat() <= p_180653_4_) { - Item item = this.func_180660_a(p_180653_3_, p_180653_1_.field_73012_v, p_180653_5_); - - if (item != Items.field_190931_a) - { - func_180635_a(p_180653_1_, p_180653_2_, new ItemStack(item, 1, this.func_180651_a(p_180653_3_))); - } + func_180635_a(p_180653_1_, p_180653_2_, item); } } } @@ -589,8 +583,13 @@ public static void func_180635_a(World p_180635_0_, BlockPos p_180635_1_, ItemStack p_180635_2_) { - if (!p_180635_0_.field_72995_K && !p_180635_2_.func_190926_b() && p_180635_0_.func_82736_K().func_82766_b("doTileDrops")) + if (!p_180635_0_.field_72995_K && !p_180635_2_.func_190926_b() && p_180635_0_.func_82736_K().func_82766_b("doTileDrops")&& !p_180635_0_.restoringBlockSnapshots) // do not drop items while restoring blockstates, prevents item dupe { + if (captureDrops.get()) + { + capturedDrops.get().add(p_180635_2_); + return; + } float f = 0.5F; double d0 = (double)(p_180635_0_.field_73012_v.nextFloat() * 0.5F) + 0.25D; double d1 = (double)(p_180635_0_.field_73012_v.nextFloat() * 0.5F) + 0.25D; @@ -619,6 +618,7 @@ return 0; } + @Deprecated //Forge: State sensitive version public float func_149638_a(Entity p_149638_1_) { return this.field_149781_w / 5.0F; @@ -657,7 +657,7 @@ public boolean func_176196_c(World p_176196_1_, BlockPos p_176196_2_) { - return p_176196_1_.func_180495_p(p_176196_2_).func_177230_c().field_149764_J.func_76222_j(); + return p_176196_1_.func_180495_p(p_176196_2_).func_177230_c().func_176200_f(p_176196_1_, p_176196_2_); } public boolean func_180639_a(World p_180639_1_, BlockPos p_180639_2_, IBlockState p_180639_3_, EntityPlayer p_180639_4_, EnumHand p_180639_5_, EnumFacing p_180639_6_, float p_180639_7_, float p_180639_8_, float p_180639_9_) @@ -669,6 +669,8 @@ { } + // Forge: use getStateForPlacement + @Deprecated public IBlockState func_180642_a(World p_180642_1_, BlockPos p_180642_2_, EnumFacing p_180642_3_, float p_180642_4_, float p_180642_5_, float p_180642_6_, int p_180642_7_, EntityLivingBase p_180642_8_) { return this.func_176203_a(p_180642_7_); @@ -710,21 +712,35 @@ p_180657_2_.func_71029_a(StatList.func_188055_a(this)); p_180657_2_.func_71020_j(0.005F); - if (this.func_149700_E() && EnchantmentHelper.func_77506_a(Enchantments.field_185306_r, p_180657_6_) > 0) + if (this.canSilkHarvest(p_180657_1_, p_180657_3_, p_180657_4_, p_180657_2_) && EnchantmentHelper.func_77506_a(Enchantments.field_185306_r, p_180657_6_) > 0) { + java.util.List items = new java.util.ArrayList(); ItemStack itemstack = this.func_180643_i(p_180657_4_); - func_180635_a(p_180657_1_, p_180657_3_, itemstack); + + if (!itemstack.func_190926_b()) + { + items.add(itemstack); + } + + net.minecraftforge.event.ForgeEventFactory.fireBlockHarvesting(items, p_180657_1_, p_180657_3_, p_180657_4_, 0, 1.0f, true, p_180657_2_); + for (ItemStack item : items) + { + func_180635_a(p_180657_1_, p_180657_3_, item); + } } else { + harvesters.set(p_180657_2_); int i = EnchantmentHelper.func_77506_a(Enchantments.field_185308_t, p_180657_6_); this.func_176226_b(p_180657_1_, p_180657_3_, p_180657_4_, i); + harvesters.set(null); } } + @Deprecated //Forge: State sensitive version protected boolean func_149700_E() { - return this.func_176223_P().func_185917_h() && !this.field_149758_A; + return this.func_176223_P().func_185917_h() && !this.hasTileEntity(silk_check_state.get()); } protected ItemStack func_180643_i(IBlockState p_180643_1_) @@ -810,6 +826,7 @@ p_176216_2_.field_70181_x = 0.0D; } + @Deprecated // Forge: Use more sensitive version below: getPickBlock public ItemStack func_185473_a(World p_185473_1_, BlockPos p_185473_2_, IBlockState p_185473_3_) { return new ItemStack(Item.func_150898_a(this), 1, this.func_180651_a(p_185473_3_)); @@ -921,6 +938,7 @@ } } + @Deprecated // Forge - World/state/pos/entity sensitive version below public SoundType func_185467_w() { return this.field_149762_H; @@ -936,6 +954,1216 @@ { } + /* ======================================== FORGE START =====================================*/ + //For ForgeInternal use Only! + protected ThreadLocal harvesters = new ThreadLocal(); + private ThreadLocal silk_check_state = new ThreadLocal(); + protected static java.util.Random RANDOM = new java.util.Random(); // Useful for random things without a seed. + /** + * Get a light value for the block at the specified coordinates, normal ranges are between 0 and 15 + * + * @param state Block state + * @param world The current world + * @param pos Block position in world + * @return The light value + */ + public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos) + { + IBlockState other = world.func_180495_p(pos); + if (other.func_177230_c() != this) + { + return other.getLightValue(world, pos); + } + return state.func_185906_d(); + } + + /** + * Checks if a player or entity can use this block to 'climb' like a ladder. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param entity The entity trying to use the ladder, CAN be null. + * @return True if the block should act like a ladder + */ + public boolean isLadder(IBlockState state, IBlockAccess world, BlockPos pos, EntityLivingBase entity) { return false; } + + /** + * Return true if the block is a normal, solid cube. This + * determines indirect power state, entity ejection from blocks, and a few + * others. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return True if the block is a full cube + */ + public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) + { + return state.func_185915_l(); + } + + /** + * Check if the face of a block should block rendering. + * + * Faces which are fully opaque should return true, faces with transparency + * or faces which do not span the full size of the block should return false. + * + * @param state The current block state + * @param world The current world + * @param pos Block position in world + * @param face The side to check + * @return True if the block is opaque on the specified side. + */ + public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) + { + return state.func_185914_p(); + } + + /** + * Checks if the block is a solid face on the given side, used by placement logic. + * + * @param base_state The base state, getActualState should be called first + * @param world The current world + * @param pos Block position in world + * @param side The side to check + * @return True if the block is solid on the specified side. + */ + @Deprecated //Use IBlockState.func_193401_d + public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side) + { + if (base_state.func_185896_q() && side == EnumFacing.UP) // Short circuit to vanilla function if its true + return true; + + if (this instanceof BlockSlab) + { + IBlockState state = this.func_176221_a(base_state, world, pos); + return base_state.func_185913_b() + || (state.func_177229_b(BlockSlab.field_176554_a) == BlockSlab.EnumBlockHalf.TOP && side == EnumFacing.UP ) + || (state.func_177229_b(BlockSlab.field_176554_a) == BlockSlab.EnumBlockHalf.BOTTOM && side == EnumFacing.DOWN); + } + else if (this instanceof BlockFarmland) + { + return (side != EnumFacing.DOWN && side != EnumFacing.UP); + } + else if (this instanceof BlockStairs) + { + IBlockState state = this.func_176221_a(base_state, world, pos); + boolean flipped = state.func_177229_b(BlockStairs.field_176308_b) == BlockStairs.EnumHalf.TOP; + BlockStairs.EnumShape shape = (BlockStairs.EnumShape)state.func_177229_b(BlockStairs.field_176310_M); + EnumFacing facing = (EnumFacing)state.func_177229_b(BlockStairs.field_176309_a); + if (side == EnumFacing.UP) return flipped; + if (side == EnumFacing.DOWN) return !flipped; + if (facing == side) return true; + if (flipped) + { + if (shape == BlockStairs.EnumShape.INNER_LEFT ) return side == facing.func_176735_f(); + if (shape == BlockStairs.EnumShape.INNER_RIGHT) return side == facing.func_176746_e(); + } + else + { + if (shape == BlockStairs.EnumShape.INNER_LEFT ) return side == facing.func_176746_e(); + if (shape == BlockStairs.EnumShape.INNER_RIGHT) return side == facing.func_176735_f(); + } + return false; + } + else if (this instanceof BlockSnow) + { + IBlockState state = this.func_176221_a(base_state, world, pos); + return ((Integer)state.func_177229_b(BlockSnow.field_176315_a)) >= 8; + } + else if (this instanceof BlockHopper && side == EnumFacing.UP) + { + return true; + } + else if (this instanceof BlockCompressedPowered) + { + return true; + } + return isNormalCube(base_state, world, pos); + } + + /** + * Determines if this block should set fire and deal fire damage + * to entities coming into contact with it. + * + * @param world The current world + * @param pos Block position in world + * @return True if the block should deal damage + */ + public boolean isBurning(IBlockAccess world, BlockPos pos) + { + return false; + } + + /** + * Determines this block should be treated as an air block + * by the rest of the code. This method is primarily + * useful for creating pure logic-blocks that will be invisible + * to the player and otherwise interact as air would. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return True if the block considered air + */ + public boolean isAir(IBlockState state, IBlockAccess world, BlockPos pos) + { + return state.func_185904_a() == Material.field_151579_a; + } + + /** + * Determines if the player can harvest this block, obtaining it's drops when the block is destroyed. + * + * @param player The player damaging the block + * @param pos The block's current position + * @return True to spawn the drops + */ + public boolean canHarvestBlock(IBlockAccess world, BlockPos pos, EntityPlayer player) + { + return net.minecraftforge.common.ForgeHooks.canHarvestBlock(this, player, world, pos); + } + + /** + * Called when a player removes a block. This is responsible for + * actually destroying the block, and the block is intact at time of call. + * This is called regardless of whether the player can harvest the block or + * not. + * + * Return true if the block is actually destroyed. + * + * Note: When used in multiplayer, this is called on both client and + * server sides! + * + * @param state The current state. + * @param world The current world + * @param player The player damaging the block, may be null + * @param pos Block position in world + * @param willHarvest True if Block.harvestBlock will be called after this, if the return in true. + * Can be useful to delay the destruction of tile entities till after harvestBlock + * @return True if the block is actually destroyed. + */ + public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) + { + this.func_176208_a(world, pos, state, player); + return world.func_180501_a(pos, net.minecraft.init.Blocks.field_150350_a.func_176223_P(), world.field_72995_K ? 11 : 3); + } + + /** + * Chance that fire will spread and consume this block. + * 300 being a 100% chance, 0, being a 0% chance. + * + * @param world The current world + * @param pos Block position in world + * @param face The face that the fire is coming from + * @return A number ranging from 0 to 300 relating used to determine if the block will be consumed by fire + */ + public int getFlammability(IBlockAccess world, BlockPos pos, EnumFacing face) + { + return net.minecraft.init.Blocks.field_150480_ab.func_176532_c(this); + } + + /** + * Called when fire is updating, checks if a block face can catch fire. + * + * + * @param world The current world + * @param pos Block position in world + * @param face The face that the fire is coming from + * @return True if the face can be on fire, false otherwise. + */ + public boolean isFlammable(IBlockAccess world, BlockPos pos, EnumFacing face) + { + return getFlammability(world, pos, face) > 0; + } + + /** + * Called when fire is updating on a neighbor block. + * The higher the number returned, the faster fire will spread around this block. + * + * @param world The current world + * @param pos Block position in world + * @param face The face that the fire is coming from + * @return A number that is used to determine the speed of fire growth around the block + */ + public int getFireSpreadSpeed(IBlockAccess world, BlockPos pos, EnumFacing face) + { + return net.minecraft.init.Blocks.field_150480_ab.func_176534_d(this); + } + + /** + * Currently only called by fire when it is on top of this block. + * Returning true will prevent the fire from naturally dying during updating. + * Also prevents firing from dying from rain. + * + * @param world The current world + * @param pos Block position in world + * @param side The face that the fire is coming from + * @return True if this block sustains fire, meaning it will never go out. + */ + public boolean isFireSource(World world, BlockPos pos, EnumFacing side) + { + if (side != EnumFacing.UP) + return false; + if (this == Blocks.field_150424_aL || this == Blocks.field_189877_df) + return true; + if ((world.field_73011_w instanceof net.minecraft.world.WorldProviderEnd) && this == Blocks.field_150357_h) + return true; + return false; + } + + private boolean isTileProvider = this instanceof ITileEntityProvider; + /** + * Called throughout the code as a replacement for block instanceof BlockContainer + * Moving this to the Block base class allows for mods that wish to extend vanilla + * blocks, and also want to have a tile entity on that block, may. + * + * Return true from this function to specify this block has a tile entity. + * + * @param state State of the current block + * @return True if block has a tile entity, false otherwise + */ + public boolean hasTileEntity(IBlockState state) + { + return isTileProvider; + } + + /** + * Called throughout the code as a replacement for ITileEntityProvider.createNewTileEntity + * Return the same thing you would from that function. + * This will fall back to ITileEntityProvider.createNewTileEntity(World) if this block is a ITileEntityProvider + * + * @param state The state of the current block + * @return A instance of a class extending TileEntity + */ + @Nullable + public TileEntity createTileEntity(World world, IBlockState state) + { + if (isTileProvider) + { + return ((ITileEntityProvider)this).func_149915_a(world, func_176201_c(state)); + } + return null; + } + + /** + * State and fortune sensitive version, this replaces the old (int meta, Random rand) + * version in 1.1. + * + * @param state Current state + * @param fortune Current item fortune level + * @param random Random number generator + * @return The number of items to drop + */ + public int quantityDropped(IBlockState state, int fortune, Random random) + { + return func_149679_a(fortune, random); + } + + /** + * This returns a complete list of items dropped from this block. + * + * @param world The current world + * @param pos Block position in world + * @param state Current state + * @param fortune Breakers fortune level + * @return A ArrayList containing all items this block drops + */ + public List getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) + { + List ret = new java.util.ArrayList(); + + Random rand = world instanceof World ? ((World)world).field_73012_v : RANDOM; + + int count = quantityDropped(state, fortune, rand); + for(int i = 0; i < count; i++) + { + Item item = this.func_180660_a(state, rand, fortune); + if (item != Items.field_190931_a) + { + ret.add(new ItemStack(item, 1, this.func_180651_a(state))); + } + } + return ret; + } + + /** + * Return true from this function if the player with silk touch can harvest this block directly, and not it's normal drops. + * + * @param world The world + * @param pos Block position in world + * @param state current block state + * @param player The player doing the harvesting + * @return True if the block can be directly harvested using silk touch + */ + public boolean canSilkHarvest(World world, BlockPos pos, IBlockState state, EntityPlayer player) + { + silk_check_state.set(state);; + boolean ret = this.func_149700_E(); + silk_check_state.set(null); + return ret; + } + + /** + * Determines if a specified mob type can spawn on this block, returning false will + * prevent any mob from spawning on the block. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param type The Mob Category Type + * @return True to allow a mob of the specified category to spawn, false to prevent it. + */ + public boolean canCreatureSpawn(IBlockState state, IBlockAccess world, BlockPos pos, net.minecraft.entity.EntityLiving.SpawnPlacementType type) + { + return isSideSolid(state, world, pos, EnumFacing.UP); + } + + /** + * Determines if this block is classified as a Bed, Allowing + * players to sleep in it, though the block has to specifically + * perform the sleeping functionality in it's activated event. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param player The player or camera entity, null in some cases. + * @return True to treat this as a bed + */ + public boolean isBed(IBlockState state, IBlockAccess world, BlockPos pos, @Nullable Entity player) + { + return this == net.minecraft.init.Blocks.field_150324_C; + } + + /** + * Returns the position that the player is moved to upon + * waking up, or respawning at the bed. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param player The player or camera entity, null in some cases. + * @return The spawn position + */ + @Nullable + public BlockPos getBedSpawnPosition(IBlockState state, IBlockAccess world, BlockPos pos, @Nullable EntityPlayer player) + { + if (world instanceof World) + return BlockBed.func_176468_a((World)world, pos, 0); + return null; + } + + /** + * Called when a user either starts or stops sleeping in the bed. + * + * @param world The current world + * @param pos Block position in world + * @param player The player or camera entity, null in some cases. + * @param occupied True if we are occupying the bed, or false if they are stopping use of the bed + */ + public void setBedOccupied(IBlockAccess world, BlockPos pos, EntityPlayer player, boolean occupied) + { + if (world instanceof World) + { + IBlockState state = world.func_180495_p(pos); + state = state.func_177230_c().func_176221_a(state, world, pos); + state = state.func_177226_a(BlockBed.field_176471_b, occupied); + ((World)world).func_180501_a(pos, state, 4); + } + } + + /** + * Returns the direction of the block. Same values that + * are returned by BlockDirectional + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return Bed direction + */ + public EnumFacing getBedDirection(IBlockState state, IBlockAccess world, BlockPos pos) + { + return (EnumFacing)func_176221_a(state, world, pos).func_177229_b(BlockHorizontal.field_185512_D); + } + + /** + * Determines if the current block is the foot half of the bed. + * + * @param world The current world + * @param pos Block position in world + * @return True if the current block is the foot side of a bed. + */ + public boolean isBedFoot(IBlockAccess world, BlockPos pos) + { + return func_176221_a(world.func_180495_p(pos), world, pos).func_177229_b(BlockBed.field_176472_a) == BlockBed.EnumPartType.FOOT; + } + + /** + * Called when a leaf should start its decay process. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + */ + public void beginLeavesDecay(IBlockState state, World world, BlockPos pos){} + + /** + * Determines if this block can prevent leaves connected to it from decaying. + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return true if the presence this block can prevent leaves from decaying. + */ + public boolean canSustainLeaves(IBlockState state, IBlockAccess world, BlockPos pos) + { + return false; + } + + /** + * Determines if this block is considered a leaf block, used to apply the leaf decay and generation system. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return true if this block is considered leaves. + */ + public boolean isLeaves(IBlockState state, IBlockAccess world, BlockPos pos) + { + return state.func_185904_a() == Material.field_151584_j; + } + + /** + * Used during tree growth to determine if newly generated leaves can replace this block. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return true if this block can be replaced by growing leaves. + */ + public boolean canBeReplacedByLeaves(IBlockState state, IBlockAccess world, BlockPos pos) + { + return isAir(state, world, pos) || isLeaves(state, world, pos); //!state.isFullBlock(); + } + + /** + * + * @param world The current world + * @param pos Block position in world + * @return true if the block is wood (logs) + */ + public boolean isWood(IBlockAccess world, BlockPos pos) + { + return false; + } + + /** + * Determines if the current block is replaceable by Ore veins during world generation. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param target The generic target block the gen is looking for, Standards define stone + * for overworld generation, and neatherack for the nether. + * @return True to allow this block to be replaced by a ore + */ + public boolean isReplaceableOreGen(IBlockState state, IBlockAccess world, BlockPos pos, com.google.common.base.Predicate target) + { + return target.apply(state); + } + + /** + * Location sensitive version of getExplosionResistance + * + * @param world The current world + * @param pos Block position in world + * @param exploder The entity that caused the explosion, can be null + * @param explosion The explosion + * @return The amount of the explosion absorbed. + */ + public float getExplosionResistance(World world, BlockPos pos, @Nullable Entity exploder, Explosion explosion) + { + return func_149638_a(exploder); + } + + /** + * Called when the block is destroyed by an explosion. + * Useful for allowing the block to take into account tile entities, + * state, etc. when exploded, before it is removed. + * + * @param world The current world + * @param pos Block position in world + * @param explosion The explosion instance affecting the block + */ + public void onBlockExploded(World world, BlockPos pos, Explosion explosion) + { + world.func_175698_g(pos); + func_180652_a(world, pos, explosion); + } + + /** + * Determine if this block can make a redstone connection on the side provided, + * Useful to control which sides are inputs and outputs for redstone wires. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param side The side that is trying to make the connection, CAN BE NULL + * @return True to make the connection + */ + public boolean canConnectRedstone(IBlockState state, IBlockAccess world, BlockPos pos, @Nullable EnumFacing side) + { + return state.func_185897_m() && side != null; + } + + /** + * Determines if a torch can be placed on the top surface of this block. + * Useful for creating your own block that torches can be on, such as fences. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return True to allow the torch to be placed + */ + public boolean canPlaceTorchOnTop(IBlockState state, IBlockAccess world, BlockPos pos) + { + if (state.func_193401_d(world, pos, EnumFacing.UP) == BlockFaceShape.SOLID) + { + return this != Blocks.field_185775_db && this != Blocks.field_150428_aP; + } + else + { + return this instanceof BlockFence || this == Blocks.field_150359_w || this == Blocks.field_150463_bK || this == Blocks.field_150399_cn; + } + } + + /** + * Called when a user uses the creative pick block button on this block + * + * @param target The full target the player is looking at + * @return A ItemStack to add to the player's inventory, empty itemstack if nothing should be added. + */ + public ItemStack getPickBlock(IBlockState state, RayTraceResult target, World world, BlockPos pos, EntityPlayer player) + { + return func_185473_a(world, pos, state); + } + + /** + * Used by getTopSolidOrLiquidBlock while placing biome decorations, villages, etc + * Also used to determine if the player can spawn on this block. + * + * @return False to disallow spawning + */ + public boolean isFoliage(IBlockAccess world, BlockPos pos) + { + return false; + } + + /** + * Allows a block to override the standard EntityLivingBase.updateFallState + * particles, this is a server side method that spawns particles with + * WorldServer.spawnParticle + * + * @param world The current Server world + * @param blockPosition of the block that the entity landed on. + * @param iblockstate State at the specific world/pos + * @param entity the entity that hit landed on the block. + * @param numberOfParticles that vanilla would have spawned. + * @return True to prevent vanilla landing particles form spawning. + */ + public boolean addLandingEffects(IBlockState state, net.minecraft.world.WorldServer worldObj, BlockPos blockPosition, IBlockState iblockstate, EntityLivingBase entity, int numberOfParticles ) + { + return false; + } + + /** + * Spawn a digging particle effect in the world, this is a wrapper + * around EffectRenderer.addBlockHitEffects to allow the block more + * control over the particles. Useful when you have entirely different + * texture sheets for different sides/locations in the world. + * + * @param state The current state + * @param world The current world + * @param target The target the player is looking at {x/y/z/side/sub} + * @param manager A reference to the current particle manager. + * @return True to prevent vanilla digging particles form spawning. + */ + @SideOnly(Side.CLIENT) + public boolean addHitEffects(IBlockState state, World worldObj, RayTraceResult target, net.minecraft.client.particle.ParticleManager manager) + { + return false; + } + + /** + * Spawn particles for when the block is destroyed. Due to the nature + * of how this is invoked, the x/y/z locations are not always guaranteed + * to host your block. So be sure to do proper sanity checks before assuming + * that the location is this block. + * + * @param world The current world + * @param pos Position to spawn the particle + * @param manager A reference to the current particle manager. + * @return True to prevent vanilla break particles from spawning. + */ + @SideOnly(Side.CLIENT) + public boolean addDestroyEffects(World world, BlockPos pos, net.minecraft.client.particle.ParticleManager manager) + { + return false; + } + + /** + * Determines if this block can support the passed in plant, allowing it to be planted and grow. + * Some examples: + * Reeds check if its a reed, or if its sand/dirt/grass and adjacent to water + * Cacti checks if its a cacti, or if its sand + * Nether types check for soul sand + * Crops check for tilled soil + * Caves check if it's a solid surface + * Plains check if its grass or dirt + * Water check if its still water + * + * @param state The Current state + * @param world The current world + * @param pos Block position in world + * @param direction The direction relative to the given position the plant wants to be, typically its UP + * @param plantable The plant that wants to check + * @return True to allow the plant to be planted/stay. + */ + public boolean canSustainPlant(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing direction, net.minecraftforge.common.IPlantable plantable) + { + IBlockState plant = plantable.getPlant(world, pos.func_177972_a(direction)); + net.minecraftforge.common.EnumPlantType plantType = plantable.getPlantType(world, pos.func_177972_a(direction)); + + if (plant.func_177230_c() == net.minecraft.init.Blocks.field_150434_aF) + { + return this == net.minecraft.init.Blocks.field_150434_aF || this == net.minecraft.init.Blocks.field_150354_m; + } + + if (plant.func_177230_c() == net.minecraft.init.Blocks.field_150436_aH && this == net.minecraft.init.Blocks.field_150436_aH) + { + return true; + } + + if (plantable instanceof BlockBush && ((BlockBush)plantable).func_185514_i(state)) + { + return true; + } + + switch (plantType) + { + case Desert: return this == net.minecraft.init.Blocks.field_150354_m || this == net.minecraft.init.Blocks.field_150405_ch || this == net.minecraft.init.Blocks.field_150406_ce; + case Nether: return this == net.minecraft.init.Blocks.field_150425_aM; + case Crop: return this == net.minecraft.init.Blocks.field_150458_ak; + case Cave: return state.isSideSolid(world, pos, EnumFacing.UP); + case Plains: return this == net.minecraft.init.Blocks.field_150349_c || this == net.minecraft.init.Blocks.field_150346_d || this == net.minecraft.init.Blocks.field_150458_ak; + case Water: return state.func_185904_a() == Material.field_151586_h && state.func_177229_b(BlockLiquid.field_176367_b) == 0; + case Beach: + boolean isBeach = this == net.minecraft.init.Blocks.field_150349_c || this == net.minecraft.init.Blocks.field_150346_d || this == net.minecraft.init.Blocks.field_150354_m; + boolean hasWater = (world.func_180495_p(pos.func_177974_f()).func_185904_a() == Material.field_151586_h || + world.func_180495_p(pos.func_177976_e()).func_185904_a() == Material.field_151586_h || + world.func_180495_p(pos.func_177978_c()).func_185904_a() == Material.field_151586_h || + world.func_180495_p(pos.func_177968_d()).func_185904_a() == Material.field_151586_h); + return isBeach && hasWater; + } + + return false; + } + + /** + * Called when a plant grows on this block, only implemented for saplings using the WorldGen*Trees classes right now. + * Modder may implement this for custom plants. + * This does not use ForgeDirection, because large/huge trees can be located in non-representable direction, + * so the source location is specified. + * Currently this just changes the block to dirt if it was grass. + * + * Note: This happens DURING the generation, the generation may not be complete when this is called. + * + * @param state The current state + * @param world Current world + * @param pos Block position in world + * @param source Source plant's position in world + */ + public void onPlantGrow(IBlockState state, World world, BlockPos pos, BlockPos source) + { + if (this == net.minecraft.init.Blocks.field_150349_c || this == net.minecraft.init.Blocks.field_150458_ak) + { + world.func_180501_a(pos, net.minecraft.init.Blocks.field_150346_d.func_176223_P(), 2); + } + } + + /** + * Checks if this soil is fertile, typically this means that growth rates + * of plants on this soil will be slightly sped up. + * Only vanilla case is tilledField when it is within range of water. + * + * @param world The current world + * @param pos Block position in world + * @return True if the soil should be considered fertile. + */ + public boolean isFertile(World world, BlockPos pos) + { + if (this == net.minecraft.init.Blocks.field_150458_ak) + { + return ((Integer)world.func_180495_p(pos).func_177229_b(BlockFarmland.field_176531_a)) > 0; + } + + return false; + } + + /** + * Location aware and overrideable version of the lightOpacity array, + * return the number to subtract from the light value when it passes through this block. + * + * This is not guaranteed to have the tile entity in place before this is called, so it is + * Recommended that you have your tile entity call relight after being placed if you + * rely on it for light info. + * + * @param state The Block state + * @param world The current world + * @param pos Block position in world + * @return The amount of light to block, 0 for air, 255 for fully opaque. + */ + public int getLightOpacity(IBlockState state, IBlockAccess world, BlockPos pos) + { + return state.func_185891_c(); + } + + /** + * Determines if this block is can be destroyed by the specified entities normal behavior. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @return True to allow the ender dragon to destroy this block + */ + public boolean canEntityDestroy(IBlockState state, IBlockAccess world, BlockPos pos, Entity entity) + { + if (entity instanceof net.minecraft.entity.boss.EntityDragon) + { + return this != net.minecraft.init.Blocks.field_180401_cv && + this != net.minecraft.init.Blocks.field_150343_Z && + this != net.minecraft.init.Blocks.field_150377_bs && + this != net.minecraft.init.Blocks.field_150357_h && + this != net.minecraft.init.Blocks.field_150384_bq && + this != net.minecraft.init.Blocks.field_150378_br && + this != net.minecraft.init.Blocks.field_150483_bI && + this != net.minecraft.init.Blocks.field_185776_dc && + this != net.minecraft.init.Blocks.field_185777_dd && + this != net.minecraft.init.Blocks.field_150411_aY && + this != net.minecraft.init.Blocks.field_185775_db; + } + else if ((entity instanceof net.minecraft.entity.boss.EntityWither) || + (entity instanceof net.minecraft.entity.projectile.EntityWitherSkull)) + { + return net.minecraft.entity.boss.EntityWither.func_181033_a(this); + } + + return true; + } + + /** + * Determines if this block can be used as the base of a beacon. + * + * @param world The current world + * @param pos Block position in world + * @param beacon Beacon position in world + * @return True, to support the beacon, and make it active with this block. + */ + public boolean isBeaconBase(IBlockAccess worldObj, BlockPos pos, BlockPos beacon) + { + return this == net.minecraft.init.Blocks.field_150475_bE || this == net.minecraft.init.Blocks.field_150340_R || this == net.minecraft.init.Blocks.field_150484_ah || this == net.minecraft.init.Blocks.field_150339_S; + } + + /** + * Rotate the block. For vanilla blocks this rotates around the axis passed in (generally, it should be the "face" that was hit). + * Note: for mod blocks, this is up to the block and modder to decide. It is not mandated that it be a rotation around the + * face, but could be a rotation to orient *to* that face, or a visiting of possible rotations. + * The method should return true if the rotation was successful though. + * + * @param world The world + * @param pos Block position in world + * @param axis The axis to rotate around + * @return True if the rotation was successful, False if the rotation failed, or is not possible + */ + public boolean rotateBlock(World world, BlockPos pos, EnumFacing axis) + { + IBlockState state = world.func_180495_p(pos); + for (IProperty prop : state.func_177228_b().keySet()) + { + if ((prop.func_177701_a().equals("facing") || prop.func_177701_a().equals("rotation")) && prop.func_177699_b() == EnumFacing.class) + { + Block block = state.func_177230_c(); + if (!(block instanceof BlockBed) && !(block instanceof BlockPistonExtension)) + { + IBlockState newState; + //noinspection unchecked + IProperty facingProperty = (IProperty) prop; + EnumFacing facing = state.func_177229_b(facingProperty); + java.util.Collection validFacings = facingProperty.func_177700_c(); + + // rotate horizontal facings clockwise + if (validFacings.size() == 4 && !validFacings.contains(EnumFacing.UP) && !validFacings.contains(EnumFacing.DOWN)) + { + newState = state.func_177226_a(facingProperty, facing.func_176746_e()); + } + else + { + // rotate other facings about the axis + EnumFacing rotatedFacing = facing.func_176732_a(axis.func_176740_k()); + if (validFacings.contains(rotatedFacing)) + { + newState = state.func_177226_a(facingProperty, rotatedFacing); + } + else // abnormal facing property, just cycle it + { + newState = state.func_177231_a(facingProperty); + } + } + + world.func_175656_a(pos, newState); + return true; + } + } + } + return false; + } + + /** + * Get the rotations that can apply to the block at the specified coordinates. Null means no rotations are possible. + * Note, this is up to the block to decide. It may not be accurate or representative. + * @param world The world + * @param pos Block position in world + * @return An array of valid axes to rotate around, or null for none or unknown + */ + @Nullable + public EnumFacing[] getValidRotations(World world, BlockPos pos) + { + IBlockState state = world.func_180495_p(pos); + for (IProperty prop : state.func_177228_b().keySet()) + { + if ((prop.func_177701_a().equals("facing") || prop.func_177701_a().equals("rotation")) && prop.func_177699_b() == EnumFacing.class) + { + @SuppressWarnings("unchecked") + java.util.Collection values = ((java.util.Collection)prop.func_177700_c()); + return values.toArray(new EnumFacing[values.size()]); + } + } + return null; + } + + /** + * Determines the amount of enchanting power this block can provide to an enchanting table. + * @param world The World + * @param pos Block position in world + * @return The amount of enchanting power this block produces. + */ + public float getEnchantPowerBonus(World world, BlockPos pos) + { + return this == net.minecraft.init.Blocks.field_150342_X ? 1 : 0; + } + + /** + * Common way to recolor a block with an external tool + * @param world The world + * @param pos Block position in world + * @param side The side hit with the coloring tool + * @param color The color to change to + * @return If the recoloring was successful + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public boolean recolorBlock(World world, BlockPos pos, EnumFacing side, net.minecraft.item.EnumDyeColor color) + { + IBlockState state = world.func_180495_p(pos); + for (IProperty prop : state.func_177228_b().keySet()) + { + if (prop.func_177701_a().equals("color") && prop.func_177699_b() == net.minecraft.item.EnumDyeColor.class) + { + net.minecraft.item.EnumDyeColor current = (net.minecraft.item.EnumDyeColor)state.func_177229_b(prop); + if (current != color) + { + world.func_175656_a(pos, state.func_177226_a(prop, color)); + return true; + } + } + } + return false; + } + + /** + * Gathers how much experience this block drops when broken. + * + * @param state The current state + * @param world The world + * @param pos Block position + * @param fortune + * @return Amount of XP from breaking this block. + */ + public int getExpDrop(IBlockState state, IBlockAccess world, BlockPos pos, int fortune) + { + return 0; + } + + /** + * Called when a tile entity on a side of this block changes is created or is destroyed. + * @param world The world + * @param pos Block position in world + * @param neighbor Block position of neighbor + */ + public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor){} + + /** + * Called on an Observer block whenever an update for an Observer is received. + * + * @param observerState The Observer block's state. + * @param world The current world. + * @param observerPos The Observer block's position. + * @param changedBlock The updated block. + * @param changedBlockPos The updated block's position. + */ + public void observedNeighborChange(IBlockState observerState, World world, BlockPos observerPos, Block changedBlock, BlockPos changedBlockPos){} + + /** + * Called to determine whether to allow the a block to handle its own indirect power rather than using the default rules. + * @param world The world + * @param pos Block position in world + * @param side The INPUT side of the block to be powered - ie the opposite of this block's output side + * @return Whether Block#isProvidingWeakPower should be called when determining indirect power + */ + public boolean shouldCheckWeakPower(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) + { + return state.func_185915_l(); + } + + /** + * If this block should be notified of weak changes. + * Weak changes are changes 1 block away through a solid block. + * Similar to comparators. + * + * @param world The current world + * @param pos Block position in world + * @return true To be notified of changes + */ + public boolean getWeakChanges(IBlockAccess world, BlockPos pos) + { + return false; + } + + private String[] harvestTool = new String[16];; + private int[] harvestLevel = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + /** + * Sets or removes the tool and level required to harvest this block. + * + * @param toolClass Class + * @param level Harvest level: + * Wood: 0 + * Stone: 1 + * Iron: 2 + * Diamond: 3 + * Gold: 0 + */ + public void setHarvestLevel(String toolClass, int level) + { + java.util.Iterator itr = func_176194_O().func_177619_a().iterator(); + while (itr.hasNext()) + { + setHarvestLevel(toolClass, level, itr.next()); + } + } + + /** + * Sets or removes the tool and level required to harvest this block. + * + * @param toolClass Class + * @param level Harvest level: + * Wood: 0 + * Stone: 1 + * Iron: 2 + * Diamond: 3 + * Gold: 0 + * @param state The specific state. + */ + public void setHarvestLevel(String toolClass, int level, IBlockState state) + { + int idx = this.func_176201_c(state); + this.harvestTool[idx] = toolClass; + this.harvestLevel[idx] = level; + } + + /** + * Queries the class of tool required to harvest this block, if null is returned + * we assume that anything can harvest this block. + */ + @Nullable public String getHarvestTool(IBlockState state) + { + return harvestTool[func_176201_c(state)]; + } + + /** + * Queries the harvest level of this item stack for the specified tool class, + * Returns -1 if this tool is not of the specified type + * + * @return Harvest level, or -1 if not the specified tool type. + */ + public int getHarvestLevel(IBlockState state) + { + return harvestLevel[func_176201_c(state)]; + } + + /** + * Checks if the specified tool type is efficient on this block, + * meaning that it digs at full speed. + */ + public boolean isToolEffective(String type, IBlockState state) + { + if ("pickaxe".equals(type) && (this == net.minecraft.init.Blocks.field_150450_ax || this == net.minecraft.init.Blocks.field_150439_ay || this == net.minecraft.init.Blocks.field_150343_Z)) + return false; + return type != null && type.equals(getHarvestTool(state)); + } + + /** + * Can return IExtendedBlockState + */ + public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) + { + return state; + } + + /** + * Called when the entity is inside this block, may be used to determined if the entity can breathing, + * display material overlays, or if the entity can swim inside a block. + * + * @param world that is being tested. + * @param blockpos position thats being tested. + * @param iblockstate state at world/blockpos + * @param entity that is being tested. + * @param yToTest, primarily for testingHead, which sends the the eye level of the entity, other wise it sends a y that can be tested vs liquid height. + * @param materialIn to test for. + * @param testingHead when true, its testing the entities head for vision, breathing ect... otherwise its testing the body, for swimming and movement adjustment. + * @return null for default behavior, true if the entity is within the material, false if it was not. + */ + @Nullable + public Boolean isEntityInsideMaterial(IBlockAccess world, BlockPos blockpos, IBlockState iblockstate, Entity entity, double yToTest, Material materialIn, boolean testingHead) + { + return null; + } + + /** + * Called when boats or fishing hooks are inside the block to check if they are inside + * the material requested. + * + * @param world world that is being tested. + * @param pos block thats being tested. + * @param boundingBox box to test, generally the bounds of an entity that are besting tested. + * @param materialIn to check for. + * @return null for default behavior, true if the box is within the material, false if it was not. + */ + @Nullable + public Boolean isAABBInsideMaterial(World world, BlockPos pos, AxisAlignedBB boundingBox, Material materialIn) + { + return null; + } + + /** + * Queries if this block should render in a given layer. + * ISmartBlockModel can use {@link net.minecraftforge.client.MinecraftForgeClient#getRenderLayer()} to alter their model based on layer. + */ + public boolean canRenderInLayer(IBlockState state, BlockRenderLayer layer) + { + return func_180664_k() == layer; + } + // For Internal use only to capture droped items inside getDrops + protected static ThreadLocal captureDrops = new ThreadLocal() + { + @Override protected Boolean initialValue() { return false; } + }; + protected static ThreadLocal> capturedDrops = new ThreadLocal>() + { + @Override protected List initialValue() { return new java.util.ArrayList(); } + }; + protected List captureDrops(boolean start) + { + if (start) + { + captureDrops.set(true); + capturedDrops.get().clear(); + return java.util.Collections.emptyList(); + } + else + { + captureDrops.set(false); + return capturedDrops.get(); + } + } + + /** + * Sensitive version of getSoundType + * @param state The state + * @param world The world + * @param pos The position. Note that the world may not necessarily have {@code state} here! + * @param entity The entity that is breaking/stepping on/placing/hitting/falling on this block, or null if no entity is in this context + * @return A SoundType to use + */ + public SoundType getSoundType(IBlockState state, World world, BlockPos pos, @Nullable Entity entity) + { + return func_185467_w(); + } + + /** + * @param state The state + * @param world The world + * @param pos The position of this state + * @param beaconPos The position of the beacon + * @return A float RGB [0.0, 1.0] array to be averaged with a beacon's existing beam color, or null to do nothing to the beam + */ + @Nullable + public float[] getBeaconColorMultiplier(IBlockState state, World world, BlockPos pos, BlockPos beaconPos) + { + return null; + } + + /** + * Gets the {@link IBlockState} to place + * @param world The world the block is being placed in + * @param pos The position the block is being placed at + * @param facing The side the block is being placed on + * @param hitX The X coordinate of the hit vector + * @param hitY The Y coordinate of the hit vector + * @param hitZ The Z coordinate of the hit vector + * @param meta The metadata of {@link ItemStack} as processed by {@link Item#getMetadata(int)} + * @param placer The entity placing the block + * @param hand The player hand used to place this block + * @return The state to be placed in the world + */ + public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer, EnumHand hand) + { + return func_180642_a(world, pos, facing, hitX, hitY, hitZ, meta, placer); + } + + /** + * Determines if another block can connect to this block + * + * @param world The current world + * @param pos The position of this block + * @param facing The side the connecting block is on + * @return True to allow another block to connect to this block + */ + public boolean canBeConnectedTo(IBlockAccess world, BlockPos pos, EnumFacing facing) + { + return false; + } + + /** + * Get the {@code PathNodeType} for this block. Return {@code null} for vanilla behavior. + * + * @return the PathNodeType + */ + @Nullable + public net.minecraft.pathfinding.PathNodeType getAiPathNodeType(IBlockState state, IBlockAccess world, BlockPos pos) + { + return isBurning(world, pos) ? net.minecraft.pathfinding.PathNodeType.DAMAGE_FIRE : null; + } + + /* ========================================= FORGE END ======================================*/ + public static void func_149671_p() { func_176215_a(0, field_176230_a, (new BlockAir()).func_149663_c("air")); @@ -1247,14 +2475,7 @@ } else { - UnmodifiableIterator unmodifiableiterator = block16.func_176194_O().func_177619_a().iterator(); - - while (unmodifiableiterator.hasNext()) - { - IBlockState iblockstate = (IBlockState)unmodifiableiterator.next(); - int k = field_149771_c.func_148757_b(block16) << 4 | block16.func_176201_c(iblockstate); - field_176229_d.func_148746_a(iblockstate, k); - } +// Handled in GameData.BlockCallbacks - leaving tripwire as it seems to be special cased } } }