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