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    }