Creating a custom weather (1.1) [programming]

How's custom weather defined?/What it is?

When you say custom weather, it's understood( at least by ProperWeather) as an event, which modifies current weather conditions in some world and occurs with some probability.

[programming]

This section is about creating a custom weather using a plugin. As of 0.7 release, you can use YAML file to create a weather. This method is still the same, but please note custom weathers are now stored in weather_defs.yml rather than weathers.yml. ProperWeather will, however, migrate weathers.yml for you if it still exists.

Changes from 0.9 (recommended to read)

The annotation @Defaults from WeatherDefaults in Weather is not needed anymore. WeatherDefaults were changed(less parameters are now needed) and there are also small changes to the weather class.

Let's get started!

To implement a class, we should know what we're doing, so I paste Weather class here, so you'll know what to implement:

package sk.tomsik68.pw.api;

import java.util.List;

import sk.tomsik68.pw.config.WeatherDescription;
import sk.tomsik68.pw.impl.WeatherController;
import sk.tomsik68.pw.plugin.ProperWeather;

/**
 * The weather.
 * 
 * @author Tomsik68
 * 
 */
public abstract class Weather {
	private int regionID;
	protected WeatherDescription wd;

	public Weather(WeatherDescription wd1, Integer region) {
		this.regionID = region.intValue();
		this.wd = wd1;
	}

	/**
	 * 
	 * @return {@link WeatherController} to be used by the weather.
	 */
	public final WeatherController getController() {
		return ProperWeather.instance().getWeatherSystem().getWeatherController(regionID);
	}

	/**
	 * 
	 * @return Random time probability.
	 */
	public final int getRandomTimeProbability() {
		return wd.getRandomTimeProbability();
	}

	/**
	 * Inits weather (start raining etc.)
	 * 
	 */
	public abstract void doInitWeather();

	public final void initWeather() {
		List<String> elements = wd.getActiveElements();
		for (String elem : elements) {
			BaseWeatherElement element = ProperWeather.instance().getWeatherElements().get(elem).create(getController());
			getController().activateElement(element);
		}
		doInitWeather();
		getController().updateAll();
	}

	/**
	 * What happens on random time of the weather (if nothing, random time
	 * probability should be 0.
	 */
	public void onRandomTime() {
	}

	public final String getName() {
		return wd.getName();
	}

	public String toString() {
		return getName();
	}
}

Implementation of Weather method by method

Weather Defaults first

WeatherDefaults tell system, what to use first time user starts your weather. User can after that change the options in yml. Don't worry, option loading is done by ProperWeather :). What you need to do to get WeatherDefaults working is, you need to create a public static final field in your weather class. The field MUST be

public static final

and its superinterface must be sk.tomsik68.api.WeatherDefaults. The default and mostly used implementation is sk.tomsik68.pw.impl.BasicWeatherDefaults. So just define your options and continue:

public static final WeatherDefaults def = new BasicWeatherDefaults(35);

The code above says that random time probability is 35%.

doInitWeather()

Your weather was chosen by system( or user ;) ) to run. You need to start the basic conditions of your weather. Example Usages: Change sky color, Start raining, Allow Thunders,... Example Implementation:

    public void doInitWeather(){
          WeatherController wc = getController();
          wc.clear();
          wc.allowThundering();
          wc.setSkyColor(java.awt.Color.BLACK);
    }

onRandomTime()

Here we get to previously mentioned random time. Example Usages: Thundering, Falling Meteorite, Spawning Custom Entities,... Example Implementation(with thunders):

public void onRandomTime() {
		final WeatherController controller = getController();
                final World world = controller.getRegion().getWorld();
                final Region region = controller.getRegion();
                final Random rand = new Random(world.getSeed() * world.getFullTime());
                for (BlockState blockState : region) {
                      if (blockState == null)
                          continue;
                      if (rand.nextInt(100000) != 0 || blockState.getType() == Material.SAND)
                          continue;
                      controller.strike(blockState.getLocation());
                }
	}

You are free to use bukkit's block and entities API in this, as it doesn't run on separate thread anymore, so everything is safe :)

How to register weather?

So far, we've implemented our weather, but that's not enought, because ProperWeather can't find it itself, so registration is needed. Luckily, I've made the registration simple:

                        WeatherFactoryRegistry registry = ProperWeather.instance().getWeathers();
                        registry.registerClass(MyWeather.class);

Let's add the code into main skeleton:

import sk.tomsik68.pw.WeatherManager
import sk.tomsik68.pw.plugin.ProperWeather;
// you can call this method in onEnable
public void setupBridge() {
		Plugin test = getServer().getPluginManager().getPlugin("ProperWeather");
		if (test != null && test instanceof ProperWeather) {
			ProperWeather pw = (ProperWeather) test;
                        WeatherFactoryRegistry registry = ProperWeather.instance().getWeathers();
                        registry.registerClass(MyWeather.class);
                        getLogger().info("Hooked into ProperWeather");
		}
	}

Also, don't forget to put

ProperWeather
to dependencies in plugin.yml!

Cheers!

You've just made your first (and hopefully not last) Weather for Minecraft! Now go ahead, compile it and try it. If you've got any questions, suggestions or anything to tell me, just PM me or comment ProperWeather.


Comments

Posts Quoted:
Reply
Clear All Quotes