    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 var1 = 0.0F;
    071
    072        for (int var2 = 0; var2 <= 15; ++var2)
    073        {
    074            float var3 = 1.0F - (float)var2 / 15.0F;
    075            this.lightBrightnessTable[var2] = (1.0F - var3) / (var3 * 3.0F + 1.0F) * (1.0F - var1) + var1;
    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 var3 = this.worldObj.getFirstUncoveredBlock(par1, par2);
    101        return var3 == 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 var4 = (int)(par1 % 24000L);
    110        float var5 = ((float)var4 + par3) / 24000.0F - 0.25F;
    111
    112        if (var5 < 0.0F)
    113        {
    114            ++var5;
    115        }
    116
    117        if (var5 > 1.0F)
    118        {
    119            --var5;
    120        }
    121
    122        float var6 = var5;
    123        var5 = 1.0F - (float)((Math.cos((double)var5 * Math.PI) + 1.0D) / 2.0D);
    124        var5 = var6 + (var5 - var6) / 3.0F;
    125        return var5;
    126    }
    127
    128    @SideOnly(Side.CLIENT)
    129    public int getMoonPhase(long par1, float par3)
    130    {
    131        return (int)(par1 / 24000L) % 8;
    132    }
    133
    134    /**
    135     * Returns 'true' if in the "main surface world", but 'false' if in the Nether or End dimensions.
    136     */
    137    public boolean isSurfaceWorld()
    138    {
    139        return true;
    140    }
    141
    142    @SideOnly(Side.CLIENT)
    143
    144    /**
    145     * Returns array with sunrise/sunset colors
    146     */
    147    public float[] calcSunriseSunsetColors(float par1, float par2)
    148    {
    149        float var3 = 0.4F;
    150        float var4 = MathHelper.cos(par1 * (float)Math.PI * 2.0F) - 0.0F;
    151        float var5 = -0.0F;
    152
    153        if (var4 >= var5 - var3 && var4 <= var5 + var3)
    154        {
    155            float var6 = (var4 - var5) / var3 * 0.5F + 0.5F;
    156            float var7 = 1.0F - (1.0F - MathHelper.sin(var6 * (float)Math.PI)) * 0.99F;
    157            var7 *= var7;
    158            this.colorsSunriseSunset[0] = var6 * 0.3F + 0.7F;
    159            this.colorsSunriseSunset[1] = var6 * var6 * 0.7F + 0.2F;
    160            this.colorsSunriseSunset[2] = var6 * var6 * 0.0F + 0.2F;
    161            this.colorsSunriseSunset[3] = var7;
    162            return this.colorsSunriseSunset;
    163        }
    164        else
    165        {
    166            return null;
    167        }
    168    }
    169
    170    @SideOnly(Side.CLIENT)
    171
    172    /**
    173     * Return Vec3D with biome specific fog color
    174     */
    175    public Vec3 getFogColor(float par1, float par2)
    176    {
    177        float var3 = MathHelper.cos(par1 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
    178
    179        if (var3 < 0.0F)
    180        {
    181            var3 = 0.0F;
    182        }
    183
    184        if (var3 > 1.0F)
    185        {
    186            var3 = 1.0F;
    187        }
    188
    189        float var4 = 0.7529412F;
    190        float var5 = 0.84705883F;
    191        float var6 = 1.0F;
    192        var4 *= var3 * 0.94F + 0.06F;
    193        var5 *= var3 * 0.94F + 0.06F;
    194        var6 *= var3 * 0.91F + 0.09F;
    195        return this.worldObj.getWorldVec3Pool().getVecFromPool((double)var4, (double)var5, (double)var6);
    196    }
    197
    198    /**
    199     * True if the player can respawn in this dimension (true = overworld, false = nether).
    200     */
    201    public boolean canRespawnHere()
    202    {
    203        return true;
    204    }
    205
    206    public static WorldProvider getProviderForDimension(int par0)
    207    {
    208        return DimensionManager.createProviderFor(par0);
    209    }
    210
    211    @SideOnly(Side.CLIENT)
    212
    213    /**
    214     * the y level at which clouds are rendered.
    215     */
    216    public float getCloudHeight()
    217    {
    218        return 128.0F;
    219    }
    220
    221    @SideOnly(Side.CLIENT)
    222    public boolean isSkyColored()
    223    {
    224        return true;
    225    }
    226
    227    /**
    228     * Gets the hard-coded portal location to use when entering this dimension.
    229     */
    230    public ChunkCoordinates getEntrancePortalLocation()
    231    {
    232        return null;
    233    }
    234
    235    public int getAverageGroundLevel()
    236    {
    237        return this.terrainType.getMinimumSpawnHeight(this.worldObj);
    238    }
    239
    240    @SideOnly(Side.CLIENT)
    241
    242    /**
    243     * returns true if this dimension is supposed to display void particles and pull in the far plane based on the
    244     * user's Y offset.
    245     */
    246    public boolean getWorldHasVoidParticles()
    247    {
    248        return this.terrainType.hasVoidParticles(this.hasNoSky);
    249    }
    250
    251    @SideOnly(Side.CLIENT)
    252
    253    /**
    254     * Returns a double value representing the Y value relative to the top of the map at which void fog is at its
    255     * maximum. The default factor of 0.03125 relative to 256, for example, means the void fog will be at its maximum at
    256     * (256*0.03125), or 8.
    257     */
    258    public double getVoidFogYFactor()
    259    {
    260        return this.terrainType.voidFadeMagnitude();
    261    }
    262
    263    @SideOnly(Side.CLIENT)
    264
    265    /**
    266     * Returns true if the given X,Z coordinate should show environmental fog.
    267     */
    268    public boolean doesXZShowFog(int par1, int par2)
    269    {
    270        return false;
    271    }
    272
    273    /**
    274     * Returns the dimension's name, e.g. "The End", "Nether", or "Overworld".
    275     */
    276    public abstract String getDimensionName();
    277
    278    /*======================================= Forge Start =========================================*/
    279    private IRenderHandler skyRenderer = null;
    280    private IRenderHandler cloudRenderer = null;
    281
    282    /**
    283     * Sets the providers current dimension ID, used in default getSaveFolder()
    284     * Added to allow default providers to be registered for multiple dimensions.
    285     *
    286     * @param dim Dimension ID
    287     */
    288    public void setDimension(int dim)
    289    {
    290        this.dimensionId = dim;
    291    }
    292
    293    /**
    294     * Returns the sub-folder of the world folder that this WorldProvider saves to.
    295     * EXA: DIM1, DIM-1
    296     * @return The sub-folder name to save this world's chunks to.
    297     */
    298    public String getSaveFolder()
    299    {
    300        return (dimensionId == 0 ? null : "DIM" + dimensionId);
    301    }
    302
    303    /**
    304     * A message to display to the user when they transfer to this dimension.
    305     *
    306     * @return The message to be displayed
    307     */
    308    public String getWelcomeMessage()
    309    {
    310        if (this instanceof WorldProviderEnd)
    311        {
    312            return "Entering the End";
    313        }
    314        else if (this instanceof WorldProviderHell)
    315        {
    316            return "Entering the Nether";
    317        }
    318        return null;
    319    }
    320
    321    /**
    322     * A Message to display to the user when they transfer out of this dismension.
    323     *
    324     * @return The message to be displayed
    325     */
    326    public String getDepartMessage()
    327    {
    328        if (this instanceof WorldProviderEnd)
    329        {
    330            return "Leaving the End";
    331        }
    332        else if (this instanceof WorldProviderHell)
    333        {
    334            return "Leaving the Nether";
    335        }
    336        return null;
    337    }
    338
    339    /**
    340     * The dimensions movement factor. Relative to normal overworld.
    341     * It is applied to the players position when they transfer dimensions.
    342     * Exa: Nether movement is 8.0
    343     * @return The movement factor
    344     */
    345    public double getMovementFactor()
    346    {
    347        if (this instanceof WorldProviderHell)
    348        {
    349            return 8.0;
    350        }
    351        return 1.0;
    352    }
    353
    354    @SideOnly(Side.CLIENT)
    355    public IRenderHandler getSkyRenderer()
    356    {
    357        return this.skyRenderer;
    358    }
    359
    360    @SideOnly(Side.CLIENT)
    361    public void setSkyRenderer(IRenderHandler skyRenderer)
    362    {
    363        this.skyRenderer = skyRenderer;
    364    }
    365
    366    @SideOnly(Side.CLIENT)
    367    public IRenderHandler getCloudRenderer()
    368    {
    369        return cloudRenderer;
    370    }
    371
    372    @SideOnly(Side.CLIENT)
    373    public void setCloudRenderer(IRenderHandler renderer)
    374    {
    375        cloudRenderer = renderer;
    376    }
    377
    378    public ChunkCoordinates getRandomizedSpawnPoint()
    379    {
    380        ChunkCoordinates var5 = new ChunkCoordinates(this.worldObj.getSpawnPoint());
    381
    382        boolean isAdventure = worldObj.getWorldInfo().getGameType() == EnumGameType.ADVENTURE;
    383        int spawnFuzz = terrainType.getSpawnFuzz();
    384        int spawnFuzzHalf = spawnFuzz / 2;
    385
    386        if (!hasNoSky && !isAdventure)
    387        {
    388            var5.posX += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
    389            var5.posZ += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
    390            var5.posY = this.worldObj.getTopSolidOrLiquidBlock(var5.posX, var5.posZ);
    391        }
    392
    393        return var5;
    394    }
    395
    396    /**
    397     * Determine if the cusor on the map should 'spin' when rendered, like it does for the player in the nether.
    398     *
    399     * @param entity The entity holding the map, playername, or frame-ENTITYID
    400     * @param x X Position
    401     * @param y Y Position
    402     * @param z Z Postion
    403     * @return True to 'spin' the cursor
    404     */
    405    public boolean shouldMapSpin(String entity, double x, double y, double z)
    406    {
    407        return dimensionId < 0;
    408    }
    409
    410    /**
    411     * Determines the dimension the player will be respawned in, typically this brings them back to the overworld.
    412     *
    413     * @param player The player that is respawning
    414     * @return The dimension to respawn the player in
    415     */
    416    public int getRespawnDimension(EntityPlayerMP player)
    417    {
    418        return 0;
    419    }
    420
    421    /*======================================= Start Moved From World =========================================*/
    422
    423    public BiomeGenBase getBiomeGenForCoords(int x, int z)
    424    {
    425        return worldObj.getBiomeGenForCoordsBody(x, z);
    426    }
    427
    428    public boolean isDaytime()
    429    {
    430        return worldObj.skylightSubtracted < 4;
    431    }
    432
    433    @SideOnly(Side.CLIENT)
    434    public Vec3 getSkyColor(Entity cameraEntity, float partialTicks)
    435    {
    436        return worldObj.getSkyColorBody(cameraEntity, partialTicks);
    437    }
    438
    439    @SideOnly(Side.CLIENT)
    440    public Vec3 drawClouds(float partialTicks)
    441    {
    442        return worldObj.drawCloudsBody(partialTicks);
    443    }
    444
    445    @SideOnly(Side.CLIENT)
    446    public float getStarBrightness(float par1)
    447    {
    448        return worldObj.getStarBrightnessBody(par1);
    449    }
    450
    451    public void setAllowedSpawnTypes(boolean allowHostile, boolean allowPeaceful)
    452    {
    453        worldObj.spawnHostileMobs = allowHostile;
    454        worldObj.spawnPeacefulMobs = allowPeaceful;
    455    }
    456
    457    public void calculateInitialWeather()
    458    {
    459        worldObj.calculateInitialWeatherBody();
    460    }
    461
    462    public void updateWeather()
    463    {
    464        worldObj.updateWeatherBody();
    465    }
    466
    467    public void toggleRain()
    468    {
    469        worldObj.worldInfo.setRainTime(1);
    470    }
    471
    472    public boolean canBlockFreeze(int x, int y, int z, boolean byWater)
    473    {
    474        return worldObj.canBlockFreezeBody(x, y, z, byWater);
    475    }
    476
    477    public boolean canSnowAt(int x, int y, int z)
    478    {
    479        return worldObj.canSnowAtBody(x, y, z);
    480    }
    481
    482    public void setWorldTime(long time)
    483    {
    484        worldObj.worldInfo.setWorldTime(time);
    485    }
    486
    487    public long getSeed()
    488    {
    489        return worldObj.worldInfo.getSeed();
    490    }
    491
    492    public long getWorldTime()
    493    {
    494        return worldObj.worldInfo.getWorldTime();
    495    }
    496
    497    public ChunkCoordinates getSpawnPoint()
    498    {
    499        WorldInfo info = worldObj.worldInfo;
    500        return new ChunkCoordinates(info.getSpawnX(), info.getSpawnY(), info.getSpawnZ());
    501    }
    502
    503    public void setSpawnPoint(int x, int y, int z)
    504    {
    505        worldObj.worldInfo.setSpawnPosition(x, y, z);
    506    }
    507
    508    public boolean canMineBlock(EntityPlayer player, int x, int y, int z)
    509    {
    510        return worldObj.canMineBlockBody(player, x, y, z);
    511    }
    512
    513    public boolean isBlockHighHumidity(int x, int y, int z)
    514    {
    515        return worldObj.getBiomeGenForCoords(x, z).isHighHumidity();
    516    }
    517
    518    public int getHeight()
    519    {
    520        return 256;
    521    }
    522
    523    public int getActualHeight()
    524    {
    525        return hasNoSky ? 128 : 256;
    526    }
    527
    528    public double getHorizon()
    529    {
    530        return worldObj.worldInfo.getTerrainType().getHorizon(worldObj);
    531    }
    532
    533    public void resetRainAndThunder()
    534    {
    535        worldObj.worldInfo.setRainTime(0);
    536        worldObj.worldInfo.setRaining(false);
    537        worldObj.worldInfo.setThunderTime(0);
    538        worldObj.worldInfo.setThundering(false);
    539    }
    540
    541    public boolean canDoLightning(Chunk chunk)
    542    {
    543        return true;
    544    }
    545
    546    public boolean canDoRainSnowIce(Chunk chunk)
    547    {
    548        return true;
    549    }
    550}