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