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