001package net.minecraft.entity.player;
002
003import java.io.ByteArrayOutputStream;
004import java.io.DataOutputStream;
005import java.io.IOException;
006import java.util.ArrayList;
007import java.util.Iterator;
008import java.util.LinkedList;
009import java.util.List;
010import net.minecraft.entity.Entity;
011import net.minecraft.entity.IMerchant;
012import net.minecraft.entity.item.EntityItem;
013import net.minecraft.entity.projectile.EntityArrow;
014import net.minecraft.inventory.Container;
015import net.minecraft.inventory.ContainerBeacon;
016import net.minecraft.inventory.ContainerBrewingStand;
017import net.minecraft.inventory.ContainerChest;
018import net.minecraft.inventory.ContainerDispenser;
019import net.minecraft.inventory.ContainerEnchantment;
020import net.minecraft.inventory.ContainerFurnace;
021import net.minecraft.inventory.ContainerMerchant;
022import net.minecraft.inventory.ContainerRepair;
023import net.minecraft.inventory.ContainerWorkbench;
024import net.minecraft.inventory.ICrafting;
025import net.minecraft.inventory.IInventory;
026import net.minecraft.inventory.InventoryMerchant;
027import net.minecraft.inventory.SlotCrafting;
028import net.minecraft.item.EnumAction;
029import net.minecraft.item.Item;
030import net.minecraft.item.ItemInWorldManager;
031import net.minecraft.item.ItemMapBase;
032import net.minecraft.item.ItemStack;
033import net.minecraft.nbt.NBTTagCompound;
034import net.minecraft.network.NetServerHandler;
035import net.minecraft.network.packet.Packet;
036import net.minecraft.network.packet.Packet100OpenWindow;
037import net.minecraft.network.packet.Packet101CloseWindow;
038import net.minecraft.network.packet.Packet103SetSlot;
039import net.minecraft.network.packet.Packet104WindowItems;
040import net.minecraft.network.packet.Packet105UpdateProgressbar;
041import net.minecraft.network.packet.Packet17Sleep;
042import net.minecraft.network.packet.Packet18Animation;
043import net.minecraft.network.packet.Packet200Statistic;
044import net.minecraft.network.packet.Packet202PlayerAbilities;
045import net.minecraft.network.packet.Packet204ClientInfo;
046import net.minecraft.network.packet.Packet250CustomPayload;
047import net.minecraft.network.packet.Packet29DestroyEntity;
048import net.minecraft.network.packet.Packet38EntityStatus;
049import net.minecraft.network.packet.Packet39AttachEntity;
050import net.minecraft.network.packet.Packet3Chat;
051import net.minecraft.network.packet.Packet41EntityEffect;
052import net.minecraft.network.packet.Packet42RemoveEntityEffect;
053import net.minecraft.network.packet.Packet43Experience;
054import net.minecraft.network.packet.Packet56MapChunks;
055import net.minecraft.network.packet.Packet70GameEvent;
056import net.minecraft.network.packet.Packet8UpdateHealth;
057import net.minecraft.potion.PotionEffect;
058import net.minecraft.server.MinecraftServer;
059import net.minecraft.stats.AchievementList;
060import net.minecraft.stats.StatBase;
061import net.minecraft.tileentity.TileEntity;
062import net.minecraft.tileentity.TileEntityBeacon;
063import net.minecraft.tileentity.TileEntityBrewingStand;
064import net.minecraft.tileentity.TileEntityDispenser;
065import net.minecraft.tileentity.TileEntityFurnace;
066import net.minecraft.util.ChunkCoordinates;
067import net.minecraft.util.DamageSource;
068import net.minecraft.util.EntityDamageSource;
069import net.minecraft.util.MathHelper;
070import net.minecraft.util.StringTranslate;
071import net.minecraft.village.MerchantRecipeList;
072import net.minecraft.world.ChunkCoordIntPair;
073import net.minecraft.world.EnumGameType;
074import net.minecraft.world.World;
075import net.minecraft.world.WorldServer;
076import net.minecraft.world.chunk.Chunk;
077
078import net.minecraftforge.common.ForgeHooks;
079import net.minecraftforge.common.MinecraftForge;
080import net.minecraftforge.event.entity.player.PlayerDropsEvent;
081import net.minecraftforge.event.world.ChunkWatchEvent;
082
083public 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().sendChatMsg(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.removeEntity(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 position for this command sender.
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}