    001    package net.minecraft.item;
    002
    003    import net.minecraft.block.Block;
    004    import net.minecraft.entity.player.EntityPlayer;
    005    import net.minecraft.entity.player.EntityPlayerMP;
    006    import net.minecraft.network.packet.Packet53BlockChange;
    007    import net.minecraft.world.EnumGameType;
    008    import net.minecraft.world.World;
    009    import net.minecraft.world.WorldServer;
    010
    011    import net.minecraftforge.common.ForgeHooks;
    012    import net.minecraftforge.common.MinecraftForge;
    013    import net.minecraftforge.event.Event;
    014    import net.minecraftforge.event.ForgeEventFactory;
    015    import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
    016    import net.minecraftforge.event.entity.player.PlayerInteractEvent;
    017    import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action;
    018
    019    public class ItemInWorldManager
    020    {
    021        /** Forge reach distance */
    022        private double blockReachDistance = 5.0d;
    023
    024        /** The world object that this object is connected to. */
    025        public World theWorld;
    026
    027        /** The EntityPlayerMP object that this object is connected to. */
    028        public EntityPlayerMP thisPlayerMP;
    029        private EnumGameType gameType;
    030
    031        /** True if the player is destroying a block */
    032        private boolean isDestroyingBlock;
    033        private int initialDamage;
    034        private int partiallyDestroyedBlockX;
    035        private int partiallyDestroyedBlockY;
    036        private int partiallyDestroyedBlockZ;
    037        private int curblockDamage;
    038
    039        /**
    040         * Set to true when the "finished destroying block" packet is received but the block wasn't fully damaged yet. The
    041         * block will not be destroyed while this is false.
    042         */
    043        private boolean receivedFinishDiggingPacket;
    044        private int posX;
    045        private int posY;
    046        private int posZ;
    047        private int field_73093_n;
    048        private int durabilityRemainingOnBlock;
    049
    050        public ItemInWorldManager(World par1World)
    051        {
    052            this.gameType = EnumGameType.NOT_SET;
    053            this.durabilityRemainingOnBlock = -1;
    054            this.theWorld = par1World;
    055        }
    056
    057        public void setGameType(EnumGameType par1EnumGameType)
    058        {
    059            this.gameType = par1EnumGameType;
    060            par1EnumGameType.configurePlayerCapabilities(this.thisPlayerMP.capabilities);
    061            this.thisPlayerMP.sendPlayerAbilities();
    062        }
    063
    064        public EnumGameType getGameType()
    065        {
    066            return this.gameType;
    067        }
    068
    069        /**
    070         * Get if we are in creative game mode.
    071         */
    072        public boolean isCreative()
    073        {
    074            return this.gameType.isCreative();
    075        }
    076
    077        /**
    078         * if the gameType is currently NOT_SET then change it to par1
    079         */
    080        public void initializeGameType(EnumGameType par1EnumGameType)
    081        {
    082            if (this.gameType == EnumGameType.NOT_SET)
    083            {
    084                this.gameType = par1EnumGameType;
    085            }
    086
    087            this.setGameType(this.gameType);
    088        }
    089
    090        public void updateBlockRemoving()
    091        {
    092            ++this.curblockDamage;
    093            int var1;
    094            float var4;
    095            int var5;
    096
    097            if (this.receivedFinishDiggingPacket)
    098            {
    099                var1 = this.curblockDamage - this.field_73093_n;
    100                int var2 = this.theWorld.getBlockId(this.posX, this.posY, this.posZ);
    101
    102                if (var2 == 0)
    103                {
    104                    this.receivedFinishDiggingPacket = false;
    105                }
    106                else
    107                {
    108                    Block var3 = Block.blocksList[var2];
    109                    var4 = var3.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.posX, this.posY, this.posZ) * (float)(var1 + 1);
    110                    var5 = (int)(var4 * 10.0F);
    111
    112                    if (var5 != this.durabilityRemainingOnBlock)
    113                    {
    114                        this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.posX, this.posY, this.posZ, var5);
    115                        this.durabilityRemainingOnBlock = var5;
    116                    }
    117
    118                    if (var4 >= 1.0F)
    119                    {
    120                        this.receivedFinishDiggingPacket = false;
    121                        this.tryHarvestBlock(this.posX, this.posY, this.posZ);
    122                    }
    123                }
    124            }
    125            else if (this.isDestroyingBlock)
    126            {
    127                var1 = this.theWorld.getBlockId(this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ);
    128                Block var6 = Block.blocksList[var1];
    129
    130                if (var6 == null)
    131                {
    132                    this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, -1);
    133                    this.durabilityRemainingOnBlock = -1;
    134                    this.isDestroyingBlock = false;
    135                }
    136                else
    137                {
    138                    int var7 = this.curblockDamage - this.initialDamage;
    139                    var4 = var6.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ) * (float)(var7 + 1);
    140                    var5 = (int)(var4 * 10.0F);
    141
    142                    if (var5 != this.durabilityRemainingOnBlock)
    143                    {
    144                        this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, var5);
    145                        this.durabilityRemainingOnBlock = var5;
    146                    }
    147                }
    148            }
    149        }
    150
    151        /**
    152         * if not creative, it calls destroyBlockInWorldPartially untill the block is broken first. par4 is the specific
    153         * side. tryHarvestBlock can also be the result of this call
    154         */
    155        public void onBlockClicked(int par1, int par2, int par3, int par4)
    156        {
    157            if (!this.gameType.isAdventure() || this.thisPlayerMP.canCurrentToolHarvestBlock(par1, par2, par3))
    158            {
    159                PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(thisPlayerMP, Action.LEFT_CLICK_BLOCK, par1, par2, par3, par4);
    160                if (event.isCanceled())
    161                {
    162                    thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld));
    163                    return;
    164                }
    165
    166                if (this.isCreative())
    167                {
    168                    if (!this.theWorld.extinguishFire((EntityPlayer)null, par1, par2, par3, par4))
    169                    {
    170                        this.tryHarvestBlock(par1, par2, par3);
    171                    }
    172                }
    173                else
    174                {
    175                    this.initialDamage = this.curblockDamage;
    176                    float var5 = 1.0F;
    177                    int var6 = this.theWorld.getBlockId(par1, par2, par3);
    178                    Block block = Block.blocksList[var6];
    179
    180                    if (block != null)
    181                    {
    182                        if (event.useBlock != Event.Result.DENY)
    183                        {
    184                            block.onBlockClicked(theWorld, par1, par2, par3, thisPlayerMP);
    185                            theWorld.extinguishFire(thisPlayerMP, par1, par2, par3, par4);
    186                        }
    187                        else
    188                        {
    189                            thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld));
    190                        }
    191                        var5 = block.getPlayerRelativeBlockHardness(thisPlayerMP, thisPlayerMP.worldObj, par1, par2, par3);
    192                    }
    193
    194                    if (event.useItem == Event.Result.DENY)
    195                    {
    196                        if (var5 >= 1.0f)
    197                        {
    198                            thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld));
    199                        }
    200                        return;
    201                    }
    202
    203                    if (var6 > 0 && var5 >= 1.0F)
    204                    {
    205                        this.tryHarvestBlock(par1, par2, par3);
    206                    }
    207                    else
    208                    {
    209                        this.isDestroyingBlock = true;
    210                        this.partiallyDestroyedBlockX = par1;
    211                        this.partiallyDestroyedBlockY = par2;
    212                        this.partiallyDestroyedBlockZ = par3;
    213                        int var7 = (int)(var5 * 10.0F);
    214                        this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, var7);
    215                        this.durabilityRemainingOnBlock = var7;
    216                    }
    217                }
    218            }
    219        }
    220
    221        public void uncheckedTryHarvestBlock(int par1, int par2, int par3)
    222        {
    223            if (par1 == this.partiallyDestroyedBlockX && par2 == this.partiallyDestroyedBlockY && par3 == this.partiallyDestroyedBlockZ)
    224            {
    225                int var4 = this.curblockDamage - this.initialDamage;
    226                int var5 = this.theWorld.getBlockId(par1, par2, par3);
    227
    228                if (var5 != 0)
    229                {
    230                    Block var6 = Block.blocksList[var5];
    231                    float var7 = var6.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, par1, par2, par3) * (float)(var4 + 1);
    232
    233                    if (var7 >= 0.7F)
    234                    {
    235                        this.isDestroyingBlock = false;
    236                        this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, -1);
    237                        this.tryHarvestBlock(par1, par2, par3);
    238                    }
    239                    else if (!this.receivedFinishDiggingPacket)
    240                    {
    241                        this.isDestroyingBlock = false;
    242                        this.receivedFinishDiggingPacket = true;
    243                        this.posX = par1;
    244                        this.posY = par2;
    245                        this.posZ = par3;
    246                        this.field_73093_n = this.initialDamage;
    247                    }
    248                }
    249            }
    250        }
    251
    252        /**
    253         * note: this ignores the pars passed in and continues to destroy the onClickedBlock
    254         */
    255        public void cancelDestroyingBlock(int par1, int par2, int par3)
    256        {
    257            this.isDestroyingBlock = false;
    258            this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, -1);
    259        }
    260
    261        /**
    262         * Removes a block and triggers the appropriate  events
    263         */
    264        private boolean removeBlock(int par1, int par2, int par3)
    265        {
    266            Block var4 = Block.blocksList[this.theWorld.getBlockId(par1, par2, par3)];
    267            int var5 = this.theWorld.getBlockMetadata(par1, par2, par3);
    268
    269            if (var4 != null)
    270            {
    271                var4.onBlockHarvested(this.theWorld, par1, par2, par3, var5, this.thisPlayerMP);
    272            }
    273
    274            boolean var6 = (var4 != null && var4.removeBlockByPlayer(theWorld, thisPlayerMP, par1, par2, par3));
    275
    276            if (var4 != null && var6)
    277            {
    278                var4.onBlockDestroyedByPlayer(this.theWorld, par1, par2, par3, var5);
    279            }
    280
    281            return var6;
    282        }
    283
    284        /**
    285         * Attempts to harvest a block at the given coordinate
    286         */
    287        public boolean tryHarvestBlock(int par1, int par2, int par3)
    288        {
    289            if (this.gameType.isAdventure() && !this.thisPlayerMP.canCurrentToolHarvestBlock(par1, par2, par3))
    290            {
    291                return false;
    292            }
    293            else
    294            {
    295                ItemStack stack = thisPlayerMP.getCurrentEquippedItem();
    296                if (stack != null && stack.getItem().onBlockStartBreak(stack, par1, par2, par3, thisPlayerMP))
    297                {
    298                    return false;
    299                }
    300                int var4 = this.theWorld.getBlockId(par1, par2, par3);
    301                int var5 = this.theWorld.getBlockMetadata(par1, par2, par3);
    302                this.theWorld.playAuxSFXAtEntity(this.thisPlayerMP, 2001, par1, par2, par3, var4 + (this.theWorld.getBlockMetadata(par1, par2, par3) << 12));
    303                boolean var6 = false;
    304
    305                if (this.isCreative())
    306                {
    307                    var6 = this.removeBlock(par1, par2, par3);
    308                    this.thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, this.theWorld));
    309                }
    310                else
    311                {
    312                    ItemStack var7 = this.thisPlayerMP.getCurrentEquippedItem();
    313                    boolean var8 = false;
    314                    Block block = Block.blocksList[var4];
    315                    if (block != null)
    316                    {
    317                        var8 = block.canHarvestBlock(thisPlayerMP, var5);
    318                    }
    319
    320                    if (var7 != null)
    321                    {
    322                        var7.onBlockDestroyed(this.theWorld, var4, par1, par2, par3, this.thisPlayerMP);
    323
    324                        if (var7.stackSize == 0)
    325                        {
    326                            this.thisPlayerMP.destroyCurrentEquippedItem();
    327                        }
    328                    }
    329
    330                    var6 = this.removeBlock(par1, par2, par3);
    331                    if (var6 && var8)
    332                    {
    333                        Block.blocksList[var4].harvestBlock(this.theWorld, this.thisPlayerMP, par1, par2, par3, var5);
    334                    }
    335                }
    336
    337                return var6;
    338            }
    339        }
    340
    341        /**
    342         * Attempts to right-click use an item by the given EntityPlayer in the given World
    343         */
    344        public boolean tryUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack)
    345        {
    346            int var4 = par3ItemStack.stackSize;
    347            int var5 = par3ItemStack.getItemDamage();
    348            ItemStack var6 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer);
    349
    350            if (var6 == par3ItemStack && (var6 == null || var6.stackSize == var4 && var6.getMaxItemUseDuration() <= 0 && var6.getItemDamage() == var5))
    351            {
    352                return false;
    353            }
    354            else
    355            {
    356                par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = var6;
    357
    358                if (this.isCreative())
    359                {
    360                    var6.stackSize = var4;
    361
    362                    if (var6.isItemStackDamageable())
    363                    {
    364                        var6.setItemDamage(var5);
    365                    }
    366                }
    367
    368                if (var6.stackSize == 0)
    369                {
    370                    par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null;
    371                    MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, var6));
    372                }
    373
    374                if (!par1EntityPlayer.isUsingItem())
    375                {
    376                    ((EntityPlayerMP)par1EntityPlayer).sendContainerToPlayer(par1EntityPlayer.inventoryContainer);
    377                }
    378
    379                return true;
    380            }
    381        }
    382
    383        /**
    384         * Activate the clicked on block, otherwise use the held item. Args: player, world, itemStack, x, y, z, side,
    385         * xOffset, yOffset, zOffset
    386         */
    387        public boolean activateBlockOrUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
    388        {
    389            PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(par1EntityPlayer, Action.RIGHT_CLICK_BLOCK, par4, par5, par6, par7);
    390            if (event.isCanceled())
    391            {
    392                thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
    393                return false;
    394            }
    395
    396            Item item = (par3ItemStack != null ? par3ItemStack.getItem() : null);
    397            if (item != null && item.onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10))
    398            {
    399                if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
    400                return true;
    401            }
    402
    403            int var11 = par2World.getBlockId(par4, par5, par6);
    404            Block block = Block.blocksList[var11];
    405            boolean result = false;
    406
    407            if (block != null && (!par1EntityPlayer.isSneaking() || ( par1EntityPlayer.getHeldItem() == null || par1EntityPlayer.getHeldItem().getItem().shouldPassSneakingClickToBlock(par2World, par4, par5, par6))))
    408            {
    409                if (event.useBlock != Event.Result.DENY)
    410                {
    411                    result = block.onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, par8, par9, par10);
    412                }
    413                else
    414                {
    415                    thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
    416                    result = event.useItem != Event.Result.ALLOW;
    417                }
    418            }
    419
    420            if (par3ItemStack != null && !result && event.useItem != Event.Result.DENY)
    421            {
    422                int meta = par3ItemStack.getItemDamage();
    423                int size = par3ItemStack.stackSize;
    424                result = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10);
    425                if (isCreative())
    426                {
    427                    par3ItemStack.setItemDamage(meta);
    428                    par3ItemStack.stackSize = size;
    429                }
    430                if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
    431            }
    432
    433            /* Re-enable if this causes bukkit incompatibility, or re-write client side to only send a single packet per right click.
    434            if (par3ItemStack != null && ((!result && event.useItem != Event.Result.DENY) || event.useItem == Event.Result.ALLOW))
    435            {
    436                this.tryUseItem(thisPlayerMP, par2World, par3ItemStack);
    437            }*/
    438            return result;
    439        }
    440
    441        /**
    442         * Sets the world instance.
    443         */
    444        public void setWorld(WorldServer par1WorldServer)
    445        {
    446            this.theWorld = par1WorldServer;
    447        }
    448
    449        public double getBlockReachDistance()
    450        {
    451            return blockReachDistance;
    452        }
    453        public void setBlockReachDistance(double distance)
    454        {
    455            blockReachDistance = distance;
    456        }
    457    }