    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 i;
    094        float f;
    095        int j;
    096
    097        if (this.receivedFinishDiggingPacket)
    098        {
    099            i = this.curblockDamage - this.field_73093_n;
    100            int k = this.theWorld.getBlockId(this.posX, this.posY, this.posZ);
    101
    102            if (k == 0)
    103            {
    104                this.receivedFinishDiggingPacket = false;
    105            }
    106            else
    107            {
    108                Block block = Block.blocksList[k];
    109                f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.posX, this.posY, this.posZ) * (float)(i + 1);
    110                j = (int)(f * 10.0F);
    111
    112                if (j != this.durabilityRemainingOnBlock)
    113                {
    114                    this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.posX, this.posY, this.posZ, j);
    115                    this.durabilityRemainingOnBlock = j;
    116                }
    117
    118                if (f >= 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            i = this.theWorld.getBlockId(this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ);
    128            Block block1 = Block.blocksList[i];
    129
    130            if (block1 == 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 l = this.curblockDamage - this.initialDamage;
    139                f = block1.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ) * (float)(l + 1);
    140                j = (int)(f * 10.0F);
    141
    142                if (j != this.durabilityRemainingOnBlock)
    143                {
    144                    this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, j);
    145                    this.durabilityRemainingOnBlock = j;
    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 f = 1.0F;
    177                int i1 = this.theWorld.getBlockId(par1, par2, par3);
    178
    179                Block block = Block.blocksList[i1];
    180
    181                if (block != null)
    182                {
    183                    if (event.useBlock != Event.Result.DENY)
    184                    {
    185                        block.onBlockClicked(theWorld, par1, par2, par3, thisPlayerMP);
    186                        theWorld.extinguishFire(thisPlayerMP, par1, par2, par3, par4);
    187                    }
    188                    else
    189                    {
    190                        thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld));
    191                    }
    192                    f = block.getPlayerRelativeBlockHardness(thisPlayerMP, thisPlayerMP.worldObj, par1, par2, par3);
    193                }
    194
    195                if (event.useItem == Event.Result.DENY)
    196                {
    197                    if (f >= 1.0f)
    198                    {
    199                        thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld));
    200                    }
    201                    return;
    202                }
    203
    204                if (i1 > 0 && f >= 1.0F)
    205                {
    206                    this.tryHarvestBlock(par1, par2, par3);
    207                }
    208                else
    209                {
    210                    this.isDestroyingBlock = true;
    211                    this.partiallyDestroyedBlockX = par1;
    212                    this.partiallyDestroyedBlockY = par2;
    213                    this.partiallyDestroyedBlockZ = par3;
    214                    int j1 = (int)(f * 10.0F);
    215                    this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, j1);
    216                    this.durabilityRemainingOnBlock = j1;
    217                }
    218            }
    219        }
    220    }
    221
    222    public void uncheckedTryHarvestBlock(int par1, int par2, int par3)
    223    {
    224        if (par1 == this.partiallyDestroyedBlockX && par2 == this.partiallyDestroyedBlockY && par3 == this.partiallyDestroyedBlockZ)
    225        {
    226            int l = this.curblockDamage - this.initialDamage;
    227            int i1 = this.theWorld.getBlockId(par1, par2, par3);
    228
    229            if (i1 != 0)
    230            {
    231                Block block = Block.blocksList[i1];
    232                float f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, par1, par2, par3) * (float)(l + 1);
    233
    234                if (f >= 0.7F)
    235                {
    236                    this.isDestroyingBlock = false;
    237                    this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, -1);
    238                    this.tryHarvestBlock(par1, par2, par3);
    239                }
    240                else if (!this.receivedFinishDiggingPacket)
    241                {
    242                    this.isDestroyingBlock = false;
    243                    this.receivedFinishDiggingPacket = true;
    244                    this.posX = par1;
    245                    this.posY = par2;
    246                    this.posZ = par3;
    247                    this.field_73093_n = this.initialDamage;
    248                }
    249            }
    250        }
    251    }
    252
    253    /**
    254     * note: this ignores the pars passed in and continues to destroy the onClickedBlock
    255     */
    256    public void cancelDestroyingBlock(int par1, int par2, int par3)
    257    {
    258        this.isDestroyingBlock = false;
    259        this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, -1);
    260    }
    261
    262    /**
    263     * Removes a block and triggers the appropriate events
    264     */
    265    private boolean removeBlock(int par1, int par2, int par3)
    266    {
    267        Block block = Block.blocksList[this.theWorld.getBlockId(par1, par2, par3)];
    268        int l = this.theWorld.getBlockMetadata(par1, par2, par3);
    269
    270        if (block != null)
    271        {
    272            block.onBlockHarvested(this.theWorld, par1, par2, par3, l, this.thisPlayerMP);
    273        }
    274
    275        boolean flag = (block != null && block.removeBlockByPlayer(theWorld, thisPlayerMP, par1, par2, par3));
    276
    277        if (block != null && flag)
    278        {
    279            block.onBlockDestroyedByPlayer(this.theWorld, par1, par2, par3, l);
    280        }
    281
    282        return flag;
    283    }
    284
    285    /**
    286     * Attempts to harvest a block at the given coordinate
    287     */
    288    public boolean tryHarvestBlock(int par1, int par2, int par3)
    289    {
    290        if (this.gameType.isAdventure() && !this.thisPlayerMP.canCurrentToolHarvestBlock(par1, par2, par3))
    291        {
    292            return false;
    293        }
    294        else
    295        {
    296            ItemStack stack = thisPlayerMP.getCurrentEquippedItem();
    297            if (stack != null && stack.getItem().onBlockStartBreak(stack, par1, par2, par3, thisPlayerMP))
    298            {
    299                return false;
    300            }
    301            int l = this.theWorld.getBlockId(par1, par2, par3);
    302            int i1 = this.theWorld.getBlockMetadata(par1, par2, par3);
    303            this.theWorld.playAuxSFXAtEntity(this.thisPlayerMP, 2001, par1, par2, par3, l + (this.theWorld.getBlockMetadata(par1, par2, par3) << 12));
    304            boolean flag = false;
    305
    306            if (this.isCreative())
    307            {
    308                flag = this.removeBlock(par1, par2, par3);
    309                this.thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, this.theWorld));
    310            }
    311            else
    312            {
    313                ItemStack itemstack = this.thisPlayerMP.getCurrentEquippedItem();
    314                boolean flag1 = false;
    315                Block block = Block.blocksList[l];
    316                if (block != null)
    317                {
    318                    flag1 = block.canHarvestBlock(thisPlayerMP, i1);
    319                }
    320
    321                if (itemstack != null)
    322                {
    323                    itemstack.onBlockDestroyed(this.theWorld, l, par1, par2, par3, this.thisPlayerMP);
    324
    325                    if (itemstack.stackSize == 0)
    326                    {
    327                        this.thisPlayerMP.destroyCurrentEquippedItem();
    328                    }
    329                }
    330
    331                flag = this.removeBlock(par1, par2, par3);
    332                if (flag && flag1)
    333                {
    334                    Block.blocksList[l].harvestBlock(this.theWorld, this.thisPlayerMP, par1, par2, par3, i1);
    335                }
    336            }
    337
    338            return flag;
    339        }
    340    }
    341
    342    /**
    343     * Attempts to right-click use an item by the given EntityPlayer in the given World
    344     */
    345    public boolean tryUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack)
    346    {
    347        int i = par3ItemStack.stackSize;
    348        int j = par3ItemStack.getItemDamage();
    349        ItemStack itemstack1 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer);
    350
    351        if (itemstack1 == par3ItemStack && (itemstack1 == null || itemstack1.stackSize == i && itemstack1.getMaxItemUseDuration() <= 0 && itemstack1.getItemDamage() == j))
    352        {
    353            return false;
    354        }
    355        else
    356        {
    357            par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = itemstack1;
    358
    359            if (this.isCreative())
    360            {
    361                itemstack1.stackSize = i;
    362
    363                if (itemstack1.isItemStackDamageable())
    364                {
    365                    itemstack1.setItemDamage(j);
    366                }
    367            }
    368
    369            if (itemstack1.stackSize == 0)
    370            {
    371                par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null;
    372                MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, itemstack1));
    373            }
    374
    375            if (!par1EntityPlayer.isUsingItem())
    376            {
    377                ((EntityPlayerMP)par1EntityPlayer).sendContainerToPlayer(par1EntityPlayer.inventoryContainer);
    378            }
    379
    380            return true;
    381        }
    382    }
    383
    384    /**
    385     * Activate the clicked on block, otherwise use the held item. Args: player, world, itemStack, x, y, z, side,
    386     * xOffset, yOffset, zOffset
    387     */
    388    public boolean activateBlockOrUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
    389    {
    390        PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(par1EntityPlayer, Action.RIGHT_CLICK_BLOCK, par4, par5, par6, par7);
    391        if (event.isCanceled())
    392        {
    393            thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
    394            return false;
    395        }
    396
    397        Item item = (par3ItemStack != null ? par3ItemStack.getItem() : null);
    398        if (item != null && item.onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10))
    399        {
    400            if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
    401            return true;
    402        }
    403
    404        int i1 = par2World.getBlockId(par4, par5, par6);
    405        Block block = Block.blocksList[i1];
    406        boolean result = false;
    407
    408        if (block != null && (!par1EntityPlayer.isSneaking() || ( par1EntityPlayer.getHeldItem() == null || par1EntityPlayer.getHeldItem().getItem().shouldPassSneakingClickToBlock(par2World, par4, par5, par6))))
    409        {
    410            if (event.useBlock != Event.Result.DENY)
    411            {
    412                result = block.onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, par8, par9, par10);
    413            }
    414            else
    415            {
    416                thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
    417                result = event.useItem != Event.Result.ALLOW;
    418            }
    419        }
    420
    421        if (par3ItemStack != null && !result && event.useItem != Event.Result.DENY)
    422        {
    423            int meta = par3ItemStack.getItemDamage();
    424            int size = par3ItemStack.stackSize;
    425            result = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10);
    426            if (isCreative())
    427            {
    428                par3ItemStack.setItemDamage(meta);
    429                par3ItemStack.stackSize = size;
    430            }
    431            if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
    432        }
    433
    434        /* Re-enable if this causes bukkit incompatibility, or re-write client side to only send a single packet per right click.
    435        if (par3ItemStack != null && ((!result && event.useItem != Event.Result.DENY) || event.useItem == Event.Result.ALLOW))
    436        {
    437            this.tryUseItem(thisPlayerMP, par2World, par3ItemStack);
    438        }*/
    439        return result;
    440    }
    441
    442    /**
    443     * Sets the world instance.
    444     */
    445    public void setWorld(WorldServer par1WorldServer)
    446    {
    447        this.theWorld = par1WorldServer;
    448    }
    449
    450    public double getBlockReachDistance()
    451    {
    452        return blockReachDistance;
    453    }
    454    public void setBlockReachDistance(double distance)
    455    {
    456        blockReachDistance = distance;
    457    }
    458}