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