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