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