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