    001package net.minecraft.item;
    002
    003import net.minecraft.block.Block;
    004import net.minecraft.entity.player.EntityPlayer;
    005import net.minecraft.entity.player.EntityPlayerMP;
    006import net.minecraft.network.packet.Packet53BlockChange;
    007import net.minecraft.world.EnumGameType;
    008import net.minecraft.world.World;
    009import net.minecraft.world.WorldServer;
    010
    011import net.minecraftforge.common.ForgeHooks;
    012import net.minecraftforge.common.MinecraftForge;
    013import net.minecraftforge.event.Event;
    014import net.minecraftforge.event.ForgeEventFactory;
    015import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
    016import net.minecraftforge.event.entity.player.PlayerInteractEvent;
    017import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action;
    018
    019public 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}