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