001    package net.minecraft.src;
002    
003    import java.io.ByteArrayOutputStream;
004    import java.io.DataOutputStream;
005    import java.io.IOException;
006    import java.util.ArrayList;
007    import java.util.Iterator;
008    import java.util.LinkedList;
009    import java.util.List;
010    import net.minecraft.server.MinecraftServer;
011    import net.minecraftforge.common.ForgeHooks;
012    import net.minecraftforge.common.MinecraftForge;
013    import net.minecraftforge.event.entity.player.PlayerDropsEvent;
014    import net.minecraftforge.event.world.ChunkWatchEvent;
015    
016    public class EntityPlayerMP extends EntityPlayer implements ICrafting
017    {
018        private StringTranslate translator = new StringTranslate("en_US");
019    
020        /**
021         * The NetServerHandler assigned to this player by the ServerConfigurationManager.
022         */
023        public NetServerHandler playerNetServerHandler;
024    
025        /** Reference to the MinecraftServer object. */
026        public MinecraftServer mcServer;
027    
028        /** The ItemInWorldManager belonging to this player */
029        public ItemInWorldManager theItemInWorldManager;
030    
031        /** player X position as seen by PlayerManager */
032        public double managedPosX;
033    
034        /** player Z position as seen by PlayerManager */
035        public double managedPosZ;
036    
037        /** LinkedList that holds the loaded chunks. */
038        public final List loadedChunks = new LinkedList();
039    
040        /** entities added to this list will  be packet29'd to the player */
041        public final List destroyedItemsNetCache = new LinkedList();
042    
043        /** set to getHealth */
044        private int lastHealth = -99999999;
045    
046        /** set to foodStats.GetFoodLevel */
047        private int lastFoodLevel = -99999999;
048    
049        /** set to foodStats.getSaturationLevel() == 0.0F each tick */
050        private boolean wasHungry = true;
051    
052        /** Amount of experience the client was last set to */
053        private int lastExperience = -99999999;
054    
055        /** de-increments onUpdate, attackEntityFrom is ignored if this >0 */
056        private int initialInvulnerability = 60;
057    
058        /** must be between 3>x>15 (strictly between) */
059        private int renderDistance = 0;
060        private int chatVisibility = 0;
061        private boolean chatColours = true;
062    
063        /**
064         * The currently in use window ID. Incremented every time a window is opened.
065         */
066        public int currentWindowId = 0;
067    
068        /**
069         * poor mans concurency flag, lets hope the jvm doesn't re-order the setting of this flag wrt the inventory change
070         * on the next line
071         */
072        public boolean playerInventoryBeingManipulated;
073        public int ping;
074    
075        /**
076         * Set when a player beats the ender dragon, used to respawn the player at the spawn point while retaining inventory
077         * and XP
078         */
079        public boolean playerConqueredTheEnd = false;
080    
081        public EntityPlayerMP(MinecraftServer par1MinecraftServer, World par2World, String par3Str, ItemInWorldManager par4ItemInWorldManager)
082        {
083            super(par2World);
084            par4ItemInWorldManager.thisPlayerMP = this;
085            this.theItemInWorldManager = par4ItemInWorldManager;
086            this.renderDistance = par1MinecraftServer.getConfigurationManager().getViewDistance();
087            ChunkCoordinates var5 = par2World.provider.getRandomizedSpawnPoint();
088            int var6 = var5.posX;
089            int var7 = var5.posZ;
090            int var8 = var5.posY;
091    
092            this.setLocationAndAngles((double)var6 + 0.5D, (double)var8, (double)var7 + 0.5D, 0.0F, 0.0F);
093            this.mcServer = par1MinecraftServer;
094            this.stepHeight = 0.0F;
095            this.username = par3Str;
096            this.yOffset = 0.0F;
097        }
098    
099        /**
100         * (abstract) Protected helper method to read subclass entity data from NBT.
101         */
102        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
103        {
104            super.readEntityFromNBT(par1NBTTagCompound);
105    
106            if (par1NBTTagCompound.hasKey("playerGameType"))
107            {
108                this.theItemInWorldManager.setGameType(EnumGameType.getByID(par1NBTTagCompound.getInteger("playerGameType")));
109            }
110        }
111    
112        /**
113         * (abstract) Protected helper method to write subclass entity data to NBT.
114         */
115        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
116        {
117            super.writeEntityToNBT(par1NBTTagCompound);
118            par1NBTTagCompound.setInteger("playerGameType", this.theItemInWorldManager.getGameType().getID());
119        }
120    
121        /**
122         * Add experience levels to this player.
123         */
124        public void addExperienceLevel(int par1)
125        {
126            super.addExperienceLevel(par1);
127            this.lastExperience = -1;
128        }
129    
130        public void addSelfToInternalCraftingInventory()
131        {
132            this.openContainer.addCraftingToCrafters(this);
133        }
134    
135        /**
136         * sets the players height back to normal after doing things like sleeping and dieing
137         */
138        protected void resetHeight()
139        {
140            this.yOffset = 0.0F;
141        }
142    
143        public float getEyeHeight()
144        {
145            return 1.62F;
146        }
147    
148        /**
149         * Called to update the entity's position/logic.
150         */
151        public void onUpdate()
152        {
153            this.theItemInWorldManager.updateBlockRemoving();
154            --this.initialInvulnerability;
155            this.openContainer.updateCraftingResults();
156    
157            while (!this.destroyedItemsNetCache.isEmpty())
158            {
159                int var1 = Math.min(this.destroyedItemsNetCache.size(), 127);
160                int[] var2 = new int[var1];
161                Iterator var3 = this.destroyedItemsNetCache.iterator();
162                int var4 = 0;
163    
164                while (var3.hasNext() && var4 < var1)
165                {
166                    var2[var4++] = ((Integer)var3.next()).intValue();
167                    var3.remove();
168                }
169    
170                this.playerNetServerHandler.sendPacketToPlayer(new Packet29DestroyEntity(var2));
171            }
172    
173            if (!this.loadedChunks.isEmpty())
174            {
175                ArrayList var6 = new ArrayList();
176                Iterator var7 = this.loadedChunks.iterator();
177                ArrayList var8 = new ArrayList();
178    
179                while (var7.hasNext() && var6.size() < 5)
180                {
181                    ChunkCoordIntPair var9 = (ChunkCoordIntPair)var7.next();
182                    var7.remove();
183    
184                    if (var9 != null && this.worldObj.blockExists(var9.chunkXPos << 4, 0, var9.chunkZPos << 4))
185                    {
186                        var6.add(this.worldObj.getChunkFromChunkCoords(var9.chunkXPos, var9.chunkZPos));
187                        //BugFix: 16 makes it load an extra chunk, which isn't associated with a player, which makes it not unload unless a player walks near it.
188                        //ToDo: Find a way to efficiently clean abandoned chunks.
189                        //var8.addAll(((WorldServer)this.worldObj).getAllTileEntityInBox(var9.chunkXPos * 16, 0, var9.chunkZPos * 16, var9.chunkXPos * 16 + 16, 256, var9.chunkZPos * 16 + 16));
190                        var8.addAll(((WorldServer)this.worldObj).getAllTileEntityInBox(var9.chunkXPos * 16, 0, var9.chunkZPos * 16, var9.chunkXPos * 16 + 15, 256, var9.chunkZPos * 16 + 15));
191                    }
192                }
193    
194                if (!var6.isEmpty())
195                {
196                    this.playerNetServerHandler.sendPacketToPlayer(new Packet56MapChunks(var6));
197                    Iterator var11 = var8.iterator();
198    
199                    while (var11.hasNext())
200                    {
201                        TileEntity var5 = (TileEntity)var11.next();
202                        this.sendTileEntityToPlayer(var5);
203                    }
204    
205                    var11 = var6.iterator();
206    
207                    while (var11.hasNext())
208                    {
209                        Chunk var10 = (Chunk)var11.next();
210                        this.getServerForPlayer().getEntityTracker().func_85172_a(this, var10);
211                        MinecraftForge.EVENT_BUS.post(new ChunkWatchEvent.Watch(var10.getChunkCoordIntPair(), this));
212                    }
213                }
214            }
215        }
216    
217        public void onUpdateEntity()
218        {
219            super.onUpdate();
220    
221            for (int var1 = 0; var1 < this.inventory.getSizeInventory(); ++var1)
222            {
223                ItemStack var2 = this.inventory.getStackInSlot(var1);
224    
225                if (var2 != null && Item.itemsList[var2.itemID].isMap() && this.playerNetServerHandler.packetSize() <= 5)
226                {
227                    Packet var3 = ((ItemMapBase)Item.itemsList[var2.itemID]).createMapDataPacket(var2, this.worldObj, this);
228    
229                    if (var3 != null)
230                    {
231                        this.playerNetServerHandler.sendPacketToPlayer(var3);
232                    }
233                }
234            }
235    
236            if (this.getHealth() != this.lastHealth || this.lastFoodLevel != this.foodStats.getFoodLevel() || this.foodStats.getSaturationLevel() == 0.0F != this.wasHungry)
237            {
238                this.playerNetServerHandler.sendPacketToPlayer(new Packet8UpdateHealth(this.getHealth(), this.foodStats.getFoodLevel(), this.foodStats.getSaturationLevel()));
239                this.lastHealth = this.getHealth();
240                this.lastFoodLevel = this.foodStats.getFoodLevel();
241                this.wasHungry = this.foodStats.getSaturationLevel() == 0.0F;
242            }
243    
244            if (this.experienceTotal != this.lastExperience)
245            {
246                this.lastExperience = this.experienceTotal;
247                this.playerNetServerHandler.sendPacketToPlayer(new Packet43Experience(this.experience, this.experienceTotal, this.experienceLevel));
248            }
249        }
250    
251        /**
252         * Called when the mob's health reaches 0.
253         */
254        public void onDeath(DamageSource par1DamageSource)
255        {
256            if (ForgeHooks.onLivingDeath(this, par1DamageSource))
257            {
258                return;
259            }
260    
261            this.mcServer.getConfigurationManager().sendPacketToAllPlayers(new Packet3Chat(par1DamageSource.getDeathMessage(this)));
262    
263            if (!this.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory"))
264            {
265                captureDrops = true;
266                capturedDrops.clear();
267    
268                this.inventory.dropAllItems();
269    
270                captureDrops = false;
271                PlayerDropsEvent event = new PlayerDropsEvent(this, par1DamageSource, capturedDrops, recentlyHit > 0);
272                if (!MinecraftForge.EVENT_BUS.post(event))
273                {
274                    for (EntityItem item : capturedDrops)
275                    {
276                        joinEntityItemWithWorld(item);
277                    }
278                }
279            }
280        }
281    
282        /**
283         * Called when the entity is attacked.
284         */
285        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
286        {
287            if (this.func_85032_ar())
288            {
289                return false;
290            }
291            else
292            {
293                boolean var3 = this.mcServer.isDedicatedServer() && this.mcServer.isPVPEnabled() && "fall".equals(par1DamageSource.damageType);
294    
295                if (!var3 && this.initialInvulnerability > 0)
296                {
297                    return false;
298                }
299                else
300                {
301                    if (!this.mcServer.isPVPEnabled() && par1DamageSource instanceof EntityDamageSource)
302                    {
303                        Entity var4 = par1DamageSource.getEntity();
304    
305                        if (var4 instanceof EntityPlayer)
306                        {
307                            return false;
308                        }
309    
310                        if (var4 instanceof EntityArrow)
311                        {
312                            EntityArrow var5 = (EntityArrow)var4;
313    
314                            if (var5.shootingEntity instanceof EntityPlayer)
315                            {
316                                return false;
317                            }
318                        }
319                    }
320    
321                    return super.attackEntityFrom(par1DamageSource, par2);
322                }
323            }
324        }
325    
326        /**
327         * returns if pvp is enabled or not
328         */
329        protected boolean isPVPEnabled()
330        {
331            return this.mcServer.isPVPEnabled();
332        }
333    
334        /**
335         * Teleports the entity to another dimension. Params: Dimension number to teleport to
336         */
337        public void travelToDimension(int par1)
338        {
339            if (this.dimension == 1 && par1 == 1)
340            {
341                this.triggerAchievement(AchievementList.theEnd2);
342                this.worldObj.setEntityDead(this);
343                this.playerConqueredTheEnd = true;
344                this.playerNetServerHandler.sendPacketToPlayer(new Packet70GameEvent(4, 0));
345            }
346            else
347            {
348                if (this.dimension == 1 && par1 == 0)
349                {
350                    this.triggerAchievement(AchievementList.theEnd);
351                    ChunkCoordinates var2 = this.mcServer.worldServerForDimension(par1).getEntrancePortalLocation();
352    
353                    if (var2 != null)
354                    {
355                        this.playerNetServerHandler.setPlayerLocation((double)var2.posX, (double)var2.posY, (double)var2.posZ, 0.0F, 0.0F);
356                    }
357    
358                    par1 = 1;
359                }
360                else
361                {
362                    this.triggerAchievement(AchievementList.portal);
363                }
364    
365                this.mcServer.getConfigurationManager().transferPlayerToDimension(this, par1);
366                this.lastExperience = -1;
367                this.lastHealth = -1;
368                this.lastFoodLevel = -1;
369            }
370        }
371    
372        /**
373         * called from onUpdate for all tileEntity in specific chunks
374         */
375        private void sendTileEntityToPlayer(TileEntity par1TileEntity)
376        {
377            if (par1TileEntity != null)
378            {
379                Packet var2 = par1TileEntity.getDescriptionPacket();
380    
381                if (var2 != null)
382                {
383                    this.playerNetServerHandler.sendPacketToPlayer(var2);
384                }
385            }
386        }
387    
388        /**
389         * Called whenever an item is picked up from walking over it. Args: pickedUpEntity, stackSize
390         */
391        public void onItemPickup(Entity par1Entity, int par2)
392        {
393            super.onItemPickup(par1Entity, par2);
394            this.openContainer.updateCraftingResults();
395        }
396    
397        /**
398         * Attempts to have the player sleep in a bed at the specified location.
399         */
400        public EnumStatus sleepInBedAt(int par1, int par2, int par3)
401        {
402            EnumStatus var4 = super.sleepInBedAt(par1, par2, par3);
403    
404            if (var4 == EnumStatus.OK)
405            {
406                Packet17Sleep var5 = new Packet17Sleep(this, 0, par1, par2, par3);
407                this.getServerForPlayer().getEntityTracker().sendPacketToAllPlayersTrackingEntity(this, var5);
408                this.playerNetServerHandler.setPlayerLocation(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
409                this.playerNetServerHandler.sendPacketToPlayer(var5);
410            }
411    
412            return var4;
413        }
414    
415        /**
416         * Wake up the player if they're sleeping.
417         */
418        public void wakeUpPlayer(boolean par1, boolean par2, boolean par3)
419        {
420            if (this.isPlayerSleeping())
421            {
422                this.getServerForPlayer().getEntityTracker().sendPacketToAllAssociatedPlayers(this, new Packet18Animation(this, 3));
423            }
424    
425            super.wakeUpPlayer(par1, par2, par3);
426    
427            if (this.playerNetServerHandler != null)
428            {
429                this.playerNetServerHandler.setPlayerLocation(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
430            }
431        }
432    
433        /**
434         * Called when a player mounts an entity. e.g. mounts a pig, mounts a boat.
435         */
436        public void mountEntity(Entity par1Entity)
437        {
438            super.mountEntity(par1Entity);
439            this.playerNetServerHandler.sendPacketToPlayer(new Packet39AttachEntity(this, this.ridingEntity));
440            this.playerNetServerHandler.setPlayerLocation(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
441        }
442    
443        /**
444         * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance
445         * and deal fall damage if landing on the ground.  Args: distanceFallenThisTick, onGround
446         */
447        protected void updateFallState(double par1, boolean par3) {}
448    
449        /**
450         * likeUpdateFallState, but called from updateFlyingState, rather than moveEntity
451         */
452        public void updateFlyingState(double par1, boolean par3)
453        {
454            super.updateFallState(par1, par3);
455        }
456    
457        public void incrementWindowID()
458        {
459            this.currentWindowId = this.currentWindowId % 100 + 1;
460        }
461    
462        /**
463         * Displays the crafting GUI for a workbench.
464         */
465        public void displayGUIWorkbench(int par1, int par2, int par3)
466        {
467            this.incrementWindowID();
468            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 1, "Crafting", 9));
469            this.openContainer = new ContainerWorkbench(this.inventory, this.worldObj, par1, par2, par3);
470            this.openContainer.windowId = this.currentWindowId;
471            this.openContainer.addCraftingToCrafters(this);
472        }
473    
474        public void displayGUIEnchantment(int par1, int par2, int par3)
475        {
476            this.incrementWindowID();
477            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 4, "Enchanting", 9));
478            this.openContainer = new ContainerEnchantment(this.inventory, this.worldObj, par1, par2, par3);
479            this.openContainer.windowId = this.currentWindowId;
480            this.openContainer.addCraftingToCrafters(this);
481        }
482    
483        /**
484         * Displays the GUI for interacting with an anvil.
485         */
486        public void displayGUIAnvil(int par1, int par2, int par3)
487        {
488            this.incrementWindowID();
489            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 8, "Repairing", 9));
490            this.openContainer = new ContainerRepair(this.inventory, this.worldObj, par1, par2, par3, this);
491            this.openContainer.windowId = this.currentWindowId;
492            this.openContainer.addCraftingToCrafters(this);
493        }
494    
495        /**
496         * Displays the GUI for interacting with a chest inventory. Args: chestInventory
497         */
498        public void displayGUIChest(IInventory par1IInventory)
499        {
500            if (this.openContainer != this.inventoryContainer)
501            {
502                this.closeScreen();
503            }
504    
505            this.incrementWindowID();
506            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 0, par1IInventory.getInvName(), par1IInventory.getSizeInventory()));
507            this.openContainer = new ContainerChest(this.inventory, par1IInventory);
508            this.openContainer.windowId = this.currentWindowId;
509            this.openContainer.addCraftingToCrafters(this);
510        }
511    
512        /**
513         * Displays the furnace GUI for the passed in furnace entity. Args: tileEntityFurnace
514         */
515        public void displayGUIFurnace(TileEntityFurnace par1TileEntityFurnace)
516        {
517            this.incrementWindowID();
518            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 2, par1TileEntityFurnace.getInvName(), par1TileEntityFurnace.getSizeInventory()));
519            this.openContainer = new ContainerFurnace(this.inventory, par1TileEntityFurnace);
520            this.openContainer.windowId = this.currentWindowId;
521            this.openContainer.addCraftingToCrafters(this);
522        }
523    
524        /**
525         * Displays the dipsenser GUI for the passed in dispenser entity. Args: TileEntityDispenser
526         */
527        public void displayGUIDispenser(TileEntityDispenser par1TileEntityDispenser)
528        {
529            this.incrementWindowID();
530            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 3, par1TileEntityDispenser.getInvName(), par1TileEntityDispenser.getSizeInventory()));
531            this.openContainer = new ContainerDispenser(this.inventory, par1TileEntityDispenser);
532            this.openContainer.windowId = this.currentWindowId;
533            this.openContainer.addCraftingToCrafters(this);
534        }
535    
536        /**
537         * Displays the GUI for interacting with a brewing stand.
538         */
539        public void displayGUIBrewingStand(TileEntityBrewingStand par1TileEntityBrewingStand)
540        {
541            this.incrementWindowID();
542            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 5, par1TileEntityBrewingStand.getInvName(), par1TileEntityBrewingStand.getSizeInventory()));
543            this.openContainer = new ContainerBrewingStand(this.inventory, par1TileEntityBrewingStand);
544            this.openContainer.windowId = this.currentWindowId;
545            this.openContainer.addCraftingToCrafters(this);
546        }
547    
548        /**
549         * Displays the GUI for interacting with a beacon.
550         */
551        public void displayGUIBeacon(TileEntityBeacon par1TileEntityBeacon)
552        {
553            this.incrementWindowID();
554            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 7, par1TileEntityBeacon.getInvName(), par1TileEntityBeacon.getSizeInventory()));
555            this.openContainer = new ContainerBeacon(this.inventory, par1TileEntityBeacon);
556            this.openContainer.windowId = this.currentWindowId;
557            this.openContainer.addCraftingToCrafters(this);
558        }
559    
560        public void displayGUIMerchant(IMerchant par1IMerchant)
561        {
562            this.incrementWindowID();
563            this.openContainer = new ContainerMerchant(this.inventory, par1IMerchant, this.worldObj);
564            this.openContainer.windowId = this.currentWindowId;
565            this.openContainer.addCraftingToCrafters(this);
566            InventoryMerchant var2 = ((ContainerMerchant)this.openContainer).getMerchantInventory();
567            this.playerNetServerHandler.sendPacketToPlayer(new Packet100OpenWindow(this.currentWindowId, 6, var2.getInvName(), var2.getSizeInventory()));
568            MerchantRecipeList var3 = par1IMerchant.getRecipes(this);
569    
570            if (var3 != null)
571            {
572                try
573                {
574                    ByteArrayOutputStream var4 = new ByteArrayOutputStream();
575                    DataOutputStream var5 = new DataOutputStream(var4);
576                    var5.writeInt(this.currentWindowId);
577                    var3.writeRecipiesToStream(var5);
578                    this.playerNetServerHandler.sendPacketToPlayer(new Packet250CustomPayload("MC|TrList", var4.toByteArray()));
579                }
580                catch (IOException var6)
581                {
582                    var6.printStackTrace();
583                }
584            }
585        }
586    
587        /**
588         * Sends the contents of an inventory slot to the client-side Container. This doesn't have to match the actual
589         * contents of that slot. Args: Container, slot number, slot contents
590         */
591        public void sendSlotContents(Container par1Container, int par2, ItemStack par3ItemStack)
592        {
593            if (!(par1Container.getSlot(par2) instanceof SlotCrafting))
594            {
595                if (!this.playerInventoryBeingManipulated)
596                {
597                    this.playerNetServerHandler.sendPacketToPlayer(new Packet103SetSlot(par1Container.windowId, par2, par3ItemStack));
598                }
599            }
600        }
601    
602        public void sendContainerToPlayer(Container par1Container)
603        {
604            this.sendContainerAndContentsToPlayer(par1Container, par1Container.getInventory());
605        }
606    
607        public void sendContainerAndContentsToPlayer(Container par1Container, List par2List)
608        {
609            this.playerNetServerHandler.sendPacketToPlayer(new Packet104WindowItems(par1Container.windowId, par2List));
610            this.playerNetServerHandler.sendPacketToPlayer(new Packet103SetSlot(-1, -1, this.inventory.getItemStack()));
611        }
612    
613        /**
614         * Sends two ints to the client-side Container. Used for furnace burning time, smelting progress, brewing progress,
615         * and enchanting level. Normally the first int identifies which variable to update, and the second contains the new
616         * value. Both are truncated to shorts in non-local SMP.
617         */
618        public void sendProgressBarUpdate(Container par1Container, int par2, int par3)
619        {
620            this.playerNetServerHandler.sendPacketToPlayer(new Packet105UpdateProgressbar(par1Container.windowId, par2, par3));
621        }
622    
623        /**
624         * sets current screen to null (used on escape buttons of GUIs)
625         */
626        public void closeScreen()
627        {
628            this.playerNetServerHandler.sendPacketToPlayer(new Packet101CloseWindow(this.openContainer.windowId));
629            this.closeInventory();
630        }
631    
632        /**
633         * updates item held by mouse
634         */
635        public void updateHeldItem()
636        {
637            if (!this.playerInventoryBeingManipulated)
638            {
639                this.playerNetServerHandler.sendPacketToPlayer(new Packet103SetSlot(-1, -1, this.inventory.getItemStack()));
640            }
641        }
642    
643        public void closeInventory()
644        {
645            this.openContainer.onCraftGuiClosed(this);
646            this.openContainer = this.inventoryContainer;
647        }
648    
649        /**
650         * Adds a value to a statistic field.
651         */
652        public void addStat(StatBase par1StatBase, int par2)
653        {
654            if (par1StatBase != null)
655            {
656                if (!par1StatBase.isIndependent)
657                {
658                    while (par2 > 100)
659                    {
660                        this.playerNetServerHandler.sendPacketToPlayer(new Packet200Statistic(par1StatBase.statId, 100));
661                        par2 -= 100;
662                    }
663    
664                    this.playerNetServerHandler.sendPacketToPlayer(new Packet200Statistic(par1StatBase.statId, par2));
665                }
666            }
667        }
668    
669        public void mountEntityAndWakeUp()
670        {
671            if (this.ridingEntity != null)
672            {
673                this.mountEntity(this.ridingEntity);
674            }
675    
676            if (this.riddenByEntity != null)
677            {
678                this.riddenByEntity.mountEntity(this);
679            }
680    
681            if (this.sleeping)
682            {
683                this.wakeUpPlayer(true, false, false);
684            }
685        }
686    
687        /**
688         * this function is called when a players inventory is sent to him, lastHealth is updated on any dimension
689         * transitions, then reset.
690         */
691        public void setPlayerHealthUpdated()
692        {
693            this.lastHealth = -99999999;
694        }
695    
696        /**
697         * Add a chat message to the player
698         */
699        public void addChatMessage(String par1Str)
700        {
701            StringTranslate var2 = StringTranslate.getInstance();
702            String var3 = var2.translateKey(par1Str);
703            this.playerNetServerHandler.sendPacketToPlayer(new Packet3Chat(var3));
704        }
705    
706        /**
707         * Used for when item use count runs out, ie: eating completed
708         */
709        protected void onItemUseFinish()
710        {
711            this.playerNetServerHandler.sendPacketToPlayer(new Packet38EntityStatus(this.entityId, (byte)9));
712            super.onItemUseFinish();
713        }
714    
715        /**
716         * sets the itemInUse when the use item button is clicked. Args: itemstack, int maxItemUseDuration
717         */
718        public void setItemInUse(ItemStack par1ItemStack, int par2)
719        {
720            super.setItemInUse(par1ItemStack, par2);
721    
722            if (par1ItemStack != null && par1ItemStack.getItem() != null && par1ItemStack.getItem().getItemUseAction(par1ItemStack) == EnumAction.eat)
723            {
724                this.getServerForPlayer().getEntityTracker().sendPacketToAllAssociatedPlayers(this, new Packet18Animation(this, 5));
725            }
726        }
727    
728        /**
729         * Copies the values from the given player into this player if boolean par2 is true. Always clones Ender Chest
730         * Inventory.
731         */
732        public void clonePlayer(EntityPlayer par1EntityPlayer, boolean par2)
733        {
734            super.clonePlayer(par1EntityPlayer, par2);
735            this.lastExperience = -1;
736            this.lastHealth = -1;
737            this.lastFoodLevel = -1;
738            this.destroyedItemsNetCache.addAll(((EntityPlayerMP)par1EntityPlayer).destroyedItemsNetCache);
739        }
740    
741        protected void onNewPotionEffect(PotionEffect par1PotionEffect)
742        {
743            super.onNewPotionEffect(par1PotionEffect);
744            this.playerNetServerHandler.sendPacketToPlayer(new Packet41EntityEffect(this.entityId, par1PotionEffect));
745        }
746    
747        protected void onChangedPotionEffect(PotionEffect par1PotionEffect)
748        {
749            super.onChangedPotionEffect(par1PotionEffect);
750            this.playerNetServerHandler.sendPacketToPlayer(new Packet41EntityEffect(this.entityId, par1PotionEffect));
751        }
752    
753        protected void onFinishedPotionEffect(PotionEffect par1PotionEffect)
754        {
755            super.onFinishedPotionEffect(par1PotionEffect);
756            this.playerNetServerHandler.sendPacketToPlayer(new Packet42RemoveEntityEffect(this.entityId, par1PotionEffect));
757        }
758    
759        /**
760         * Move the entity to the coordinates informed, but keep yaw/pitch values.
761         */
762        public void setPositionAndUpdate(double par1, double par3, double par5)
763        {
764            this.playerNetServerHandler.setPlayerLocation(par1, par3, par5, this.rotationYaw, this.rotationPitch);
765        }
766    
767        /**
768         * Called when the player performs a critical hit on the Entity. Args: entity that was hit critically
769         */
770        public void onCriticalHit(Entity par1Entity)
771        {
772            this.getServerForPlayer().getEntityTracker().sendPacketToAllAssociatedPlayers(this, new Packet18Animation(par1Entity, 6));
773        }
774    
775        public void onEnchantmentCritical(Entity par1Entity)
776        {
777            this.getServerForPlayer().getEntityTracker().sendPacketToAllAssociatedPlayers(this, new Packet18Animation(par1Entity, 7));
778        }
779    
780        /**
781         * Sends the player's abilities to the server (if there is one).
782         */
783        public void sendPlayerAbilities()
784        {
785            if (this.playerNetServerHandler != null)
786            {
787                this.playerNetServerHandler.sendPacketToPlayer(new Packet202PlayerAbilities(this.capabilities));
788            }
789        }
790    
791        public WorldServer getServerForPlayer()
792        {
793            return (WorldServer)this.worldObj;
794        }
795    
796        public void sendGameTypeToPlayer(EnumGameType par1EnumGameType)
797        {
798            this.theItemInWorldManager.setGameType(par1EnumGameType);
799            this.playerNetServerHandler.sendPacketToPlayer(new Packet70GameEvent(3, par1EnumGameType.getID()));
800        }
801    
802        public void sendChatToPlayer(String par1Str)
803        {
804            this.playerNetServerHandler.sendPacketToPlayer(new Packet3Chat(par1Str));
805        }
806    
807        /**
808         * Returns true if the command sender is allowed to use the given command.
809         */
810        public boolean canCommandSenderUseCommand(int par1, String par2Str)
811        {
812            return "seed".equals(par2Str) && !this.mcServer.isDedicatedServer() ? true : (!"tell".equals(par2Str) && !"help".equals(par2Str) && !"me".equals(par2Str) ? this.mcServer.getConfigurationManager().areCommandsAllowed(this.username) : true);
813        }
814    
815        public String func_71114_r()
816        {
817            String var1 = this.playerNetServerHandler.netManager.getSocketAddress().toString();
818            var1 = var1.substring(var1.indexOf("/") + 1);
819            var1 = var1.substring(0, var1.indexOf(":"));
820            return var1;
821        }
822    
823        public void updateClientInfo(Packet204ClientInfo par1Packet204ClientInfo)
824        {
825            if (this.translator.getLanguageList().containsKey(par1Packet204ClientInfo.getLanguage()))
826            {
827                this.translator.setLanguage(par1Packet204ClientInfo.getLanguage());
828            }
829    
830            int var2 = 256 >> par1Packet204ClientInfo.getRenderDistance();
831    
832            if (var2 > 3 && var2 < 15)
833            {
834                this.renderDistance = var2;
835            }
836    
837            this.chatVisibility = par1Packet204ClientInfo.getChatVisibility();
838            this.chatColours = par1Packet204ClientInfo.getChatColours();
839    
840            if (this.mcServer.isSinglePlayer() && this.mcServer.getServerOwner().equals(this.username))
841            {
842                this.mcServer.setDifficultyForAllWorlds(par1Packet204ClientInfo.getDifficulty());
843            }
844    
845            this.setHideCape(1, !par1Packet204ClientInfo.getShowCape());
846        }
847    
848        public StringTranslate getTranslator()
849        {
850            return this.translator;
851        }
852    
853        public int getChatVisibility()
854        {
855            return this.chatVisibility;
856        }
857    
858        /**
859         * on recieving this message the client (if permission is given) will download the requested textures
860         */
861        public void requestTexturePackLoad(String par1Str, int par2)
862        {
863            String var3 = par1Str + "\u0000" + par2;
864            this.playerNetServerHandler.sendPacketToPlayer(new Packet250CustomPayload("MC|TPack", var3.getBytes()));
865        }
866    
867        /**
868         * Return the coordinates for this player as ChunkCoordinates.
869         */
870        public ChunkCoordinates getPlayerCoordinates()
871        {
872            return new ChunkCoordinates(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY + 0.5D), MathHelper.floor_double(this.posZ));
873        }
874    }