001    package net.minecraft.src;
002    
003    import net.minecraftforge.client.SkyProvider;
004    import net.minecraftforge.common.DimensionManager;
005    import cpw.mods.fml.common.Side;
006    import cpw.mods.fml.common.asm.SideOnly;
007    
008    public abstract class WorldProvider
009    {
010        /** world object being used */
011        public World worldObj;
012        public WorldType terrainType;
013        public String field_82913_c;
014    
015        /** World chunk manager being used to generate chunks */
016        public WorldChunkManager worldChunkMgr;
017    
018        /**
019         * States whether the Hell world provider is used(true) or if the normal world provider is used(false)
020         */
021        public boolean isHellWorld = false;
022    
023        /**
024         * A boolean that tells if a world does not have a sky. Used in calculating weather and skylight
025         */
026        public boolean hasNoSky = false;
027    
028        /** Light to brightness conversion table */
029        public float[] lightBrightnessTable = new float[16];
030    
031        /** The id for the dimension (ex. -1: Nether, 0: Overworld, 1: The End) */
032        public int dimensionId = 0;
033    
034        /** Array for sunrise/sunset colors (RGBA) */
035        private float[] colorsSunriseSunset = new float[4];
036    
037        /**
038         * associate an existing world with a World provider, and setup its lightbrightness table
039         */
040        public final void registerWorld(World par1World)
041        {
042            this.worldObj = par1World;
043            this.terrainType = par1World.getWorldInfo().getTerrainType();
044            this.field_82913_c = par1World.getWorldInfo().func_82571_y();
045            this.registerWorldChunkManager();
046            this.generateLightBrightnessTable();
047        }
048    
049        /**
050         * Creates the light to brightness table
051         */
052        protected void generateLightBrightnessTable()
053        {
054            float var1 = 0.0F;
055    
056            for (int var2 = 0; var2 <= 15; ++var2)
057            {
058                float var3 = 1.0F - (float)var2 / 15.0F;
059                this.lightBrightnessTable[var2] = (1.0F - var3) / (var3 * 3.0F + 1.0F) * (1.0F - var1) + var1;
060            }
061        }
062    
063        /**
064         * creates a new world chunk manager for WorldProvider
065         */
066        protected void registerWorldChunkManager()
067        {
068            worldChunkMgr = terrainType.getChunkManager(worldObj);
069        }
070    
071        /**
072         * Returns a new chunk provider which generates chunks for this world
073         */
074        public IChunkProvider createChunkGenerator()
075        {
076            return terrainType.getChunkGenerator(worldObj, field_82913_c);
077        }
078    
079        /**
080         * Will check if the x, z position specified is alright to be set as the map spawn point
081         */
082        public boolean canCoordinateBeSpawn(int par1, int par2)
083        {
084            int var3 = this.worldObj.getFirstUncoveredBlock(par1, par2);
085            return var3 == Block.grass.blockID;
086        }
087    
088        /**
089         * Calculates the angle of sun and moon in the sky relative to a specified time (usually worldTime)
090         */
091        public float calculateCelestialAngle(long par1, float par3)
092        {
093            int var4 = (int)(par1 % 24000L);
094            float var5 = ((float)var4 + par3) / 24000.0F - 0.25F;
095    
096            if (var5 < 0.0F)
097            {
098                ++var5;
099            }
100    
101            if (var5 > 1.0F)
102            {
103                --var5;
104            }
105    
106            float var6 = var5;
107            var5 = 1.0F - (float)((Math.cos((double)var5 * Math.PI) + 1.0D) / 2.0D);
108            var5 = var6 + (var5 - var6) / 3.0F;
109            return var5;
110        }
111    
112        @SideOnly(Side.CLIENT)
113        public int getMoonPhase(long par1, float par3)
114        {
115            return (int)(par1 / 24000L) % 8;
116        }
117    
118        /**
119         * Returns 'true' if in the "main surface world", but 'false' if in the Nether or End dimensions.
120         */
121        public boolean isSurfaceWorld()
122        {
123            return true;
124        }
125    
126        @SideOnly(Side.CLIENT)
127    
128        /**
129         * Returns array with sunrise/sunset colors
130         */
131        public float[] calcSunriseSunsetColors(float par1, float par2)
132        {
133            float var3 = 0.4F;
134            float var4 = MathHelper.cos(par1 * (float)Math.PI * 2.0F) - 0.0F;
135            float var5 = -0.0F;
136    
137            if (var4 >= var5 - var3 && var4 <= var5 + var3)
138            {
139                float var6 = (var4 - var5) / var3 * 0.5F + 0.5F;
140                float var7 = 1.0F - (1.0F - MathHelper.sin(var6 * (float)Math.PI)) * 0.99F;
141                var7 *= var7;
142                this.colorsSunriseSunset[0] = var6 * 0.3F + 0.7F;
143                this.colorsSunriseSunset[1] = var6 * var6 * 0.7F + 0.2F;
144                this.colorsSunriseSunset[2] = var6 * var6 * 0.0F + 0.2F;
145                this.colorsSunriseSunset[3] = var7;
146                return this.colorsSunriseSunset;
147            }
148            else
149            {
150                return null;
151            }
152        }
153    
154        @SideOnly(Side.CLIENT)
155    
156        /**
157         * Return Vec3D with biome specific fog color
158         */
159        public Vec3 getFogColor(float par1, float par2)
160        {
161            float var3 = MathHelper.cos(par1 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
162    
163            if (var3 < 0.0F)
164            {
165                var3 = 0.0F;
166            }
167    
168            if (var3 > 1.0F)
169            {
170                var3 = 1.0F;
171            }
172    
173            float var4 = 0.7529412F;
174            float var5 = 0.84705883F;
175            float var6 = 1.0F;
176            var4 *= var3 * 0.94F + 0.06F;
177            var5 *= var3 * 0.94F + 0.06F;
178            var6 *= var3 * 0.91F + 0.09F;
179            return this.worldObj.getWorldVec3Pool().getVecFromPool((double)var4, (double)var5, (double)var6);
180        }
181    
182        /**
183         * True if the player can respawn in this dimension (true = overworld, false = nether).
184         */
185        public boolean canRespawnHere()
186        {
187            return true;
188        }
189    
190        public static WorldProvider getProviderForDimension(int par0)
191        {
192            return DimensionManager.createProviderFor(par0);
193        }
194    
195        @SideOnly(Side.CLIENT)
196    
197        /**
198         * the y level at which clouds are rendered.
199         */
200        public float getCloudHeight()
201        {
202            return 128.0F;
203        }
204    
205        @SideOnly(Side.CLIENT)
206        public boolean isSkyColored()
207        {
208            return true;
209        }
210    
211        /**
212         * Gets the hard-coded portal location to use when entering this dimension.
213         */
214        public ChunkCoordinates getEntrancePortalLocation()
215        {
216            return null;
217        }
218    
219        public int getAverageGroundLevel()
220        {
221            return this.terrainType.getMinimumSpawnHeight(this.worldObj);
222        }
223    
224        @SideOnly(Side.CLIENT)
225    
226        /**
227         * returns true if this dimension is supposed to display void particles and pull in the far plane based on the
228         * user's Y offset.
229         */
230        public boolean getWorldHasVoidParticles()
231        {
232            return this.terrainType.hasVoidParticles(this.hasNoSky);
233        }
234    
235        @SideOnly(Side.CLIENT)
236    
237        /**
238         * Returns a double value representing the Y value relative to the top of the map at which void fog is at its
239         * maximum. The default factor of 0.03125 relative to 256, for example, means the void fog will be at its maximum at
240         * (256*0.03125), or 8.
241         */
242        public double getVoidFogYFactor()
243        {
244            return this.terrainType.voidFadeMagnitude();
245        }
246    
247        @SideOnly(Side.CLIENT)
248    
249        /**
250         * Returns true if the given X,Z coordinate should show environmental fog.
251         */
252        public boolean doesXZShowFog(int par1, int par2)
253        {
254            return false;
255        }
256    
257        /**
258         * Returns the dimension's name, e.g. "The End", "Nether", or "Overworld".
259         */
260        public abstract String getDimensionName();
261    
262        /*======================================= Forge Start =========================================*/
263        private SkyProvider skyProvider = null;
264        private SkyProvider cloudRenderer = null;
265        
266        /**
267         * Sets the providers current dimension ID, used in default getSaveFolder()
268         * Added to allow default providers to be registered for multiple dimensions.
269         * 
270         * @param dim Dimension ID
271         */
272        public void setDimension(int dim)
273        {
274            this.dimensionId = dim;
275        }
276    
277        /**
278         * Returns the sub-folder of the world folder that this WorldProvider saves to.
279         * EXA: DIM1, DIM-1
280         * @return The sub-folder name to save this world's chunks to.
281         */
282        public String getSaveFolder()
283        {
284            return (dimensionId == 0 ? null : "DIM" + dimensionId);
285        }
286    
287        /**
288         * A message to display to the user when they transfer to this dimension.
289         *
290         * @return The message to be displayed
291         */
292        public String getWelcomeMessage()
293        {
294            if (this instanceof WorldProviderEnd)
295            {
296                return "Entering the End";
297            }
298            else if (this instanceof WorldProviderHell)
299            {
300                return "Entering the Nether";
301            }
302            return null;
303        }
304    
305        /**
306         * A Message to display to the user when they transfer out of this dismension.
307         *
308         * @return The message to be displayed
309         */
310        public String getDepartMessage()
311        {
312            if (this instanceof WorldProviderEnd)
313            {
314                return "Leaving the End";
315            }
316            else if (this instanceof WorldProviderHell)
317            {
318                return "Leaving the Nether";
319            } 
320            return null;
321        }
322    
323        /**
324         * The dimensions movement factor. Relative to normal overworld.
325         * It is applied to the players position when they transfer dimensions.
326         * Exa: Nether movement is 8.0
327         * @return The movement factor
328         */
329        public double getMovementFactor()
330        {
331            if (this instanceof WorldProviderHell)
332            {
333                return 8.0;
334            }
335            return 1.0;
336        }
337    
338        @SideOnly(Side.CLIENT)
339        public SkyProvider getSkyProvider()
340        {
341            return this.skyProvider;
342        }
343    
344        @SideOnly(Side.CLIENT)
345        public void setSkyProvider(SkyProvider skyProvider)
346        {
347            this.skyProvider = skyProvider;
348        }
349    
350        @SideOnly(Side.CLIENT)
351        public SkyProvider getCloudRenderer()
352        {
353            return cloudRenderer;
354        }
355    
356        @SideOnly(Side.CLIENT)
357        public void setCloudRenderer(SkyProvider renderer)
358        {
359            cloudRenderer = renderer;
360        }
361    
362        public ChunkCoordinates getRandomizedSpawnPoint()
363        {
364            ChunkCoordinates var5 = new ChunkCoordinates(this.worldObj.getSpawnPoint());
365    
366            boolean isAdventure = worldObj.getWorldInfo().getGameType() == EnumGameType.ADVENTURE;
367            int spawnFuzz = terrainType.getSpawnFuzz();
368            int spawnFuzzHalf = spawnFuzz / 2;
369    
370            if (!hasNoSky && !isAdventure)
371            {
372                var5.posX += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
373                var5.posZ += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
374                var5.posY = this.worldObj.getTopSolidOrLiquidBlock(var5.posX, var5.posZ);
375            }
376    
377            return var5;
378        }
379        
380        /**
381         * Determine if the cusor on the map should 'spin' when rendered, like it does for the player in the nether.
382         * 
383         * @param entity The entity holding the map, playername, or frame-ENTITYID
384         * @param x X Position
385         * @param y Y Position
386         * @param z Z Postion
387         * @return True to 'spin' the cursor
388         */
389        public boolean shouldMapSpin(String entity, double x, double y, double z)
390        {
391            return dimensionId < 0;
392        }
393    
394        /**
395         * Determines the dimension the player will be respawned in, typically this brings them back to the overworld.
396         * 
397         * @param player The player that is respawning
398         * @return The dimension to respawn the player in
399         */
400        public int getRespawnDimension(EntityPlayerMP player)
401        {
402            return 0;
403        }
404    
405        /*======================================= Start Moved From World =========================================*/
406    
407        public BiomeGenBase getBiomeGenForCoords(int x, int z)
408        {
409            return worldObj.getBiomeGenForCoordsBody(x, z);
410        }
411    
412        public boolean isDaytime()
413        {
414            return worldObj.skylightSubtracted < 4;
415        }
416    
417        @SideOnly(Side.CLIENT)
418        public Vec3 getSkyColor(Entity cameraEntity, float partialTicks)
419        {
420            return worldObj.getSkyColorBody(cameraEntity, partialTicks);
421        }
422    
423        @SideOnly(Side.CLIENT)
424        public Vec3 drawClouds(float partialTicks)
425        {
426            return worldObj.drawCloudsBody(partialTicks);
427        }
428    
429        @SideOnly(Side.CLIENT)
430        public float getStarBrightness(float par1)
431        {
432            return worldObj.getStarBrightnessBody(par1);
433        }
434    
435        public void setAllowedSpawnTypes(boolean allowHostile, boolean allowPeaceful)
436        {
437            worldObj.spawnHostileMobs = allowHostile;
438            worldObj.spawnPeacefulMobs = allowPeaceful;
439        }
440    
441        public void calculateInitialWeather()
442        {
443            worldObj.calculateInitialWeatherBody();
444        }
445    
446        public void updateWeather()
447        {
448            worldObj.updateWeatherBody();
449        }
450    
451        public void toggleRain()
452        {
453            worldObj.worldInfo.setRainTime(1);
454        }
455    
456        public boolean canBlockFreeze(int x, int y, int z, boolean byWater)
457        {
458            return worldObj.canBlockFreezeBody(x, y, z, byWater);
459        }
460    
461        public boolean canSnowAt(int x, int y, int z)
462        {
463            return worldObj.canSnowAtBody(x, y, z);
464        }
465    
466        public void setWorldTime(long time)
467        {
468            worldObj.worldInfo.setWorldTime(time);
469        }
470    
471        public long getSeed()
472        {
473            return worldObj.worldInfo.getSeed();
474        }
475    
476        public long getWorldTime()
477        {
478            return worldObj.worldInfo.getWorldTime();
479        }
480    
481        public ChunkCoordinates getSpawnPoint()
482        {
483            WorldInfo info = worldObj.worldInfo;
484            return new ChunkCoordinates(info.getSpawnX(), info.getSpawnY(), info.getSpawnZ());
485        }
486    
487        public void setSpawnPoint(int x, int y, int z)
488        {
489            worldObj.worldInfo.setSpawnPosition(x, y, z);
490        }
491    
492        public boolean canMineBlock(EntityPlayer player, int x, int y, int z)
493        {
494            return worldObj.canMineBlockBody(player, x, y, z);
495        }
496    
497        public boolean isBlockHighHumidity(int x, int y, int z)
498        {
499            return worldObj.getBiomeGenForCoords(x, z).isHighHumidity();
500        }
501    
502        public int getHeight()
503        {
504            return 256;
505        }
506    
507        public int getActualHeight()
508        {
509            return hasNoSky ? 128 : 256;
510        }
511    
512        public double getHorizon()
513        {
514            return worldObj.worldInfo.getTerrainType().getHorizon(worldObj);
515        }
516    
517        public void resetRainAndThunder()
518        {
519            worldObj.worldInfo.setRainTime(0);
520            worldObj.worldInfo.setRaining(false);
521            worldObj.worldInfo.setThunderTime(0);
522            worldObj.worldInfo.setThundering(false);
523        }
524        
525        public boolean canDoLightning(Chunk chunk)
526        {
527            return true;
528        }
529        
530        public boolean canDoRainSnowIce(Chunk chunk)
531        {
532            return true;
533        }
534    }