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 }