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    }