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