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