001 package net.minecraft.world; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import net.minecraft.block.Block; 006 import net.minecraft.entity.Entity; 007 import net.minecraft.entity.player.EntityPlayer; 008 import net.minecraft.entity.player.EntityPlayerMP; 009 import net.minecraft.util.ChunkCoordinates; 010 import net.minecraft.util.MathHelper; 011 import net.minecraft.util.Vec3; 012 import net.minecraft.world.biome.BiomeGenBase; 013 import net.minecraft.world.biome.WorldChunkManager; 014 import net.minecraft.world.biome.WorldChunkManagerHell; 015 import net.minecraft.world.chunk.Chunk; 016 import net.minecraft.world.chunk.IChunkProvider; 017 import net.minecraft.world.gen.ChunkProviderFlat; 018 import net.minecraft.world.gen.ChunkProviderGenerate; 019 import net.minecraft.world.gen.FlatGeneratorInfo; 020 import net.minecraft.world.storage.WorldInfo; 021 import net.minecraftforge.client.IRenderHandler; 022 import net.minecraftforge.common.DimensionManager; 023 024 public 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 }