001    package net.minecraft.src;
002    
003    import cpw.mods.fml.common.Side;
004    import cpw.mods.fml.common.asm.SideOnly;
005    import java.util.ArrayList;
006    import java.util.Collection;
007    import java.util.HashSet;
008    import java.util.Iterator;
009    import java.util.List;
010    import java.util.Random;
011    import java.util.Set;
012    
013    import com.google.common.collect.SetMultimap;
014    
015    import net.minecraftforge.common.ForgeChunkManager;
016    import net.minecraftforge.common.ForgeChunkManager.Ticket;
017    import net.minecraftforge.common.ForgeHooks;
018    import net.minecraftforge.common.MinecraftForge;
019    import net.minecraftforge.common.ForgeDirection;
020    import net.minecraftforge.event.entity.EntityEvent;
021    import net.minecraftforge.event.entity.EntityJoinWorldEvent;
022    import net.minecraftforge.event.world.WorldEvent;
023    import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
024    
025    public abstract class World implements IBlockAccess
026    {
027        /**
028         * Used in the getEntitiesWithinAABB functions to expand the search area for entities.
029         * Modders should change this variable to a higher value if it is less then the radius
030         * of one of there entities.
031         */
032        public static double MAX_ENTITY_RADIUS = 2.0D;
033    
034        /**
035         * boolean; if true updates scheduled by scheduleBlockUpdate happen immediately
036         */
037        public boolean scheduledUpdatesAreImmediate = false;
038    
039        /** A list of all Entities in all currently-loaded chunks */
040        public List loadedEntityList = new ArrayList();
041        protected List unloadedEntityList = new ArrayList();
042    
043        /** A list of all TileEntities in all currently-loaded chunks */
044        public List loadedTileEntityList = new ArrayList();
045        private List addedTileEntityList = new ArrayList();
046    
047        /** Entities marked for removal. */
048        private List entityRemoval = new ArrayList();
049    
050        /** Array list of players in the world. */
051        public List playerEntities = new ArrayList();
052    
053        /** a list of all the lightning entities */
054        public List weatherEffects = new ArrayList();
055        private long cloudColour = 16777215L;
056    
057        /** How much light is subtracted from full daylight */
058        public int skylightSubtracted = 0;
059    
060        /**
061         * Contains the current Linear Congruential Generator seed for block updates. Used with an A value of 3 and a C
062         * value of 0x3c6ef35f, producing a highly planar series of values ill-suited for choosing random blocks in a
063         * 16x128x16 field.
064         */
065        protected int updateLCG = (new Random()).nextInt();
066    
067        /**
068         * magic number used to generate fast random numbers for 3d distribution within a chunk
069         */
070        protected final int DIST_HASH_MAGIC = 1013904223;
071        protected float prevRainingStrength;
072        protected float rainingStrength;
073        protected float prevThunderingStrength;
074        protected float thunderingStrength;
075    
076        /**
077         * Set to 2 whenever a lightning bolt is generated in SSP. Decrements if > 0 in updateWeather(). Value appears to be
078         * unused.
079         */
080        protected int lastLightningBolt = 0;
081    
082        /**
083         * If > 0, the sky and skylight colors are illuminated by a lightning flash
084         */
085        public int lightningFlash = 0;
086    
087        /** true while the world is editing blocks */
088        public boolean editingBlocks = false;
089    
090        /** Option > Difficulty setting (0 - 3) */
091        public int difficultySetting;
092    
093        /** RNG for World. */
094        public Random rand = new Random();
095    
096        /** The WorldProvider instance that World uses. */
097        public final WorldProvider provider;
098        protected List worldAccesses = new ArrayList();
099    
100        /** Handles chunk operations and caching */
101        protected IChunkProvider chunkProvider;
102        protected final ISaveHandler saveHandler;
103    
104        /**
105         * holds information about a world (size on disk, time, spawn point, seed, ...)
106         */
107        protected WorldInfo worldInfo;
108    
109        /** Boolean that is set to true when trying to find a spawn point */
110        public boolean findingSpawnPoint;
111        public MapStorage mapStorage;
112        public VillageCollection villageCollectionObj;
113        protected final VillageSiege villageSiegeObj = new VillageSiege(this);
114        public final Profiler theProfiler;
115        private final Vec3Pool field_82741_K = new Vec3Pool(300, 2000);
116        private ArrayList collidingBoundingBoxes = new ArrayList();
117        private boolean scanningTileEntities;
118    
119        /** indicates if enemies are spawned or not */
120        protected boolean spawnHostileMobs = true;
121    
122        /** A flag indicating whether we should spawn peaceful mobs. */
123        protected boolean spawnPeacefulMobs = true;
124    
125        /** Positions to update */
126        protected Set activeChunkSet = new HashSet();
127    
128        /** number of ticks until the next random ambients play */
129        private int ambientTickCountdown;
130    
131        /**
132         * is a temporary list of blocks and light values used when updating light levels. Holds up to 32x32x32 blocks (the
133         * maximum influence of a light source.) Every element is a packed bit value: 0000000000LLLLzzzzzzyyyyyyxxxxxx. The
134         * 4-bit L is a light level used when darkening blocks. 6-bit numbers x, y and z represent the block's offset from
135         * the original block, plus 32 (i.e. value of 31 would mean a -1 offset
136         */
137        int[] lightUpdateBlockList;
138    
139        /**
140         * entities within AxisAlignedBB excluding one, set and returned in getEntitiesWithinAABBExcludingEntity(Entity
141         * var1, AxisAlignedBB var2)
142         */
143        private List entitiesWithinAABBExcludingEntity;
144    
145        /**
146         * This is set to true when you are a client connected to a multiplayer world, false otherwise. As of Minecraft 1.3
147         * and the integrated server, this will always return true.
148         */
149        public boolean isRemote;
150    
151        /**
152         * Gets the biome for a given set of x/z coordinates
153         */
154        public BiomeGenBase getBiomeGenForCoords(int par1, int par2)
155        {
156            return provider.getBiomeGenForCoords(par1, par2);
157        }
158    
159        public BiomeGenBase getBiomeGenForCoordsBody(int par1, int par2)
160        {
161            if (this.blockExists(par1, 0, par2))
162            {
163                Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
164    
165                if (var3 != null)
166                {
167                    return var3.getBiomeGenForWorldCoords(par1 & 15, par2 & 15, this.provider.worldChunkMgr);
168                }
169            }
170    
171            return this.provider.worldChunkMgr.getBiomeGenAt(par1, par2);
172        }
173    
174        public WorldChunkManager getWorldChunkManager()
175        {
176            return this.provider.worldChunkMgr;
177        }
178    
179        @SideOnly(Side.CLIENT)
180        public World(ISaveHandler par1ISaveHandler, String par2Str, WorldProvider par3WorldProvider, WorldSettings par4WorldSettings, Profiler par5Profiler)
181        {
182            this.ambientTickCountdown = this.rand.nextInt(12000);
183            this.lightUpdateBlockList = new int[32768];
184            this.entitiesWithinAABBExcludingEntity = new ArrayList();
185            this.isRemote = false;
186            this.saveHandler = par1ISaveHandler;
187            this.theProfiler = par5Profiler;
188            this.worldInfo = new WorldInfo(par4WorldSettings, par2Str);
189            this.provider = par3WorldProvider;
190        }
191    
192        // Broken up so that the WorldClient gets the chance to set the mapstorage object before the dimension initializes
193        @SideOnly(Side.CLIENT)
194        protected void finishSetup()
195        {
196            this.provider.registerWorld(this);
197    
198            this.mapStorage = new MapStorage(saveHandler);
199            VillageCollection var6 = (VillageCollection)this.mapStorage.loadData(VillageCollection.class, "villages");
200    
201            if (var6 == null)
202            {
203                this.villageCollectionObj = new VillageCollection(this);
204                this.mapStorage.setData("villages", this.villageCollectionObj);
205            }
206            else
207            {
208                this.villageCollectionObj = var6;
209                this.villageCollectionObj.func_82566_a(this);
210            }
211    
212            this.provider.registerWorld(this);
213            this.chunkProvider = this.createChunkProvider();
214            this.calculateInitialSkylight();
215            this.calculateInitialWeather();
216        }
217    
218        public World(ISaveHandler par1ISaveHandler, String par2Str, WorldSettings par3WorldSettings, WorldProvider par4WorldProvider, Profiler par5Profiler)
219        {
220            this.ambientTickCountdown = this.rand.nextInt(12000);
221            this.lightUpdateBlockList = new int[32768];
222            this.entitiesWithinAABBExcludingEntity = new ArrayList();
223            this.isRemote = false;
224            this.saveHandler = par1ISaveHandler;
225            this.theProfiler = par5Profiler;
226            this.mapStorage = getMapStorage(par1ISaveHandler);
227            this.worldInfo = par1ISaveHandler.loadWorldInfo();
228    
229            if (par4WorldProvider != null)
230            {
231                this.provider = par4WorldProvider;
232            }
233            else if (this.worldInfo != null && this.worldInfo.getDimension() != 0)
234            {
235                this.provider = WorldProvider.getProviderForDimension(this.worldInfo.getDimension());
236            }
237            else
238            {
239                this.provider = WorldProvider.getProviderForDimension(0);
240            }
241    
242            if (this.worldInfo == null)
243            {
244                this.worldInfo = new WorldInfo(par3WorldSettings, par2Str);
245            }
246            else
247            {
248                this.worldInfo.setWorldName(par2Str);
249            }
250    
251            this.provider.registerWorld(this);
252            this.chunkProvider = this.createChunkProvider();
253    
254            if (!this.worldInfo.isInitialized())
255            {
256                this.initialize(par3WorldSettings);
257                this.worldInfo.setServerInitialized(true);
258            }
259    
260            VillageCollection var6 = (VillageCollection)this.mapStorage.loadData(VillageCollection.class, "villages");
261    
262            if (var6 == null)
263            {
264                this.villageCollectionObj = new VillageCollection(this);
265                this.mapStorage.setData("villages", this.villageCollectionObj);
266            }
267            else
268            {
269                this.villageCollectionObj = var6;
270                this.villageCollectionObj.func_82566_a(this);
271            }
272    
273            this.calculateInitialSkylight();
274            this.calculateInitialWeather();
275        }
276    
277        private static MapStorage s_mapStorage;
278        private static ISaveHandler s_savehandler;
279        //Provides a solution for different worlds getting different copies of the same data, potentially rewriting the data or causing race conditions/stale data
280        //Buildcraft has suffered from the issue this fixes.  If you load the same data from two different worlds they can get two different copies of the same object, thus the last saved gets final say.
281        private MapStorage getMapStorage(ISaveHandler savehandler)
282        {
283            if (s_savehandler != savehandler || s_mapStorage == null) {
284                s_mapStorage = new MapStorage(savehandler);
285                s_savehandler = savehandler;
286            }
287            return s_mapStorage;
288        }
289    
290        /**
291         * Creates the chunk provider for this world. Called in the constructor. Retrieves provider from worldProvider?
292         */
293        protected abstract IChunkProvider createChunkProvider();
294    
295        protected void initialize(WorldSettings par1WorldSettings)
296        {
297            this.worldInfo.setServerInitialized(true);
298        }
299    
300        @SideOnly(Side.CLIENT)
301    
302        /**
303         * Sets a new spawn location by finding an uncovered block at a random (x,z) location in the chunk.
304         */
305        public void setSpawnLocation()
306        {
307            this.setSpawnLocation(8, 64, 8);
308        }
309    
310        /**
311         * Returns the block ID of the first block at this (x,z) location with air above it, searching from sea level
312         * upwards.
313         */
314        public int getFirstUncoveredBlock(int par1, int par2)
315        {
316            int var3;
317    
318            for (var3 = 63; !this.isAirBlock(par1, var3 + 1, par2); ++var3)
319            {
320                ;
321            }
322    
323            return this.getBlockId(par1, var3, par2);
324        }
325    
326        /**
327         * Returns the block ID at coords x,y,z
328         */
329        public int getBlockId(int par1, int par2, int par3)
330        {
331            return par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000 ? (par2 < 0 ? 0 : (par2 >= 256 ? 0 : this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockID(par1 & 15, par2, par3 & 15))) : 0;
332        }
333    
334        public int getBlockLightOpacity(int par1, int par2, int par3)
335        {
336            return par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000 ? (par2 < 0 ? 0 : (par2 >= 256 ? 0 : this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockLightOpacity(par1 & 15, par2, par3 & 15))) : 0;
337        }
338    
339        /**
340         * Returns true if the block at the specified coordinates is empty
341         */
342        public boolean isAirBlock(int par1, int par2, int par3)
343        {
344            int id = getBlockId(par1, par2, par3);
345            return id == 0 || Block.blocksList[id] == null || Block.blocksList[id].isAirBlock(this, par1, par2, par3);
346        }
347    
348        /**
349         * Checks if a block at a given position should have a tile entity.
350         */
351        public boolean blockHasTileEntity(int par1, int par2, int par3)
352        {
353            int var4 = this.getBlockId(par1, par2, par3);
354            int meta = this.getBlockMetadata(par1, par2, par3);
355            return Block.blocksList[var4] != null && Block.blocksList[var4].hasTileEntity(meta);
356        }
357    
358        /**
359         * Returns whether a block exists at world coordinates x, y, z
360         */
361        public boolean blockExists(int par1, int par2, int par3)
362        {
363            return par2 >= 0 && par2 < 256 ? this.chunkExists(par1 >> 4, par3 >> 4) : false;
364        }
365    
366        /**
367         * Checks if any of the chunks within distance (argument 4) blocks of the given block exist
368         */
369        public boolean doChunksNearChunkExist(int par1, int par2, int par3, int par4)
370        {
371            return this.checkChunksExist(par1 - par4, par2 - par4, par3 - par4, par1 + par4, par2 + par4, par3 + par4);
372        }
373    
374        /**
375         * Checks between a min and max all the chunks inbetween actually exist. Args: minX, minY, minZ, maxX, maxY, maxZ
376         */
377        public boolean checkChunksExist(int par1, int par2, int par3, int par4, int par5, int par6)
378        {
379            if (par5 >= 0 && par2 < 256)
380            {
381                par1 >>= 4;
382                par3 >>= 4;
383                par4 >>= 4;
384                par6 >>= 4;
385    
386                for (int var7 = par1; var7 <= par4; ++var7)
387                {
388                    for (int var8 = par3; var8 <= par6; ++var8)
389                    {
390                        if (!this.chunkExists(var7, var8))
391                        {
392                            return false;
393                        }
394                    }
395                }
396    
397                return true;
398            }
399            else
400            {
401                return false;
402            }
403        }
404    
405        /**
406         * Returns whether a chunk exists at chunk coordinates x, y
407         */
408        protected boolean chunkExists(int par1, int par2)
409        {
410            return this.chunkProvider.chunkExists(par1, par2);
411        }
412    
413        /**
414         * Returns a chunk looked up by block coordinates. Args: x, z
415         */
416        public Chunk getChunkFromBlockCoords(int par1, int par2)
417        {
418            return this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
419        }
420    
421        /**
422         * Returns back a chunk looked up by chunk coordinates Args: x, y
423         */
424        public Chunk getChunkFromChunkCoords(int par1, int par2)
425        {
426            return this.chunkProvider.provideChunk(par1, par2);
427        }
428    
429        /**
430         * Sets the block ID and metadata of a block in global coordinates
431         */
432        public boolean setBlockAndMetadata(int par1, int par2, int par3, int par4, int par5)
433        {
434            return this.setBlockAndMetadataWithUpdate(par1, par2, par3, par4, par5, true);
435        }
436    
437        /**
438         * Sets the block ID and metadata of a block, optionally marking it as needing update. Args: X,Y,Z, blockID,
439         * metadata, needsUpdate
440         */
441        public boolean setBlockAndMetadataWithUpdate(int par1, int par2, int par3, int par4, int par5, boolean par6)
442        {
443            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
444            {
445                if (par2 < 0)
446                {
447                    return false;
448                }
449                else if (par2 >= 256)
450                {
451                    return false;
452                }
453                else
454                {
455                    Chunk var7 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
456                    boolean var8 = var7.setBlockIDWithMetadata(par1 & 15, par2, par3 & 15, par4, par5);
457                    this.theProfiler.startSection("checkLight");
458                    this.updateAllLightTypes(par1, par2, par3);
459                    this.theProfiler.endSection();
460    
461                    if (par6 && var8 && (this.isRemote || var7.deferRender))
462                    {
463                        this.markBlockNeedsUpdate(par1, par2, par3);
464                    }
465    
466                    return var8;
467                }
468            }
469            else
470            {
471                return false;
472            }
473        }
474    
475        /**
476         * Sets the block to the specified blockID at the block coordinates Args x, y, z, blockID
477         */
478        public boolean setBlock(int par1, int par2, int par3, int par4)
479        {
480            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
481            {
482                if (par2 < 0)
483                {
484                    return false;
485                }
486                else if (par2 >= 256)
487                {
488                    return false;
489                }
490                else
491                {
492                    Chunk var5 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
493                    boolean var6 = var5.setBlockID(par1 & 15, par2, par3 & 15, par4);
494                    this.theProfiler.startSection("checkLight");
495                    this.updateAllLightTypes(par1, par2, par3);
496                    this.theProfiler.endSection();
497    
498                    if (var6 && (this.isRemote || var5.deferRender))
499                    {
500                        this.markBlockNeedsUpdate(par1, par2, par3);
501                    }
502    
503                    return var6;
504                }
505            }
506            else
507            {
508                return false;
509            }
510        }
511    
512        /**
513         * Returns the block's material.
514         */
515        public Material getBlockMaterial(int par1, int par2, int par3)
516        {
517            int var4 = this.getBlockId(par1, par2, par3);
518            return var4 == 0 ? Material.air : Block.blocksList[var4].blockMaterial;
519        }
520    
521        /**
522         * Returns the block metadata at coords x,y,z
523         */
524        public int getBlockMetadata(int par1, int par2, int par3)
525        {
526            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
527            {
528                if (par2 < 0)
529                {
530                    return 0;
531                }
532                else if (par2 >= 256)
533                {
534                    return 0;
535                }
536                else
537                {
538                    Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
539                    par1 &= 15;
540                    par3 &= 15;
541                    return var4.getBlockMetadata(par1, par2, par3);
542                }
543            }
544            else
545            {
546                return 0;
547            }
548        }
549    
550        /**
551         * Sets the blocks metadata and if set will then notify blocks that this block changed. Args: x, y, z, metadata
552         */
553        public void setBlockMetadataWithNotify(int par1, int par2, int par3, int par4)
554        {
555            if (this.setBlockMetadata(par1, par2, par3, par4))
556            {
557                this.notifyBlockChange(par1, par2, par3, this.getBlockId(par1, par2, par3));
558            }
559        }
560    
561        /**
562         * Set the metadata of a block in global coordinates
563         */
564        public boolean setBlockMetadata(int par1, int par2, int par3, int par4)
565        {
566            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
567            {
568                if (par2 < 0)
569                {
570                    return false;
571                }
572                else if (par2 >= 256)
573                {
574                    return false;
575                }
576                else
577                {
578                    Chunk var5 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
579                    int var6 = par1 & 15;
580                    int var7 = par3 & 15;
581                    boolean var8 = var5.setBlockMetadata(var6, par2, var7, par4);
582    
583                    if (var8 && (this.isRemote || var5.deferRender && Block.requiresSelfNotify[var5.getBlockID(var6, par2, var7) & 4095]))
584                    {
585                        this.markBlockNeedsUpdate(par1, par2, par3);
586                    }
587    
588                    return var8;
589                }
590            }
591            else
592            {
593                return false;
594            }
595        }
596    
597        /**
598         * Sets a block and notifies relevant systems with the block change  Args: x, y, z, blockID
599         */
600        public boolean setBlockWithNotify(int par1, int par2, int par3, int par4)
601        {
602            if (this.setBlock(par1, par2, par3, par4))
603            {
604                this.notifyBlockChange(par1, par2, par3, par4);
605                return true;
606            }
607            else
608            {
609                return false;
610            }
611        }
612    
613        /**
614         * Sets the block ID and metadata, then notifies neighboring blocks of the change Params: x, y, z, BlockID, Metadata
615         */
616        public boolean setBlockAndMetadataWithNotify(int par1, int par2, int par3, int par4, int par5)
617        {
618            if (this.setBlockAndMetadata(par1, par2, par3, par4, par5))
619            {
620                this.notifyBlockChange(par1, par2, par3, par4);
621                return true;
622            }
623            else
624            {
625                return false;
626            }
627        }
628    
629        /**
630         * Marks the block as needing an update with the renderer. Args: x, y, z
631         */
632        public void markBlockNeedsUpdate(int par1, int par2, int par3)
633        {
634            Iterator var4 = this.worldAccesses.iterator();
635    
636            while (var4.hasNext())
637            {
638                IWorldAccess var5 = (IWorldAccess)var4.next();
639                var5.markBlockNeedsUpdate(par1, par2, par3);
640            }
641        }
642    
643        /**
644         * The block type change and need to notify other systems  Args: x, y, z, blockID
645         */
646        public void notifyBlockChange(int par1, int par2, int par3, int par4)
647        {
648            this.notifyBlocksOfNeighborChange(par1, par2, par3, par4);
649        }
650    
651        /**
652         * marks a vertical line of blocks as dirty
653         */
654        public void markBlocksDirtyVertical(int par1, int par2, int par3, int par4)
655        {
656            int var5;
657    
658            if (par3 > par4)
659            {
660                var5 = par4;
661                par4 = par3;
662                par3 = var5;
663            }
664    
665            if (!this.provider.hasNoSky)
666            {
667                for (var5 = par3; var5 <= par4; ++var5)
668                {
669                    this.updateLightByType(EnumSkyBlock.Sky, par1, var5, par2);
670                }
671            }
672    
673            this.markBlocksDirty(par1, par3, par2, par1, par4, par2);
674        }
675    
676        /**
677         * calls the 'MarkBlockAsNeedsUpdate' in all block accesses in this world
678         */
679        public void markBlockAsNeedsUpdate(int par1, int par2, int par3)
680        {
681            Iterator var4 = this.worldAccesses.iterator();
682    
683            while (var4.hasNext())
684            {
685                IWorldAccess var5 = (IWorldAccess)var4.next();
686                var5.markBlockRangeNeedsUpdate(par1, par2, par3, par1, par2, par3);
687            }
688        }
689    
690        public void markBlocksDirty(int par1, int par2, int par3, int par4, int par5, int par6)
691        {
692            Iterator var7 = this.worldAccesses.iterator();
693    
694            while (var7.hasNext())
695            {
696                IWorldAccess var8 = (IWorldAccess)var7.next();
697                var8.markBlockRangeNeedsUpdate(par1, par2, par3, par4, par5, par6);
698            }
699        }
700    
701        /**
702         * Notifies neighboring blocks that this specified block changed  Args: x, y, z, blockID
703         */
704        public void notifyBlocksOfNeighborChange(int par1, int par2, int par3, int par4)
705        {
706            this.notifyBlockOfNeighborChange(par1 - 1, par2, par3, par4);
707            this.notifyBlockOfNeighborChange(par1 + 1, par2, par3, par4);
708            this.notifyBlockOfNeighborChange(par1, par2 - 1, par3, par4);
709            this.notifyBlockOfNeighborChange(par1, par2 + 1, par3, par4);
710            this.notifyBlockOfNeighborChange(par1, par2, par3 - 1, par4);
711            this.notifyBlockOfNeighborChange(par1, par2, par3 + 1, par4);
712        }
713    
714        /**
715         * Notifies a block that one of its neighbor change to the specified type Args: x, y, z, blockID
716         */
717        private void notifyBlockOfNeighborChange(int par1, int par2, int par3, int par4)
718        {
719            if (!this.editingBlocks && !this.isRemote)
720            {
721                Block var5 = Block.blocksList[this.getBlockId(par1, par2, par3)];
722    
723                if (var5 != null)
724                {
725                    var5.onNeighborBlockChange(this, par1, par2, par3, par4);
726                }
727            }
728        }
729    
730        /**
731         * Checks if the specified block is able to see the sky
732         */
733        public boolean canBlockSeeTheSky(int par1, int par2, int par3)
734        {
735            return this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).canBlockSeeTheSky(par1 & 15, par2, par3 & 15);
736        }
737    
738        /**
739         * Does the same as getBlockLightValue_do but without checking if its not a normal block
740         */
741        public int getFullBlockLightValue(int par1, int par2, int par3)
742        {
743            if (par2 < 0)
744            {
745                return 0;
746            }
747            else
748            {
749                if (par2 >= 256)
750                {
751                    par2 = 255;
752                }
753    
754                return this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockLightValue(par1 & 15, par2, par3 & 15, 0);
755            }
756        }
757    
758        /**
759         * Gets the light value of a block location
760         */
761        public int getBlockLightValue(int par1, int par2, int par3)
762        {
763            return this.getBlockLightValue_do(par1, par2, par3, true);
764        }
765    
766        /**
767         * Gets the light value of a block location. This is the actual function that gets the value and has a bool flag
768         * that indicates if its a half step block to get the maximum light value of a direct neighboring block (left,
769         * right, forward, back, and up)
770         */
771        public int getBlockLightValue_do(int par1, int par2, int par3, boolean par4)
772        {
773            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
774            {
775                if (par4)
776                {
777                    int var5 = this.getBlockId(par1, par2, par3);
778    
779                    if (var5 == Block.stoneSingleSlab.blockID || var5 == Block.woodSingleSlab.blockID || var5 == Block.tilledField.blockID || var5 == Block.stairCompactCobblestone.blockID || var5 == Block.stairCompactPlanks.blockID)
780                    {
781                        int var6 = this.getBlockLightValue_do(par1, par2 + 1, par3, false);
782                        int var7 = this.getBlockLightValue_do(par1 + 1, par2, par3, false);
783                        int var8 = this.getBlockLightValue_do(par1 - 1, par2, par3, false);
784                        int var9 = this.getBlockLightValue_do(par1, par2, par3 + 1, false);
785                        int var10 = this.getBlockLightValue_do(par1, par2, par3 - 1, false);
786    
787                        if (var7 > var6)
788                        {
789                            var6 = var7;
790                        }
791    
792                        if (var8 > var6)
793                        {
794                            var6 = var8;
795                        }
796    
797                        if (var9 > var6)
798                        {
799                            var6 = var9;
800                        }
801    
802                        if (var10 > var6)
803                        {
804                            var6 = var10;
805                        }
806    
807                        return var6;
808                    }
809                }
810    
811                if (par2 < 0)
812                {
813                    return 0;
814                }
815                else
816                {
817                    if (par2 >= 256)
818                    {
819                        par2 = 255;
820                    }
821    
822                    Chunk var11 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
823                    par1 &= 15;
824                    par3 &= 15;
825                    return var11.getBlockLightValue(par1, par2, par3, this.skylightSubtracted);
826                }
827            }
828            else
829            {
830                return 15;
831            }
832        }
833    
834        /**
835         * Returns the y coordinate with a block in it at this x, z coordinate
836         */
837        public int getHeightValue(int par1, int par2)
838        {
839            if (par1 >= -30000000 && par2 >= -30000000 && par1 < 30000000 && par2 < 30000000)
840            {
841                if (!this.chunkExists(par1 >> 4, par2 >> 4))
842                {
843                    return 0;
844                }
845                else
846                {
847                    Chunk var3 = this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
848                    return var3.getHeightValue(par1 & 15, par2 & 15);
849                }
850            }
851            else
852            {
853                return 0;
854            }
855        }
856    
857        public int func_82734_g(int par1, int par2)
858        {
859            if (par1 >= -30000000 && par2 >= -30000000 && par1 < 30000000 && par2 < 30000000)
860            {
861                if (!this.chunkExists(par1 >> 4, par2 >> 4))
862                {
863                    return 0;
864                }
865                else
866                {
867                    Chunk var3 = this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
868                    return var3.field_82912_p;
869                }
870            }
871            else
872            {
873                return 0;
874            }
875        }
876    
877        @SideOnly(Side.CLIENT)
878    
879        /**
880         * Brightness for SkyBlock.Sky is clear white and (through color computing it is assumed) DEPENDENT ON DAYTIME.
881         * Brightness for SkyBlock.Block is yellowish and independent.
882         */
883        public int getSkyBlockTypeBrightness(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
884        {
885            if (this.provider.hasNoSky && par1EnumSkyBlock == EnumSkyBlock.Sky)
886            {
887                return 0;
888            }
889            else
890            {
891                if (par3 < 0)
892                {
893                    par3 = 0;
894                }
895    
896                if (par3 >= 256)
897                {
898                    return par1EnumSkyBlock.defaultLightValue;
899                }
900                else if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
901                {
902                    int var5 = par2 >> 4;
903                    int var6 = par4 >> 4;
904    
905                    if (!this.chunkExists(var5, var6))
906                    {
907                        return par1EnumSkyBlock.defaultLightValue;
908                    }
909                    else if (Block.useNeighborBrightness[this.getBlockId(par2, par3, par4)])
910                    {
911                        int var12 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3 + 1, par4);
912                        int var8 = this.getSavedLightValue(par1EnumSkyBlock, par2 + 1, par3, par4);
913                        int var9 = this.getSavedLightValue(par1EnumSkyBlock, par2 - 1, par3, par4);
914                        int var10 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4 + 1);
915                        int var11 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4 - 1);
916    
917                        if (var8 > var12)
918                        {
919                            var12 = var8;
920                        }
921    
922                        if (var9 > var12)
923                        {
924                            var12 = var9;
925                        }
926    
927                        if (var10 > var12)
928                        {
929                            var12 = var10;
930                        }
931    
932                        if (var11 > var12)
933                        {
934                            var12 = var11;
935                        }
936    
937                        return var12;
938                    }
939                    else
940                    {
941                        Chunk var7 = this.getChunkFromChunkCoords(var5, var6);
942                        return var7.getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
943                    }
944                }
945                else
946                {
947                    return par1EnumSkyBlock.defaultLightValue;
948                }
949            }
950        }
951    
952        /**
953         * Returns saved light value without taking into account the time of day.  Either looks in the sky light map or
954         * block light map based on the enumSkyBlock arg.
955         */
956        public int getSavedLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
957        {
958            if (par3 < 0)
959            {
960                par3 = 0;
961            }
962    
963            if (par3 >= 256)
964            {
965                par3 = 255;
966            }
967    
968            if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
969            {
970                int var5 = par2 >> 4;
971                int var6 = par4 >> 4;
972    
973                if (!this.chunkExists(var5, var6))
974                {
975                    return par1EnumSkyBlock.defaultLightValue;
976                }
977                else
978                {
979                    Chunk var7 = this.getChunkFromChunkCoords(var5, var6);
980                    return var7.getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
981                }
982            }
983            else
984            {
985                return par1EnumSkyBlock.defaultLightValue;
986            }
987        }
988    
989        /**
990         * Sets the light value either into the sky map or block map depending on if enumSkyBlock is set to sky or block.
991         * Args: enumSkyBlock, x, y, z, lightValue
992         */
993        public void setLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4, int par5)
994        {
995            if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
996            {
997                if (par3 >= 0)
998                {
999                    if (par3 < 256)
1000                    {
1001                        if (this.chunkExists(par2 >> 4, par4 >> 4))
1002                        {
1003                            Chunk var6 = this.getChunkFromChunkCoords(par2 >> 4, par4 >> 4);
1004                            var6.setLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15, par5);
1005                            Iterator var7 = this.worldAccesses.iterator();
1006    
1007                            while (var7.hasNext())
1008                            {
1009                                IWorldAccess var8 = (IWorldAccess)var7.next();
1010                                var8.markBlockNeedsUpdate2(par2, par3, par4);
1011                            }
1012                        }
1013                    }
1014                }
1015            }
1016        }
1017    
1018        /**
1019         * all WorldAcceses mark this block as dirty
1020         */
1021        public void markBlockNeedsUpdateForAll(int par1, int par2, int par3)
1022        {
1023            Iterator var4 = this.worldAccesses.iterator();
1024    
1025            while (var4.hasNext())
1026            {
1027                IWorldAccess var5 = (IWorldAccess)var4.next();
1028                var5.markBlockNeedsUpdate2(par1, par2, par3);
1029            }
1030        }
1031    
1032        @SideOnly(Side.CLIENT)
1033    
1034        /**
1035         * Any Light rendered on a 1.8 Block goes through here
1036         */
1037        public int getLightBrightnessForSkyBlocks(int par1, int par2, int par3, int par4)
1038        {
1039            int var5 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, par1, par2, par3);
1040            int var6 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Block, par1, par2, par3);
1041    
1042            if (var6 < par4)
1043            {
1044                var6 = par4;
1045            }
1046    
1047            return var5 << 20 | var6 << 4;
1048        }
1049    
1050        @SideOnly(Side.CLIENT)
1051        public float getBrightness(int par1, int par2, int par3, int par4)
1052        {
1053            int var5 = this.getBlockLightValue(par1, par2, par3);
1054    
1055            if (var5 < par4)
1056            {
1057                var5 = par4;
1058            }
1059    
1060            return this.provider.lightBrightnessTable[var5];
1061        }
1062    
1063        /**
1064         * Returns how bright the block is shown as which is the block's light value looked up in a lookup table (light
1065         * values aren't linear for brightness). Args: x, y, z
1066         */
1067        public float getLightBrightness(int par1, int par2, int par3)
1068        {
1069            return this.provider.lightBrightnessTable[this.getBlockLightValue(par1, par2, par3)];
1070        }
1071    
1072        /**
1073         * Checks whether its daytime by seeing if the light subtracted from the skylight is less than 4
1074         */
1075        public boolean isDaytime()
1076        {
1077            return provider.isDaytime();
1078        }
1079    
1080        /**
1081         * ray traces all blocks, including non-collideable ones
1082         */
1083        public MovingObjectPosition rayTraceBlocks(Vec3 par1Vec3, Vec3 par2Vec3)
1084        {
1085            return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, false, false);
1086        }
1087    
1088        public MovingObjectPosition rayTraceBlocks_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3)
1089        {
1090            return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, par3, false);
1091        }
1092    
1093        public MovingObjectPosition rayTraceBlocks_do_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3, boolean par4)
1094        {
1095            if (!Double.isNaN(par1Vec3.xCoord) && !Double.isNaN(par1Vec3.yCoord) && !Double.isNaN(par1Vec3.zCoord))
1096            {
1097                if (!Double.isNaN(par2Vec3.xCoord) && !Double.isNaN(par2Vec3.yCoord) && !Double.isNaN(par2Vec3.zCoord))
1098                {
1099                    int var5 = MathHelper.floor_double(par2Vec3.xCoord);
1100                    int var6 = MathHelper.floor_double(par2Vec3.yCoord);
1101                    int var7 = MathHelper.floor_double(par2Vec3.zCoord);
1102                    int var8 = MathHelper.floor_double(par1Vec3.xCoord);
1103                    int var9 = MathHelper.floor_double(par1Vec3.yCoord);
1104                    int var10 = MathHelper.floor_double(par1Vec3.zCoord);
1105                    int var11 = this.getBlockId(var8, var9, var10);
1106                    int var12 = this.getBlockMetadata(var8, var9, var10);
1107                    Block var13 = Block.blocksList[var11];
1108    
1109                    if (var13 != null && (!par4 || var13 == null || var13.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var11 > 0 && var13.canCollideCheck(var12, par3))
1110                    {
1111                        MovingObjectPosition var14 = var13.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1112    
1113                        if (var14 != null)
1114                        {
1115                            return var14;
1116                        }
1117                    }
1118    
1119                    var11 = 200;
1120    
1121                    while (var11-- >= 0)
1122                    {
1123                        if (Double.isNaN(par1Vec3.xCoord) || Double.isNaN(par1Vec3.yCoord) || Double.isNaN(par1Vec3.zCoord))
1124                        {
1125                            return null;
1126                        }
1127    
1128                        if (var8 == var5 && var9 == var6 && var10 == var7)
1129                        {
1130                            return null;
1131                        }
1132    
1133                        boolean var39 = true;
1134                        boolean var40 = true;
1135                        boolean var41 = true;
1136                        double var15 = 999.0D;
1137                        double var17 = 999.0D;
1138                        double var19 = 999.0D;
1139    
1140                        if (var5 > var8)
1141                        {
1142                            var15 = (double)var8 + 1.0D;
1143                        }
1144                        else if (var5 < var8)
1145                        {
1146                            var15 = (double)var8 + 0.0D;
1147                        }
1148                        else
1149                        {
1150                            var39 = false;
1151                        }
1152    
1153                        if (var6 > var9)
1154                        {
1155                            var17 = (double)var9 + 1.0D;
1156                        }
1157                        else if (var6 < var9)
1158                        {
1159                            var17 = (double)var9 + 0.0D;
1160                        }
1161                        else
1162                        {
1163                            var40 = false;
1164                        }
1165    
1166                        if (var7 > var10)
1167                        {
1168                            var19 = (double)var10 + 1.0D;
1169                        }
1170                        else if (var7 < var10)
1171                        {
1172                            var19 = (double)var10 + 0.0D;
1173                        }
1174                        else
1175                        {
1176                            var41 = false;
1177                        }
1178    
1179                        double var21 = 999.0D;
1180                        double var23 = 999.0D;
1181                        double var25 = 999.0D;
1182                        double var27 = par2Vec3.xCoord - par1Vec3.xCoord;
1183                        double var29 = par2Vec3.yCoord - par1Vec3.yCoord;
1184                        double var31 = par2Vec3.zCoord - par1Vec3.zCoord;
1185    
1186                        if (var39)
1187                        {
1188                            var21 = (var15 - par1Vec3.xCoord) / var27;
1189                        }
1190    
1191                        if (var40)
1192                        {
1193                            var23 = (var17 - par1Vec3.yCoord) / var29;
1194                        }
1195    
1196                        if (var41)
1197                        {
1198                            var25 = (var19 - par1Vec3.zCoord) / var31;
1199                        }
1200    
1201                        boolean var33 = false;
1202                        byte var42;
1203    
1204                        if (var21 < var23 && var21 < var25)
1205                        {
1206                            if (var5 > var8)
1207                            {
1208                                var42 = 4;
1209                            }
1210                            else
1211                            {
1212                                var42 = 5;
1213                            }
1214    
1215                            par1Vec3.xCoord = var15;
1216                            par1Vec3.yCoord += var29 * var21;
1217                            par1Vec3.zCoord += var31 * var21;
1218                        }
1219                        else if (var23 < var25)
1220                        {
1221                            if (var6 > var9)
1222                            {
1223                                var42 = 0;
1224                            }
1225                            else
1226                            {
1227                                var42 = 1;
1228                            }
1229    
1230                            par1Vec3.xCoord += var27 * var23;
1231                            par1Vec3.yCoord = var17;
1232                            par1Vec3.zCoord += var31 * var23;
1233                        }
1234                        else
1235                        {
1236                            if (var7 > var10)
1237                            {
1238                                var42 = 2;
1239                            }
1240                            else
1241                            {
1242                                var42 = 3;
1243                            }
1244    
1245                            par1Vec3.xCoord += var27 * var25;
1246                            par1Vec3.yCoord += var29 * var25;
1247                            par1Vec3.zCoord = var19;
1248                        }
1249    
1250                        Vec3 var34 = this.func_82732_R().getVecFromPool(par1Vec3.xCoord, par1Vec3.yCoord, par1Vec3.zCoord);
1251                        var8 = (int)(var34.xCoord = (double)MathHelper.floor_double(par1Vec3.xCoord));
1252    
1253                        if (var42 == 5)
1254                        {
1255                            --var8;
1256                            ++var34.xCoord;
1257                        }
1258    
1259                        var9 = (int)(var34.yCoord = (double)MathHelper.floor_double(par1Vec3.yCoord));
1260    
1261                        if (var42 == 1)
1262                        {
1263                            --var9;
1264                            ++var34.yCoord;
1265                        }
1266    
1267                        var10 = (int)(var34.zCoord = (double)MathHelper.floor_double(par1Vec3.zCoord));
1268    
1269                        if (var42 == 3)
1270                        {
1271                            --var10;
1272                            ++var34.zCoord;
1273                        }
1274    
1275                        int var35 = this.getBlockId(var8, var9, var10);
1276                        int var36 = this.getBlockMetadata(var8, var9, var10);
1277                        Block var37 = Block.blocksList[var35];
1278    
1279                        if ((!par4 || var37 == null || var37.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var35 > 0 && var37.canCollideCheck(var36, par3))
1280                        {
1281                            MovingObjectPosition var38 = var37.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1282    
1283                            if (var38 != null)
1284                            {
1285                                return var38;
1286                            }
1287                        }
1288                    }
1289    
1290                    return null;
1291                }
1292                else
1293                {
1294                    return null;
1295                }
1296            }
1297            else
1298            {
1299                return null;
1300            }
1301        }
1302    
1303        /**
1304         * Plays a sound at the entity's position. Args: entity, sound, volume (relative to 1.0), and frequency (or pitch,
1305         * also relative to 1.0).
1306         */
1307        public void playSoundAtEntity(Entity par1Entity, String par2Str, float par3, float par4)
1308        {
1309            PlaySoundAtEntityEvent event = new PlaySoundAtEntityEvent(par1Entity, par2Str, par3, par4);
1310            if (MinecraftForge.EVENT_BUS.post(event))
1311            {
1312                return;
1313            }
1314            par2Str = event.name;
1315            if (par1Entity != null && par2Str != null)
1316            {
1317                Iterator var5 = this.worldAccesses.iterator();
1318    
1319                while (var5.hasNext())
1320                {
1321                    IWorldAccess var6 = (IWorldAccess)var5.next();
1322                    var6.playSound(par2Str, par1Entity.posX, par1Entity.posY - (double)par1Entity.yOffset, par1Entity.posZ, par3, par4);
1323                }
1324            }
1325        }
1326    
1327        /**
1328         * Play a sound effect. Many many parameters for this function. Not sure what they do, but a classic call is :
1329         * (double)i + 0.5D, (double)j + 0.5D, (double)k + 0.5D, 'random.door_open', 1.0F, world.rand.nextFloat() * 0.1F +
1330         * 0.9F with i,j,k position of the block.
1331         */
1332        public void playSoundEffect(double par1, double par3, double par5, String par7Str, float par8, float par9)
1333        {
1334            if (par7Str != null)
1335            {
1336                Iterator var10 = this.worldAccesses.iterator();
1337    
1338                while (var10.hasNext())
1339                {
1340                    IWorldAccess var11 = (IWorldAccess)var10.next();
1341                    var11.playSound(par7Str, par1, par3, par5, par8, par9);
1342                }
1343            }
1344        }
1345    
1346        /**
1347         * par8 is loudness, all pars passed to minecraftInstance.sndManager.playSound
1348         */
1349        public void playSound(double par1, double par3, double par5, String par7Str, float par8, float par9) {}
1350    
1351        /**
1352         * Plays a record at the specified coordinates of the specified name. Args: recordName, x, y, z
1353         */
1354        public void playRecord(String par1Str, int par2, int par3, int par4)
1355        {
1356            Iterator var5 = this.worldAccesses.iterator();
1357    
1358            while (var5.hasNext())
1359            {
1360                IWorldAccess var6 = (IWorldAccess)var5.next();
1361                var6.playRecord(par1Str, par2, par3, par4);
1362            }
1363        }
1364    
1365        /**
1366         * Spawns a particle.  Args particleName, x, y, z, velX, velY, velZ
1367         */
1368        public void spawnParticle(String par1Str, double par2, double par4, double par6, double par8, double par10, double par12)
1369        {
1370            Iterator var14 = this.worldAccesses.iterator();
1371    
1372            while (var14.hasNext())
1373            {
1374                IWorldAccess var15 = (IWorldAccess)var14.next();
1375                var15.spawnParticle(par1Str, par2, par4, par6, par8, par10, par12);
1376            }
1377        }
1378    
1379        /**
1380         * adds a lightning bolt to the list of lightning bolts in this world.
1381         */
1382        public boolean addWeatherEffect(Entity par1Entity)
1383        {
1384            this.weatherEffects.add(par1Entity);
1385            return true;
1386        }
1387    
1388        /**
1389         * Called to place all entities as part of a world
1390         */
1391        public boolean spawnEntityInWorld(Entity par1Entity)
1392        {
1393            int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
1394            int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
1395            boolean var4 = false;
1396    
1397            if (par1Entity instanceof EntityPlayer)
1398            {
1399                var4 = true;
1400            }
1401    
1402            if (!var4 && !this.chunkExists(var2, var3))
1403            {
1404                return false;
1405            }
1406            else
1407            {
1408                if (par1Entity instanceof EntityPlayer)
1409                {
1410                    EntityPlayer var5 = (EntityPlayer)par1Entity;
1411                    this.playerEntities.add(var5);
1412                    this.updateAllPlayersSleepingFlag();
1413                }
1414    
1415                if (!var4 && MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
1416                {
1417                    return false;
1418                }
1419    
1420                this.getChunkFromChunkCoords(var2, var3).addEntity(par1Entity);
1421                this.loadedEntityList.add(par1Entity);
1422                this.obtainEntitySkin(par1Entity);
1423                return true;
1424            }
1425        }
1426    
1427        /**
1428         * Start the skin for this entity downloading, if necessary, and increment its reference counter
1429         */
1430        protected void obtainEntitySkin(Entity par1Entity)
1431        {
1432            Iterator var2 = this.worldAccesses.iterator();
1433    
1434            while (var2.hasNext())
1435            {
1436                IWorldAccess var3 = (IWorldAccess)var2.next();
1437                var3.obtainEntitySkin(par1Entity);
1438            }
1439        }
1440    
1441        /**
1442         * Decrement the reference counter for this entity's skin image data
1443         */
1444        protected void releaseEntitySkin(Entity par1Entity)
1445        {
1446            Iterator var2 = this.worldAccesses.iterator();
1447    
1448            while (var2.hasNext())
1449            {
1450                IWorldAccess var3 = (IWorldAccess)var2.next();
1451                var3.releaseEntitySkin(par1Entity);
1452            }
1453        }
1454    
1455        /**
1456         * Dismounts the entity (and anything riding the entity), sets the dead flag, and removes the player entity from the
1457         * player entity list. Called by the playerLoggedOut function.
1458         */
1459        public void setEntityDead(Entity par1Entity)
1460        {
1461            if (par1Entity.riddenByEntity != null)
1462            {
1463                par1Entity.riddenByEntity.mountEntity((Entity)null);
1464            }
1465    
1466            if (par1Entity.ridingEntity != null)
1467            {
1468                par1Entity.mountEntity((Entity)null);
1469            }
1470    
1471            par1Entity.setDead();
1472    
1473            if (par1Entity instanceof EntityPlayer)
1474            {
1475                this.playerEntities.remove(par1Entity);
1476                this.updateAllPlayersSleepingFlag();
1477            }
1478        }
1479    
1480        /**
1481         * remove dat player from dem servers
1482         */
1483        public void removeEntity(Entity par1Entity)
1484        {
1485            par1Entity.setDead();
1486    
1487            if (par1Entity instanceof EntityPlayer)
1488            {
1489                this.playerEntities.remove(par1Entity);
1490                this.updateAllPlayersSleepingFlag();
1491            }
1492    
1493            int var2 = par1Entity.chunkCoordX;
1494            int var3 = par1Entity.chunkCoordZ;
1495    
1496            if (par1Entity.addedToChunk && this.chunkExists(var2, var3))
1497            {
1498                this.getChunkFromChunkCoords(var2, var3).removeEntity(par1Entity);
1499            }
1500    
1501            this.loadedEntityList.remove(par1Entity);
1502            this.releaseEntitySkin(par1Entity);
1503        }
1504    
1505        /**
1506         * Adds a IWorldAccess to the list of worldAccesses
1507         */
1508        public void addWorldAccess(IWorldAccess par1IWorldAccess)
1509        {
1510            this.worldAccesses.add(par1IWorldAccess);
1511        }
1512    
1513        /**
1514         * Returns a list of bounding boxes that collide with aabb excluding the passed in entity's collision. Args: entity,
1515         * aabb
1516         */
1517        public List getCollidingBoundingBoxes(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
1518        {
1519            this.collidingBoundingBoxes.clear();
1520            int var3 = MathHelper.floor_double(par2AxisAlignedBB.minX);
1521            int var4 = MathHelper.floor_double(par2AxisAlignedBB.maxX + 1.0D);
1522            int var5 = MathHelper.floor_double(par2AxisAlignedBB.minY);
1523            int var6 = MathHelper.floor_double(par2AxisAlignedBB.maxY + 1.0D);
1524            int var7 = MathHelper.floor_double(par2AxisAlignedBB.minZ);
1525            int var8 = MathHelper.floor_double(par2AxisAlignedBB.maxZ + 1.0D);
1526    
1527            for (int var9 = var3; var9 < var4; ++var9)
1528            {
1529                for (int var10 = var7; var10 < var8; ++var10)
1530                {
1531                    if (this.blockExists(var9, 64, var10))
1532                    {
1533                        for (int var11 = var5 - 1; var11 < var6; ++var11)
1534                        {
1535                            Block var12 = Block.blocksList[this.getBlockId(var9, var11, var10)];
1536    
1537                            if (var12 != null)
1538                            {
1539                                var12.addCollidingBlockToList(this, var9, var11, var10, par2AxisAlignedBB, this.collidingBoundingBoxes, par1Entity);
1540                            }
1541                        }
1542                    }
1543                }
1544            }
1545    
1546            double var15 = 0.25D;
1547            List var17 = this.getEntitiesWithinAABBExcludingEntity(par1Entity, par2AxisAlignedBB.expand(var15, var15, var15));
1548            Iterator var16 = var17.iterator();
1549    
1550            while (var16.hasNext())
1551            {
1552                Entity var13 = (Entity)var16.next();
1553                AxisAlignedBB var14 = var13.getBoundingBox();
1554    
1555                if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1556                {
1557                    this.collidingBoundingBoxes.add(var14);
1558                }
1559    
1560                var14 = par1Entity.getCollisionBox(var13);
1561    
1562                if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1563                {
1564                    this.collidingBoundingBoxes.add(var14);
1565                }
1566            }
1567    
1568            return this.collidingBoundingBoxes;
1569        }
1570    
1571        /**
1572         * calculates and returns a list of colliding bounding boxes within a given AABB
1573         */
1574        public List getAllCollidingBoundingBoxes(AxisAlignedBB par1AxisAlignedBB)
1575        {
1576            this.collidingBoundingBoxes.clear();
1577            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
1578            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
1579            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
1580            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
1581            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
1582            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
1583    
1584            for (int var8 = var2; var8 < var3; ++var8)
1585            {
1586                for (int var9 = var6; var9 < var7; ++var9)
1587                {
1588                    if (this.blockExists(var8, 64, var9))
1589                    {
1590                        for (int var10 = var4 - 1; var10 < var5; ++var10)
1591                        {
1592                            Block var11 = Block.blocksList[this.getBlockId(var8, var10, var9)];
1593    
1594                            if (var11 != null)
1595                            {
1596                                var11.addCollidingBlockToList(this, var8, var10, var9, par1AxisAlignedBB, this.collidingBoundingBoxes, (Entity)null);
1597                            }
1598                        }
1599                    }
1600                }
1601            }
1602    
1603            return this.collidingBoundingBoxes;
1604        }
1605    
1606        /**
1607         * Returns the amount of skylight subtracted for the current time
1608         */
1609        public int calculateSkylightSubtracted(float par1)
1610        {
1611            float var2 = this.getCelestialAngle(par1);
1612            float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F);
1613    
1614            if (var3 < 0.0F)
1615            {
1616                var3 = 0.0F;
1617            }
1618    
1619            if (var3 > 1.0F)
1620            {
1621                var3 = 1.0F;
1622            }
1623    
1624            var3 = 1.0F - var3;
1625            var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1626            var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1627            var3 = 1.0F - var3;
1628            return (int)(var3 * 11.0F);
1629        }
1630    
1631        @SideOnly(Side.CLIENT)
1632    
1633        /**
1634         * Removes a worldAccess from the worldAccesses object
1635         */
1636        public void removeWorldAccess(IWorldAccess par1IWorldAccess)
1637        {
1638            this.worldAccesses.remove(par1IWorldAccess);
1639        }
1640    
1641        @SideOnly(Side.CLIENT)
1642        public float func_72971_b(float par1)
1643        {
1644            float var2 = this.getCelestialAngle(par1);
1645            float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.2F);
1646    
1647            if (var3 < 0.0F)
1648            {
1649                var3 = 0.0F;
1650            }
1651    
1652            if (var3 > 1.0F)
1653            {
1654                var3 = 1.0F;
1655            }
1656    
1657            var3 = 1.0F - var3;
1658            var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1659            var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1660            return var3 * 0.8F + 0.2F;
1661        }
1662    
1663        @SideOnly(Side.CLIENT)
1664    
1665        /**
1666         * Calculates the color for the skybox
1667         */
1668        public Vec3 getSkyColor(Entity par1Entity, float par2)
1669        {
1670            return provider.getSkyColor(par1Entity, par2);
1671        }
1672    
1673        @SideOnly(Side.CLIENT)
1674        public Vec3 getSkyColorBody(Entity par1Entity, float par2)
1675        {
1676            float var3 = this.getCelestialAngle(par2);
1677            float var4 = MathHelper.cos(var3 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1678    
1679            if (var4 < 0.0F)
1680            {
1681                var4 = 0.0F;
1682            }
1683    
1684            if (var4 > 1.0F)
1685            {
1686                var4 = 1.0F;
1687            }
1688    
1689            int var5 = MathHelper.floor_double(par1Entity.posX);
1690            int var6 = MathHelper.floor_double(par1Entity.posZ);
1691            BiomeGenBase var7 = this.getBiomeGenForCoords(var5, var6);
1692            float var8 = var7.getFloatTemperature();
1693            int var9 = var7.getSkyColorByTemp(var8);
1694            float var10 = (float)(var9 >> 16 & 255) / 255.0F;
1695            float var11 = (float)(var9 >> 8 & 255) / 255.0F;
1696            float var12 = (float)(var9 & 255) / 255.0F;
1697            var10 *= var4;
1698            var11 *= var4;
1699            var12 *= var4;
1700            float var13 = this.getRainStrength(par2);
1701            float var14;
1702            float var15;
1703    
1704            if (var13 > 0.0F)
1705            {
1706                var14 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.6F;
1707                var15 = 1.0F - var13 * 0.75F;
1708                var10 = var10 * var15 + var14 * (1.0F - var15);
1709                var11 = var11 * var15 + var14 * (1.0F - var15);
1710                var12 = var12 * var15 + var14 * (1.0F - var15);
1711            }
1712    
1713            var14 = this.getWeightedThunderStrength(par2);
1714    
1715            if (var14 > 0.0F)
1716            {
1717                var15 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.2F;
1718                float var16 = 1.0F - var14 * 0.75F;
1719                var10 = var10 * var16 + var15 * (1.0F - var16);
1720                var11 = var11 * var16 + var15 * (1.0F - var16);
1721                var12 = var12 * var16 + var15 * (1.0F - var16);
1722            }
1723    
1724            if (this.lightningFlash > 0)
1725            {
1726                var15 = (float)this.lightningFlash - par2;
1727    
1728                if (var15 > 1.0F)
1729                {
1730                    var15 = 1.0F;
1731                }
1732    
1733                var15 *= 0.45F;
1734                var10 = var10 * (1.0F - var15) + 0.8F * var15;
1735                var11 = var11 * (1.0F - var15) + 0.8F * var15;
1736                var12 = var12 * (1.0F - var15) + 1.0F * var15;
1737            }
1738    
1739            return this.func_82732_R().getVecFromPool((double)var10, (double)var11, (double)var12);
1740        }
1741    
1742        /**
1743         * calls calculateCelestialAngle
1744         */
1745        public float getCelestialAngle(float par1)
1746        {
1747            return this.provider.calculateCelestialAngle(this.worldInfo.getWorldTime(), par1);
1748        }
1749    
1750        @SideOnly(Side.CLIENT)
1751        public int getMoonPhase(float par1)
1752        {
1753            return this.provider.getMoonPhase(this.worldInfo.getWorldTime(), par1);
1754        }
1755    
1756        @SideOnly(Side.CLIENT)
1757    
1758        /**
1759         * Return getCelestialAngle()*2*PI
1760         */
1761        public float getCelestialAngleRadians(float par1)
1762        {
1763            float var2 = this.getCelestialAngle(par1);
1764            return var2 * (float)Math.PI * 2.0F;
1765        }
1766    
1767        @SideOnly(Side.CLIENT)
1768        public Vec3 drawClouds(float par1)
1769        {
1770            return provider.drawClouds(par1);
1771        }
1772    
1773        @SideOnly(Side.CLIENT)
1774        public Vec3 drawCloudsBody(float par1)
1775        {
1776            float var2 = this.getCelestialAngle(par1);
1777            float var3 = MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1778    
1779            if (var3 < 0.0F)
1780            {
1781                var3 = 0.0F;
1782            }
1783    
1784            if (var3 > 1.0F)
1785            {
1786                var3 = 1.0F;
1787            }
1788    
1789            float var4 = (float)(this.cloudColour >> 16 & 255L) / 255.0F;
1790            float var5 = (float)(this.cloudColour >> 8 & 255L) / 255.0F;
1791            float var6 = (float)(this.cloudColour & 255L) / 255.0F;
1792            float var7 = this.getRainStrength(par1);
1793            float var8;
1794            float var9;
1795    
1796            if (var7 > 0.0F)
1797            {
1798                var8 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.6F;
1799                var9 = 1.0F - var7 * 0.95F;
1800                var4 = var4 * var9 + var8 * (1.0F - var9);
1801                var5 = var5 * var9 + var8 * (1.0F - var9);
1802                var6 = var6 * var9 + var8 * (1.0F - var9);
1803            }
1804    
1805            var4 *= var3 * 0.9F + 0.1F;
1806            var5 *= var3 * 0.9F + 0.1F;
1807            var6 *= var3 * 0.85F + 0.15F;
1808            var8 = this.getWeightedThunderStrength(par1);
1809    
1810            if (var8 > 0.0F)
1811            {
1812                var9 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.2F;
1813                float var10 = 1.0F - var8 * 0.95F;
1814                var4 = var4 * var10 + var9 * (1.0F - var10);
1815                var5 = var5 * var10 + var9 * (1.0F - var10);
1816                var6 = var6 * var10 + var9 * (1.0F - var10);
1817            }
1818    
1819            return this.func_82732_R().getVecFromPool((double)var4, (double)var5, (double)var6);
1820        }
1821    
1822        @SideOnly(Side.CLIENT)
1823    
1824        /**
1825         * Returns vector(ish) with R/G/B for fog
1826         */
1827        public Vec3 getFogColor(float par1)
1828        {
1829            float var2 = this.getCelestialAngle(par1);
1830            return this.provider.getFogColor(var2, par1);
1831        }
1832    
1833        /**
1834         * Gets the height to which rain/snow will fall. Calculates it if not already stored.
1835         */
1836        public int getPrecipitationHeight(int par1, int par2)
1837        {
1838            return this.getChunkFromBlockCoords(par1, par2).getPrecipitationHeight(par1 & 15, par2 & 15);
1839        }
1840    
1841        /**
1842         * Finds the highest block on the x, z coordinate that is solid and returns its y coord. Args x, z
1843         */
1844        public int getTopSolidOrLiquidBlock(int par1, int par2)
1845        {
1846            Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
1847            int var4 = var3.getTopFilledSegment() + 15;
1848            par1 &= 15;
1849    
1850            for (par2 &= 15; var4 > 0; --var4)
1851            {
1852                int var5 = var3.getBlockID(par1, var4, par2);
1853    
1854                if (var5 != 0 && Block.blocksList[var5].blockMaterial.blocksMovement() && Block.blocksList[var5].blockMaterial != Material.leaves && !Block.blocksList[var5].isBlockFoliage(this, par1, var4, par2))
1855                {
1856                    return var4 + 1;
1857                }
1858            }
1859    
1860            return -1;
1861        }
1862    
1863        @SideOnly(Side.CLIENT)
1864    
1865        /**
1866         * How bright are stars in the sky
1867         */
1868        public float getStarBrightness(float par1)
1869        {
1870            return provider.getStarBrightness(par1);
1871        }
1872    
1873        @SideOnly(Side.CLIENT)
1874        public float getStarBrightnessBody(float par1)
1875        {
1876            float var2 = this.getCelestialAngle(par1);
1877            float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
1878    
1879            if (var3 < 0.0F)
1880            {
1881                var3 = 0.0F;
1882            }
1883    
1884            if (var3 > 1.0F)
1885            {
1886                var3 = 1.0F;
1887            }
1888    
1889            return var3 * var3 * 0.5F;
1890        }
1891    
1892        /**
1893         * Schedules a tick to a block with a delay (Most commonly the tick rate)
1894         */
1895        public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) {}
1896    
1897        public void func_82740_a(int par1, int par2, int par3, int par4, int par5, int par6) {}
1898    
1899        /**
1900         * Schedules a block update from the saved information in a chunk. Called when the chunk is loaded.
1901         */
1902        public void scheduleBlockUpdateFromLoad(int par1, int par2, int par3, int par4, int par5) {}
1903    
1904        /**
1905         * Updates (and cleans up) entities and tile entities
1906         */
1907        public void updateEntities()
1908        {
1909            this.theProfiler.startSection("entities");
1910            this.theProfiler.startSection("global");
1911            int var1;
1912            Entity var2;
1913    
1914            for (var1 = 0; var1 < this.weatherEffects.size(); ++var1)
1915            {
1916                var2 = (Entity)this.weatherEffects.get(var1);
1917                var2.onUpdate();
1918    
1919                if (var2.isDead)
1920                {
1921                    this.weatherEffects.remove(var1--);
1922                }
1923            }
1924    
1925            this.theProfiler.endStartSection("remove");
1926            this.loadedEntityList.removeAll(this.unloadedEntityList);
1927            Iterator var5 = this.unloadedEntityList.iterator();
1928            int var3;
1929            int var4;
1930    
1931            while (var5.hasNext())
1932            {
1933                var2 = (Entity)var5.next();
1934                var3 = var2.chunkCoordX;
1935                var4 = var2.chunkCoordZ;
1936    
1937                if (var2.addedToChunk && this.chunkExists(var3, var4))
1938                {
1939                    this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1940                }
1941            }
1942    
1943            var5 = this.unloadedEntityList.iterator();
1944    
1945            while (var5.hasNext())
1946            {
1947                var2 = (Entity)var5.next();
1948                this.releaseEntitySkin(var2);
1949            }
1950    
1951            this.unloadedEntityList.clear();
1952            this.theProfiler.endStartSection("regular");
1953    
1954            for (var1 = 0; var1 < this.loadedEntityList.size(); ++var1)
1955            {
1956                var2 = (Entity)this.loadedEntityList.get(var1);
1957    
1958                if (var2.ridingEntity != null)
1959                {
1960                    if (!var2.ridingEntity.isDead && var2.ridingEntity.riddenByEntity == var2)
1961                    {
1962                        continue;
1963                    }
1964    
1965                    var2.ridingEntity.riddenByEntity = null;
1966                    var2.ridingEntity = null;
1967                }
1968    
1969                this.theProfiler.startSection("tick");
1970    
1971                if (!var2.isDead)
1972                {
1973                    this.updateEntity(var2);
1974                }
1975    
1976                this.theProfiler.endSection();
1977                this.theProfiler.startSection("remove");
1978    
1979                if (var2.isDead)
1980                {
1981                    var3 = var2.chunkCoordX;
1982                    var4 = var2.chunkCoordZ;
1983    
1984                    if (var2.addedToChunk && this.chunkExists(var3, var4))
1985                    {
1986                        this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1987                    }
1988    
1989                    this.loadedEntityList.remove(var1--);
1990                    this.releaseEntitySkin(var2);
1991                }
1992    
1993                this.theProfiler.endSection();
1994            }
1995    
1996            this.theProfiler.endStartSection("tileEntities");
1997            this.scanningTileEntities = true;
1998            var5 = this.loadedTileEntityList.iterator();
1999    
2000            while (var5.hasNext())
2001            {
2002                TileEntity var6 = (TileEntity)var5.next();
2003    
2004                if (!var6.isInvalid() && var6.func_70309_m() && this.blockExists(var6.xCoord, var6.yCoord, var6.zCoord))
2005                {
2006                    var6.updateEntity();
2007                }
2008    
2009                if (var6.isInvalid())
2010                {
2011                    var5.remove();
2012    
2013                    if (this.chunkExists(var6.xCoord >> 4, var6.zCoord >> 4))
2014                    {
2015                        Chunk var8 = this.getChunkFromChunkCoords(var6.xCoord >> 4, var6.zCoord >> 4);
2016    
2017                        if (var8 != null)
2018                        {
2019                            var8.cleanChunkBlockTileEntity(var6.xCoord & 15, var6.yCoord, var6.zCoord & 15);
2020                        }
2021                    }
2022                }
2023            }
2024    
2025            this.scanningTileEntities = false;
2026    
2027            if (!this.entityRemoval.isEmpty())
2028            {
2029                for (Object tile : entityRemoval)
2030                {
2031                   ((TileEntity)tile).onChunkUnload();
2032                }
2033                this.loadedTileEntityList.removeAll(this.entityRemoval);
2034                this.entityRemoval.clear();
2035            }
2036    
2037            this.theProfiler.endStartSection("pendingTileEntities");
2038    
2039            if (!this.addedTileEntityList.isEmpty())
2040            {
2041                Iterator var7 = this.addedTileEntityList.iterator();
2042    
2043                while (var7.hasNext())
2044                {
2045                    TileEntity var9 = (TileEntity)var7.next();
2046    
2047                    if (!var9.isInvalid())
2048                    {
2049                        if (!this.loadedTileEntityList.contains(var9))
2050                        {
2051                            this.loadedTileEntityList.add(var9);
2052                        }
2053                    }
2054                    else
2055                    {
2056                        if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4))
2057                        {
2058                            Chunk var10 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4);
2059    
2060                            if (var10 != null)
2061                            {
2062                                var10.setChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15, var9);
2063                            }
2064                        }
2065                    }
2066                }
2067    
2068                this.addedTileEntityList.clear();
2069            }
2070    
2071            this.theProfiler.endSection();
2072            this.theProfiler.endSection();
2073        }
2074    
2075        public void addTileEntity(Collection par1Collection)
2076        {
2077            List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2078            for(Object entity : par1Collection)
2079            {
2080                if(((TileEntity)entity).canUpdate())
2081                {
2082                    dest.add(entity);
2083                }
2084            }
2085        }
2086    
2087        /**
2088         * Will update the entity in the world if the chunk the entity is in is currently loaded. Args: entity
2089         */
2090        public void updateEntity(Entity par1Entity)
2091        {
2092            this.updateEntityWithOptionalForce(par1Entity, true);
2093        }
2094    
2095        /**
2096         * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update.
2097         * Args: entity, forceUpdate
2098         */
2099        public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2)
2100        {
2101            int var3 = MathHelper.floor_double(par1Entity.posX);
2102            int var4 = MathHelper.floor_double(par1Entity.posZ);
2103    
2104            boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4));
2105            byte var5 = isForced ? (byte)0 : 32;
2106            boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5);
2107            if (!canUpdate)
2108            {
2109                EntityEvent.CanUpdate event = new EntityEvent.CanUpdate(par1Entity);
2110                MinecraftForge.EVENT_BUS.post(event);
2111                canUpdate = event.canUpdate;
2112            }
2113            if (canUpdate)
2114            {
2115                par1Entity.lastTickPosX = par1Entity.posX;
2116                par1Entity.lastTickPosY = par1Entity.posY;
2117                par1Entity.lastTickPosZ = par1Entity.posZ;
2118                par1Entity.prevRotationYaw = par1Entity.rotationYaw;
2119                par1Entity.prevRotationPitch = par1Entity.rotationPitch;
2120    
2121                if (par2 && par1Entity.addedToChunk)
2122                {
2123                    if (par1Entity.ridingEntity != null)
2124                    {
2125                        par1Entity.updateRidden();
2126                    }
2127                    else
2128                    {
2129                        par1Entity.onUpdate();
2130                    }
2131                }
2132    
2133                this.theProfiler.startSection("chunkCheck");
2134    
2135                if (Double.isNaN(par1Entity.posX) || Double.isInfinite(par1Entity.posX))
2136                {
2137                    par1Entity.posX = par1Entity.lastTickPosX;
2138                }
2139    
2140                if (Double.isNaN(par1Entity.posY) || Double.isInfinite(par1Entity.posY))
2141                {
2142                    par1Entity.posY = par1Entity.lastTickPosY;
2143                }
2144    
2145                if (Double.isNaN(par1Entity.posZ) || Double.isInfinite(par1Entity.posZ))
2146                {
2147                    par1Entity.posZ = par1Entity.lastTickPosZ;
2148                }
2149    
2150                if (Double.isNaN((double)par1Entity.rotationPitch) || Double.isInfinite((double)par1Entity.rotationPitch))
2151                {
2152                    par1Entity.rotationPitch = par1Entity.prevRotationPitch;
2153                }
2154    
2155                if (Double.isNaN((double)par1Entity.rotationYaw) || Double.isInfinite((double)par1Entity.rotationYaw))
2156                {
2157                    par1Entity.rotationYaw = par1Entity.prevRotationYaw;
2158                }
2159    
2160                int var6 = MathHelper.floor_double(par1Entity.posX / 16.0D);
2161                int var7 = MathHelper.floor_double(par1Entity.posY / 16.0D);
2162                int var8 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
2163    
2164                if (!par1Entity.addedToChunk || par1Entity.chunkCoordX != var6 || par1Entity.chunkCoordY != var7 || par1Entity.chunkCoordZ != var8)
2165                {
2166                    if (par1Entity.addedToChunk && this.chunkExists(par1Entity.chunkCoordX, par1Entity.chunkCoordZ))
2167                    {
2168                        this.getChunkFromChunkCoords(par1Entity.chunkCoordX, par1Entity.chunkCoordZ).removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY);
2169                    }
2170    
2171                    if (this.chunkExists(var6, var8))
2172                    {
2173                        par1Entity.addedToChunk = true;
2174                        this.getChunkFromChunkCoords(var6, var8).addEntity(par1Entity);
2175                    }
2176                    else
2177                    {
2178                        par1Entity.addedToChunk = false;
2179                    }
2180                }
2181    
2182                this.theProfiler.endSection();
2183    
2184                if (par2 && par1Entity.addedToChunk && par1Entity.riddenByEntity != null)
2185                {
2186                    if (!par1Entity.riddenByEntity.isDead && par1Entity.riddenByEntity.ridingEntity == par1Entity)
2187                    {
2188                        this.updateEntity(par1Entity.riddenByEntity);
2189                    }
2190                    else
2191                    {
2192                        par1Entity.riddenByEntity.ridingEntity = null;
2193                        par1Entity.riddenByEntity = null;
2194                    }
2195                }
2196            }
2197        }
2198    
2199        /**
2200         * Returns true if there are no solid, live entities in the specified AxisAlignedBB
2201         */
2202        public boolean checkIfAABBIsClear(AxisAlignedBB par1AxisAlignedBB)
2203        {
2204            return this.checkIfAABBIsClearExcludingEntity(par1AxisAlignedBB, (Entity)null);
2205        }
2206    
2207        /**
2208         * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
2209         */
2210        public boolean checkIfAABBIsClearExcludingEntity(AxisAlignedBB par1AxisAlignedBB, Entity par2Entity)
2211        {
2212            List var3 = this.getEntitiesWithinAABBExcludingEntity((Entity)null, par1AxisAlignedBB);
2213            Iterator var4 = var3.iterator();
2214            Entity var5;
2215    
2216            do
2217            {
2218                if (!var4.hasNext())
2219                {
2220                    return true;
2221                }
2222    
2223                var5 = (Entity)var4.next();
2224            }
2225            while (var5.isDead || !var5.preventEntitySpawning || var5 == par2Entity);
2226    
2227            return false;
2228        }
2229    
2230        /**
2231         * Returns true if there are any blocks in the region constrained by an AxisAlignedBB
2232         */
2233        public boolean isAABBNonEmpty(AxisAlignedBB par1AxisAlignedBB)
2234        {
2235            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2236            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2237            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2238            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2239            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2240            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2241    
2242            if (par1AxisAlignedBB.minX < 0.0D)
2243            {
2244                --var2;
2245            }
2246    
2247            if (par1AxisAlignedBB.minY < 0.0D)
2248            {
2249                --var4;
2250            }
2251    
2252            if (par1AxisAlignedBB.minZ < 0.0D)
2253            {
2254                --var6;
2255            }
2256    
2257            for (int var8 = var2; var8 < var3; ++var8)
2258            {
2259                for (int var9 = var4; var9 < var5; ++var9)
2260                {
2261                    for (int var10 = var6; var10 < var7; ++var10)
2262                    {
2263                        Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2264    
2265                        if (var11 != null)
2266                        {
2267                            return true;
2268                        }
2269                    }
2270                }
2271            }
2272    
2273            return false;
2274        }
2275    
2276        /**
2277         * Returns if any of the blocks within the aabb are liquids. Args: aabb
2278         */
2279        public boolean isAnyLiquid(AxisAlignedBB par1AxisAlignedBB)
2280        {
2281            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2282            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2283            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2284            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2285            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2286            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2287    
2288            if (par1AxisAlignedBB.minX < 0.0D)
2289            {
2290                --var2;
2291            }
2292    
2293            if (par1AxisAlignedBB.minY < 0.0D)
2294            {
2295                --var4;
2296            }
2297    
2298            if (par1AxisAlignedBB.minZ < 0.0D)
2299            {
2300                --var6;
2301            }
2302    
2303            for (int var8 = var2; var8 < var3; ++var8)
2304            {
2305                for (int var9 = var4; var9 < var5; ++var9)
2306                {
2307                    for (int var10 = var6; var10 < var7; ++var10)
2308                    {
2309                        Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2310    
2311                        if (var11 != null && var11.blockMaterial.isLiquid())
2312                        {
2313                            return true;
2314                        }
2315                    }
2316                }
2317            }
2318    
2319            return false;
2320        }
2321    
2322        /**
2323         * Returns whether or not the given bounding box is on fire or not
2324         */
2325        public boolean isBoundingBoxBurning(AxisAlignedBB par1AxisAlignedBB)
2326        {
2327            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2328            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2329            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2330            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2331            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2332            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2333    
2334            if (this.checkChunksExist(var2, var4, var6, var3, var5, var7))
2335            {
2336                for (int var8 = var2; var8 < var3; ++var8)
2337                {
2338                    for (int var9 = var4; var9 < var5; ++var9)
2339                    {
2340                        for (int var10 = var6; var10 < var7; ++var10)
2341                        {
2342                            int var11 = this.getBlockId(var8, var9, var10);
2343    
2344                            if (var11 == Block.fire.blockID || var11 == Block.lavaMoving.blockID || var11 == Block.lavaStill.blockID)
2345                            {
2346                                return true;
2347                            }
2348                            else
2349                            {
2350                                Block block = Block.blocksList[var11];
2351                                if (block != null && block.isBlockBurning(this, var8, var9, var10))
2352                                {
2353                                    return true;
2354                                }
2355                            }
2356                        }
2357                    }
2358                }
2359            }
2360    
2361            return false;
2362        }
2363    
2364        /**
2365         * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere.
2366         */
2367        public boolean handleMaterialAcceleration(AxisAlignedBB par1AxisAlignedBB, Material par2Material, Entity par3Entity)
2368        {
2369            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2370            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2371            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2372            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2373            int var8 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2374            int var9 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2375    
2376            if (!this.checkChunksExist(var4, var6, var8, var5, var7, var9))
2377            {
2378                return false;
2379            }
2380            else
2381            {
2382                boolean var10 = false;
2383                Vec3 var11 = this.func_82732_R().getVecFromPool(0.0D, 0.0D, 0.0D);
2384    
2385                for (int var12 = var4; var12 < var5; ++var12)
2386                {
2387                    for (int var13 = var6; var13 < var7; ++var13)
2388                    {
2389                        for (int var14 = var8; var14 < var9; ++var14)
2390                        {
2391                            Block var15 = Block.blocksList[this.getBlockId(var12, var13, var14)];
2392    
2393                            if (var15 != null && var15.blockMaterial == par2Material)
2394                            {
2395                                double var16 = (double)((float)(var13 + 1) - BlockFluid.getFluidHeightPercent(this.getBlockMetadata(var12, var13, var14)));
2396    
2397                                if ((double)var7 >= var16)
2398                                {
2399                                    var10 = true;
2400                                    var15.velocityToAddToEntity(this, var12, var13, var14, par3Entity, var11);
2401                                }
2402                            }
2403                        }
2404                    }
2405                }
2406    
2407                if (var11.lengthVector() > 0.0D)
2408                {
2409                    var11 = var11.normalize();
2410                    double var18 = 0.014D;
2411                    par3Entity.motionX += var11.xCoord * var18;
2412                    par3Entity.motionY += var11.yCoord * var18;
2413                    par3Entity.motionZ += var11.zCoord * var18;
2414                }
2415    
2416                return var10;
2417            }
2418        }
2419    
2420        /**
2421         * Returns true if the given bounding box contains the given material
2422         */
2423        public boolean isMaterialInBB(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2424        {
2425            int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2426            int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2427            int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2428            int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2429            int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2430            int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2431    
2432            for (int var9 = var3; var9 < var4; ++var9)
2433            {
2434                for (int var10 = var5; var10 < var6; ++var10)
2435                {
2436                    for (int var11 = var7; var11 < var8; ++var11)
2437                    {
2438                        Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2439    
2440                        if (var12 != null && var12.blockMaterial == par2Material)
2441                        {
2442                            return true;
2443                        }
2444                    }
2445                }
2446            }
2447    
2448            return false;
2449        }
2450    
2451        /**
2452         * checks if the given AABB is in the material given. Used while swimming.
2453         */
2454        public boolean isAABBInMaterial(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2455        {
2456            int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2457            int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2458            int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2459            int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2460            int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2461            int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2462    
2463            for (int var9 = var3; var9 < var4; ++var9)
2464            {
2465                for (int var10 = var5; var10 < var6; ++var10)
2466                {
2467                    for (int var11 = var7; var11 < var8; ++var11)
2468                    {
2469                        Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2470    
2471                        if (var12 != null && var12.blockMaterial == par2Material)
2472                        {
2473                            int var13 = this.getBlockMetadata(var9, var10, var11);
2474                            double var14 = (double)(var10 + 1);
2475    
2476                            if (var13 < 8)
2477                            {
2478                                var14 = (double)(var10 + 1) - (double)var13 / 8.0D;
2479                            }
2480    
2481                            if (var14 >= par1AxisAlignedBB.minY)
2482                            {
2483                                return true;
2484                            }
2485                        }
2486                    }
2487                }
2488            }
2489    
2490            return false;
2491        }
2492    
2493        /**
2494         * Creates an explosion. Args: entity, x, y, z, strength
2495         */
2496        public Explosion createExplosion(Entity var1, double var2, double var4, double var6, float var8, boolean var9)
2497        {
2498            return this.newExplosion(var1, var2, var4, var6, var8, false, var9);
2499        }
2500    
2501        /**
2502         * returns a new explosion. Does initiation (at time of writing Explosion is not finished)
2503         */
2504        public Explosion newExplosion(Entity var1, double var2, double var4, double var6, float var8, boolean var9, boolean var10)
2505        {
2506            Explosion var11 = new Explosion(this, var1, var2, var4, var6, var8);
2507            var11.isFlaming = var9;
2508            var11.field_82755_b = var10;
2509            var11.doExplosionA();
2510            var11.doExplosionB(true);
2511            return var11;
2512        }
2513    
2514        /**
2515         * Gets the percentage of real blocks within within a bounding box, along a specified vector.
2516         */
2517        public float getBlockDensity(Vec3 par1Vec3, AxisAlignedBB par2AxisAlignedBB)
2518        {
2519            double var3 = 1.0D / ((par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * 2.0D + 1.0D);
2520            double var5 = 1.0D / ((par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * 2.0D + 1.0D);
2521            double var7 = 1.0D / ((par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * 2.0D + 1.0D);
2522            int var9 = 0;
2523            int var10 = 0;
2524    
2525            for (float var11 = 0.0F; var11 <= 1.0F; var11 = (float)((double)var11 + var3))
2526            {
2527                for (float var12 = 0.0F; var12 <= 1.0F; var12 = (float)((double)var12 + var5))
2528                {
2529                    for (float var13 = 0.0F; var13 <= 1.0F; var13 = (float)((double)var13 + var7))
2530                    {
2531                        double var14 = par2AxisAlignedBB.minX + (par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * (double)var11;
2532                        double var16 = par2AxisAlignedBB.minY + (par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * (double)var12;
2533                        double var18 = par2AxisAlignedBB.minZ + (par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * (double)var13;
2534    
2535                        if (this.rayTraceBlocks(this.func_82732_R().getVecFromPool(var14, var16, var18), par1Vec3) == null)
2536                        {
2537                            ++var9;
2538                        }
2539    
2540                        ++var10;
2541                    }
2542                }
2543            }
2544    
2545            return (float)var9 / (float)var10;
2546        }
2547    
2548        /**
2549         * If the block in the given direction of the given coordinate is fire, extinguish it. Args: Player, X,Y,Z,
2550         * blockDirection
2551         */
2552        public boolean extinguishFire(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5)
2553        {
2554            if (par5 == 0)
2555            {
2556                --par3;
2557            }
2558    
2559            if (par5 == 1)
2560            {
2561                ++par3;
2562            }
2563    
2564            if (par5 == 2)
2565            {
2566                --par4;
2567            }
2568    
2569            if (par5 == 3)
2570            {
2571                ++par4;
2572            }
2573    
2574            if (par5 == 4)
2575            {
2576                --par2;
2577            }
2578    
2579            if (par5 == 5)
2580            {
2581                ++par2;
2582            }
2583    
2584            if (this.getBlockId(par2, par3, par4) == Block.fire.blockID)
2585            {
2586                this.playAuxSFXAtEntity(par1EntityPlayer, 1004, par2, par3, par4, 0);
2587                this.setBlockWithNotify(par2, par3, par4, 0);
2588                return true;
2589            }
2590            else
2591            {
2592                return false;
2593            }
2594        }
2595    
2596        @SideOnly(Side.CLIENT)
2597    
2598        /**
2599         * This string is 'All: (number of loaded entities)' Viewable by press ing F3
2600         */
2601        public String getDebugLoadedEntities()
2602        {
2603            return "All: " + this.loadedEntityList.size();
2604        }
2605    
2606        @SideOnly(Side.CLIENT)
2607    
2608        /**
2609         * Returns the name of the current chunk provider, by calling chunkprovider.makeString()
2610         */
2611        public String getProviderName()
2612        {
2613            return this.chunkProvider.makeString();
2614        }
2615    
2616        /**
2617         * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists
2618         */
2619        public TileEntity getBlockTileEntity(int par1, int par2, int par3)
2620        {
2621            if (par2 >= 256)
2622            {
2623                return null;
2624            }
2625            else
2626            {
2627                Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2628    
2629                if (var4 == null)
2630                {
2631                    return null;
2632                }
2633                else
2634                {
2635                    TileEntity var5 = var4.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2636    
2637                    if (var5 == null)
2638                    {
2639                        Iterator var6 = this.addedTileEntityList.iterator();
2640    
2641                        while (var6.hasNext())
2642                        {
2643                            TileEntity var7 = (TileEntity)var6.next();
2644    
2645                            if (!var7.isInvalid() && var7.xCoord == par1 && var7.yCoord == par2 && var7.zCoord == par3)
2646                            {
2647                                var5 = var7;
2648                                break;
2649                            }
2650                        }
2651                    }
2652    
2653                    return var5;
2654                }
2655            }
2656        }
2657    
2658        /**
2659         * Sets the TileEntity for a given block in X, Y, Z coordinates
2660         */
2661        public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity)
2662        {
2663            if (par4TileEntity == null || par4TileEntity.isInvalid())
2664            {
2665                return;
2666            }
2667    
2668            if (par4TileEntity.canUpdate())
2669            {
2670                List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2671                dest.add(par4TileEntity);
2672            }
2673    
2674            Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2675            if (chunk != null)
2676            {
2677                chunk.setChunkBlockTileEntity(par1 & 15, par2, par3 & 15, par4TileEntity);
2678            }
2679        }
2680    
2681        /**
2682         * Removes the TileEntity for a given block in X,Y,Z coordinates
2683         */
2684        public void removeBlockTileEntity(int par1, int par2, int par3)
2685        {
2686            Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2687            if (chunk != null)
2688            {
2689                chunk.removeChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2690            }
2691        }
2692    
2693        /**
2694         * adds tile entity to despawn list (renamed from markEntityForDespawn)
2695         */
2696        public void markTileEntityForDespawn(TileEntity par1TileEntity)
2697        {
2698            this.entityRemoval.add(par1TileEntity);
2699        }
2700    
2701        /**
2702         * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z
2703         */
2704        public boolean isBlockOpaqueCube(int par1, int par2, int par3)
2705        {
2706            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2707            return var4 == null ? false : var4.isOpaqueCube();
2708        }
2709    
2710        /**
2711         * Indicate if a material is a normal solid opaque cube.
2712         */
2713        public boolean isBlockNormalCube(int par1, int par2, int par3)
2714        {
2715            Block block = Block.blocksList[getBlockId(par1, par2, par3)];
2716            return block != null && block.isBlockNormalCube(this, par1, par2, par3);
2717        }
2718    
2719        /**
2720         * Returns true if the block at the given coordinate has a solid (buildable) top surface.
2721         */
2722        public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
2723        {
2724            return isBlockSolidOnSide(par1, par2, par3, ForgeDirection.UP);
2725        }
2726    
2727        /**
2728         * Checks if the block is a solid, normal cube. If the chunk does not exist, or is not loaded, it returns the
2729         * boolean parameter.
2730         */
2731        public boolean isBlockNormalCubeDefault(int par1, int par2, int par3, boolean par4)
2732        {
2733            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
2734            {
2735                Chunk var5 = this.chunkProvider.provideChunk(par1 >> 4, par3 >> 4);
2736    
2737                if (var5 != null && !var5.isEmpty())
2738                {
2739                    Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2740                    return var6 == null ? false : isBlockNormalCube(par1, par2, par3);
2741                }
2742                else
2743                {
2744                    return par4;
2745                }
2746            }
2747            else
2748            {
2749                return par4;
2750            }
2751        }
2752    
2753        /**
2754         * Called on construction of the World class to setup the initial skylight values
2755         */
2756        public void calculateInitialSkylight()
2757        {
2758            int var1 = this.calculateSkylightSubtracted(1.0F);
2759    
2760            if (var1 != this.skylightSubtracted)
2761            {
2762                this.skylightSubtracted = var1;
2763            }
2764        }
2765    
2766        /**
2767         * Set which types of mobs are allowed to spawn (peaceful vs hostile).
2768         */
2769        public void setAllowedSpawnTypes(boolean par1, boolean par2)
2770        {
2771            provider.setAllowedSpawnTypes(par1, par2);
2772        }
2773    
2774        /**
2775         * Runs a single tick for the world
2776         */
2777        public void tick()
2778        {
2779            this.updateWeather();
2780        }
2781    
2782        /**
2783         * Called from World constructor to set rainingStrength and thunderingStrength
2784         */
2785        private void calculateInitialWeather()
2786        {
2787            provider.calculateInitialWeather();
2788        }
2789    
2790        public void calculateInitialWeatherBody()
2791        {
2792            if (this.worldInfo.isRaining())
2793            {
2794                this.rainingStrength = 1.0F;
2795    
2796                if (this.worldInfo.isThundering())
2797                {
2798                    this.thunderingStrength = 1.0F;
2799                }
2800            }
2801        }
2802    
2803        /**
2804         * Updates all weather states.
2805         */
2806        protected void updateWeather()
2807        {
2808            provider.updateWeather();
2809        }
2810    
2811        public void updateWeatherBody()
2812        {
2813            if (!this.provider.hasNoSky)
2814            {
2815                if (this.lastLightningBolt > 0)
2816                {
2817                    --this.lastLightningBolt;
2818                }
2819    
2820                int var1 = this.worldInfo.getThunderTime();
2821    
2822                if (var1 <= 0)
2823                {
2824                    if (this.worldInfo.isThundering())
2825                    {
2826                        this.worldInfo.setThunderTime(this.rand.nextInt(12000) + 3600);
2827                    }
2828                    else
2829                    {
2830                        this.worldInfo.setThunderTime(this.rand.nextInt(168000) + 12000);
2831                    }
2832                }
2833                else
2834                {
2835                    --var1;
2836                    this.worldInfo.setThunderTime(var1);
2837    
2838                    if (var1 <= 0)
2839                    {
2840                        this.worldInfo.setThundering(!this.worldInfo.isThundering());
2841                    }
2842                }
2843    
2844                int var2 = this.worldInfo.getRainTime();
2845    
2846                if (var2 <= 0)
2847                {
2848                    if (this.worldInfo.isRaining())
2849                    {
2850                        this.worldInfo.setRainTime(this.rand.nextInt(12000) + 12000);
2851                    }
2852                    else
2853                    {
2854                        this.worldInfo.setRainTime(this.rand.nextInt(168000) + 12000);
2855                    }
2856                }
2857                else
2858                {
2859                    --var2;
2860                    this.worldInfo.setRainTime(var2);
2861    
2862                    if (var2 <= 0)
2863                    {
2864                        this.worldInfo.setRaining(!this.worldInfo.isRaining());
2865                    }
2866                }
2867    
2868                this.prevRainingStrength = this.rainingStrength;
2869    
2870                if (this.worldInfo.isRaining())
2871                {
2872                    this.rainingStrength = (float)((double)this.rainingStrength + 0.01D);
2873                }
2874                else
2875                {
2876                    this.rainingStrength = (float)((double)this.rainingStrength - 0.01D);
2877                }
2878    
2879                if (this.rainingStrength < 0.0F)
2880                {
2881                    this.rainingStrength = 0.0F;
2882                }
2883    
2884                if (this.rainingStrength > 1.0F)
2885                {
2886                    this.rainingStrength = 1.0F;
2887                }
2888    
2889                this.prevThunderingStrength = this.thunderingStrength;
2890    
2891                if (this.worldInfo.isThundering())
2892                {
2893                    this.thunderingStrength = (float)((double)this.thunderingStrength + 0.01D);
2894                }
2895                else
2896                {
2897                    this.thunderingStrength = (float)((double)this.thunderingStrength - 0.01D);
2898                }
2899    
2900                if (this.thunderingStrength < 0.0F)
2901                {
2902                    this.thunderingStrength = 0.0F;
2903                }
2904    
2905                if (this.thunderingStrength > 1.0F)
2906                {
2907                    this.thunderingStrength = 1.0F;
2908                }
2909            }
2910        }
2911    
2912        public void toggleRain()
2913        {
2914            provider.toggleRain();
2915        }
2916    
2917        protected void setActivePlayerChunksAndCheckLight()
2918        {
2919            this.activeChunkSet.clear();
2920            this.activeChunkSet.addAll(getPersistentChunks().keySet());
2921    
2922            this.theProfiler.startSection("buildList");
2923            int var1;
2924            EntityPlayer var2;
2925            int var3;
2926            int var4;
2927    
2928            for (var1 = 0; var1 < this.playerEntities.size(); ++var1)
2929            {
2930                var2 = (EntityPlayer)this.playerEntities.get(var1);
2931                var3 = MathHelper.floor_double(var2.posX / 16.0D);
2932                var4 = MathHelper.floor_double(var2.posZ / 16.0D);
2933                byte var5 = 7;
2934    
2935                for (int var6 = -var5; var6 <= var5; ++var6)
2936                {
2937                    for (int var7 = -var5; var7 <= var5; ++var7)
2938                    {
2939                        this.activeChunkSet.add(new ChunkCoordIntPair(var6 + var3, var7 + var4));
2940                    }
2941                }
2942            }
2943    
2944            this.theProfiler.endSection();
2945    
2946            if (this.ambientTickCountdown > 0)
2947            {
2948                --this.ambientTickCountdown;
2949            }
2950    
2951            this.theProfiler.startSection("playerCheckLight");
2952    
2953            if (!this.playerEntities.isEmpty())
2954            {
2955                var1 = this.rand.nextInt(this.playerEntities.size());
2956                var2 = (EntityPlayer)this.playerEntities.get(var1);
2957                var3 = MathHelper.floor_double(var2.posX) + this.rand.nextInt(11) - 5;
2958                var4 = MathHelper.floor_double(var2.posY) + this.rand.nextInt(11) - 5;
2959                int var8 = MathHelper.floor_double(var2.posZ) + this.rand.nextInt(11) - 5;
2960                this.updateAllLightTypes(var3, var4, var8);
2961            }
2962    
2963            this.theProfiler.endSection();
2964        }
2965    
2966        protected void moodSoundAndLightCheck(int par1, int par2, Chunk par3Chunk)
2967        {
2968            this.theProfiler.endStartSection("moodSound");
2969    
2970            if (this.ambientTickCountdown == 0 && !this.isRemote)
2971            {
2972                this.updateLCG = this.updateLCG * 3 + 1013904223;
2973                int var4 = this.updateLCG >> 2;
2974                int var5 = var4 & 15;
2975                int var6 = var4 >> 8 & 15;
2976                int var7 = var4 >> 16 & 127;
2977                int var8 = par3Chunk.getBlockID(var5, var7, var6);
2978                var5 += par1;
2979                var6 += par2;
2980    
2981                if (var8 == 0 && this.getFullBlockLightValue(var5, var7, var6) <= this.rand.nextInt(8) && this.getSavedLightValue(EnumSkyBlock.Sky, var5, var7, var6) <= 0)
2982                {
2983                    EntityPlayer var9 = this.getClosestPlayer((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, 8.0D);
2984    
2985                    if (var9 != null && var9.getDistanceSq((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D) > 4.0D)
2986                    {
2987                        this.playSoundEffect((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, "ambient.cave.cave", 0.7F, 0.8F + this.rand.nextFloat() * 0.2F);
2988                        this.ambientTickCountdown = this.rand.nextInt(12000) + 6000;
2989                    }
2990                }
2991            }
2992    
2993            this.theProfiler.endStartSection("checkLight");
2994            par3Chunk.enqueueRelightChecks();
2995        }
2996    
2997        /**
2998         * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a
2999         * player
3000         */
3001        protected void tickBlocksAndAmbiance()
3002        {
3003            this.setActivePlayerChunksAndCheckLight();
3004        }
3005    
3006        /**
3007         * checks to see if a given block is both water and is cold enough to freeze
3008         */
3009        public boolean isBlockFreezable(int par1, int par2, int par3)
3010        {
3011            return this.canBlockFreeze(par1, par2, par3, false);
3012        }
3013    
3014        /**
3015         * checks to see if a given block is both water and has at least one immediately adjacent non-water block
3016         */
3017        public boolean isBlockFreezableNaturally(int par1, int par2, int par3)
3018        {
3019            return this.canBlockFreeze(par1, par2, par3, true);
3020        }
3021    
3022        /**
3023         * checks to see if a given block is both water, and cold enough to freeze - if the par4 boolean is set, this will
3024         * only return true if there is a non-water block immediately adjacent to the specified block
3025         */
3026        public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4)
3027        {
3028            return provider.canBlockFreeze(par1, par2, par3, par4);
3029        }
3030    
3031        public boolean canBlockFreezeBody(int par1, int par2, int par3, boolean par4)
3032        {
3033            BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3);
3034            float var6 = var5.getFloatTemperature();
3035    
3036            if (var6 > 0.15F)
3037            {
3038                return false;
3039            }
3040            else
3041            {
3042                if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3043                {
3044                    int var7 = this.getBlockId(par1, par2, par3);
3045    
3046                    if ((var7 == Block.waterStill.blockID || var7 == Block.waterMoving.blockID) && this.getBlockMetadata(par1, par2, par3) == 0)
3047                    {
3048                        if (!par4)
3049                        {
3050                            return true;
3051                        }
3052    
3053                        boolean var8 = true;
3054    
3055                        if (var8 && this.getBlockMaterial(par1 - 1, par2, par3) != Material.water)
3056                        {
3057                            var8 = false;
3058                        }
3059    
3060                        if (var8 && this.getBlockMaterial(par1 + 1, par2, par3) != Material.water)
3061                        {
3062                            var8 = false;
3063                        }
3064    
3065                        if (var8 && this.getBlockMaterial(par1, par2, par3 - 1) != Material.water)
3066                        {
3067                            var8 = false;
3068                        }
3069    
3070                        if (var8 && this.getBlockMaterial(par1, par2, par3 + 1) != Material.water)
3071                        {
3072                            var8 = false;
3073                        }
3074    
3075                        if (!var8)
3076                        {
3077                            return true;
3078                        }
3079                    }
3080                }
3081    
3082                return false;
3083            }
3084        }
3085    
3086        /**
3087         * Tests whether or not snow can be placed at a given location
3088         */
3089        public boolean canSnowAt(int par1, int par2, int par3)
3090        {
3091            return provider.canSnowAt(par1, par2, par3);
3092        }
3093    
3094        public boolean canSnowAtBody(int par1, int par2, int par3)
3095        {
3096            BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3097            float var5 = var4.getFloatTemperature();
3098    
3099            if (var5 > 0.15F)
3100            {
3101                return false;
3102            }
3103            else
3104            {
3105                if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3106                {
3107                    int var6 = this.getBlockId(par1, par2 - 1, par3);
3108                    int var7 = this.getBlockId(par1, par2, par3);
3109    
3110                    if (var7 == 0 && Block.snow.canPlaceBlockAt(this, par1, par2, par3) && var6 != 0 && var6 != Block.ice.blockID && Block.blocksList[var6].blockMaterial.blocksMovement())
3111                    {
3112                        return true;
3113                    }
3114                }
3115    
3116                return false;
3117            }
3118        }
3119    
3120        public void updateAllLightTypes(int par1, int par2, int par3)
3121        {
3122            if (!this.provider.hasNoSky)
3123            {
3124                this.updateLightByType(EnumSkyBlock.Sky, par1, par2, par3);
3125            }
3126    
3127            this.updateLightByType(EnumSkyBlock.Block, par1, par2, par3);
3128        }
3129    
3130        private int computeSkyLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3131        {
3132            int var7 = 0;
3133    
3134            if (this.canBlockSeeTheSky(par2, par3, par4))
3135            {
3136                var7 = 15;
3137            }
3138            else
3139            {
3140                if (par6 == 0)
3141                {
3142                    par6 = 1;
3143                }
3144    
3145                int var8 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 - 1, par3, par4) - par6;
3146                int var9 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 + 1, par3, par4) - par6;
3147                int var10 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 - 1, par4) - par6;
3148                int var11 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 + 1, par4) - par6;
3149                int var12 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 - 1) - par6;
3150                int var13 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 + 1) - par6;
3151    
3152                if (var8 > var7)
3153                {
3154                    var7 = var8;
3155                }
3156    
3157                if (var9 > var7)
3158                {
3159                    var7 = var9;
3160                }
3161    
3162                if (var10 > var7)
3163                {
3164                    var7 = var10;
3165                }
3166    
3167                if (var11 > var7)
3168                {
3169                    var7 = var11;
3170                }
3171    
3172                if (var12 > var7)
3173                {
3174                    var7 = var12;
3175                }
3176    
3177                if (var13 > var7)
3178                {
3179                    var7 = var13;
3180                }
3181            }
3182    
3183            return var7;
3184        }
3185    
3186        private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3187        {
3188            int var7 = (par5 == 0 || Block.blocksList[par5] == null ? 0 : Block.blocksList[par5].getLightValue(this, par2, par3, par4));
3189            int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6;
3190            int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6;
3191            int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6;
3192            int var11 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 + 1, par4) - par6;
3193            int var12 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 - 1) - par6;
3194            int var13 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 + 1) - par6;
3195    
3196            if (var8 > var7)
3197            {
3198                var7 = var8;
3199            }
3200    
3201            if (var9 > var7)
3202            {
3203                var7 = var9;
3204            }
3205    
3206            if (var10 > var7)
3207            {
3208                var7 = var10;
3209            }
3210    
3211            if (var11 > var7)
3212            {
3213                var7 = var11;
3214            }
3215    
3216            if (var12 > var7)
3217            {
3218                var7 = var12;
3219            }
3220    
3221            if (var13 > var7)
3222            {
3223                var7 = var13;
3224            }
3225    
3226            return var7;
3227        }
3228    
3229        public void updateLightByType(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
3230        {
3231            if (this.doChunksNearChunkExist(par2, par3, par4, 17))
3232            {
3233                int var5 = 0;
3234                int var6 = 0;
3235                this.theProfiler.startSection("getBrightness");
3236                int var7 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4);
3237                boolean var8 = false;
3238                int var9 = this.getBlockId(par2, par3, par4);
3239                int var10 = this.getBlockLightOpacity(par2, par3, par4);
3240    
3241                if (var10 == 0)
3242                {
3243                    var10 = 1;
3244                }
3245    
3246                boolean var11 = false;
3247                int var24;
3248    
3249                if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3250                {
3251                    var24 = this.computeSkyLightValue(var7, par2, par3, par4, var9, var10);
3252                }
3253                else
3254                {
3255                    var24 = this.computeBlockLightValue(var7, par2, par3, par4, var9, var10);
3256                }
3257    
3258                int var12;
3259                int var13;
3260                int var14;
3261                int var15;
3262                int var17;
3263                int var16;
3264                int var19;
3265                int var18;
3266    
3267                if (var24 > var7)
3268                {
3269                    this.lightUpdateBlockList[var6++] = 133152;
3270                }
3271                else if (var24 < var7)
3272                {
3273                    if (par1EnumSkyBlock != EnumSkyBlock.Block)
3274                    {
3275                        ;
3276                    }
3277    
3278                    this.lightUpdateBlockList[var6++] = 133152 + (var7 << 18);
3279    
3280                    while (var5 < var6)
3281                    {
3282                        var9 = this.lightUpdateBlockList[var5++];
3283                        var10 = (var9 & 63) - 32 + par2;
3284                        var24 = (var9 >> 6 & 63) - 32 + par3;
3285                        var12 = (var9 >> 12 & 63) - 32 + par4;
3286                        var13 = var9 >> 18 & 15;
3287                        var14 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3288    
3289                        if (var14 == var13)
3290                        {
3291                            this.setLightValue(par1EnumSkyBlock, var10, var24, var12, 0);
3292    
3293                            if (var13 > 0)
3294                            {
3295                                var15 = var10 - par2;
3296                                var16 = var24 - par3;
3297                                var17 = var12 - par4;
3298    
3299                                if (var15 < 0)
3300                                {
3301                                    var15 = -var15;
3302                                }
3303    
3304                                if (var16 < 0)
3305                                {
3306                                    var16 = -var16;
3307                                }
3308    
3309                                if (var17 < 0)
3310                                {
3311                                    var17 = -var17;
3312                                }
3313    
3314                                if (var15 + var16 + var17 < 17)
3315                                {
3316                                    for (var18 = 0; var18 < 6; ++var18)
3317                                    {
3318                                        var19 = var18 % 2 * 2 - 1;
3319                                        int var20 = var10 + var18 / 2 % 3 / 2 * var19;
3320                                        int var21 = var24 + (var18 / 2 + 1) % 3 / 2 * var19;
3321                                        int var22 = var12 + (var18 / 2 + 2) % 3 / 2 * var19;
3322                                        var14 = this.getSavedLightValue(par1EnumSkyBlock, var20, var21, var22);
3323                                        int var23 = this.getBlockLightOpacity(var20, var21, var22);
3324    
3325                                        if (var23 == 0)
3326                                        {
3327                                            var23 = 1;
3328                                        }
3329    
3330                                        if (var14 == var13 - var23 && var6 < this.lightUpdateBlockList.length)
3331                                        {
3332                                            this.lightUpdateBlockList[var6++] = var20 - par2 + 32 + (var21 - par3 + 32 << 6) + (var22 - par4 + 32 << 12) + (var13 - var23 << 18);
3333                                        }
3334                                    }
3335                                }
3336                            }
3337                        }
3338                    }
3339    
3340                    var5 = 0;
3341                }
3342    
3343                this.theProfiler.endSection();
3344                this.theProfiler.startSection("checkedPosition < toCheckCount");
3345    
3346                while (var5 < var6)
3347                {
3348                    var9 = this.lightUpdateBlockList[var5++];
3349                    var10 = (var9 & 63) - 32 + par2;
3350                    var24 = (var9 >> 6 & 63) - 32 + par3;
3351                    var12 = (var9 >> 12 & 63) - 32 + par4;
3352                    var13 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3353                    var14 = this.getBlockId(var10, var24, var12);
3354                    var15 = this.getBlockLightOpacity(var10, var24, var12);
3355    
3356                    if (var15 == 0)
3357                    {
3358                        var15 = 1;
3359                    }
3360    
3361                    boolean var25 = false;
3362    
3363                    if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3364                    {
3365                        var16 = this.computeSkyLightValue(var13, var10, var24, var12, var14, var15);
3366                    }
3367                    else
3368                    {
3369                        var16 = this.computeBlockLightValue(var13, var10, var24, var12, var14, var15);
3370                    }
3371    
3372                    if (var16 != var13)
3373                    {
3374                        this.setLightValue(par1EnumSkyBlock, var10, var24, var12, var16);
3375    
3376                        if (var16 > var13)
3377                        {
3378                            var17 = var10 - par2;
3379                            var18 = var24 - par3;
3380                            var19 = var12 - par4;
3381    
3382                            if (var17 < 0)
3383                            {
3384                                var17 = -var17;
3385                            }
3386    
3387                            if (var18 < 0)
3388                            {
3389                                var18 = -var18;
3390                            }
3391    
3392                            if (var19 < 0)
3393                            {
3394                                var19 = -var19;
3395                            }
3396    
3397                            if (var17 + var18 + var19 < 17 && var6 < this.lightUpdateBlockList.length - 6)
3398                            {
3399                                if (this.getSavedLightValue(par1EnumSkyBlock, var10 - 1, var24, var12) < var16)
3400                                {
3401                                    this.lightUpdateBlockList[var6++] = var10 - 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3402                                }
3403    
3404                                if (this.getSavedLightValue(par1EnumSkyBlock, var10 + 1, var24, var12) < var16)
3405                                {
3406                                    this.lightUpdateBlockList[var6++] = var10 + 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3407                                }
3408    
3409                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 - 1, var12) < var16)
3410                                {
3411                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3412                                }
3413    
3414                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 + 1, var12) < var16)
3415                                {
3416                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 + 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3417                                }
3418    
3419                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 - 1) < var16)
3420                                {
3421                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - 1 - par4 + 32 << 12);
3422                                }
3423    
3424                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 + 1) < var16)
3425                                {
3426                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 + 1 - par4 + 32 << 12);
3427                                }
3428                            }
3429                        }
3430                    }
3431                }
3432    
3433                this.theProfiler.endSection();
3434            }
3435        }
3436    
3437        /**
3438         * Runs through the list of updates to run and ticks them
3439         */
3440        public boolean tickUpdates(boolean par1)
3441        {
3442            return false;
3443        }
3444    
3445        public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2)
3446        {
3447            return null;
3448        }
3449    
3450        /**
3451         * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb
3452         */
3453        public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
3454        {
3455            this.entitiesWithinAABBExcludingEntity.clear();
3456            int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3457            int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3458            int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3459            int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3460    
3461            for (int var7 = var3; var7 <= var4; ++var7)
3462            {
3463                for (int var8 = var5; var8 <= var6; ++var8)
3464                {
3465                    if (this.chunkExists(var7, var8))
3466                    {
3467                        this.getChunkFromChunkCoords(var7, var8).getEntitiesWithinAABBForEntity(par1Entity, par2AxisAlignedBB, this.entitiesWithinAABBExcludingEntity);
3468                    }
3469                }
3470            }
3471    
3472            return this.entitiesWithinAABBExcludingEntity;
3473        }
3474    
3475        /**
3476         * Returns all entities of the specified class type which intersect with the AABB. Args: entityClass, aabb
3477         */
3478        public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB)
3479        {
3480            return this.func_82733_a(par1Class, par2AxisAlignedBB, (IEntitySelector)null);
3481        }
3482    
3483        public List func_82733_a(Class par1Class, AxisAlignedBB par2AxisAlignedBB, IEntitySelector par3IEntitySelector)
3484        {
3485            int var4 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3486            int var5 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3487            int var6 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3488            int var7 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3489            ArrayList var8 = new ArrayList();
3490    
3491            for (int var9 = var4; var9 <= var5; ++var9)
3492            {
3493                for (int var10 = var6; var10 <= var7; ++var10)
3494                {
3495                    if (this.chunkExists(var9, var10))
3496                    {
3497                        this.getChunkFromChunkCoords(var9, var10).getEntitiesOfTypeWithinAAAB(par1Class, par2AxisAlignedBB, var8, par3IEntitySelector);
3498                    }
3499                }
3500            }
3501    
3502            return var8;
3503        }
3504    
3505        public Entity findNearestEntityWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, Entity par3Entity)
3506        {
3507            List var4 = this.getEntitiesWithinAABB(par1Class, par2AxisAlignedBB);
3508            Entity var5 = null;
3509            double var6 = Double.MAX_VALUE;
3510            Iterator var8 = var4.iterator();
3511    
3512            while (var8.hasNext())
3513            {
3514                Entity var9 = (Entity)var8.next();
3515    
3516                if (var9 != par3Entity)
3517                {
3518                    double var10 = par3Entity.getDistanceSqToEntity(var9);
3519    
3520                    if (var10 <= var6)
3521                    {
3522                        var5 = var9;
3523                        var6 = var10;
3524                    }
3525                }
3526            }
3527    
3528            return var5;
3529        }
3530    
3531        /**
3532         * Returns the Entity with the given ID, or null if it doesn't exist in this World.
3533         */
3534        public abstract Entity getEntityByID(int var1);
3535    
3536        @SideOnly(Side.CLIENT)
3537    
3538        /**
3539         * Accessor for world Loaded Entity List
3540         */
3541        public List getLoadedEntityList()
3542        {
3543            return this.loadedEntityList;
3544        }
3545    
3546        /**
3547         * marks the chunk that contains this tilentity as modified and then calls worldAccesses.doNothingWithTileEntity
3548         */
3549        public void updateTileEntityChunkAndDoNothing(int par1, int par2, int par3, TileEntity par4TileEntity)
3550        {
3551            if (this.blockExists(par1, par2, par3))
3552            {
3553                this.getChunkFromBlockCoords(par1, par3).setChunkModified();
3554            }
3555        }
3556    
3557        /**
3558         * Counts how many entities of an entity class exist in the world. Args: entityClass
3559         */
3560        public int countEntities(Class par1Class)
3561        {
3562            int var2 = 0;
3563    
3564            for (int var3 = 0; var3 < this.loadedEntityList.size(); ++var3)
3565            {
3566                Entity var4 = (Entity)this.loadedEntityList.get(var3);
3567    
3568                if (par1Class.isAssignableFrom(var4.getClass()))
3569                {
3570                    ++var2;
3571                }
3572            }
3573    
3574            return var2;
3575        }
3576    
3577        /**
3578         * adds entities to the loaded entities list, and loads thier skins.
3579         */
3580        public void addLoadedEntities(List par1List)
3581        {
3582            for (int var2 = 0; var2 < par1List.size(); ++var2)
3583            {
3584                Entity entity = (Entity)par1List.get(var2);
3585                if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this)))
3586                {
3587                    loadedEntityList.add(entity);
3588                    this.obtainEntitySkin(entity);
3589                }
3590            }
3591        }
3592    
3593        /**
3594         * Adds a list of entities to be unloaded on the next pass of World.updateEntities()
3595         */
3596        public void unloadEntities(List par1List)
3597        {
3598            this.unloadedEntityList.addAll(par1List);
3599        }
3600    
3601        /**
3602         * Returns true if the given Entity can be placed on the given side of the given block position.
3603         */
3604        public boolean canPlaceEntityOnSide(int par1, int par2, int par3, int par4, boolean par5, int par6, Entity par7Entity)
3605        {
3606            int var8 = this.getBlockId(par2, par3, par4);
3607            Block var9 = Block.blocksList[var8];
3608            Block var10 = Block.blocksList[par1];
3609            AxisAlignedBB var11 = var10.getCollisionBoundingBoxFromPool(this, par2, par3, par4);
3610    
3611            if (par5)
3612            {
3613                var11 = null;
3614            }
3615    
3616            if (var11 != null && !this.checkIfAABBIsClearExcludingEntity(var11, par7Entity))
3617            {
3618                return false;
3619            }
3620            else
3621            {
3622                if (var9 != null && (var9 == Block.waterMoving || var9 == Block.waterStill || var9 == Block.lavaMoving || var9 == Block.lavaStill || var9 == Block.fire || var9.blockMaterial.isGroundCover()))
3623                {
3624                    var9 = null;
3625                }
3626    
3627                if (var9 != null && var9.isBlockReplaceable(this, par2, par3, par4))
3628                {
3629                    var9 = null;
3630                }
3631    
3632                return var9 != null && var9.blockMaterial == Material.circuits && var10 == Block.field_82510_ck ? true : par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6);
3633            }
3634        }
3635    
3636        public PathEntity getPathEntityToEntity(Entity par1Entity, Entity par2Entity, float par3, boolean par4, boolean par5, boolean par6, boolean par7)
3637        {
3638            this.theProfiler.startSection("pathfind");
3639            int var8 = MathHelper.floor_double(par1Entity.posX);
3640            int var9 = MathHelper.floor_double(par1Entity.posY + 1.0D);
3641            int var10 = MathHelper.floor_double(par1Entity.posZ);
3642            int var11 = (int)(par3 + 16.0F);
3643            int var12 = var8 - var11;
3644            int var13 = var9 - var11;
3645            int var14 = var10 - var11;
3646            int var15 = var8 + var11;
3647            int var16 = var9 + var11;
3648            int var17 = var10 + var11;
3649            ChunkCache var18 = new ChunkCache(this, var12, var13, var14, var15, var16, var17);
3650            PathEntity var19 = (new PathFinder(var18, par4, par5, par6, par7)).createEntityPathTo(par1Entity, par2Entity, par3);
3651            this.theProfiler.endSection();
3652            return var19;
3653        }
3654    
3655        public PathEntity getEntityPathToXYZ(Entity par1Entity, int par2, int par3, int par4, float par5, boolean par6, boolean par7, boolean par8, boolean par9)
3656        {
3657            this.theProfiler.startSection("pathfind");
3658            int var10 = MathHelper.floor_double(par1Entity.posX);
3659            int var11 = MathHelper.floor_double(par1Entity.posY);
3660            int var12 = MathHelper.floor_double(par1Entity.posZ);
3661            int var13 = (int)(par5 + 8.0F);
3662            int var14 = var10 - var13;
3663            int var15 = var11 - var13;
3664            int var16 = var12 - var13;
3665            int var17 = var10 + var13;
3666            int var18 = var11 + var13;
3667            int var19 = var12 + var13;
3668            ChunkCache var20 = new ChunkCache(this, var14, var15, var16, var17, var18, var19);
3669            PathEntity var21 = (new PathFinder(var20, par6, par7, par8, par9)).createEntityPathTo(par1Entity, par2, par3, par4, par5);
3670            this.theProfiler.endSection();
3671            return var21;
3672        }
3673    
3674        /**
3675         * Is this block powering in the specified direction Args: x, y, z, direction
3676         */
3677        public boolean isBlockProvidingPowerTo(int par1, int par2, int par3, int par4)
3678        {
3679            int var5 = this.getBlockId(par1, par2, par3);
3680            return var5 == 0 ? false : Block.blocksList[var5].isIndirectlyPoweringTo(this, par1, par2, par3, par4);
3681        }
3682    
3683        /**
3684         * Whether one of the neighboring blocks is putting power into this block. Args: x, y, z
3685         */
3686        public boolean isBlockGettingPowered(int par1, int par2, int par3)
3687        {
3688            return this.isBlockProvidingPowerTo(par1, par2 - 1, par3, 0) ? true : (this.isBlockProvidingPowerTo(par1, par2 + 1, par3, 1) ? true : (this.isBlockProvidingPowerTo(par1, par2, par3 - 1, 2) ? true : (this.isBlockProvidingPowerTo(par1, par2, par3 + 1, 3) ? true : (this.isBlockProvidingPowerTo(par1 - 1, par2, par3, 4) ? true : this.isBlockProvidingPowerTo(par1 + 1, par2, par3, 5)))));
3689        }
3690    
3691        /**
3692         * Is a block next to you getting powered (if its an attachable block) or is it providing power directly to you.
3693         * Args: x, y, z, direction
3694         */
3695        public boolean isBlockIndirectlyProvidingPowerTo(int par1, int par2, int par3, int par4)
3696        {
3697            if (this.isBlockNormalCube(par1, par2, par3))
3698            {
3699                return this.isBlockGettingPowered(par1, par2, par3);
3700            }
3701            else
3702            {
3703                int var5 = this.getBlockId(par1, par2, par3);
3704                return var5 == 0 ? false : Block.blocksList[var5].isPoweringTo(this, par1, par2, par3, par4);
3705            }
3706        }
3707    
3708        /**
3709         * Used to see if one of the blocks next to you or your block is getting power from a neighboring block. Used by
3710         * items like TNT or Doors so they don't have redstone going straight into them.  Args: x, y, z
3711         */
3712        public boolean isBlockIndirectlyGettingPowered(int par1, int par2, int par3)
3713        {
3714            return this.isBlockIndirectlyProvidingPowerTo(par1, par2 - 1, par3, 0) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2 + 1, par3, 1) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2, par3 - 1, 2) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2, par3 + 1, 3) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1 - 1, par2, par3, 4) ? true : this.isBlockIndirectlyProvidingPowerTo(par1 + 1, par2, par3, 5)))));
3715        }
3716    
3717        /**
3718         * Gets the closest player to the entity within the specified distance (if distance is less than 0 then ignored).
3719         * Args: entity, dist
3720         */
3721        public EntityPlayer getClosestPlayerToEntity(Entity par1Entity, double par2)
3722        {
3723            return this.getClosestPlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3724        }
3725    
3726        /**
3727         * Gets the closest player to the point within the specified distance (distance can be set to less than 0 to not
3728         * limit the distance). Args: x, y, z, dist
3729         */
3730        public EntityPlayer getClosestPlayer(double par1, double par3, double par5, double par7)
3731        {
3732            double var9 = -1.0D;
3733            EntityPlayer var11 = null;
3734    
3735            for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3736            {
3737                EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3738                double var14 = var13.getDistanceSq(par1, par3, par5);
3739    
3740                if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3741                {
3742                    var9 = var14;
3743                    var11 = var13;
3744                }
3745            }
3746    
3747            return var11;
3748        }
3749    
3750        /**
3751         * Returns the closest vulnerable player to this entity within the given radius, or null if none is found
3752         */
3753        public EntityPlayer getClosestVulnerablePlayerToEntity(Entity par1Entity, double par2)
3754        {
3755            return this.getClosestVulnerablePlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3756        }
3757    
3758        /**
3759         * Returns the closest vulnerable player within the given radius, or null if none is found.
3760         */
3761        public EntityPlayer getClosestVulnerablePlayer(double par1, double par3, double par5, double par7)
3762        {
3763            double var9 = -1.0D;
3764            EntityPlayer var11 = null;
3765    
3766            for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3767            {
3768                EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3769    
3770                if (!var13.capabilities.disableDamage)
3771                {
3772                    double var14 = var13.getDistanceSq(par1, par3, par5);
3773                    double var16 = par7;
3774    
3775                    if (var13.isSneaking())
3776                    {
3777                        var16 = par7 * 0.800000011920929D;
3778                    }
3779    
3780                    if (var13.func_82150_aj())
3781                    {
3782                        float var18 = var13.func_82243_bO();
3783    
3784                        if (var18 < 0.1F)
3785                        {
3786                            var18 = 0.1F;
3787                        }
3788    
3789                        var16 *= (double)(0.7F * var18);
3790                    }
3791    
3792                    if ((par7 < 0.0D || var14 < var16 * var16) && (var9 == -1.0D || var14 < var9))
3793                    {
3794                        var9 = var14;
3795                        var11 = var13;
3796                    }
3797                }
3798            }
3799    
3800            return var11;
3801        }
3802    
3803        /**
3804         * Find a player by name in this world.
3805         */
3806        public EntityPlayer getPlayerEntityByName(String par1Str)
3807        {
3808            for (int var2 = 0; var2 < this.playerEntities.size(); ++var2)
3809            {
3810                if (par1Str.equals(((EntityPlayer)this.playerEntities.get(var2)).username))
3811                {
3812                    return (EntityPlayer)this.playerEntities.get(var2);
3813                }
3814            }
3815    
3816            return null;
3817        }
3818    
3819        @SideOnly(Side.CLIENT)
3820    
3821        /**
3822         * If on MP, sends a quitting packet.
3823         */
3824        public void sendQuittingDisconnectingPacket() {}
3825    
3826        /**
3827         * Checks whether the session lock file was modified by another process
3828         */
3829        public void checkSessionLock() throws MinecraftException
3830        {
3831            this.saveHandler.checkSessionLock();
3832        }
3833    
3834        @SideOnly(Side.CLIENT)
3835        public void func_82738_a(long par1)
3836        {
3837            this.worldInfo.func_82572_b(par1);
3838        }
3839    
3840        /**
3841         * Retrieve the world seed from level.dat
3842         */
3843        public long getSeed()
3844        {
3845            return provider.getSeed();
3846        }
3847    
3848        public long func_82737_E()
3849        {
3850            return this.worldInfo.func_82573_f();
3851        }
3852    
3853        public long getWorldTime()
3854        {
3855            return provider.getWorldTime();
3856        }
3857    
3858        /**
3859         * Sets the world time.
3860         */
3861        public void setWorldTime(long par1)
3862        {
3863            provider.setWorldTime(par1);
3864        }
3865    
3866        /**
3867         * Returns the coordinates of the spawn point
3868         */
3869        public ChunkCoordinates getSpawnPoint()
3870        {
3871            return provider.getSpawnPoint();
3872        }
3873    
3874        @SideOnly(Side.CLIENT)
3875        public void setSpawnLocation(int par1, int par2, int par3)
3876        {
3877            provider.setSpawnPoint(par1, par2, par3);
3878        }
3879    
3880        @SideOnly(Side.CLIENT)
3881    
3882        /**
3883         * spwans an entity and loads surrounding chunks
3884         */
3885        public void joinEntityInSurroundings(Entity par1Entity)
3886        {
3887            int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
3888            int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
3889            byte var4 = 2;
3890    
3891            for (int var5 = var2 - var4; var5 <= var2 + var4; ++var5)
3892            {
3893                for (int var6 = var3 - var4; var6 <= var3 + var4; ++var6)
3894                {
3895                    this.getChunkFromChunkCoords(var5, var6);
3896                }
3897            }
3898    
3899            if (!this.loadedEntityList.contains(par1Entity))
3900            {
3901                if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
3902                {
3903                    loadedEntityList.add(par1Entity);
3904                }
3905            }
3906        }
3907    
3908        /**
3909         * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
3910         */
3911        public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3912        {
3913            return provider.canMineBlock(par1EntityPlayer, par2, par3, par4);
3914        }
3915    
3916        public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3917        {
3918            return true;
3919        }
3920    
3921        /**
3922         * sends a Packet 38 (Entity Status) to all tracked players of that entity
3923         */
3924        public void setEntityState(Entity par1Entity, byte par2) {}
3925    
3926        /**
3927         * gets the IChunkProvider this world uses.
3928         */
3929        public IChunkProvider getChunkProvider()
3930        {
3931            return this.chunkProvider;
3932        }
3933    
3934        /**
3935         * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will
3936         * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter
3937         */
3938        public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6)
3939        {
3940            if (par4 > 0)
3941            {
3942                Block.blocksList[par4].onBlockEventReceived(this, par1, par2, par3, par5, par6);
3943            }
3944        }
3945    
3946        /**
3947         * Returns this world's current save handler
3948         */
3949        public ISaveHandler getSaveHandler()
3950        {
3951            return this.saveHandler;
3952        }
3953    
3954        /**
3955         * Gets the World's WorldInfo instance
3956         */
3957        public WorldInfo getWorldInfo()
3958        {
3959            return this.worldInfo;
3960        }
3961    
3962        public GameRules func_82736_K()
3963        {
3964            return this.worldInfo.func_82574_x();
3965        }
3966    
3967        /**
3968         * Updates the flag that indicates whether or not all players in the world are sleeping.
3969         */
3970        public void updateAllPlayersSleepingFlag() {}
3971    
3972        public float getWeightedThunderStrength(float par1)
3973        {
3974            return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * par1) * this.getRainStrength(par1);
3975        }
3976    
3977        /**
3978         * Not sure about this actually. Reverting this one myself.
3979         */
3980        public float getRainStrength(float par1)
3981        {
3982            return this.prevRainingStrength + (this.rainingStrength - this.prevRainingStrength) * par1;
3983        }
3984    
3985        @SideOnly(Side.CLIENT)
3986        public void setRainStrength(float par1)
3987        {
3988            this.prevRainingStrength = par1;
3989            this.rainingStrength = par1;
3990        }
3991    
3992        /**
3993         * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9
3994         */
3995        public boolean isThundering()
3996        {
3997            return (double)this.getWeightedThunderStrength(1.0F) > 0.9D;
3998        }
3999    
4000        /**
4001         * Returns true if the current rain strength is greater than 0.2
4002         */
4003        public boolean isRaining()
4004        {
4005            return (double)this.getRainStrength(1.0F) > 0.2D;
4006        }
4007    
4008        public boolean canLightningStrikeAt(int par1, int par2, int par3)
4009        {
4010            if (!this.isRaining())
4011            {
4012                return false;
4013            }
4014            else if (!this.canBlockSeeTheSky(par1, par2, par3))
4015            {
4016                return false;
4017            }
4018            else if (this.getPrecipitationHeight(par1, par3) > par2)
4019            {
4020                return false;
4021            }
4022            else
4023            {
4024                BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
4025                return var4.getEnableSnow() ? false : var4.canSpawnLightningBolt();
4026            }
4027        }
4028    
4029        /**
4030         * Checks to see if the biome rainfall values for a given x,y,z coordinate set are extremely high
4031         */
4032        public boolean isBlockHighHumidity(int par1, int par2, int par3)
4033        {
4034            return provider.isBlockHighHumidity(par1, par2, par3);
4035        }
4036    
4037        /**
4038         * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same
4039         * id.
4040         */
4041        public void setItemData(String par1Str, WorldSavedData par2WorldSavedData)
4042        {
4043            this.mapStorage.setData(par1Str, par2WorldSavedData);
4044        }
4045    
4046        /**
4047         * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating
4048         * the given Class, or returns null if none such file exists. args: Class to instantiate, String dataid
4049         */
4050        public WorldSavedData loadItemData(Class par1Class, String par2Str)
4051        {
4052            return this.mapStorage.loadData(par1Class, par2Str);
4053        }
4054    
4055        /**
4056         * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the
4057         * 'idcounts' file.
4058         */
4059        public int getUniqueDataId(String par1Str)
4060        {
4061            return this.mapStorage.getUniqueDataId(par1Str);
4062        }
4063    
4064        public void func_82739_e(int par1, int par2, int par3, int par4, int par5)
4065        {
4066            for (int var6 = 0; var6 < this.worldAccesses.size(); ++var6)
4067            {
4068                ((IWorldAccess)this.worldAccesses.get(var6)).func_82746_a(par1, par2, par3, par4, par5);
4069            }
4070        }
4071    
4072        /**
4073         * See description for playAuxSFX.
4074         */
4075        public void playAuxSFX(int par1, int par2, int par3, int par4, int par5)
4076        {
4077            this.playAuxSFXAtEntity((EntityPlayer)null, par1, par2, par3, par4, par5);
4078        }
4079    
4080        /**
4081         * See description for playAuxSFX.
4082         */
4083        public void playAuxSFXAtEntity(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5, int par6)
4084        {
4085            for (int var7 = 0; var7 < this.worldAccesses.size(); ++var7)
4086            {
4087                ((IWorldAccess)this.worldAccesses.get(var7)).playAuxSFX(par1EntityPlayer, par2, par3, par4, par5, par6);
4088            }
4089        }
4090    
4091        /**
4092         * Returns current world height.
4093         */
4094        public int getHeight()
4095        {
4096            return provider.getHeight();
4097        }
4098    
4099        /**
4100         * Returns current world height.
4101         */
4102        public int getActualHeight()
4103        {
4104            return provider.getActualHeight();
4105        }
4106    
4107        public IUpdatePlayerListBox func_82735_a(EntityMinecart par1EntityMinecart)
4108        {
4109            return null;
4110        }
4111    
4112        /**
4113         * puts the World Random seed to a specific state dependant on the inputs
4114         */
4115        public Random setRandomSeed(int par1, int par2, int par3)
4116        {
4117            long var4 = (long)par1 * 341873128712L + (long)par2 * 132897987541L + this.getWorldInfo().getSeed() + (long)par3;
4118            this.rand.setSeed(var4);
4119            return this.rand;
4120        }
4121    
4122        /**
4123         * Returns the location of the closest structure of the specified type. If not found returns null.
4124         */
4125        public ChunkPosition findClosestStructure(String par1Str, int par2, int par3, int par4)
4126        {
4127            return this.getChunkProvider().findClosestStructure(this, par1Str, par2, par3, par4);
4128        }
4129    
4130        @SideOnly(Side.CLIENT)
4131    
4132        /**
4133         * set by !chunk.getAreLevelsEmpty
4134         */
4135        public boolean extendedLevelsInChunkCache()
4136        {
4137            return false;
4138        }
4139    
4140        @SideOnly(Side.CLIENT)
4141    
4142        /**
4143         * Returns horizon height for use in rendering the sky.
4144         */
4145        public double getHorizon()
4146        {
4147            return provider.getHorizon();
4148        }
4149    
4150        /**
4151         * Adds some basic stats of the world to the given crash report.
4152         */
4153        public CrashReport addWorldInfoToCrashReport(CrashReport par1CrashReport)
4154        {
4155            par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Entities", new CallableLvl1(this));
4156            par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Players", new CallableLvl2(this));
4157            par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Chunk Stats", new CallableLvl3(this));
4158            return par1CrashReport;
4159        }
4160    
4161        /**
4162         * Starts (or continues) destroying a block with given ID at the given coordinates for the given partially destroyed
4163         * value
4164         */
4165        public void destroyBlockInWorldPartially(int par1, int par2, int par3, int par4, int par5)
4166        {
4167            Iterator var6 = this.worldAccesses.iterator();
4168    
4169            while (var6.hasNext())
4170            {
4171                IWorldAccess var7 = (IWorldAccess)var6.next();
4172                var7.destroyBlockPartially(par1, par2, par3, par4, par5);
4173            }
4174        }
4175    
4176        public Vec3Pool func_82732_R()
4177        {
4178            return this.field_82741_K;
4179        }
4180    
4181        /**
4182         * Adds a single TileEntity to the world.
4183         * @param entity The TileEntity to be added.
4184         */
4185        public void addTileEntity(TileEntity entity)
4186        {
4187            List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
4188            if(entity.canUpdate())
4189            {
4190                dest.add(entity);
4191            }
4192        }
4193    
4194        /**
4195         * Determine if the given block is considered solid on the
4196         * specified side.  Used by placement logic.
4197         *
4198         * @param X Block X Position
4199         * @param Y Block Y Position
4200         * @param Z Block Z Position
4201         * @param side The Side in question
4202         * @return True if the side is solid
4203         */
4204        public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side)
4205        {
4206            return isBlockSolidOnSide(X, Y, Z, side, false);
4207        }
4208    
4209        /**
4210         * Determine if the given block is considered solid on the
4211         * specified side.  Used by placement logic.
4212         *
4213         * @param X Block X Position
4214         * @param Y Block Y Position
4215         * @param Z Block Z Position
4216         * @param side The Side in question
4217         * @param _default The defult to return if the block doesn't exist.
4218         * @return True if the side is solid
4219         */
4220        public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side, boolean _default)
4221        {
4222            if (X < -30000000 || Z < -30000000 || X >= 30000000 || Z >= 30000000)
4223            {
4224                return _default;
4225            }
4226    
4227            Chunk var5 = this.chunkProvider.provideChunk(X >> 4, Z >> 4);
4228            if (var5 == null || var5.isEmpty())
4229            {
4230                return _default;
4231            }
4232    
4233            Block block = Block.blocksList[getBlockId(X, Y, Z)];
4234            if(block == null)
4235            {
4236                return false;
4237            }
4238    
4239            return block.isBlockSolidOnSide(this, X, Y, Z, side);
4240        }
4241    
4242        /**
4243         * Get the persistent chunks for this world
4244         *
4245         * @return
4246         */
4247        SetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunks()
4248        {
4249            return ForgeChunkManager.getPersistentChunksFor(this);
4250        }
4251    }