    001package net.minecraft.world;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import net.minecraft.block.Block;
    006import net.minecraft.entity.Entity;
    007import net.minecraft.entity.player.EntityPlayer;
    008import net.minecraft.entity.player.EntityPlayerMP;
    009import net.minecraft.util.ChunkCoordinates;
    010import net.minecraft.util.MathHelper;
    011import net.minecraft.util.Vec3;
    012import net.minecraft.world.biome.BiomeGenBase;
    013import net.minecraft.world.biome.WorldChunkManager;
    014import net.minecraft.world.biome.WorldChunkManagerHell;
    015import net.minecraft.world.chunk.Chunk;
    016import net.minecraft.world.chunk.IChunkProvider;
    017import net.minecraft.world.gen.ChunkProviderFlat;
    018import net.minecraft.world.gen.ChunkProviderGenerate;
    019import net.minecraft.world.gen.FlatGeneratorInfo;
    020import net.minecraft.world.storage.WorldInfo;
    021import net.minecraftforge.client.IRenderHandler;
    022import net.minecraftforge.common.DimensionManager;
    023
    024public abstract class WorldProvider
    025{
    026    /** world object being used */
    027    public World worldObj;
    028    public WorldType terrainType;
    029    public String field_82913_c;
    030
    031    /** World chunk manager being used to generate chunks */
    032    public WorldChunkManager worldChunkMgr;
    033
    034    /**
    035     * States whether the Hell world provider is used(true) or if the normal world provider is used(false)
    036     */
    037    public boolean isHellWorld = false;
    038
    039    /**
    040     * A boolean that tells if a world does not have a sky. Used in calculating weather and skylight
    041     */
    042    public boolean hasNoSky = false;
    043
    044    /** Light to brightness conversion table */
    045    public float[] lightBrightnessTable = new float[16];
    046
    047    /** The id for the dimension (ex. -1: Nether, 0: Overworld, 1: The End) */
    048    public int dimensionId = 0;
    049
    050    /** Array for sunrise/sunset colors (RGBA) */
    051    private float[] colorsSunriseSunset = new float[4];
    052
    053    /**
    054     * associate an existing world with a World provider, and setup its lightbrightness table
    055     */
    056    public final void registerWorld(World par1World)
    057    {
    058        this.worldObj = par1World;
    059        this.terrainType = par1World.getWorldInfo().getTerrainType();
    060        this.field_82913_c = par1World.getWorldInfo().getGeneratorOptions();
    061        this.registerWorldChunkManager();
    062        this.generateLightBrightnessTable();
    063    }
    064
    065    /**
    066     * Creates the light to brightness table
    067     */
    068    protected void generateLightBrightnessTable()
    069    {
    070        float f = 0.0F;
    071
    072        for (int i = 0; i <= 15; ++i)
    073        {
    074            float f1 = 1.0F - (float)i / 15.0F;
    075            this.lightBrightnessTable[i] = (1.0F - f1) / (f1 * 3.0F + 1.0F) * (1.0F - f) + f;
    076        }
    077    }
    078
    079    /**
    080     * creates a new world chunk manager for WorldProvider
    081     */
    082    protected void registerWorldChunkManager()
    083    {
    084        worldChunkMgr = terrainType.getChunkManager(worldObj);
    085    }
    086
    087    /**
    088     * Returns a new chunk provider which generates chunks for this world
    089     */
    090    public IChunkProvider createChunkGenerator()
    091    {
    092        return terrainType.getChunkGenerator(worldObj, field_82913_c);
    093    }
    094
    095    /**
    096     * Will check if the x, z position specified is alright to be set as the map spawn point
    097     */
    098    public boolean canCoordinateBeSpawn(int par1, int par2)
    099    {
    100        int k = this.worldObj.getFirstUncoveredBlock(par1, par2);
    101        return k == Block.grass.blockID;
    102    }
    103
    104    /**
    105     * Calculates the angle of sun and moon in the sky relative to a specified time (usually worldTime)
    106     */
    107    public float calculateCelestialAngle(long par1, float par3)
    108    {
    109        int j = (int)(par1 % 24000L);
    110        float f1 = ((float)j + par3) / 24000.0F - 0.25F;
    111
    112        if (f1 < 0.0F)
    113        {
    114            ++f1;
    115        }
    116
    117        if (f1 > 1.0F)
    118        {
    119            --f1;
    120        }
    121
    122        float f2 = f1;
    123        f1 = 1.0F - (float)((Math.cos((double)f1 * Math.PI) + 1.0D) / 2.0D);
    124        f1 = f2 + (f1 - f2) / 3.0F;
    125        return f1;
    126    }
    127
    128    public int getMoonPhase(long par1)
    129    {
    130        return (int)(par1 / 24000L) % 8;
    131    }
    132
    133    /**
    134     * Returns 'true' if in the "main surface world", but 'false' if in the Nether or End dimensions.
    135     */
    136    public boolean isSurfaceWorld()
    137    {
    138        return true;
    139    }
    140
    141    @SideOnly(Side.CLIENT)
    142
    143    /**
    144     * Returns array with sunrise/sunset colors
    145     */
    146    public float[] calcSunriseSunsetColors(float par1, float par2)
    147    {
    148        float f2 = 0.4F;
    149        float f3 = MathHelper.cos(par1 * (float)Math.PI * 2.0F) - 0.0F;
    150        float f4 = -0.0F;
    151
    152        if (f3 >= f4 - f2 && f3 <= f4 + f2)
    153        {
    154            float f5 = (f3 - f4) / f2 * 0.5F + 0.5F;
    155            float f6 = 1.0F - (1.0F - MathHelper.sin(f5 * (float)Math.PI)) * 0.99F;
    156            f6 *= f6;
    157            this.colorsSunriseSunset[0] = f5 * 0.3F + 0.7F;
    158            this.colorsSunriseSunset[1] = f5 * f5 * 0.7F + 0.2F;
    159            this.colorsSunriseSunset[2] = f5 * f5 * 0.0F + 0.2F;
    160            this.colorsSunriseSunset[3] = f6;
    161            return this.colorsSunriseSunset;
    162        }
    163        else
    164        {
    165            return null;
    166        }
    167    }
    168
    169    @SideOnly(Side.CLIENT)
    170
    171    /**
    172     * Return Vec3D with biome specific fog color
    173     */
    174    public Vec3 getFogColor(float par1, float par2)
    175    {
    176        float f2 = MathHelper.cos(par1 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
    177
    178        if (f2 < 0.0F)
    179        {
    180            f2 = 0.0F;
    181        }
    182
    183        if (f2 > 1.0F)
    184        {
    185            f2 = 1.0F;
    186        }
    187
    188        float f3 = 0.7529412F;
    189        float f4 = 0.84705883F;
    190        float f5 = 1.0F;
    191        f3 *= f2 * 0.94F + 0.06F;
    192        f4 *= f2 * 0.94F + 0.06F;
    193        f5 *= f2 * 0.91F + 0.09F;
    194        return this.worldObj.getWorldVec3Pool().getVecFromPool((double)f3, (double)f4, (double)f5);
    195    }
    196
    197    /**
    198     * True if the player can respawn in this dimension (true = overworld, false = nether).
    199     */
    200    public boolean canRespawnHere()
    201    {
    202        return true;
    203    }
    204
    205    public static WorldProvider getProviderForDimension(int par0)
    206    {
    207        return DimensionManager.createProviderFor(par0);
    208    }
    209
    210    @SideOnly(Side.CLIENT)
    211
    212    /**
    213     * the y level at which clouds are rendered.
    214     */
    215    public float getCloudHeight()
    216    {
    217        return 128.0F;
    218    }
    219
    220    @SideOnly(Side.CLIENT)
    221    public boolean isSkyColored()
    222    {
    223        return true;
    224    }
    225
    226    /**
    227     * Gets the hard-coded portal location to use when entering this dimension.
    228     */
    229    public ChunkCoordinates getEntrancePortalLocation()
    230    {
    231        return null;
    232    }
    233
    234    public int getAverageGroundLevel()
    235    {
    236        return this.terrainType.getMinimumSpawnHeight(this.worldObj);
    237    }
    238
    239    @SideOnly(Side.CLIENT)
    240
    241    /**
    242     * returns true if this dimension is supposed to display void particles and pull in the far plane based on the
    243     * user's Y offset.
    244     */
    245    public boolean getWorldHasVoidParticles()
    246    {
    247        return this.terrainType.hasVoidParticles(this.hasNoSky);
    248    }
    249
    250    @SideOnly(Side.CLIENT)
    251
    252    /**
    253     * Returns a double value representing the Y value relative to the top of the map at which void fog is at its
    254     * maximum. The default factor of 0.03125 relative to 256, for example, means the void fog will be at its maximum at
    255     * (256*0.03125), or 8.
    256     */
    257    public double getVoidFogYFactor()
    258    {
    259        return this.terrainType.voidFadeMagnitude();
    260    }
    261
    262    @SideOnly(Side.CLIENT)
    263
    264    /**
    265     * Returns true if the given X,Z coordinate should show environmental fog.
    266     */
    267    public boolean doesXZShowFog(int par1, int par2)
    268    {
    269        return false;
    270    }
    271
    272    /**
    273     * Returns the dimension's name, e.g. "The End", "Nether", or "Overworld".
    274     */
    275    public abstract String getDimensionName();
    276
    277    /*======================================= Forge Start =========================================*/
    278    private IRenderHandler skyRenderer = null;
    279    private IRenderHandler cloudRenderer = null;
    280
    281    /**
    282     * Sets the providers current dimension ID, used in default getSaveFolder()
    283     * Added to allow default providers to be registered for multiple dimensions.
    284     *
    285     * @param dim Dimension ID
    286     */
    287    public void setDimension(int dim)
    288    {
    289        this.dimensionId = dim;
    290    }
    291
    292    /**
    293     * Returns the sub-folder of the world folder that this WorldProvider saves to.
    294     * EXA: DIM1, DIM-1
    295     * @return The sub-folder name to save this world's chunks to.
    296     */
    297    public String getSaveFolder()
    298    {
    299        return (dimensionId == 0 ? null : "DIM" + dimensionId);
    300    }
    301
    302    /**
    303     * A message to display to the user when they transfer to this dimension.
    304     *
    305     * @return The message to be displayed
    306     */
    307    public String getWelcomeMessage()
    308    {
    309        if (this instanceof WorldProviderEnd)
    310        {
    311            return "Entering the End";
    312        }
    313        else if (this instanceof WorldProviderHell)
    314        {
    315            return "Entering the Nether";
    316        }
    317        return null;
    318    }
    319
    320    /**
    321     * A Message to display to the user when they transfer out of this dismension.
    322     *
    323     * @return The message to be displayed
    324     */
    325    public String getDepartMessage()
    326    {
    327        if (this instanceof WorldProviderEnd)
    328        {
    329            return "Leaving the End";
    330        }
    331        else if (this instanceof WorldProviderHell)
    332        {
    333            return "Leaving the Nether";
    334        }
    335        return null;
    336    }
    337
    338    /**
    339     * The dimensions movement factor. Relative to normal overworld.
    340     * It is applied to the players position when they transfer dimensions.
    341     * Exa: Nether movement is 8.0
    342     * @return The movement factor
    343     */
    344    public double getMovementFactor()
    345    {
    346        if (this instanceof WorldProviderHell)
    347        {
    348            return 8.0;
    349        }
    350        return 1.0;
    351    }
    352
    353    @SideOnly(Side.CLIENT)
    354    public IRenderHandler getSkyRenderer()
    355    {
    356        return this.skyRenderer;
    357    }
    358
    359    @SideOnly(Side.CLIENT)
    360    public void setSkyRenderer(IRenderHandler skyRenderer)
    361    {
    362        this.skyRenderer = skyRenderer;
    363    }
    364
    365    @SideOnly(Side.CLIENT)
    366    public IRenderHandler getCloudRenderer()
    367    {
    368        return cloudRenderer;
    369    }
    370
    371    @SideOnly(Side.CLIENT)
    372    public void setCloudRenderer(IRenderHandler renderer)
    373    {
    374        cloudRenderer = renderer;
    375    }
    376
    377    public ChunkCoordinates getRandomizedSpawnPoint()
    378    {
    379        ChunkCoordinates chunkcoordinates = new ChunkCoordinates(this.worldObj.getSpawnPoint());
    380
    381        boolean isAdventure = worldObj.getWorldInfo().getGameType() == EnumGameType.ADVENTURE;
    382        int spawnFuzz = terrainType.getSpawnFuzz();
    383        int spawnFuzzHalf = spawnFuzz / 2;
    384
    385        if (!hasNoSky && !isAdventure)
    386        {
    387            chunkcoordinates.posX += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
    388            chunkcoordinates.posZ += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
    389            chunkcoordinates.posY = this.worldObj.getTopSolidOrLiquidBlock(chunkcoordinates.posX, chunkcoordinates.posZ);
    390        }
    391
    392        return chunkcoordinates;
    393    }
    394
    395    /**
    396     * Determine if the cusor on the map should 'spin' when rendered, like it does for the player in the nether.
    397     *
    398     * @param entity The entity holding the map, playername, or frame-ENTITYID
    399     * @param x X Position
    400     * @param y Y Position
    401     * @param z Z Postion
    402     * @return True to 'spin' the cursor
    403     */
    404    public boolean shouldMapSpin(String entity, double x, double y, double z)
    405    {
    406        return dimensionId < 0;
    407    }
    408
    409    /**
    410     * Determines the dimension the player will be respawned in, typically this brings them back to the overworld.
    411     *
    412     * @param player The player that is respawning
    413     * @return The dimension to respawn the player in
    414     */
    415    public int getRespawnDimension(EntityPlayerMP player)
    416    {
    417        return 0;
    418    }
    419
    420    /*======================================= Start Moved From World =========================================*/
    421
    422    public BiomeGenBase getBiomeGenForCoords(int x, int z)
    423    {
    424        return worldObj.getBiomeGenForCoordsBody(x, z);
    425    }
    426
    427    public boolean isDaytime()
    428    {
    429        return worldObj.skylightSubtracted < 4;
    430    }
    431
    432    @SideOnly(Side.CLIENT)
    433    public Vec3 getSkyColor(Entity cameraEntity, float partialTicks)
    434    {
    435        return worldObj.getSkyColorBody(cameraEntity, partialTicks);
    436    }
    437
    438    @SideOnly(Side.CLIENT)
    439    public Vec3 drawClouds(float partialTicks)
    440    {
    441        return worldObj.drawCloudsBody(partialTicks);
    442    }
    443
    444    @SideOnly(Side.CLIENT)
    445    public float getStarBrightness(float par1)
    446    {
    447        return worldObj.getStarBrightnessBody(par1);
    448    }
    449
    450    public void setAllowedSpawnTypes(boolean allowHostile, boolean allowPeaceful)
    451    {
    452        worldObj.spawnHostileMobs = allowHostile;
    453        worldObj.spawnPeacefulMobs = allowPeaceful;
    454    }
    455
    456    public void calculateInitialWeather()
    457    {
    458        worldObj.calculateInitialWeatherBody();
    459    }
    460
    461    public void updateWeather()
    462    {
    463        worldObj.updateWeatherBody();
    464    }
    465
    466    public void toggleRain()
    467    {
    468        worldObj.worldInfo.setRainTime(1);
    469    }
    470
    471    public boolean canBlockFreeze(int x, int y, int z, boolean byWater)
    472    {
    473        return worldObj.canBlockFreezeBody(x, y, z, byWater);
    474    }
    475
    476    public boolean canSnowAt(int x, int y, int z)
    477    {
    478        return worldObj.canSnowAtBody(x, y, z);
    479    }
    480
    481    public void setWorldTime(long time)
    482    {
    483        worldObj.worldInfo.setWorldTime(time);
    484    }
    485
    486    public long getSeed()
    487    {
    488        return worldObj.worldInfo.getSeed();
    489    }
    490
    491    public long getWorldTime()
    492    {
    493        return worldObj.worldInfo.getWorldTime();
    494    }
    495
    496    public ChunkCoordinates getSpawnPoint()
    497    {
    498        WorldInfo info = worldObj.worldInfo;
    499        return new ChunkCoordinates(info.getSpawnX(), info.getSpawnY(), info.getSpawnZ());
    500    }
    501
    502    public void setSpawnPoint(int x, int y, int z)
    503    {
    504        worldObj.worldInfo.setSpawnPosition(x, y, z);
    505    }
    506
    507    public boolean canMineBlock(EntityPlayer player, int x, int y, int z)
    508    {
    509        return worldObj.canMineBlockBody(player, x, y, z);
    510    }
    511
    512    public boolean isBlockHighHumidity(int x, int y, int z)
    513    {
    514        return worldObj.getBiomeGenForCoords(x, z).isHighHumidity();
    515    }
    516
    517    public int getHeight()
    518    {
    519        return 256;
    520    }
    521
    522    public int getActualHeight()
    523    {
    524        return hasNoSky ? 128 : 256;
    525    }
    526
    527    public double getHorizon()
    528    {
    529        return worldObj.worldInfo.getTerrainType().getHorizon(worldObj);
    530    }
    531
    532    public void resetRainAndThunder()
    533    {
    534        worldObj.worldInfo.setRainTime(0);
    535        worldObj.worldInfo.setRaining(false);
    536        worldObj.worldInfo.setThunderTime(0);
    537        worldObj.worldInfo.setThundering(false);
    538    }
    539
    540    public boolean canDoLightning(Chunk chunk)
    541    {
    542        return true;
    543    }
    544
    545    public boolean canDoRainSnowIce(Chunk chunk)
    546    {
    547        return true;
    548    }
    549}