    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}