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