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