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