001package net.minecraft.client.entity; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import net.minecraft.client.Minecraft; 006import net.minecraft.client.gui.GuiCommandBlock; 007import net.minecraft.client.gui.GuiEnchantment; 008import net.minecraft.client.gui.GuiHopper; 009import net.minecraft.client.gui.GuiMerchant; 010import net.minecraft.client.gui.GuiRepair; 011import net.minecraft.client.gui.GuiScreen; 012import net.minecraft.client.gui.GuiScreenBook; 013import net.minecraft.client.gui.inventory.GuiBeacon; 014import net.minecraft.client.gui.inventory.GuiBrewingStand; 015import net.minecraft.client.gui.inventory.GuiChest; 016import net.minecraft.client.gui.inventory.GuiCrafting; 017import net.minecraft.client.gui.inventory.GuiDispenser; 018import net.minecraft.client.gui.inventory.GuiEditSign; 019import net.minecraft.client.gui.inventory.GuiFurnace; 020import net.minecraft.client.particle.EntityCrit2FX; 021import net.minecraft.client.particle.EntityPickupFX; 022import net.minecraft.entity.Entity; 023import net.minecraft.entity.IMerchant; 024import net.minecraft.entity.item.EntityMinecartHopper; 025import net.minecraft.entity.player.EntityPlayer; 026import net.minecraft.inventory.IInventory; 027import net.minecraft.item.Item; 028import net.minecraft.item.ItemStack; 029import net.minecraft.potion.Potion; 030import net.minecraft.stats.Achievement; 031import net.minecraft.stats.AchievementList; 032import net.minecraft.stats.StatBase; 033import net.minecraft.tileentity.TileEntity; 034import net.minecraft.tileentity.TileEntityBeacon; 035import net.minecraft.tileentity.TileEntityBrewingStand; 036import net.minecraft.tileentity.TileEntityCommandBlock; 037import net.minecraft.tileentity.TileEntityDispenser; 038import net.minecraft.tileentity.TileEntityFurnace; 039import net.minecraft.tileentity.TileEntityHopper; 040import net.minecraft.tileentity.TileEntitySign; 041import net.minecraft.util.ChunkCoordinates; 042import net.minecraft.util.DamageSource; 043import net.minecraft.util.MathHelper; 044import net.minecraft.util.MouseFilter; 045import net.minecraft.util.MovementInput; 046import net.minecraft.util.Session; 047import net.minecraft.util.StringUtils; 048import net.minecraft.world.World; 049 050@SideOnly(Side.CLIENT) 051public class EntityPlayerSP extends EntityPlayer 052{ 053 public MovementInput movementInput; 054 protected Minecraft mc; 055 056 /** 057 * Used to tell if the player pressed forward twice. If this is at 0 and it's pressed (And they are allowed to 058 * sprint, aka enough food on the ground etc) it sets this to 7. If it's pressed and it's greater than 0 enable 059 * sprinting. 060 */ 061 protected int sprintToggleTimer = 0; 062 063 /** Ticks left before sprinting is disabled. */ 064 public int sprintingTicksLeft = 0; 065 public float renderArmYaw; 066 public float renderArmPitch; 067 public float prevRenderArmYaw; 068 public float prevRenderArmPitch; 069 private MouseFilter field_71162_ch = new MouseFilter(); 070 private MouseFilter field_71160_ci = new MouseFilter(); 071 private MouseFilter field_71161_cj = new MouseFilter(); 072 073 /** The amount of time an entity has been in a Portal */ 074 public float timeInPortal; 075 076 /** The amount of time an entity has been in a Portal the previous tick */ 077 public float prevTimeInPortal; 078 079 public EntityPlayerSP(Minecraft par1Minecraft, World par2World, Session par3Session, int par4) 080 { 081 super(par2World); 082 this.mc = par1Minecraft; 083 this.dimension = par4; 084 085 if (par3Session != null && par3Session.username != null && par3Session.username.length() > 0) 086 { 087 this.skinUrl = "http://skins.minecraft.net/MinecraftSkins/" + StringUtils.stripControlCodes(par3Session.username) + ".png"; 088 } 089 090 this.username = par3Session.username; 091 } 092 093 /** 094 * Tries to moves the entity by the passed in displacement. Args: x, y, z 095 */ 096 public void moveEntity(double par1, double par3, double par5) 097 { 098 super.moveEntity(par1, par3, par5); 099 } 100 101 public void updateEntityActionState() 102 { 103 super.updateEntityActionState(); 104 this.moveStrafing = this.movementInput.moveStrafe; 105 this.moveForward = this.movementInput.moveForward; 106 this.isJumping = this.movementInput.jump; 107 this.prevRenderArmYaw = this.renderArmYaw; 108 this.prevRenderArmPitch = this.renderArmPitch; 109 this.renderArmPitch = (float)((double)this.renderArmPitch + (double)(this.rotationPitch - this.renderArmPitch) * 0.5D); 110 this.renderArmYaw = (float)((double)this.renderArmYaw + (double)(this.rotationYaw - this.renderArmYaw) * 0.5D); 111 } 112 113 /** 114 * Returns whether the entity is in a local (client) world 115 */ 116 protected boolean isClientWorld() 117 { 118 return true; 119 } 120 121 /** 122 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons 123 * use this to react to sunlight and start to burn. 124 */ 125 public void onLivingUpdate() 126 { 127 if (this.sprintingTicksLeft > 0) 128 { 129 --this.sprintingTicksLeft; 130 131 if (this.sprintingTicksLeft == 0) 132 { 133 this.setSprinting(false); 134 } 135 } 136 137 if (this.sprintToggleTimer > 0) 138 { 139 --this.sprintToggleTimer; 140 } 141 142 if (this.mc.playerController.enableEverythingIsScrewedUpMode()) 143 { 144 this.posX = this.posZ = 0.5D; 145 this.posX = 0.0D; 146 this.posZ = 0.0D; 147 this.rotationYaw = (float)this.ticksExisted / 12.0F; 148 this.rotationPitch = 10.0F; 149 this.posY = 68.5D; 150 } 151 else 152 { 153 if (!this.mc.statFileWriter.hasAchievementUnlocked(AchievementList.openInventory)) 154 { 155 this.mc.guiAchievement.queueAchievementInformation(AchievementList.openInventory); 156 } 157 158 this.prevTimeInPortal = this.timeInPortal; 159 160 if (this.inPortal) 161 { 162 if (this.mc.currentScreen != null) 163 { 164 this.mc.displayGuiScreen((GuiScreen)null); 165 } 166 167 if (this.timeInPortal == 0.0F) 168 { 169 this.mc.sndManager.playSoundFX("portal.trigger", 1.0F, this.rand.nextFloat() * 0.4F + 0.8F); 170 } 171 172 this.timeInPortal += 0.0125F; 173 174 if (this.timeInPortal >= 1.0F) 175 { 176 this.timeInPortal = 1.0F; 177 } 178 179 this.inPortal = false; 180 } 181 else if (this.isPotionActive(Potion.confusion) && this.getActivePotionEffect(Potion.confusion).getDuration() > 60) 182 { 183 this.timeInPortal += 0.006666667F; 184 185 if (this.timeInPortal > 1.0F) 186 { 187 this.timeInPortal = 1.0F; 188 } 189 } 190 else 191 { 192 if (this.timeInPortal > 0.0F) 193 { 194 this.timeInPortal -= 0.05F; 195 } 196 197 if (this.timeInPortal < 0.0F) 198 { 199 this.timeInPortal = 0.0F; 200 } 201 } 202 203 if (this.timeUntilPortal > 0) 204 { 205 --this.timeUntilPortal; 206 } 207 208 boolean flag = this.movementInput.jump; 209 float f = 0.8F; 210 boolean flag1 = this.movementInput.moveForward >= f; 211 this.movementInput.updatePlayerMoveState(); 212 213 if (this.isUsingItem()) 214 { 215 this.movementInput.moveStrafe *= 0.2F; 216 this.movementInput.moveForward *= 0.2F; 217 this.sprintToggleTimer = 0; 218 } 219 220 if (this.movementInput.sneak && this.ySize < 0.2F) 221 { 222 this.ySize = 0.2F; 223 } 224 225 this.pushOutOfBlocks(this.posX - (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ + (double)this.width * 0.35D); 226 this.pushOutOfBlocks(this.posX - (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ - (double)this.width * 0.35D); 227 this.pushOutOfBlocks(this.posX + (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ - (double)this.width * 0.35D); 228 this.pushOutOfBlocks(this.posX + (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ + (double)this.width * 0.35D); 229 boolean flag2 = (float)this.getFoodStats().getFoodLevel() > 6.0F || this.capabilities.allowFlying; 230 231 if (this.onGround && !flag1 && this.movementInput.moveForward >= f && !this.isSprinting() && flag2 && !this.isUsingItem() && !this.isPotionActive(Potion.blindness)) 232 { 233 if (this.sprintToggleTimer == 0) 234 { 235 this.sprintToggleTimer = 7; 236 } 237 else 238 { 239 this.setSprinting(true); 240 this.sprintToggleTimer = 0; 241 } 242 } 243 244 if (this.isSneaking()) 245 { 246 this.sprintToggleTimer = 0; 247 } 248 249 if (this.isSprinting() && (this.movementInput.moveForward < f || this.isCollidedHorizontally || !flag2)) 250 { 251 this.setSprinting(false); 252 } 253 254 if (this.capabilities.allowFlying && !flag && this.movementInput.jump) 255 { 256 if (this.flyToggleTimer == 0) 257 { 258 this.flyToggleTimer = 7; 259 } 260 else 261 { 262 this.capabilities.isFlying = !this.capabilities.isFlying; 263 this.sendPlayerAbilities(); 264 this.flyToggleTimer = 0; 265 } 266 } 267 268 if (this.capabilities.isFlying) 269 { 270 if (this.movementInput.sneak) 271 { 272 this.motionY -= 0.15D; 273 } 274 275 if (this.movementInput.jump) 276 { 277 this.motionY += 0.15D; 278 } 279 } 280 281 super.onLivingUpdate(); 282 283 if (this.onGround && this.capabilities.isFlying) 284 { 285 this.capabilities.isFlying = false; 286 this.sendPlayerAbilities(); 287 } 288 } 289 } 290 291 /** 292 * Gets the player's field of view multiplier. (ex. when flying) 293 */ 294 public float getFOVMultiplier() 295 { 296 float f = 1.0F; 297 298 if (this.capabilities.isFlying) 299 { 300 f *= 1.1F; 301 } 302 303 f *= (this.landMovementFactor * this.getSpeedModifier() / this.speedOnGround + 1.0F) / 2.0F; 304 305 if (this.isUsingItem() && this.getItemInUse().itemID == Item.bow.itemID) 306 { 307 int i = this.getItemInUseDuration(); 308 float f1 = (float)i / 20.0F; 309 310 if (f1 > 1.0F) 311 { 312 f1 = 1.0F; 313 } 314 else 315 { 316 f1 *= f1; 317 } 318 319 f *= 1.0F - f1 * 0.15F; 320 } 321 322 return f; 323 } 324 325 public void updateCloak() 326 { 327 this.cloakUrl = "http://skins.minecraft.net/MinecraftCloaks/" + StringUtils.stripControlCodes(this.username) + ".png"; 328 } 329 330 /** 331 * sets current screen to null (used on escape buttons of GUIs) 332 */ 333 public void closeScreen() 334 { 335 super.closeScreen(); 336 this.mc.displayGuiScreen((GuiScreen)null); 337 } 338 339 /** 340 * Displays the GUI for editing a sign. Args: tileEntitySign 341 */ 342 public void displayGUIEditSign(TileEntity par1TileEntity) 343 { 344 if (par1TileEntity instanceof TileEntitySign) 345 { 346 this.mc.displayGuiScreen(new GuiEditSign((TileEntitySign)par1TileEntity)); 347 } 348 else if (par1TileEntity instanceof TileEntityCommandBlock) 349 { 350 this.mc.displayGuiScreen(new GuiCommandBlock((TileEntityCommandBlock)par1TileEntity)); 351 } 352 } 353 354 /** 355 * Displays the GUI for interacting with a book. 356 */ 357 public void displayGUIBook(ItemStack par1ItemStack) 358 { 359 Item item = par1ItemStack.getItem(); 360 361 if (item == Item.writtenBook) 362 { 363 this.mc.displayGuiScreen(new GuiScreenBook(this, par1ItemStack, false)); 364 } 365 else if (item == Item.writableBook) 366 { 367 this.mc.displayGuiScreen(new GuiScreenBook(this, par1ItemStack, true)); 368 } 369 } 370 371 /** 372 * Displays the GUI for interacting with a chest inventory. Args: chestInventory 373 */ 374 public void displayGUIChest(IInventory par1IInventory) 375 { 376 this.mc.displayGuiScreen(new GuiChest(this.inventory, par1IInventory)); 377 } 378 379 public void func_94064_a(TileEntityHopper par1TileEntityHopper) 380 { 381 this.mc.displayGuiScreen(new GuiHopper(this.inventory, par1TileEntityHopper)); 382 } 383 384 public void func_96125_a(EntityMinecartHopper par1EntityMinecartHopper) 385 { 386 this.mc.displayGuiScreen(new GuiHopper(this.inventory, par1EntityMinecartHopper)); 387 } 388 389 /** 390 * Displays the crafting GUI for a workbench. 391 */ 392 public void displayGUIWorkbench(int par1, int par2, int par3) 393 { 394 this.mc.displayGuiScreen(new GuiCrafting(this.inventory, this.worldObj, par1, par2, par3)); 395 } 396 397 public void displayGUIEnchantment(int par1, int par2, int par3, String par4Str) 398 { 399 this.mc.displayGuiScreen(new GuiEnchantment(this.inventory, this.worldObj, par1, par2, par3, par4Str)); 400 } 401 402 /** 403 * Displays the GUI for interacting with an anvil. 404 */ 405 public void displayGUIAnvil(int par1, int par2, int par3) 406 { 407 this.mc.displayGuiScreen(new GuiRepair(this.inventory, this.worldObj, par1, par2, par3)); 408 } 409 410 /** 411 * Displays the furnace GUI for the passed in furnace entity. Args: tileEntityFurnace 412 */ 413 public void displayGUIFurnace(TileEntityFurnace par1TileEntityFurnace) 414 { 415 this.mc.displayGuiScreen(new GuiFurnace(this.inventory, par1TileEntityFurnace)); 416 } 417 418 /** 419 * Displays the GUI for interacting with a brewing stand. 420 */ 421 public void displayGUIBrewingStand(TileEntityBrewingStand par1TileEntityBrewingStand) 422 { 423 this.mc.displayGuiScreen(new GuiBrewingStand(this.inventory, par1TileEntityBrewingStand)); 424 } 425 426 /** 427 * Displays the GUI for interacting with a beacon. 428 */ 429 public void displayGUIBeacon(TileEntityBeacon par1TileEntityBeacon) 430 { 431 this.mc.displayGuiScreen(new GuiBeacon(this.inventory, par1TileEntityBeacon)); 432 } 433 434 /** 435 * Displays the dipsenser GUI for the passed in dispenser entity. Args: TileEntityDispenser 436 */ 437 public void displayGUIDispenser(TileEntityDispenser par1TileEntityDispenser) 438 { 439 this.mc.displayGuiScreen(new GuiDispenser(this.inventory, par1TileEntityDispenser)); 440 } 441 442 public void displayGUIMerchant(IMerchant par1IMerchant, String par2Str) 443 { 444 this.mc.displayGuiScreen(new GuiMerchant(this.inventory, par1IMerchant, this.worldObj, par2Str)); 445 } 446 447 /** 448 * Called when the player performs a critical hit on the Entity. Args: entity that was hit critically 449 */ 450 public void onCriticalHit(Entity par1Entity) 451 { 452 this.mc.effectRenderer.addEffect(new EntityCrit2FX(this.mc.theWorld, par1Entity)); 453 } 454 455 public void onEnchantmentCritical(Entity par1Entity) 456 { 457 EntityCrit2FX entitycrit2fx = new EntityCrit2FX(this.mc.theWorld, par1Entity, "magicCrit"); 458 this.mc.effectRenderer.addEffect(entitycrit2fx); 459 } 460 461 /** 462 * Called whenever an item is picked up from walking over it. Args: pickedUpEntity, stackSize 463 */ 464 public void onItemPickup(Entity par1Entity, int par2) 465 { 466 this.mc.effectRenderer.addEffect(new EntityPickupFX(this.mc.theWorld, par1Entity, this, -0.5F)); 467 } 468 469 /** 470 * Returns if this entity is sneaking. 471 */ 472 public boolean isSneaking() 473 { 474 return this.movementInput.sneak && !this.sleeping; 475 } 476 477 /** 478 * Updates health locally. 479 */ 480 public void setHealth(int par1) 481 { 482 int j = this.getHealth() - par1; 483 484 if (j <= 0) 485 { 486 this.setEntityHealth(par1); 487 488 if (j < 0) 489 { 490 this.hurtResistantTime = this.maxHurtResistantTime / 2; 491 } 492 } 493 else 494 { 495 this.lastDamage = j; 496 this.setEntityHealth(this.getHealth()); 497 this.hurtResistantTime = this.maxHurtResistantTime; 498 this.damageEntity(DamageSource.generic, j); 499 this.hurtTime = this.maxHurtTime = 10; 500 } 501 } 502 503 /** 504 * Add a chat message to the player 505 */ 506 public void addChatMessage(String par1Str) 507 { 508 this.mc.ingameGUI.getChatGUI().addTranslatedMessage(par1Str, new Object[0]); 509 } 510 511 /** 512 * Adds a value to a statistic field. 513 */ 514 public void addStat(StatBase par1StatBase, int par2) 515 { 516 if (par1StatBase != null) 517 { 518 if (par1StatBase.isAchievement()) 519 { 520 Achievement achievement = (Achievement)par1StatBase; 521 522 if (achievement.parentAchievement == null || this.mc.statFileWriter.hasAchievementUnlocked(achievement.parentAchievement)) 523 { 524 if (!this.mc.statFileWriter.hasAchievementUnlocked(achievement)) 525 { 526 this.mc.guiAchievement.queueTakenAchievement(achievement); 527 } 528 529 this.mc.statFileWriter.readStat(par1StatBase, par2); 530 } 531 } 532 else 533 { 534 this.mc.statFileWriter.readStat(par1StatBase, par2); 535 } 536 } 537 } 538 539 private boolean isBlockTranslucent(int par1, int par2, int par3) 540 { 541 return this.worldObj.isBlockNormalCube(par1, par2, par3); 542 } 543 544 /** 545 * Adds velocity to push the entity out of blocks at the specified x, y, z position Args: x, y, z 546 */ 547 protected boolean pushOutOfBlocks(double par1, double par3, double par5) 548 { 549 int i = MathHelper.floor_double(par1); 550 int j = MathHelper.floor_double(par3); 551 int k = MathHelper.floor_double(par5); 552 double d3 = par1 - (double)i; 553 double d4 = par5 - (double)k; 554 555 if (this.isBlockTranslucent(i, j, k) || this.isBlockTranslucent(i, j + 1, k)) 556 { 557 boolean flag = !this.isBlockTranslucent(i - 1, j, k) && !this.isBlockTranslucent(i - 1, j + 1, k); 558 boolean flag1 = !this.isBlockTranslucent(i + 1, j, k) && !this.isBlockTranslucent(i + 1, j + 1, k); 559 boolean flag2 = !this.isBlockTranslucent(i, j, k - 1) && !this.isBlockTranslucent(i, j + 1, k - 1); 560 boolean flag3 = !this.isBlockTranslucent(i, j, k + 1) && !this.isBlockTranslucent(i, j + 1, k + 1); 561 byte b0 = -1; 562 double d5 = 9999.0D; 563 564 if (flag && d3 < d5) 565 { 566 d5 = d3; 567 b0 = 0; 568 } 569 570 if (flag1 && 1.0D - d3 < d5) 571 { 572 d5 = 1.0D - d3; 573 b0 = 1; 574 } 575 576 if (flag2 && d4 < d5) 577 { 578 d5 = d4; 579 b0 = 4; 580 } 581 582 if (flag3 && 1.0D - d4 < d5) 583 { 584 d5 = 1.0D - d4; 585 b0 = 5; 586 } 587 588 float f = 0.1F; 589 590 if (b0 == 0) 591 { 592 this.motionX = (double)(-f); 593 } 594 595 if (b0 == 1) 596 { 597 this.motionX = (double)f; 598 } 599 600 if (b0 == 4) 601 { 602 this.motionZ = (double)(-f); 603 } 604 605 if (b0 == 5) 606 { 607 this.motionZ = (double)f; 608 } 609 } 610 611 return false; 612 } 613 614 /** 615 * Set sprinting switch for Entity. 616 */ 617 public void setSprinting(boolean par1) 618 { 619 super.setSprinting(par1); 620 this.sprintingTicksLeft = par1 ? 600 : 0; 621 } 622 623 /** 624 * Sets the current XP, total XP, and level number. 625 */ 626 public void setXPStats(float par1, int par2, int par3) 627 { 628 this.experience = par1; 629 this.experienceTotal = par2; 630 this.experienceLevel = par3; 631 } 632 633 public void sendChatToPlayer(String par1Str) 634 { 635 this.mc.ingameGUI.getChatGUI().printChatMessage(par1Str); 636 } 637 638 /** 639 * Returns true if the command sender is allowed to use the given command. 640 */ 641 public boolean canCommandSenderUseCommand(int par1, String par2Str) 642 { 643 return par1 <= 0; 644 } 645 646 /** 647 * Return the position for this command sender. 648 */ 649 public ChunkCoordinates getPlayerCoordinates() 650 { 651 return new ChunkCoordinates(MathHelper.floor_double(this.posX + 0.5D), MathHelper.floor_double(this.posY + 0.5D), MathHelper.floor_double(this.posZ + 0.5D)); 652 } 653 654 /** 655 * Returns the item that this EntityLiving is holding, if any. 656 */ 657 public ItemStack getHeldItem() 658 { 659 return this.inventory.getCurrentItem(); 660 } 661 662 public void playSound(String par1Str, float par2, float par3) 663 { 664 this.worldObj.playSound(this.posX, this.posY - (double)this.yOffset, this.posZ, par1Str, par2, par3, false); 665 } 666}