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