001 package net.minecraft.src; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.SideOnly; 005 006 import java.util.ArrayList; 007 import java.util.Iterator; 008 import java.util.List; 009 import java.util.Random; 010 import java.util.UUID; 011 012 public abstract class Entity 013 { 014 private static int nextEntityID = 0; 015 public int entityId; 016 public double renderDistanceWeight; 017 018 /** 019 * Blocks entities from spawning when they do their AABB check to make sure the spot is clear of entities that can 020 * prevent spawning. 021 */ 022 public boolean preventEntitySpawning; 023 024 /** The entity that is riding this entity */ 025 public Entity riddenByEntity; 026 027 /** The entity we are currently riding */ 028 public Entity ridingEntity; 029 030 /** Reference to the World object. */ 031 public World worldObj; 032 public double prevPosX; 033 public double prevPosY; 034 public double prevPosZ; 035 036 /** Entity position X */ 037 public double posX; 038 039 /** Entity position Y */ 040 public double posY; 041 042 /** Entity position Z */ 043 public double posZ; 044 045 /** Entity motion X */ 046 public double motionX; 047 048 /** Entity motion Y */ 049 public double motionY; 050 051 /** Entity motion Z */ 052 public double motionZ; 053 054 /** Entity rotation Yaw */ 055 public float rotationYaw; 056 057 /** Entity rotation Pitch */ 058 public float rotationPitch; 059 public float prevRotationYaw; 060 public float prevRotationPitch; 061 062 /** Axis aligned bounding box. */ 063 public final AxisAlignedBB boundingBox; 064 public boolean onGround; 065 066 /** 067 * True if after a move this entity has collided with something on X- or Z-axis 068 */ 069 public boolean isCollidedHorizontally; 070 071 /** 072 * True if after a move this entity has collided with something on Y-axis 073 */ 074 public boolean isCollidedVertically; 075 076 /** 077 * True if after a move this entity has collided with something either vertically or horizontally 078 */ 079 public boolean isCollided; 080 public boolean velocityChanged; 081 protected boolean isInWeb; 082 public boolean field_70135_K; 083 084 /** 085 * Gets set by setDead, so this must be the flag whether an Entity is dead (inactive may be better term) 086 */ 087 public boolean isDead; 088 public float yOffset; 089 090 /** How wide this entity is considered to be */ 091 public float width; 092 093 /** How high this entity is considered to be */ 094 public float height; 095 096 /** The previous ticks distance walked multiplied by 0.6 */ 097 public float prevDistanceWalkedModified; 098 099 /** The distance walked multiplied by 0.6 */ 100 public float distanceWalkedModified; 101 public float fallDistance; 102 103 /** 104 * The distance that has to be exceeded in order to triger a new step sound and an onEntityWalking event on a block 105 */ 106 private int nextStepDistance; 107 108 /** 109 * The entity's X coordinate at the previous tick, used to calculate position during rendering routines 110 */ 111 public double lastTickPosX; 112 113 /** 114 * The entity's Y coordinate at the previous tick, used to calculate position during rendering routines 115 */ 116 public double lastTickPosY; 117 118 /** 119 * The entity's Z coordinate at the previous tick, used to calculate position during rendering routines 120 */ 121 public double lastTickPosZ; 122 public float ySize; 123 124 /** 125 * How high this entity can step up when running into a block to try to get over it (currently make note the entity 126 * will always step up this amount and not just the amount needed) 127 */ 128 public float stepHeight; 129 130 /** 131 * Whether this entity won't clip with collision or not (make note it won't disable gravity) 132 */ 133 public boolean noClip; 134 135 /** 136 * Reduces the velocity applied by entity collisions by the specified percent. 137 */ 138 public float entityCollisionReduction; 139 protected Random rand; 140 141 /** How many ticks has this entity had ran since being alive */ 142 public int ticksExisted; 143 144 /** 145 * The amount of ticks you have to stand inside of fire before be set on fire 146 */ 147 public int fireResistance; 148 private int fire; 149 150 /** 151 * Whether this entity is currently inside of water (if it handles water movement that is) 152 */ 153 protected boolean inWater; 154 155 /** 156 * Remaining time an entity will be "immune" to further damage after being hurt. 157 */ 158 public int hurtResistantTime; 159 private boolean firstUpdate; 160 @SideOnly(Side.CLIENT) 161 162 /** downloadable location of player's skin */ 163 public String skinUrl; 164 @SideOnly(Side.CLIENT) 165 166 /** downloadable location of player's cloak */ 167 public String cloakUrl; 168 protected boolean isImmuneToFire; 169 protected DataWatcher dataWatcher; 170 private double entityRiderPitchDelta; 171 private double entityRiderYawDelta; 172 173 /** Has this entity been added to the chunk its within */ 174 public boolean addedToChunk; 175 public int chunkCoordX; 176 public int chunkCoordY; 177 public int chunkCoordZ; 178 @SideOnly(Side.CLIENT) 179 public int serverPosX; 180 @SideOnly(Side.CLIENT) 181 public int serverPosY; 182 @SideOnly(Side.CLIENT) 183 public int serverPosZ; 184 185 /** 186 * Render entity even if it is outside the camera frustum. Only true in EntityFish for now. Used in RenderGlobal: 187 * render if ignoreFrustumCheck or in frustum. 188 */ 189 public boolean ignoreFrustumCheck; 190 public boolean isAirBorne; 191 public EnumEntitySize myEntitySize; 192 /** Forge: Used to store custom data for each entity. */ 193 private NBTTagCompound customEntityData; 194 public boolean captureDrops = false; 195 public ArrayList<EntityItem> capturedDrops = new ArrayList<EntityItem>(); 196 private UUID persistentID; 197 198 public Entity(World par1World) 199 { 200 this.entityId = nextEntityID++; 201 this.renderDistanceWeight = 1.0D; 202 this.preventEntitySpawning = false; 203 this.boundingBox = AxisAlignedBB.getBoundingBox(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D); 204 this.onGround = false; 205 this.isCollided = false; 206 this.velocityChanged = false; 207 this.field_70135_K = true; 208 this.isDead = false; 209 this.yOffset = 0.0F; 210 this.width = 0.6F; 211 this.height = 1.8F; 212 this.prevDistanceWalkedModified = 0.0F; 213 this.distanceWalkedModified = 0.0F; 214 this.fallDistance = 0.0F; 215 this.nextStepDistance = 1; 216 this.ySize = 0.0F; 217 this.stepHeight = 0.0F; 218 this.noClip = false; 219 this.entityCollisionReduction = 0.0F; 220 this.rand = new Random(); 221 this.ticksExisted = 0; 222 this.fireResistance = 1; 223 this.fire = 0; 224 this.inWater = false; 225 this.hurtResistantTime = 0; 226 this.firstUpdate = true; 227 this.isImmuneToFire = false; 228 this.dataWatcher = new DataWatcher(); 229 this.addedToChunk = false; 230 this.myEntitySize = EnumEntitySize.SIZE_2; 231 this.worldObj = par1World; 232 this.setPosition(0.0D, 0.0D, 0.0D); 233 this.dataWatcher.addObject(0, Byte.valueOf((byte)0)); 234 this.dataWatcher.addObject(1, Short.valueOf((short)300)); 235 this.entityInit(); 236 } 237 238 protected abstract void entityInit(); 239 240 public DataWatcher getDataWatcher() 241 { 242 return this.dataWatcher; 243 } 244 245 public boolean equals(Object par1Obj) 246 { 247 return par1Obj instanceof Entity ? ((Entity)par1Obj).entityId == this.entityId : false; 248 } 249 250 public int hashCode() 251 { 252 return this.entityId; 253 } 254 255 @SideOnly(Side.CLIENT) 256 257 /** 258 * Keeps moving the entity up so it isn't colliding with blocks and other requirements for this entity to be spawned 259 * (only actually used on players though its also on Entity) 260 */ 261 protected void preparePlayerToSpawn() 262 { 263 if (this.worldObj != null) 264 { 265 while (this.posY > 0.0D) 266 { 267 this.setPosition(this.posX, this.posY, this.posZ); 268 269 if (this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty()) 270 { 271 break; 272 } 273 274 ++this.posY; 275 } 276 277 this.motionX = this.motionY = this.motionZ = 0.0D; 278 this.rotationPitch = 0.0F; 279 } 280 } 281 282 /** 283 * Will get destroyed next tick. 284 */ 285 public void setDead() 286 { 287 this.isDead = true; 288 } 289 290 /** 291 * Sets the width and height of the entity. Args: width, height 292 */ 293 protected void setSize(float par1, float par2) 294 { 295 this.width = par1; 296 this.height = par2; 297 float var3 = par1 % 2.0F; 298 299 if ((double)var3 < 0.375D) 300 { 301 this.myEntitySize = EnumEntitySize.SIZE_1; 302 } 303 else if ((double)var3 < 0.75D) 304 { 305 this.myEntitySize = EnumEntitySize.SIZE_2; 306 } 307 else if ((double)var3 < 1.0D) 308 { 309 this.myEntitySize = EnumEntitySize.SIZE_3; 310 } 311 else if ((double)var3 < 1.375D) 312 { 313 this.myEntitySize = EnumEntitySize.SIZE_4; 314 } 315 else if ((double)var3 < 1.75D) 316 { 317 this.myEntitySize = EnumEntitySize.SIZE_5; 318 } 319 else 320 { 321 this.myEntitySize = EnumEntitySize.SIZE_6; 322 } 323 } 324 325 /** 326 * Sets the rotation of the entity 327 */ 328 protected void setRotation(float par1, float par2) 329 { 330 this.rotationYaw = par1 % 360.0F; 331 this.rotationPitch = par2 % 360.0F; 332 } 333 334 /** 335 * Sets the x,y,z of the entity from the given parameters. Also seems to set up a bounding box. 336 */ 337 public void setPosition(double par1, double par3, double par5) 338 { 339 this.posX = par1; 340 this.posY = par3; 341 this.posZ = par5; 342 float var7 = this.width / 2.0F; 343 float var8 = this.height; 344 this.boundingBox.setBounds(par1 - (double)var7, par3 - (double)this.yOffset + (double)this.ySize, par5 - (double)var7, par1 + (double)var7, par3 - (double)this.yOffset + (double)this.ySize + (double)var8, par5 + (double)var7); 345 } 346 347 @SideOnly(Side.CLIENT) 348 349 /** 350 * Adds par1*0.15 to the entity's yaw, and *subtracts* par2*0.15 from the pitch. Clamps pitch from -90 to 90. Both 351 * arguments in degrees. 352 */ 353 public void setAngles(float par1, float par2) 354 { 355 float var3 = this.rotationPitch; 356 float var4 = this.rotationYaw; 357 this.rotationYaw = (float)((double)this.rotationYaw + (double)par1 * 0.15D); 358 this.rotationPitch = (float)((double)this.rotationPitch - (double)par2 * 0.15D); 359 360 if (this.rotationPitch < -90.0F) 361 { 362 this.rotationPitch = -90.0F; 363 } 364 365 if (this.rotationPitch > 90.0F) 366 { 367 this.rotationPitch = 90.0F; 368 } 369 370 this.prevRotationPitch += this.rotationPitch - var3; 371 this.prevRotationYaw += this.rotationYaw - var4; 372 } 373 374 /** 375 * Called to update the entity's position/logic. 376 */ 377 public void onUpdate() 378 { 379 this.onEntityUpdate(); 380 } 381 382 /** 383 * Gets called every tick from main Entity class 384 */ 385 public void onEntityUpdate() 386 { 387 this.worldObj.theProfiler.startSection("entityBaseTick"); 388 389 if (this.ridingEntity != null && this.ridingEntity.isDead) 390 { 391 this.ridingEntity = null; 392 } 393 394 ++this.ticksExisted; 395 this.prevDistanceWalkedModified = this.distanceWalkedModified; 396 this.prevPosX = this.posX; 397 this.prevPosY = this.posY; 398 this.prevPosZ = this.posZ; 399 this.prevRotationPitch = this.rotationPitch; 400 this.prevRotationYaw = this.rotationYaw; 401 int var3; 402 403 if (this.isSprinting() && !this.isInWater()) 404 { 405 int var1 = MathHelper.floor_double(this.posX); 406 int var2 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 407 var3 = MathHelper.floor_double(this.posZ); 408 int var4 = this.worldObj.getBlockId(var1, var2, var3); 409 410 if (var4 > 0) 411 { 412 this.worldObj.spawnParticle("tilecrack_" + var4, this.posX + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, this.boundingBox.minY + 0.1D, this.posZ + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, -this.motionX * 4.0D, 1.5D, -this.motionZ * 4.0D); 413 } 414 } 415 416 if (this.handleWaterMovement()) 417 { 418 if (!this.inWater && !this.firstUpdate) 419 { 420 float var6 = MathHelper.sqrt_double(this.motionX * this.motionX * 0.20000000298023224D + this.motionY * this.motionY + this.motionZ * this.motionZ * 0.20000000298023224D) * 0.2F; 421 422 if (var6 > 1.0F) 423 { 424 var6 = 1.0F; 425 } 426 427 this.worldObj.playSoundAtEntity(this, "random.splash", var6, 1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.4F); 428 float var7 = (float)MathHelper.floor_double(this.boundingBox.minY); 429 float var5; 430 float var8; 431 432 for (var3 = 0; (float)var3 < 1.0F + this.width * 20.0F; ++var3) 433 { 434 var8 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 435 var5 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 436 this.worldObj.spawnParticle("bubble", this.posX + (double)var8, (double)(var7 + 1.0F), this.posZ + (double)var5, this.motionX, this.motionY - (double)(this.rand.nextFloat() * 0.2F), this.motionZ); 437 } 438 439 for (var3 = 0; (float)var3 < 1.0F + this.width * 20.0F; ++var3) 440 { 441 var8 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 442 var5 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width; 443 this.worldObj.spawnParticle("splash", this.posX + (double)var8, (double)(var7 + 1.0F), this.posZ + (double)var5, this.motionX, this.motionY, this.motionZ); 444 } 445 } 446 447 this.fallDistance = 0.0F; 448 this.inWater = true; 449 this.fire = 0; 450 } 451 else 452 { 453 this.inWater = false; 454 } 455 456 if (this.worldObj.isRemote) 457 { 458 this.fire = 0; 459 } 460 else if (this.fire > 0) 461 { 462 if (this.isImmuneToFire) 463 { 464 this.fire -= 4; 465 466 if (this.fire < 0) 467 { 468 this.fire = 0; 469 } 470 } 471 else 472 { 473 if (this.fire % 20 == 0) 474 { 475 this.attackEntityFrom(DamageSource.onFire, 1); 476 } 477 478 --this.fire; 479 } 480 } 481 482 if (this.handleLavaMovement()) 483 { 484 this.setOnFireFromLava(); 485 this.fallDistance *= 0.5F; 486 } 487 488 if (this.posY < -64.0D) 489 { 490 this.kill(); 491 } 492 493 if (!this.worldObj.isRemote) 494 { 495 this.setFlag(0, this.fire > 0); 496 this.setFlag(2, this.ridingEntity != null); 497 } 498 499 this.firstUpdate = false; 500 this.worldObj.theProfiler.endSection(); 501 } 502 503 /** 504 * Called whenever the entity is walking inside of lava. 505 */ 506 protected void setOnFireFromLava() 507 { 508 if (!this.isImmuneToFire) 509 { 510 this.attackEntityFrom(DamageSource.lava, 4); 511 this.setFire(15); 512 } 513 } 514 515 /** 516 * Sets entity to burn for x amount of seconds, cannot lower amount of existing fire. 517 */ 518 public void setFire(int par1) 519 { 520 int var2 = par1 * 20; 521 522 if (this.fire < var2) 523 { 524 this.fire = var2; 525 } 526 } 527 528 /** 529 * Removes fire from entity. 530 */ 531 public void extinguish() 532 { 533 this.fire = 0; 534 } 535 536 /** 537 * sets the dead flag. Used when you fall off the bottom of the world. 538 */ 539 protected void kill() 540 { 541 this.setDead(); 542 } 543 544 /** 545 * Checks if the offset position from the entity's current position is inside of liquid. Args: x, y, z 546 */ 547 public boolean isOffsetPositionInLiquid(double par1, double par3, double par5) 548 { 549 AxisAlignedBB var7 = this.boundingBox.getOffsetBoundingBox(par1, par3, par5); 550 List var8 = this.worldObj.getCollidingBoundingBoxes(this, var7); 551 return !var8.isEmpty() ? false : !this.worldObj.isAnyLiquid(var7); 552 } 553 554 /** 555 * Tries to moves the entity by the passed in displacement. Args: x, y, z 556 */ 557 public void moveEntity(double par1, double par3, double par5) 558 { 559 if (this.noClip) 560 { 561 this.boundingBox.offset(par1, par3, par5); 562 this.posX = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0D; 563 this.posY = this.boundingBox.minY + (double)this.yOffset - (double)this.ySize; 564 this.posZ = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0D; 565 } 566 else 567 { 568 this.worldObj.theProfiler.startSection("move"); 569 this.ySize *= 0.4F; 570 double var7 = this.posX; 571 double var9 = this.posZ; 572 573 if (this.isInWeb) 574 { 575 this.isInWeb = false; 576 par1 *= 0.25D; 577 par3 *= 0.05000000074505806D; 578 par5 *= 0.25D; 579 this.motionX = 0.0D; 580 this.motionY = 0.0D; 581 this.motionZ = 0.0D; 582 } 583 584 double var11 = par1; 585 double var13 = par3; 586 double var15 = par5; 587 AxisAlignedBB var17 = this.boundingBox.copy(); 588 boolean var18 = this.onGround && this.isSneaking() && this instanceof EntityPlayer; 589 590 if (var18) 591 { 592 double var19; 593 594 for (var19 = 0.05D; par1 != 0.0D && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.getOffsetBoundingBox(par1, -1.0D, 0.0D)).isEmpty(); var11 = par1) 595 { 596 if (par1 < var19 && par1 >= -var19) 597 { 598 par1 = 0.0D; 599 } 600 else if (par1 > 0.0D) 601 { 602 par1 -= var19; 603 } 604 else 605 { 606 par1 += var19; 607 } 608 } 609 610 for (; par5 != 0.0D && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.getOffsetBoundingBox(0.0D, -1.0D, par5)).isEmpty(); var15 = par5) 611 { 612 if (par5 < var19 && par5 >= -var19) 613 { 614 par5 = 0.0D; 615 } 616 else if (par5 > 0.0D) 617 { 618 par5 -= var19; 619 } 620 else 621 { 622 par5 += var19; 623 } 624 } 625 626 while (par1 != 0.0D && par5 != 0.0D && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.getOffsetBoundingBox(par1, -1.0D, par5)).isEmpty()) 627 { 628 if (par1 < var19 && par1 >= -var19) 629 { 630 par1 = 0.0D; 631 } 632 else if (par1 > 0.0D) 633 { 634 par1 -= var19; 635 } 636 else 637 { 638 par1 += var19; 639 } 640 641 if (par5 < var19 && par5 >= -var19) 642 { 643 par5 = 0.0D; 644 } 645 else if (par5 > 0.0D) 646 { 647 par5 -= var19; 648 } 649 else 650 { 651 par5 += var19; 652 } 653 654 var11 = par1; 655 var15 = par5; 656 } 657 } 658 659 List var30 = this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.addCoord(par1, par3, par5)); 660 AxisAlignedBB var21; 661 662 for (Iterator var20 = var30.iterator(); var20.hasNext(); par3 = var21.calculateYOffset(this.boundingBox, par3)) 663 { 664 var21 = (AxisAlignedBB)var20.next(); 665 } 666 667 this.boundingBox.offset(0.0D, par3, 0.0D); 668 669 if (!this.field_70135_K && var13 != par3) 670 { 671 par5 = 0.0D; 672 par3 = 0.0D; 673 par1 = 0.0D; 674 } 675 676 boolean var31 = this.onGround || var13 != par3 && var13 < 0.0D; 677 AxisAlignedBB var22; 678 Iterator var32; 679 680 for (var32 = var30.iterator(); var32.hasNext(); par1 = var22.calculateXOffset(this.boundingBox, par1)) 681 { 682 var22 = (AxisAlignedBB)var32.next(); 683 } 684 685 this.boundingBox.offset(par1, 0.0D, 0.0D); 686 687 if (!this.field_70135_K && var11 != par1) 688 { 689 par5 = 0.0D; 690 par3 = 0.0D; 691 par1 = 0.0D; 692 } 693 694 for (var32 = var30.iterator(); var32.hasNext(); par5 = var22.calculateZOffset(this.boundingBox, par5)) 695 { 696 var22 = (AxisAlignedBB)var32.next(); 697 } 698 699 this.boundingBox.offset(0.0D, 0.0D, par5); 700 701 if (!this.field_70135_K && var15 != par5) 702 { 703 par5 = 0.0D; 704 par3 = 0.0D; 705 par1 = 0.0D; 706 } 707 708 double var23; 709 double var33; 710 711 if (this.stepHeight > 0.0F && var31 && (var18 || this.ySize < 0.05F) && (var11 != par1 || var15 != par5)) 712 { 713 var33 = par1; 714 var23 = par3; 715 double var25 = par5; 716 par1 = var11; 717 par3 = (double)this.stepHeight; 718 par5 = var15; 719 AxisAlignedBB var27 = this.boundingBox.copy(); 720 this.boundingBox.setBB(var17); 721 var30 = this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.addCoord(var11, par3, var15)); 722 AxisAlignedBB var29; 723 Iterator var28; 724 725 for (var28 = var30.iterator(); var28.hasNext(); par3 = var29.calculateYOffset(this.boundingBox, par3)) 726 { 727 var29 = (AxisAlignedBB)var28.next(); 728 } 729 730 this.boundingBox.offset(0.0D, par3, 0.0D); 731 732 if (!this.field_70135_K && var13 != par3) 733 { 734 par5 = 0.0D; 735 par3 = 0.0D; 736 par1 = 0.0D; 737 } 738 739 for (var28 = var30.iterator(); var28.hasNext(); par1 = var29.calculateXOffset(this.boundingBox, par1)) 740 { 741 var29 = (AxisAlignedBB)var28.next(); 742 } 743 744 this.boundingBox.offset(par1, 0.0D, 0.0D); 745 746 if (!this.field_70135_K && var11 != par1) 747 { 748 par5 = 0.0D; 749 par3 = 0.0D; 750 par1 = 0.0D; 751 } 752 753 for (var28 = var30.iterator(); var28.hasNext(); par5 = var29.calculateZOffset(this.boundingBox, par5)) 754 { 755 var29 = (AxisAlignedBB)var28.next(); 756 } 757 758 this.boundingBox.offset(0.0D, 0.0D, par5); 759 760 if (!this.field_70135_K && var15 != par5) 761 { 762 par5 = 0.0D; 763 par3 = 0.0D; 764 par1 = 0.0D; 765 } 766 767 if (!this.field_70135_K && var13 != par3) 768 { 769 par5 = 0.0D; 770 par3 = 0.0D; 771 par1 = 0.0D; 772 } 773 else 774 { 775 par3 = (double)(-this.stepHeight); 776 777 for (var28 = var30.iterator(); var28.hasNext(); par3 = var29.calculateYOffset(this.boundingBox, par3)) 778 { 779 var29 = (AxisAlignedBB)var28.next(); 780 } 781 782 this.boundingBox.offset(0.0D, par3, 0.0D); 783 } 784 785 if (var33 * var33 + var25 * var25 >= par1 * par1 + par5 * par5) 786 { 787 par1 = var33; 788 par3 = var23; 789 par5 = var25; 790 this.boundingBox.setBB(var27); 791 } 792 else 793 { 794 double var37 = this.boundingBox.minY - (double)((int)this.boundingBox.minY); 795 796 if (var37 > 0.0D) 797 { 798 this.ySize = (float)((double)this.ySize + var37 + 0.01D); 799 } 800 } 801 } 802 803 this.worldObj.theProfiler.endSection(); 804 this.worldObj.theProfiler.startSection("rest"); 805 this.posX = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0D; 806 this.posY = this.boundingBox.minY + (double)this.yOffset - (double)this.ySize; 807 this.posZ = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0D; 808 this.isCollidedHorizontally = var11 != par1 || var15 != par5; 809 this.isCollidedVertically = var13 != par3; 810 this.onGround = var13 != par3 && var13 < 0.0D; 811 this.isCollided = this.isCollidedHorizontally || this.isCollidedVertically; 812 this.updateFallState(par3, this.onGround); 813 814 if (var11 != par1) 815 { 816 this.motionX = 0.0D; 817 } 818 819 if (var13 != par3) 820 { 821 this.motionY = 0.0D; 822 } 823 824 if (var15 != par5) 825 { 826 this.motionZ = 0.0D; 827 } 828 829 var33 = this.posX - var7; 830 var23 = this.posZ - var9; 831 832 if (this.canTriggerWalking() && !var18 && this.ridingEntity == null) 833 { 834 this.distanceWalkedModified = (float)((double)this.distanceWalkedModified + (double)MathHelper.sqrt_double(var33 * var33 + var23 * var23) * 0.6D); 835 int var34 = MathHelper.floor_double(this.posX); 836 int var26 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 837 int var36 = MathHelper.floor_double(this.posZ); 838 int var38 = this.worldObj.getBlockId(var34, var26, var36); 839 840 if (var38 == 0 && this.worldObj.getBlockId(var34, var26 - 1, var36) == Block.fence.blockID) 841 { 842 var38 = this.worldObj.getBlockId(var34, var26 - 1, var36); 843 } 844 845 if (this.distanceWalkedModified > (float)this.nextStepDistance && var38 > 0) 846 { 847 this.nextStepDistance = (int)this.distanceWalkedModified + 1; 848 this.playStepSound(var34, var26, var36, var38); 849 Block.blocksList[var38].onEntityWalking(this.worldObj, var34, var26, var36, this); 850 } 851 } 852 853 this.doBlockCollisions(); 854 boolean var35 = this.isWet(); 855 856 if (this.worldObj.isBoundingBoxBurning(this.boundingBox.contract(0.001D, 0.001D, 0.001D))) 857 { 858 this.dealFireDamage(1); 859 860 if (!var35) 861 { 862 ++this.fire; 863 864 if (this.fire == 0) 865 { 866 this.setFire(8); 867 } 868 } 869 } 870 else if (this.fire <= 0) 871 { 872 this.fire = -this.fireResistance; 873 } 874 875 if (var35 && this.fire > 0) 876 { 877 this.worldObj.playSoundAtEntity(this, "random.fizz", 0.7F, 1.6F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.4F); 878 this.fire = -this.fireResistance; 879 } 880 881 this.worldObj.theProfiler.endSection(); 882 } 883 } 884 885 /** 886 * Checks for block collisions, and calls the associated onBlockCollided method for the collided block. 887 */ 888 protected void doBlockCollisions() 889 { 890 int var1 = MathHelper.floor_double(this.boundingBox.minX + 0.001D); 891 int var2 = MathHelper.floor_double(this.boundingBox.minY + 0.001D); 892 int var3 = MathHelper.floor_double(this.boundingBox.minZ + 0.001D); 893 int var4 = MathHelper.floor_double(this.boundingBox.maxX - 0.001D); 894 int var5 = MathHelper.floor_double(this.boundingBox.maxY - 0.001D); 895 int var6 = MathHelper.floor_double(this.boundingBox.maxZ - 0.001D); 896 897 if (this.worldObj.checkChunksExist(var1, var2, var3, var4, var5, var6)) 898 { 899 for (int var7 = var1; var7 <= var4; ++var7) 900 { 901 for (int var8 = var2; var8 <= var5; ++var8) 902 { 903 for (int var9 = var3; var9 <= var6; ++var9) 904 { 905 int var10 = this.worldObj.getBlockId(var7, var8, var9); 906 907 if (var10 > 0) 908 { 909 Block.blocksList[var10].onEntityCollidedWithBlock(this.worldObj, var7, var8, var9, this); 910 } 911 } 912 } 913 } 914 } 915 } 916 917 /** 918 * Plays step sound at given x, y, z for the entity 919 */ 920 protected void playStepSound(int par1, int par2, int par3, int par4) 921 { 922 StepSound var5 = Block.blocksList[par4].stepSound; 923 924 if (this.worldObj.getBlockId(par1, par2 + 1, par3) == Block.snow.blockID) 925 { 926 var5 = Block.snow.stepSound; 927 this.worldObj.playSoundAtEntity(this, var5.getStepSound(), var5.getVolume() * 0.15F, var5.getPitch()); 928 } 929 else if (!Block.blocksList[par4].blockMaterial.isLiquid()) 930 { 931 this.worldObj.playSoundAtEntity(this, var5.getStepSound(), var5.getVolume() * 0.15F, var5.getPitch()); 932 } 933 } 934 935 /** 936 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to 937 * prevent them from trampling crops 938 */ 939 protected boolean canTriggerWalking() 940 { 941 return true; 942 } 943 944 /** 945 * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance 946 * and deal fall damage if landing on the ground. Args: distanceFallenThisTick, onGround 947 */ 948 protected void updateFallState(double par1, boolean par3) 949 { 950 if (par3) 951 { 952 if (this.fallDistance > 0.0F) 953 { 954 if (this instanceof EntityLiving) 955 { 956 int var4 = MathHelper.floor_double(this.posX); 957 int var5 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 958 int var6 = MathHelper.floor_double(this.posZ); 959 int var7 = this.worldObj.getBlockId(var4, var5, var6); 960 961 if (var7 == 0 && this.worldObj.getBlockId(var4, var5 - 1, var6) == Block.fence.blockID) 962 { 963 var7 = this.worldObj.getBlockId(var4, var5 - 1, var6); 964 } 965 966 if (var7 > 0) 967 { 968 Block.blocksList[var7].onFallenUpon(this.worldObj, var4, var5, var6, this, this.fallDistance); 969 } 970 } 971 972 this.fall(this.fallDistance); 973 this.fallDistance = 0.0F; 974 } 975 } 976 else if (par1 < 0.0D) 977 { 978 this.fallDistance = (float)((double)this.fallDistance - par1); 979 } 980 } 981 982 /** 983 * returns the bounding box for this entity 984 */ 985 public AxisAlignedBB getBoundingBox() 986 { 987 return null; 988 } 989 990 /** 991 * Will deal the specified amount of damage to the entity if the entity isn't immune to fire damage. Args: 992 * amountDamage 993 */ 994 protected void dealFireDamage(int par1) 995 { 996 if (!this.isImmuneToFire) 997 { 998 this.attackEntityFrom(DamageSource.inFire, par1); 999 } 1000 } 1001 1002 public final boolean isImmuneToFire() 1003 { 1004 return this.isImmuneToFire; 1005 } 1006 1007 /** 1008 * Called when the mob is falling. Calculates and applies fall damage. 1009 */ 1010 protected void fall(float par1) 1011 { 1012 if (this.riddenByEntity != null) 1013 { 1014 this.riddenByEntity.fall(par1); 1015 } 1016 } 1017 1018 /** 1019 * Checks if this entity is either in water or on an open air block in rain (used in wolves). 1020 */ 1021 public boolean isWet() 1022 { 1023 return this.inWater || this.worldObj.canLightningStrikeAt(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)); 1024 } 1025 1026 /** 1027 * Checks if this entity is inside water (if inWater field is true as a result of handleWaterMovement() returning 1028 * true) 1029 */ 1030 public boolean isInWater() 1031 { 1032 return this.inWater; 1033 } 1034 1035 /** 1036 * Returns if this entity is in water and will end up adding the waters velocity to the entity 1037 */ 1038 public boolean handleWaterMovement() 1039 { 1040 return this.worldObj.handleMaterialAcceleration(this.boundingBox.expand(0.0D, -0.4000000059604645D, 0.0D).contract(0.001D, 0.001D, 0.001D), Material.water, this); 1041 } 1042 1043 /** 1044 * Checks if the current block the entity is within of the specified material type 1045 */ 1046 public boolean isInsideOfMaterial(Material par1Material) 1047 { 1048 double var2 = this.posY + (double)this.getEyeHeight(); 1049 int var4 = MathHelper.floor_double(this.posX); 1050 int var5 = MathHelper.floor_float((float)MathHelper.floor_double(var2)); 1051 int var6 = MathHelper.floor_double(this.posZ); 1052 int var7 = this.worldObj.getBlockId(var4, var5, var6); 1053 1054 if (var7 != 0 && Block.blocksList[var7].blockMaterial == par1Material) 1055 { 1056 float var8 = BlockFluid.getFluidHeightPercent(this.worldObj.getBlockMetadata(var4, var5, var6)) - 0.11111111F; 1057 float var9 = (float)(var5 + 1) - var8; 1058 return var2 < (double)var9; 1059 } 1060 else 1061 { 1062 return false; 1063 } 1064 } 1065 1066 public float getEyeHeight() 1067 { 1068 return 0.0F; 1069 } 1070 1071 /** 1072 * Whether or not the current entity is in lava 1073 */ 1074 public boolean handleLavaMovement() 1075 { 1076 return this.worldObj.isMaterialInBB(this.boundingBox.expand(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.lava); 1077 } 1078 1079 /** 1080 * Used in both water and by flying objects 1081 */ 1082 public void moveFlying(float par1, float par2, float par3) 1083 { 1084 float var4 = par1 * par1 + par2 * par2; 1085 1086 if (var4 >= 1.0E-4F) 1087 { 1088 var4 = MathHelper.sqrt_float(var4); 1089 1090 if (var4 < 1.0F) 1091 { 1092 var4 = 1.0F; 1093 } 1094 1095 var4 = par3 / var4; 1096 par1 *= var4; 1097 par2 *= var4; 1098 float var5 = MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F); 1099 float var6 = MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F); 1100 this.motionX += (double)(par1 * var6 - par2 * var5); 1101 this.motionZ += (double)(par2 * var6 + par1 * var5); 1102 } 1103 } 1104 1105 @SideOnly(Side.CLIENT) 1106 public int getBrightnessForRender(float par1) 1107 { 1108 int var2 = MathHelper.floor_double(this.posX); 1109 int var3 = MathHelper.floor_double(this.posZ); 1110 1111 if (this.worldObj.blockExists(var2, 0, var3)) 1112 { 1113 double var4 = (this.boundingBox.maxY - this.boundingBox.minY) * 0.66D; 1114 int var6 = MathHelper.floor_double(this.posY - (double)this.yOffset + var4); 1115 return this.worldObj.getLightBrightnessForSkyBlocks(var2, var6, var3, 0); 1116 } 1117 else 1118 { 1119 return 0; 1120 } 1121 } 1122 1123 /** 1124 * Gets how bright this entity is. 1125 */ 1126 public float getBrightness(float par1) 1127 { 1128 int var2 = MathHelper.floor_double(this.posX); 1129 int var3 = MathHelper.floor_double(this.posZ); 1130 1131 if (this.worldObj.blockExists(var2, 0, var3)) 1132 { 1133 double var4 = (this.boundingBox.maxY - this.boundingBox.minY) * 0.66D; 1134 int var6 = MathHelper.floor_double(this.posY - (double)this.yOffset + var4); 1135 return this.worldObj.getLightBrightness(var2, var6, var3); 1136 } 1137 else 1138 { 1139 return 0.0F; 1140 } 1141 } 1142 1143 /** 1144 * Sets the reference to the World object. 1145 */ 1146 public void setWorld(World par1World) 1147 { 1148 this.worldObj = par1World; 1149 } 1150 1151 /** 1152 * Sets the entity's position and rotation. Args: posX, posY, posZ, yaw, pitch 1153 */ 1154 public void setPositionAndRotation(double par1, double par3, double par5, float par7, float par8) 1155 { 1156 this.prevPosX = this.posX = par1; 1157 this.prevPosY = this.posY = par3; 1158 this.prevPosZ = this.posZ = par5; 1159 this.prevRotationYaw = this.rotationYaw = par7; 1160 this.prevRotationPitch = this.rotationPitch = par8; 1161 this.ySize = 0.0F; 1162 double var9 = (double)(this.prevRotationYaw - par7); 1163 1164 if (var9 < -180.0D) 1165 { 1166 this.prevRotationYaw += 360.0F; 1167 } 1168 1169 if (var9 >= 180.0D) 1170 { 1171 this.prevRotationYaw -= 360.0F; 1172 } 1173 1174 this.setPosition(this.posX, this.posY, this.posZ); 1175 this.setRotation(par7, par8); 1176 } 1177 1178 /** 1179 * Sets the location and Yaw/Pitch of an entity in the world 1180 */ 1181 public void setLocationAndAngles(double par1, double par3, double par5, float par7, float par8) 1182 { 1183 this.lastTickPosX = this.prevPosX = this.posX = par1; 1184 this.lastTickPosY = this.prevPosY = this.posY = par3 + (double)this.yOffset; 1185 this.lastTickPosZ = this.prevPosZ = this.posZ = par5; 1186 this.rotationYaw = par7; 1187 this.rotationPitch = par8; 1188 this.setPosition(this.posX, this.posY, this.posZ); 1189 } 1190 1191 /** 1192 * Returns the distance to the entity. Args: entity 1193 */ 1194 public float getDistanceToEntity(Entity par1Entity) 1195 { 1196 float var2 = (float)(this.posX - par1Entity.posX); 1197 float var3 = (float)(this.posY - par1Entity.posY); 1198 float var4 = (float)(this.posZ - par1Entity.posZ); 1199 return MathHelper.sqrt_float(var2 * var2 + var3 * var3 + var4 * var4); 1200 } 1201 1202 /** 1203 * Gets the squared distance to the position. Args: x, y, z 1204 */ 1205 public double getDistanceSq(double par1, double par3, double par5) 1206 { 1207 double var7 = this.posX - par1; 1208 double var9 = this.posY - par3; 1209 double var11 = this.posZ - par5; 1210 return var7 * var7 + var9 * var9 + var11 * var11; 1211 } 1212 1213 /** 1214 * Gets the distance to the position. Args: x, y, z 1215 */ 1216 public double getDistance(double par1, double par3, double par5) 1217 { 1218 double var7 = this.posX - par1; 1219 double var9 = this.posY - par3; 1220 double var11 = this.posZ - par5; 1221 return (double)MathHelper.sqrt_double(var7 * var7 + var9 * var9 + var11 * var11); 1222 } 1223 1224 /** 1225 * Returns the squared distance to the entity. Args: entity 1226 */ 1227 public double getDistanceSqToEntity(Entity par1Entity) 1228 { 1229 double var2 = this.posX - par1Entity.posX; 1230 double var4 = this.posY - par1Entity.posY; 1231 double var6 = this.posZ - par1Entity.posZ; 1232 return var2 * var2 + var4 * var4 + var6 * var6; 1233 } 1234 1235 /** 1236 * Called by a player entity when they collide with an entity 1237 */ 1238 public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) {} 1239 1240 /** 1241 * Applies a velocity to each of the entities pushing them away from each other. Args: entity 1242 */ 1243 public void applyEntityCollision(Entity par1Entity) 1244 { 1245 if (par1Entity.riddenByEntity != this && par1Entity.ridingEntity != this) 1246 { 1247 double var2 = par1Entity.posX - this.posX; 1248 double var4 = par1Entity.posZ - this.posZ; 1249 double var6 = MathHelper.abs_max(var2, var4); 1250 1251 if (var6 >= 0.009999999776482582D) 1252 { 1253 var6 = (double)MathHelper.sqrt_double(var6); 1254 var2 /= var6; 1255 var4 /= var6; 1256 double var8 = 1.0D / var6; 1257 1258 if (var8 > 1.0D) 1259 { 1260 var8 = 1.0D; 1261 } 1262 1263 var2 *= var8; 1264 var4 *= var8; 1265 var2 *= 0.05000000074505806D; 1266 var4 *= 0.05000000074505806D; 1267 var2 *= (double)(1.0F - this.entityCollisionReduction); 1268 var4 *= (double)(1.0F - this.entityCollisionReduction); 1269 this.addVelocity(-var2, 0.0D, -var4); 1270 par1Entity.addVelocity(var2, 0.0D, var4); 1271 } 1272 } 1273 } 1274 1275 /** 1276 * Adds to the current velocity of the entity. Args: x, y, z 1277 */ 1278 public void addVelocity(double par1, double par3, double par5) 1279 { 1280 this.motionX += par1; 1281 this.motionY += par3; 1282 this.motionZ += par5; 1283 this.isAirBorne = true; 1284 } 1285 1286 /** 1287 * Sets that this entity has been attacked. 1288 */ 1289 protected void setBeenAttacked() 1290 { 1291 this.velocityChanged = true; 1292 } 1293 1294 /** 1295 * Called when the entity is attacked. 1296 */ 1297 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 1298 { 1299 this.setBeenAttacked(); 1300 return false; 1301 } 1302 1303 /** 1304 * Returns true if other Entities should be prevented from moving through this Entity. 1305 */ 1306 public boolean canBeCollidedWith() 1307 { 1308 return false; 1309 } 1310 1311 /** 1312 * Returns true if this entity should push and be pushed by other entities when colliding. 1313 */ 1314 public boolean canBePushed() 1315 { 1316 return false; 1317 } 1318 1319 /** 1320 * Adds a value to the player score. Currently not actually used and the entity passed in does nothing. Args: 1321 * entity, scoreToAdd 1322 */ 1323 public void addToPlayerScore(Entity par1Entity, int par2) {} 1324 1325 /** 1326 * adds the ID of this entity to the NBT given 1327 */ 1328 public boolean addEntityID(NBTTagCompound par1NBTTagCompound) 1329 { 1330 String var2 = this.getEntityString(); 1331 1332 if (!this.isDead && var2 != null) 1333 { 1334 par1NBTTagCompound.setString("id", var2); 1335 this.writeToNBT(par1NBTTagCompound); 1336 return true; 1337 } 1338 else 1339 { 1340 return false; 1341 } 1342 } 1343 1344 @SideOnly(Side.CLIENT) 1345 1346 /** 1347 * Checks using a Vec3d to determine if this entity is within range of that vector to be rendered. Args: vec3D 1348 */ 1349 public boolean isInRangeToRenderVec3D(Vec3 par1Vec3) 1350 { 1351 double var2 = this.posX - par1Vec3.xCoord; 1352 double var4 = this.posY - par1Vec3.yCoord; 1353 double var6 = this.posZ - par1Vec3.zCoord; 1354 double var8 = var2 * var2 + var4 * var4 + var6 * var6; 1355 return this.isInRangeToRenderDist(var8); 1356 } 1357 1358 @SideOnly(Side.CLIENT) 1359 1360 /** 1361 * Checks if the entity is in range to render by using the past in distance and comparing it to its average edge 1362 * length * 64 * renderDistanceWeight Args: distance 1363 */ 1364 public boolean isInRangeToRenderDist(double par1) 1365 { 1366 double var3 = this.boundingBox.getAverageEdgeLength(); 1367 var3 *= 64.0D * this.renderDistanceWeight; 1368 return par1 < var3 * var3; 1369 } 1370 1371 @SideOnly(Side.CLIENT) 1372 1373 /** 1374 * Returns the texture's file path as a String. 1375 */ 1376 public String getTexture() 1377 { 1378 return null; 1379 } 1380 1381 /** 1382 * Save the entity to NBT (calls an abstract helper method to write extra data) 1383 */ 1384 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 1385 { 1386 par1NBTTagCompound.setTag("Pos", this.newDoubleNBTList(new double[] {this.posX, this.posY + (double)this.ySize, this.posZ})); 1387 par1NBTTagCompound.setTag("Motion", this.newDoubleNBTList(new double[] {this.motionX, this.motionY, this.motionZ})); 1388 par1NBTTagCompound.setTag("Rotation", this.newFloatNBTList(new float[] {this.rotationYaw, this.rotationPitch})); 1389 par1NBTTagCompound.setFloat("FallDistance", this.fallDistance); 1390 par1NBTTagCompound.setShort("Fire", (short)this.fire); 1391 par1NBTTagCompound.setShort("Air", (short)this.getAir()); 1392 par1NBTTagCompound.setBoolean("OnGround", this.onGround); 1393 if (persistentID != null) 1394 { 1395 par1NBTTagCompound.setLong("PersistentIDMSB", persistentID.getMostSignificantBits()); 1396 par1NBTTagCompound.setLong("PersistentIDLSB", persistentID.getLeastSignificantBits()); 1397 } 1398 if (customEntityData != null) 1399 { 1400 par1NBTTagCompound.setCompoundTag("ForgeData", customEntityData); 1401 } 1402 this.writeEntityToNBT(par1NBTTagCompound); 1403 } 1404 1405 /** 1406 * Reads the entity from NBT (calls an abstract helper method to read specialized data) 1407 */ 1408 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 1409 { 1410 NBTTagList var2 = par1NBTTagCompound.getTagList("Pos"); 1411 NBTTagList var3 = par1NBTTagCompound.getTagList("Motion"); 1412 NBTTagList var4 = par1NBTTagCompound.getTagList("Rotation"); 1413 this.motionX = ((NBTTagDouble)var3.tagAt(0)).data; 1414 this.motionY = ((NBTTagDouble)var3.tagAt(1)).data; 1415 this.motionZ = ((NBTTagDouble)var3.tagAt(2)).data; 1416 1417 if (Math.abs(this.motionX) > 10.0D) 1418 { 1419 this.motionX = 0.0D; 1420 } 1421 1422 if (Math.abs(this.motionY) > 10.0D) 1423 { 1424 this.motionY = 0.0D; 1425 } 1426 1427 if (Math.abs(this.motionZ) > 10.0D) 1428 { 1429 this.motionZ = 0.0D; 1430 } 1431 1432 this.prevPosX = this.lastTickPosX = this.posX = ((NBTTagDouble)var2.tagAt(0)).data; 1433 this.prevPosY = this.lastTickPosY = this.posY = ((NBTTagDouble)var2.tagAt(1)).data; 1434 this.prevPosZ = this.lastTickPosZ = this.posZ = ((NBTTagDouble)var2.tagAt(2)).data; 1435 this.prevRotationYaw = this.rotationYaw = ((NBTTagFloat)var4.tagAt(0)).data; 1436 this.prevRotationPitch = this.rotationPitch = ((NBTTagFloat)var4.tagAt(1)).data; 1437 this.fallDistance = par1NBTTagCompound.getFloat("FallDistance"); 1438 this.fire = par1NBTTagCompound.getShort("Fire"); 1439 this.setAir(par1NBTTagCompound.getShort("Air")); 1440 this.onGround = par1NBTTagCompound.getBoolean("OnGround"); 1441 this.setPosition(this.posX, this.posY, this.posZ); 1442 this.setRotation(this.rotationYaw, this.rotationPitch); 1443 if (par1NBTTagCompound.hasKey("ForgeData")) 1444 { 1445 customEntityData = par1NBTTagCompound.getCompoundTag("ForgeData"); 1446 } 1447 if (par1NBTTagCompound.hasKey("PersistentIDMSB") && par1NBTTagCompound.hasKey("PersistentIDLSB")) 1448 { 1449 persistentID = new UUID(par1NBTTagCompound.getLong("PersistentIDMSB"), par1NBTTagCompound.getLong("PersistentIDLSB")); 1450 } 1451 this.readEntityFromNBT(par1NBTTagCompound); 1452 } 1453 1454 /** 1455 * Returns the string that identifies this Entity's class 1456 */ 1457 protected final String getEntityString() 1458 { 1459 return EntityList.getEntityString(this); 1460 } 1461 1462 /** 1463 * (abstract) Protected helper method to read subclass entity data from NBT. 1464 */ 1465 protected abstract void readEntityFromNBT(NBTTagCompound var1); 1466 1467 /** 1468 * (abstract) Protected helper method to write subclass entity data to NBT. 1469 */ 1470 protected abstract void writeEntityToNBT(NBTTagCompound var1); 1471 1472 /** 1473 * creates a NBT list from the array of doubles passed to this function 1474 */ 1475 protected NBTTagList newDoubleNBTList(double ... par1ArrayOfDouble) 1476 { 1477 NBTTagList var2 = new NBTTagList(); 1478 double[] var3 = par1ArrayOfDouble; 1479 int var4 = par1ArrayOfDouble.length; 1480 1481 for (int var5 = 0; var5 < var4; ++var5) 1482 { 1483 double var6 = var3[var5]; 1484 var2.appendTag(new NBTTagDouble((String)null, var6)); 1485 } 1486 1487 return var2; 1488 } 1489 1490 /** 1491 * Returns a new NBTTagList filled with the specified floats 1492 */ 1493 protected NBTTagList newFloatNBTList(float ... par1ArrayOfFloat) 1494 { 1495 NBTTagList var2 = new NBTTagList(); 1496 float[] var3 = par1ArrayOfFloat; 1497 int var4 = par1ArrayOfFloat.length; 1498 1499 for (int var5 = 0; var5 < var4; ++var5) 1500 { 1501 float var6 = var3[var5]; 1502 var2.appendTag(new NBTTagFloat((String)null, var6)); 1503 } 1504 1505 return var2; 1506 } 1507 1508 @SideOnly(Side.CLIENT) 1509 public float getShadowSize() 1510 { 1511 return this.height / 2.0F; 1512 } 1513 1514 /** 1515 * Drops an item stack at the entity's position. Args: itemID, count 1516 */ 1517 public EntityItem dropItem(int par1, int par2) 1518 { 1519 return this.dropItemWithOffset(par1, par2, 0.0F); 1520 } 1521 1522 /** 1523 * Drops an item stack with a specified y offset. Args: itemID, count, yOffset 1524 */ 1525 public EntityItem dropItemWithOffset(int par1, int par2, float par3) 1526 { 1527 return this.entityDropItem(new ItemStack(par1, par2, 0), par3); 1528 } 1529 1530 /** 1531 * Drops an item at the position of the entity. 1532 */ 1533 public EntityItem entityDropItem(ItemStack par1ItemStack, float par2) 1534 { 1535 EntityItem var3 = new EntityItem(this.worldObj, this.posX, this.posY + (double)par2, this.posZ, par1ItemStack); 1536 var3.delayBeforeCanPickup = 10; 1537 if (captureDrops) 1538 { 1539 capturedDrops.add(var3); 1540 } 1541 else 1542 { 1543 this.worldObj.spawnEntityInWorld(var3); 1544 } 1545 return var3; 1546 } 1547 1548 /** 1549 * Checks whether target entity is alive. 1550 */ 1551 public boolean isEntityAlive() 1552 { 1553 return !this.isDead; 1554 } 1555 1556 /** 1557 * Checks if this entity is inside of an opaque block 1558 */ 1559 public boolean isEntityInsideOpaqueBlock() 1560 { 1561 for (int var1 = 0; var1 < 8; ++var1) 1562 { 1563 float var2 = ((float)((var1 >> 0) % 2) - 0.5F) * this.width * 0.8F; 1564 float var3 = ((float)((var1 >> 1) % 2) - 0.5F) * 0.1F; 1565 float var4 = ((float)((var1 >> 2) % 2) - 0.5F) * this.width * 0.8F; 1566 int var5 = MathHelper.floor_double(this.posX + (double)var2); 1567 int var6 = MathHelper.floor_double(this.posY + (double)this.getEyeHeight() + (double)var3); 1568 int var7 = MathHelper.floor_double(this.posZ + (double)var4); 1569 1570 if (this.worldObj.isBlockNormalCube(var5, var6, var7)) 1571 { 1572 return true; 1573 } 1574 } 1575 1576 return false; 1577 } 1578 1579 /** 1580 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 1581 */ 1582 public boolean interact(EntityPlayer par1EntityPlayer) 1583 { 1584 return false; 1585 } 1586 1587 /** 1588 * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be 1589 * pushable on contact, like boats or minecarts. 1590 */ 1591 public AxisAlignedBB getCollisionBox(Entity par1Entity) 1592 { 1593 return null; 1594 } 1595 1596 /** 1597 * Handles updating while being ridden by an entity 1598 */ 1599 public void updateRidden() 1600 { 1601 if (this.ridingEntity.isDead) 1602 { 1603 this.ridingEntity = null; 1604 } 1605 else 1606 { 1607 this.motionX = 0.0D; 1608 this.motionY = 0.0D; 1609 this.motionZ = 0.0D; 1610 this.onUpdate(); 1611 1612 if (this.ridingEntity != null) 1613 { 1614 this.ridingEntity.updateRiderPosition(); 1615 this.entityRiderYawDelta += (double)(this.ridingEntity.rotationYaw - this.ridingEntity.prevRotationYaw); 1616 1617 for (this.entityRiderPitchDelta += (double)(this.ridingEntity.rotationPitch - this.ridingEntity.prevRotationPitch); this.entityRiderYawDelta >= 180.0D; this.entityRiderYawDelta -= 360.0D) 1618 { 1619 ; 1620 } 1621 1622 while (this.entityRiderYawDelta < -180.0D) 1623 { 1624 this.entityRiderYawDelta += 360.0D; 1625 } 1626 1627 while (this.entityRiderPitchDelta >= 180.0D) 1628 { 1629 this.entityRiderPitchDelta -= 360.0D; 1630 } 1631 1632 while (this.entityRiderPitchDelta < -180.0D) 1633 { 1634 this.entityRiderPitchDelta += 360.0D; 1635 } 1636 1637 double var1 = this.entityRiderYawDelta * 0.5D; 1638 double var3 = this.entityRiderPitchDelta * 0.5D; 1639 float var5 = 10.0F; 1640 1641 if (var1 > (double)var5) 1642 { 1643 var1 = (double)var5; 1644 } 1645 1646 if (var1 < (double)(-var5)) 1647 { 1648 var1 = (double)(-var5); 1649 } 1650 1651 if (var3 > (double)var5) 1652 { 1653 var3 = (double)var5; 1654 } 1655 1656 if (var3 < (double)(-var5)) 1657 { 1658 var3 = (double)(-var5); 1659 } 1660 1661 this.entityRiderYawDelta -= var1; 1662 this.entityRiderPitchDelta -= var3; 1663 this.rotationYaw = (float)((double)this.rotationYaw + var1); 1664 this.rotationPitch = (float)((double)this.rotationPitch + var3); 1665 } 1666 } 1667 } 1668 1669 public void updateRiderPosition() 1670 { 1671 if (!(this.riddenByEntity instanceof EntityPlayer) || !((EntityPlayer)this.riddenByEntity).func_71066_bF()) 1672 { 1673 this.riddenByEntity.lastTickPosX = this.riddenByEntity.posX; 1674 this.riddenByEntity.lastTickPosY = this.riddenByEntity.posY; 1675 this.riddenByEntity.lastTickPosZ = this.riddenByEntity.posZ; 1676 } 1677 1678 this.riddenByEntity.setPosition(this.posX, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset(), this.posZ); 1679 } 1680 1681 /** 1682 * Returns the Y Offset of this entity. 1683 */ 1684 public double getYOffset() 1685 { 1686 return (double)this.yOffset; 1687 } 1688 1689 /** 1690 * Returns the Y offset from the entity's position for any entity riding this one. 1691 */ 1692 public double getMountedYOffset() 1693 { 1694 return (double)this.height * 0.75D; 1695 } 1696 1697 /** 1698 * Called when a player mounts an entity. e.g. mounts a pig, mounts a boat. 1699 */ 1700 public void mountEntity(Entity par1Entity) 1701 { 1702 this.entityRiderPitchDelta = 0.0D; 1703 this.entityRiderYawDelta = 0.0D; 1704 1705 if (par1Entity == null) 1706 { 1707 if (this.ridingEntity != null) 1708 { 1709 this.setLocationAndAngles(this.ridingEntity.posX, this.ridingEntity.boundingBox.minY + (double)this.ridingEntity.height, this.ridingEntity.posZ, this.rotationYaw, this.rotationPitch); 1710 this.ridingEntity.riddenByEntity = null; 1711 } 1712 1713 this.ridingEntity = null; 1714 } 1715 else if (this.ridingEntity == par1Entity) 1716 { 1717 this.unmountEntity(par1Entity); 1718 this.ridingEntity.riddenByEntity = null; 1719 this.ridingEntity = null; 1720 } 1721 else 1722 { 1723 if (this.ridingEntity != null) 1724 { 1725 this.ridingEntity.riddenByEntity = null; 1726 } 1727 1728 if (par1Entity.riddenByEntity != null) 1729 { 1730 par1Entity.riddenByEntity.ridingEntity = null; 1731 } 1732 1733 this.ridingEntity = par1Entity; 1734 par1Entity.riddenByEntity = this; 1735 } 1736 } 1737 1738 /** 1739 * Called when a player unounts an entity. 1740 */ 1741 public void unmountEntity(Entity par1Entity) 1742 { 1743 double var3 = par1Entity.posX; 1744 double var5 = par1Entity.boundingBox.minY + (double)par1Entity.height; 1745 double var7 = par1Entity.posZ; 1746 1747 for (double var9 = -1.5D; var9 < 2.0D; ++var9) 1748 { 1749 for (double var11 = -1.5D; var11 < 2.0D; ++var11) 1750 { 1751 if (var9 != 0.0D || var11 != 0.0D) 1752 { 1753 int var13 = (int)(this.posX + var9); 1754 int var14 = (int)(this.posZ + var11); 1755 AxisAlignedBB var2 = this.boundingBox.getOffsetBoundingBox(var9, 1.0D, var11); 1756 1757 if (this.worldObj.getAllCollidingBoundingBoxes(var2).isEmpty()) 1758 { 1759 if (this.worldObj.doesBlockHaveSolidTopSurface(var13, (int)this.posY, var14)) 1760 { 1761 this.setLocationAndAngles(this.posX + var9, this.posY + 1.0D, this.posZ + var11, this.rotationYaw, this.rotationPitch); 1762 return; 1763 } 1764 1765 if (this.worldObj.doesBlockHaveSolidTopSurface(var13, (int)this.posY - 1, var14) || this.worldObj.getBlockMaterial(var13, (int)this.posY - 1, var14) == Material.water) 1766 { 1767 var3 = this.posX + var9; 1768 var5 = this.posY + 1.0D; 1769 var7 = this.posZ + var11; 1770 } 1771 } 1772 } 1773 } 1774 } 1775 1776 this.setLocationAndAngles(var3, var5, var7, this.rotationYaw, this.rotationPitch); 1777 } 1778 1779 @SideOnly(Side.CLIENT) 1780 1781 /** 1782 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX, 1783 * posY, posZ, yaw, pitch 1784 */ 1785 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) 1786 { 1787 this.setPosition(par1, par3, par5); 1788 this.setRotation(par7, par8); 1789 List var10 = this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox.contract(0.03125D, 0.0D, 0.03125D)); 1790 1791 if (!var10.isEmpty()) 1792 { 1793 double var11 = 0.0D; 1794 Iterator var13 = var10.iterator(); 1795 1796 while (var13.hasNext()) 1797 { 1798 AxisAlignedBB var14 = (AxisAlignedBB)var13.next(); 1799 1800 if (var14.maxY > var11) 1801 { 1802 var11 = var14.maxY; 1803 } 1804 } 1805 1806 par3 += var11 - this.boundingBox.minY; 1807 this.setPosition(par1, par3, par5); 1808 } 1809 } 1810 1811 public float getCollisionBorderSize() 1812 { 1813 return 0.1F; 1814 } 1815 1816 /** 1817 * returns a (normalized) vector of where this entity is looking 1818 */ 1819 public Vec3 getLookVec() 1820 { 1821 return null; 1822 } 1823 1824 /** 1825 * Called by portal blocks when an entity is within it. 1826 */ 1827 public void setInPortal() {} 1828 1829 @SideOnly(Side.CLIENT) 1830 1831 /** 1832 * Sets the velocity to the args. Args: x, y, z 1833 */ 1834 public void setVelocity(double par1, double par3, double par5) 1835 { 1836 this.motionX = par1; 1837 this.motionY = par3; 1838 this.motionZ = par5; 1839 } 1840 1841 @SideOnly(Side.CLIENT) 1842 public void handleHealthUpdate(byte par1) {} 1843 1844 @SideOnly(Side.CLIENT) 1845 1846 /** 1847 * Setups the entity to do the hurt animation. Only used by packets in multiplayer. 1848 */ 1849 public void performHurtAnimation() {} 1850 1851 @SideOnly(Side.CLIENT) 1852 public void updateCloak() {} 1853 1854 public ItemStack[] getLastActiveItems() 1855 { 1856 return null; 1857 } 1858 1859 @SideOnly(Side.CLIENT) 1860 public void func_70062_b(int par1, ItemStack par2ItemStack) {} 1861 1862 /** 1863 * Returns true if the entity is on fire. Used by render to add the fire effect on rendering. 1864 */ 1865 public boolean isBurning() 1866 { 1867 return this.fire > 0 || this.getFlag(0); 1868 } 1869 1870 @SideOnly(Side.CLIENT) 1871 1872 /** 1873 * Returns true if the entity is riding another entity, used by render to rotate the legs to be in 'sit' position 1874 * for players. 1875 */ 1876 public boolean isRiding() 1877 { 1878 return (this.ridingEntity != null && ridingEntity.shouldRiderSit()) || this.getFlag(2); 1879 } 1880 1881 /** 1882 * Returns if this entity is sneaking. 1883 */ 1884 public boolean isSneaking() 1885 { 1886 return this.getFlag(1); 1887 } 1888 1889 /** 1890 * Sets the sneaking flag. 1891 */ 1892 public void setSneaking(boolean par1) 1893 { 1894 this.setFlag(1, par1); 1895 } 1896 1897 /** 1898 * Get if the Entity is sprinting. 1899 */ 1900 public boolean isSprinting() 1901 { 1902 return this.getFlag(3); 1903 } 1904 1905 /** 1906 * Set sprinting switch for Entity. 1907 */ 1908 public void setSprinting(boolean par1) 1909 { 1910 this.setFlag(3, par1); 1911 } 1912 1913 @SideOnly(Side.CLIENT) 1914 public boolean isEating() 1915 { 1916 return this.getFlag(4); 1917 } 1918 1919 public void setEating(boolean par1) 1920 { 1921 this.setFlag(4, par1); 1922 } 1923 1924 /** 1925 * Returns true if the flag is active for the entity. Known flags: 0) is burning; 1) is sneaking; 2) is riding 1926 * something; 3) is sprinting; 4) is eating 1927 */ 1928 protected boolean getFlag(int par1) 1929 { 1930 return (this.dataWatcher.getWatchableObjectByte(0) & 1 << par1) != 0; 1931 } 1932 1933 /** 1934 * Enable or disable a entity flag, see getEntityFlag to read the know flags. 1935 */ 1936 protected void setFlag(int par1, boolean par2) 1937 { 1938 byte var3 = this.dataWatcher.getWatchableObjectByte(0); 1939 1940 if (par2) 1941 { 1942 this.dataWatcher.updateObject(0, Byte.valueOf((byte)(var3 | 1 << par1))); 1943 } 1944 else 1945 { 1946 this.dataWatcher.updateObject(0, Byte.valueOf((byte)(var3 & ~(1 << par1)))); 1947 } 1948 } 1949 1950 public int getAir() 1951 { 1952 return this.dataWatcher.getWatchableObjectShort(1); 1953 } 1954 1955 public void setAir(int par1) 1956 { 1957 this.dataWatcher.updateObject(1, Short.valueOf((short)par1)); 1958 } 1959 1960 /** 1961 * Called when a lightning bolt hits the entity. 1962 */ 1963 public void onStruckByLightning(EntityLightningBolt par1EntityLightningBolt) 1964 { 1965 this.dealFireDamage(5); 1966 ++this.fire; 1967 1968 if (this.fire == 0) 1969 { 1970 this.setFire(8); 1971 } 1972 } 1973 1974 /** 1975 * This method gets called when the entity kills another one. 1976 */ 1977 public void onKillEntity(EntityLiving par1EntityLiving) {} 1978 1979 /** 1980 * Adds velocity to push the entity out of blocks at the specified x, y, z position Args: x, y, z 1981 */ 1982 protected boolean pushOutOfBlocks(double par1, double par3, double par5) 1983 { 1984 int var7 = MathHelper.floor_double(par1); 1985 int var8 = MathHelper.floor_double(par3); 1986 int var9 = MathHelper.floor_double(par5); 1987 double var10 = par1 - (double)var7; 1988 double var12 = par3 - (double)var8; 1989 double var14 = par5 - (double)var9; 1990 1991 if (this.worldObj.isBlockNormalCube(var7, var8, var9)) 1992 { 1993 boolean var16 = !this.worldObj.isBlockNormalCube(var7 - 1, var8, var9); 1994 boolean var17 = !this.worldObj.isBlockNormalCube(var7 + 1, var8, var9); 1995 boolean var18 = !this.worldObj.isBlockNormalCube(var7, var8 - 1, var9); 1996 boolean var19 = !this.worldObj.isBlockNormalCube(var7, var8 + 1, var9); 1997 boolean var20 = !this.worldObj.isBlockNormalCube(var7, var8, var9 - 1); 1998 boolean var21 = !this.worldObj.isBlockNormalCube(var7, var8, var9 + 1); 1999 byte var22 = -1; 2000 double var23 = 9999.0D; 2001 2002 if (var16 && var10 < var23) 2003 { 2004 var23 = var10; 2005 var22 = 0; 2006 } 2007 2008 if (var17 && 1.0D - var10 < var23) 2009 { 2010 var23 = 1.0D - var10; 2011 var22 = 1; 2012 } 2013 2014 if (var18 && var12 < var23) 2015 { 2016 var23 = var12; 2017 var22 = 2; 2018 } 2019 2020 if (var19 && 1.0D - var12 < var23) 2021 { 2022 var23 = 1.0D - var12; 2023 var22 = 3; 2024 } 2025 2026 if (var20 && var14 < var23) 2027 { 2028 var23 = var14; 2029 var22 = 4; 2030 } 2031 2032 if (var21 && 1.0D - var14 < var23) 2033 { 2034 var23 = 1.0D - var14; 2035 var22 = 5; 2036 } 2037 2038 float var25 = this.rand.nextFloat() * 0.2F + 0.1F; 2039 2040 if (var22 == 0) 2041 { 2042 this.motionX = (double)(-var25); 2043 } 2044 2045 if (var22 == 1) 2046 { 2047 this.motionX = (double)var25; 2048 } 2049 2050 if (var22 == 2) 2051 { 2052 this.motionY = (double)(-var25); 2053 } 2054 2055 if (var22 == 3) 2056 { 2057 this.motionY = (double)var25; 2058 } 2059 2060 if (var22 == 4) 2061 { 2062 this.motionZ = (double)(-var25); 2063 } 2064 2065 if (var22 == 5) 2066 { 2067 this.motionZ = (double)var25; 2068 } 2069 2070 return true; 2071 } 2072 else 2073 { 2074 return false; 2075 } 2076 } 2077 2078 /** 2079 * Sets the Entity inside a web block. 2080 */ 2081 public void setInWeb() 2082 { 2083 this.isInWeb = true; 2084 this.fallDistance = 0.0F; 2085 } 2086 2087 /** 2088 * Gets the username of the entity. 2089 */ 2090 public String getEntityName() 2091 { 2092 String var1 = EntityList.getEntityString(this); 2093 2094 if (var1 == null) 2095 { 2096 var1 = "generic"; 2097 } 2098 2099 return StatCollector.translateToLocal("entity." + var1 + ".name"); 2100 } 2101 2102 /** 2103 * Return the Entity parts making up this Entity (currently only for dragons) 2104 */ 2105 public Entity[] getParts() 2106 { 2107 return null; 2108 } 2109 2110 /** 2111 * Returns true if Entity argument is equal to this Entity 2112 */ 2113 public boolean isEntityEqual(Entity par1Entity) 2114 { 2115 return this == par1Entity; 2116 } 2117 2118 public float func_70079_am() 2119 { 2120 return 0.0F; 2121 } 2122 2123 @SideOnly(Side.CLIENT) 2124 2125 /** 2126 * Sets the head's yaw rotation of the entity. 2127 */ 2128 public void setHeadRotationYaw(float par1) {} 2129 2130 /** 2131 * If returns false, the item will not inflict any damage against entities. 2132 */ 2133 public boolean canAttackWithItem() 2134 { 2135 return true; 2136 } 2137 2138 public String toString() 2139 { 2140 return String.format("%s[\'%s\'/%d, l=\'%s\', x=%.2f, y=%.2f, z=%.2f]", new Object[] {this.getClass().getSimpleName(), this.getEntityName(), Integer.valueOf(this.entityId), this.worldObj == null ? "~NULL~" : this.worldObj.getWorldInfo().getWorldName(), Double.valueOf(this.posX), Double.valueOf(this.posY), Double.valueOf(this.posZ)}); 2141 } 2142 2143 /* ================================== Forge Start =====================================*/ 2144 /** 2145 * Returns a NBTTagCompound that can be used to store custom data for this entity. 2146 * It will be written, and read from disc, so it persists over world saves. 2147 * @return A NBTTagCompound 2148 */ 2149 public NBTTagCompound getEntityData() 2150 { 2151 if (customEntityData == null) 2152 { 2153 customEntityData = new NBTTagCompound(); 2154 } 2155 return customEntityData; 2156 } 2157 2158 /** 2159 * Used in model rendering to determine if the entity riding this entity should be in the 'sitting' position. 2160 * @return false to prevent an entity that is mounted to this entity from displaying the 'sitting' animation. 2161 */ 2162 public boolean shouldRiderSit() 2163 { 2164 return true; 2165 } 2166 2167 /** 2168 * Called when a user uses the creative pick block button on this entity. 2169 * 2170 * @param target The full target the player is looking at 2171 * @return A ItemStack to add to the player's inventory, Null if nothing should be added. 2172 */ 2173 public ItemStack getPickedResult(MovingObjectPosition target) 2174 { 2175 if (this instanceof EntityPainting) 2176 { 2177 return new ItemStack(Item.painting); 2178 } 2179 else if (this instanceof EntityMinecart) 2180 { 2181 return ((EntityMinecart)this).getCartItem(); 2182 } 2183 else if (this instanceof EntityBoat) 2184 { 2185 return new ItemStack(Item.boat); 2186 } 2187 else 2188 { 2189 int id = EntityList.getEntityID(this); 2190 if (id > 0 && EntityList.entityEggs.containsKey(id)) 2191 { 2192 return new ItemStack(Item.monsterPlacer, 1, id); 2193 } 2194 } 2195 return null; 2196 } 2197 2198 public UUID getPersistentID() 2199 { 2200 return persistentID; 2201 } 2202 2203 public synchronized void generatePersistentID() 2204 { 2205 if (persistentID == null) 2206 { 2207 persistentID = UUID.randomUUID(); 2208 } 2209 } 2210 }