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    
014        /** World chunk manager being used to generate chunks */
015        public WorldChunkManager worldChunkMgr;
016    
017        /**
018         * States whether the Hell world provider is used(true) or if the normal world provider is used(false)
019         */
020        public boolean isHellWorld = false;
021    
022        /**
023         * A boolean that tells if a world does not have a sky. Used in calculating weather and skylight
024         */
025        public boolean hasNoSky = false;
026    
027        /** Light to brightness conversion table */
028        public float[] lightBrightnessTable = new float[16];
029    
030        /** The id for the dimension (ex. -1: Nether, 0: Overworld, 1: The End) */
031        public int dimensionId = 0;
032    
033        /** Array for sunrise/sunset colors (RGBA) */
034        private float[] colorsSunriseSunset = new float[4];
035    
036        private SkyProvider skyProvider = null;
037    
038        /**
039         * associate an existing world with a World provider, and setup its lightbrightness table
040         */
041        public final void registerWorld(World par1World)
042        {
043            this.worldObj = par1World;
044            this.terrainType = par1World.getWorldInfo().getTerrainType();
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            this.worldChunkMgr = this.terrainType.getChunkManager(this.worldObj);
069        }
070    
071        /**
072         * Returns the chunk provider back for the world provider
073         */
074        public IChunkProvider getChunkProvider()
075        {
076            return this.terrainType.getChunkGenerator(this.worldObj);
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 Vec3.getVec3Pool().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    
263        /*======================================= Forge Start =========================================*/
264        private int dimensionID = 0;
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        public ChunkCoordinates getRandomizedSpawnPoint()
351        {
352            ChunkCoordinates var5 = new ChunkCoordinates(this.worldObj.getSpawnPoint());
353    
354            boolean isAdventure = worldObj.getWorldInfo().getGameType() != EnumGameType.ADVENTURE;
355            int spawnFuzz = terrainType.getSpawnFuzz();
356            int spawnFuzzHalf = spawnFuzz / 2;
357    
358            if (!this.hasNoSky && !isAdventure)
359            {
360                var5.posX += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
361                var5.posZ += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
362                var5.posY = this.worldObj.getTopSolidOrLiquidBlock(var5.posX, var5.posZ);
363            }
364    
365            return var5;
366        }
367        
368    
369        /*======================================= Start Moved From World =========================================*/
370    
371        public BiomeGenBase getBiomeGenForCoords(int x, int z)
372        {
373            return worldObj.getBiomeGenForCoordsBody(x, z);
374        }
375    
376        public boolean isDaytime()
377        {
378            return worldObj.skylightSubtracted < 4;
379        }
380    
381        @SideOnly(Side.CLIENT)
382        public Vec3 getSkyColor(Entity cameraEntity, float partialTicks)
383        {
384            return worldObj.getSkyColorBody(cameraEntity, partialTicks);
385        }
386    
387        @SideOnly(Side.CLIENT)
388        public Vec3 drawClouds(float partialTicks)
389        {
390            return worldObj.drawCloudsBody(partialTicks);
391        }
392    
393        @SideOnly(Side.CLIENT)
394        public float getStarBrightness(float par1)
395        {
396            return worldObj.getStarBrightnessBody(par1);
397        }
398    
399        public void setAllowedSpawnTypes(boolean allowHostile, boolean allowPeaceful)
400        {
401            worldObj.spawnHostileMobs = allowHostile;
402            worldObj.spawnPeacefulMobs = allowPeaceful;
403        }
404    
405        public void calculateInitialWeather()
406        {
407            worldObj.calculateInitialWeatherBody();
408        }
409    
410        public void updateWeather()
411        {
412            worldObj.updateWeatherBody();
413        }
414    
415        public void toggleRain()
416        {
417            worldObj.worldInfo.setRainTime(1);
418        }
419    
420        public boolean canBlockFreeze(int x, int y, int z, boolean byWater)
421        {
422            return worldObj.canBlockFreezeBody(x, y, z, byWater);
423        }
424    
425        public boolean canSnowAt(int x, int y, int z)
426        {
427            return worldObj.canSnowAtBody(x, y, z);
428        }
429    
430        public void setWorldTime(long time)
431        {
432            worldObj.worldInfo.setWorldTime(time);
433        }
434    
435        public long getSeed()
436        {
437            return worldObj.worldInfo.getSeed();
438        }
439    
440        public long getWorldTime()
441        {
442            return worldObj.worldInfo.getWorldTime();
443        }
444    
445        public ChunkCoordinates getSpawnPoint()
446        {
447            WorldInfo info = worldObj.worldInfo;
448            return new ChunkCoordinates(info.getSpawnX(), info.getSpawnY(), info.getSpawnZ());
449        }
450    
451        public void setSpawnPoint(int x, int y, int z)
452        {
453            worldObj.worldInfo.setSpawnPosition(x, y, z);
454        }
455    
456        public boolean canMineBlock(EntityPlayer player, int x, int y, int z)
457        {
458            return worldObj.canMineBlockBody(player, x, y, z);
459        }
460    
461        public boolean isBlockHighHumidity(int x, int y, int z)
462        {
463            return worldObj.getBiomeGenForCoords(x, z).isHighHumidity();
464        }
465    
466        public int getHeight()
467        {
468            return 256;
469        }
470    
471        public int getActualHeight()
472        {
473            return hasNoSky ? 128 : 256;
474        }
475    
476        public double getHorizon()
477        {
478            return worldObj.worldInfo.getTerrainType().getHorizon(worldObj);
479        }
480    
481        public void resetRainAndThunder()
482        {
483            worldObj.worldInfo.setRainTime(0);
484            worldObj.worldInfo.setRaining(false);
485            worldObj.worldInfo.setThunderTime(0);
486            worldObj.worldInfo.setThundering(false);
487        }
488        
489        public boolean canDoLightning(Chunk chunk)
490        {
491            return true;
492        }
493        
494        public boolean canDoRainSnowIce(Chunk chunk)
495        {
496            return true;
497        }
498    }