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