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 the chunk provider back for the world provider
073         */
074        public IChunkProvider getChunkProvider()
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        /**
265         * Sets the providers current dimension ID, used in default getSaveFolder()
266         * Added to allow default providers to be registered for multiple dimensions.
267         * 
268         * @param dim Dimension ID
269         */
270        public void setDimension(int dim)
271        {
272            this.dimensionId = dim;
273        }
274    
275        /**
276         * Returns the sub-folder of the world folder that this WorldProvider saves to.
277         * EXA: DIM1, DIM-1
278         * @return The sub-folder name to save this world's chunks to.
279         */
280        public String getSaveFolder()
281        {
282            return (dimensionId == 0 ? null : "DIM" + dimensionId);
283        }
284    
285        /**
286         * A message to display to the user when they transfer to this dimension.
287         *
288         * @return The message to be displayed
289         */
290        public String getWelcomeMessage()
291        {
292            if (this instanceof WorldProviderEnd)
293            {
294                return "Entering the End";
295            }
296            else if (this instanceof WorldProviderHell)
297            {
298                return "Entering the Nether";
299            }
300            return null;
301        }
302    
303        /**
304         * A Message to display to the user when they transfer out of this dismension.
305         *
306         * @return The message to be displayed
307         */
308        public String getDepartMessage()
309        {
310            if (this instanceof WorldProviderEnd)
311            {
312                return "Leaving the End";
313            }
314            else if (this instanceof WorldProviderHell)
315            {
316                return "Leaving the Nether";
317            } 
318            return null;
319        }
320    
321        /**
322         * The dimensions movement factor. Relative to normal overworld.
323         * It is applied to the players position when they transfer dimensions.
324         * Exa: Nether movement is 8.0
325         * @return The movement factor
326         */
327        public double getMovementFactor()
328        {
329            if (this instanceof WorldProviderHell)
330            {
331                return 8.0;
332            }
333            return 1.0;
334        }
335    
336        @SideOnly(Side.CLIENT)
337        public SkyProvider getSkyProvider()
338        {
339            return this.skyProvider;
340        }
341    
342        @SideOnly(Side.CLIENT)
343        public void setSkyProvider(SkyProvider skyProvider)
344        {
345            this.skyProvider = skyProvider;
346        }
347    
348        public ChunkCoordinates getRandomizedSpawnPoint()
349        {
350            ChunkCoordinates var5 = new ChunkCoordinates(this.worldObj.getSpawnPoint());
351    
352            boolean isAdventure = worldObj.getWorldInfo().getGameType() == EnumGameType.ADVENTURE;
353            int spawnFuzz = terrainType.getSpawnFuzz();
354            int spawnFuzzHalf = spawnFuzz / 2;
355    
356            if (!hasNoSky && !isAdventure)
357            {
358                var5.posX += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
359                var5.posZ += this.worldObj.rand.nextInt(spawnFuzz) - spawnFuzzHalf;
360                var5.posY = this.worldObj.getTopSolidOrLiquidBlock(var5.posX, var5.posZ);
361            }
362    
363            return var5;
364        }
365    
366        /*======================================= Start Moved From World =========================================*/
367    
368        public BiomeGenBase getBiomeGenForCoords(int x, int z)
369        {
370            return worldObj.getBiomeGenForCoordsBody(x, z);
371        }
372    
373        public boolean isDaytime()
374        {
375            return worldObj.skylightSubtracted < 4;
376        }
377    
378        @SideOnly(Side.CLIENT)
379        public Vec3 getSkyColor(Entity cameraEntity, float partialTicks)
380        {
381            return worldObj.getSkyColorBody(cameraEntity, partialTicks);
382        }
383    
384        @SideOnly(Side.CLIENT)
385        public Vec3 drawClouds(float partialTicks)
386        {
387            return worldObj.drawCloudsBody(partialTicks);
388        }
389    
390        @SideOnly(Side.CLIENT)
391        public float getStarBrightness(float par1)
392        {
393            return worldObj.getStarBrightnessBody(par1);
394        }
395    
396        public void setAllowedSpawnTypes(boolean allowHostile, boolean allowPeaceful)
397        {
398            worldObj.spawnHostileMobs = allowHostile;
399            worldObj.spawnPeacefulMobs = allowPeaceful;
400        }
401    
402        public void calculateInitialWeather()
403        {
404            worldObj.calculateInitialWeatherBody();
405        }
406    
407        public void updateWeather()
408        {
409            worldObj.updateWeatherBody();
410        }
411    
412        public void toggleRain()
413        {
414            worldObj.worldInfo.setRainTime(1);
415        }
416    
417        public boolean canBlockFreeze(int x, int y, int z, boolean byWater)
418        {
419            return worldObj.canBlockFreezeBody(x, y, z, byWater);
420        }
421    
422        public boolean canSnowAt(int x, int y, int z)
423        {
424            return worldObj.canSnowAtBody(x, y, z);
425        }
426    
427        public void setWorldTime(long time)
428        {
429            worldObj.worldInfo.setWorldTime(time);
430        }
431    
432        public long getSeed()
433        {
434            return worldObj.worldInfo.getSeed();
435        }
436    
437        public long getWorldTime()
438        {
439            return worldObj.worldInfo.getWorldTime();
440        }
441    
442        public ChunkCoordinates getSpawnPoint()
443        {
444            WorldInfo info = worldObj.worldInfo;
445            return new ChunkCoordinates(info.getSpawnX(), info.getSpawnY(), info.getSpawnZ());
446        }
447    
448        public void setSpawnPoint(int x, int y, int z)
449        {
450            worldObj.worldInfo.setSpawnPosition(x, y, z);
451        }
452    
453        public boolean canMineBlock(EntityPlayer player, int x, int y, int z)
454        {
455            return worldObj.canMineBlockBody(player, x, y, z);
456        }
457    
458        public boolean isBlockHighHumidity(int x, int y, int z)
459        {
460            return worldObj.getBiomeGenForCoords(x, z).isHighHumidity();
461        }
462    
463        public int getHeight()
464        {
465            return 256;
466        }
467    
468        public int getActualHeight()
469        {
470            return hasNoSky ? 128 : 256;
471        }
472    
473        public double getHorizon()
474        {
475            return worldObj.worldInfo.getTerrainType().getHorizon(worldObj);
476        }
477    
478        public void resetRainAndThunder()
479        {
480            worldObj.worldInfo.setRainTime(0);
481            worldObj.worldInfo.setRaining(false);
482            worldObj.worldInfo.setThunderTime(0);
483            worldObj.worldInfo.setThundering(false);
484        }
485        
486        public boolean canDoLightning(Chunk chunk)
487        {
488            return true;
489        }
490        
491        public boolean canDoRainSnowIce(Chunk chunk)
492        {
493            return true;
494        }
495    }