Minecraft Modding: Sky and Weather

Changing The Sky and Weather


The "sky" in Minecraft consists of the sun, moon/star textures plus the clouds. To change these, you should make a custom dimension (look up tutorials on that but basically the idea is you register a WorldProvider class to a dimension ID) and then in your custom WorldProvider class you can override the following methods to change the sky rendering:
  • getSunTexture()-- @Override this to return your own texture resource
  • getMoonTexture()-- @Override this to return your own texture resource
  • setSkyRenderer()
  • setCloudRenderer()
  • setWeatherRenderer()
For each of these renderer methods, you could return your own renderers (which should extend IRenderHandler).

Other interesting stuff related to sky in WorldProvider class (you could extend the class and @Override these to customize them):
  • getHasNoSky() -- if true, then weather isn't used and sky-based lighting is not calculated.
  • calcSunriseSunsetColors() can use the celestial angle to add a tint to the sky.
  • getSkyColor()
  • isSkyColored()
  • getSunBrightness()
  • getStarBrightness()
  • getCloudHeight()
  • drawClouds()
  • updateWeather()
  • canDoLightning() and canDoRainSnowIce() tell whether those weather effects should be allowed.
  • canSnowAt() controls whether the snow is allowed at a specific location.
Anyway, you can see that there is a lot of control over the sky, clouds and weather possible by combining these various methods.

Example Approach -- Custom Cloud Renderer


The setCloudRenderer() method is a Forge hook. If no renderer is set by a mod (vanilla never calls this method) then it is null. This is handled later during actual rendering where in FMLClientHandler the renderCloud() method checks for null and if it is null then it creates a new CloudRenderer instance. If it is not null then it will use the IRenderHandler class you gave it in setCloudRenderer(). In both cases, it calls a render() method but technically as you noted these are different classes that don't share a type hierarchy.

In other words, for mods it will call an IRenderHandler#render() and for vanilla it calls a CloudRenderer#render() function.

 This means that you cannot just instantiate, copy or extend CloudRenderer class and pass that to setCloudRenderer() because that expects an IRenderHandler. Instead you should probably do this by "wrapping" a CloudRenderer instance in an IRenderHandler implementation.

So like this:

  1. create a custom CloudRenderer class called something like CloudRendererCustom that extends CloudRenderer. You would override the render() method to make any changes you wanted to the way clouds look.
  2. create an IRenderHandler implementation called something like CloudRenderHandler. The implementation would do two things:
    • create an instance of a CloudRendererCustom from Step #1, and
    • it would implement a render() function that simply calls the render() function of that CloudRendererCustom instance.
  3. call the setCloudRenderer() method on the WorldProvider at the time the world is created, passing an instance of CloudRenderHandler from Step #2.


Key Point: You're just making an IRender implementation that calls the render() method of a custom CloudRenderer extended class.

Changing The Frequency That Sky "Time" Is Updated


Many people update the sky time on the server (e.g. in WorldTickEvent) every tick but the server only syncs time with the client once every 20 ticks = 1 second. If for some reason you need immediate or different interval of update you can have the server send an SPacketTimeUpdate to all players in the dimension manually, or also update the time on the client.

4 comments:

  1. Was the tutorial made?

    ReplyDelete
  2. Hi can you give me an example so I can reproduce it? Thank you

    ReplyDelete
  3. Hi i try to change the sun light can anyone help me pls my dc tag: MrScautHD#0350

    ReplyDelete