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                            MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, var7));
325                        }
326                    }
327    
328                    var6 = this.removeBlock(par1, par2, par3);
329                    if (var6 && var8)
330                    {
331                        Block.blocksList[var4].harvestBlock(this.theWorld, this.thisPlayerMP, par1, par2, par3, var5);
332                    }
333                }
334    
335                return var6;
336            }
337        }
338    
339        /**
340         * Attempts to right-click use an item by the given EntityPlayer in the given World
341         */
342        public boolean tryUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack)
343        {
344            int var4 = par3ItemStack.stackSize;
345            int var5 = par3ItemStack.getItemDamage();
346            ItemStack var6 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer);
347    
348            if (var6 == par3ItemStack && (var6 == null || var6.stackSize == var4 && var6.getMaxItemUseDuration() <= 0 && var6.getItemDamage() == var5))
349            {
350                return false;
351            }
352            else
353            {
354                par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = var6;
355    
356                if (this.isCreative())
357                {
358                    var6.stackSize = var4;
359    
360                    if (var6.isItemStackDamageable())
361                    {
362                        var6.setItemDamage(var5);
363                    }
364                }
365    
366                if (var6.stackSize == 0)
367                {
368                    par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null;
369                    MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, var6));
370                }
371    
372                if (!par1EntityPlayer.isUsingItem())
373                {
374                    ((EntityPlayerMP)par1EntityPlayer).sendContainerToPlayer(par1EntityPlayer.inventoryContainer);
375                }
376    
377                return true;
378            }
379        }
380    
381        /**
382         * Activate the clicked on block, otherwise use the held item. Args: player, world, itemStack, x, y, z, side,
383         * xOffset, yOffset, zOffset
384         */
385        public boolean activateBlockOrUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
386        {
387            PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(par1EntityPlayer, Action.RIGHT_CLICK_BLOCK, par4, par5, par6, par7);
388            if (event.isCanceled())
389            {
390                thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
391                return false;
392            }
393    
394            Item item = (par3ItemStack != null ? par3ItemStack.getItem() : null);
395            if (item != null && item.onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10))
396            {
397                if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
398                return true;
399            }
400    
401            int var11 = par2World.getBlockId(par4, par5, par6);
402            Block block = Block.blocksList[var11];
403            boolean result = false;
404    
405            if (block != null)
406            {
407                if (event.useBlock != Event.Result.DENY)
408                {
409                    result = block.onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, par8, par9, par10);
410                }
411                else
412                {
413                    thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
414                    result = event.useItem != Event.Result.ALLOW;
415                }
416            }
417    
418            if (par3ItemStack != null && !result)
419            {
420                int meta = par3ItemStack.getItemDamage();
421                int size = par3ItemStack.stackSize;
422                result = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10);
423                if (isCreative())
424                {
425                    par3ItemStack.setItemDamage(meta);
426                    par3ItemStack.stackSize = size;
427                }
428                if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
429            }
430    
431            /* Re-enable if this causes bukkit incompatibility, or re-write client side to only send a single packet per right click.
432            if (par3ItemStack != null && ((!result && event.useItem != Event.Result.DENY) || event.useItem == Event.Result.ALLOW))
433            {
434                this.tryUseItem(thisPlayerMP, par2World, par3ItemStack);
435            }*/
436            return result;
437        }
438    
439        /**
440         * Sets the world instance.
441         */
442        public void setWorld(WorldServer par1WorldServer)
443        {
444            this.theWorld = par1WorldServer;
445        }
446    
447        public double getBlockReachDistance()
448        {
449            return blockReachDistance;
450        }
451        public void setBlockReachDistance(double distance)
452        {
453            blockReachDistance = distance;
454        }
455    }