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 }