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}