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