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.getScoreboard().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.isInvNameLocalized())); 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.isInvNameLocalized())); 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.isInvNameLocalized())); 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.isInvNameLocalized())); 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.isInvNameLocalized())); 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.isInvNameLocalized())); 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.isInvNameLocalized())); 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}