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