Weather Providers

A weather provider answers MythicSeasons' weather questions for a location. See API for setup.

How a question is answered

The WeatherRegistry asks its providers by priority, highest first, and returns the first answer that is not null (false, 0 and 0.0 are answers). When no provider answers, it returns null.

Built-in providers

Priority Provider Answers Returns null when
1000 Permanent weather spots isRaining, isThundering No WorldGuard region with the permanent-weather flag at the middle column of the location's chunk, at the world's sea level, or no WorldGuard support (it needs WorldGuard and WorldEdit). See AtmosphereSpot.
100 Atmosphere simulation All six The simulation is off, does not run in the world or has no weather there yet, or a WorldGuard region sets season-atmosphere to deny (Land Claims).
0 Your provider, unless it sets a priority What you answer You have nothing to say.

The simulation answers snow only where it also answers rain, and rain, snow and thunder only where its first solid cloud layer (the first in clouds.layers with opacity: 1.0) draws cloud above the location.

WeatherProvider

WeatherProvider (in net.taiyou.mythicseasons.api.weather) has only default methods: the six questions return null and priority() returns 0. Override what you answer, in a class, since it cannot be a lambda.

Method Returns Answers Unit
priority() int Where the provider ranks. Higher is asked first. Default 0. none
isRaining(Location loc) Boolean Whether it rains at loc. none
isSnowing(Location loc) Boolean Whether the precipitation at loc falls as snow. none
isThundering(Location loc) Boolean Whether a thunderstorm is overhead at loc. none
isInCloud(Location loc) Boolean Whether loc is inside a cloud. none
airTemperature(Location loc) Integer The air temperature at loc. Whole degrees Celsius
surfaceWindSpeed(Location loc) Double The wind speed at the ground at loc. Metres per second
  • Return null when loc.getWorld() is null.
  • null passes a question on, false answers it: a provider that returns false for isRaining in a world keeps the simulation from answering that question there.
  • Conditions test each question on its own, so answer isSnowing as true only where isRaining is also true, as the simulation does.

Priority

  • Above 100, your provider overrides the simulation. Above 1000, it overrides permanent spots.
  • Below 100 (the default is 0), it answers only where the simulation has no answer, such as worlds without the simulation.
  • Providers with the same priority are asked in the order they registered. MythicSeasons registers the built-in ones after every plugin has enabled, so at 100 or 1000 a provider registered in onEnable is asked before them.
  • The registry reads priority() only when providers register, not on every question, so return a constant.

Registering

Register in your onEnable and unregister in your onDisable:

WeatherRegistry registry = SeasonsAPI.getInstance().getWeatherRegistry();
registry.register(provider);
registry.unregister(provider);
Method Returns Description
register(WeatherProvider provider) void Adds the provider unless an equal one is registered, then sorts all providers by priority().
unregister(WeatherProvider provider) void Removes the provider, if registered.

Both methods are safe from any thread and never block a question being answered. Registrations survive /ms reload, but not MythicSeasons being disabled and enabled again.

Reading the answers

The registry has one query method per question, returning null when no provider answered.

Method Returns
isRaining(Location loc) Boolean
isSnowing(Location loc) Boolean
isThundering(Location loc) Boolean
isInCloud(Location loc) Boolean
airTemperature(Location loc) Integer
surfaceWindSpeed(Location loc) Double
Boolean raining = SeasonsAPI.getInstance().getWeatherRegistry().isRaining(player.getLocation());

Use WeatherState to get a fallback.

WeatherState

WeatherState is a final class of static methods that ask the registry and fall back to the server when no provider answers, like MythicSeasons' own conditions and placeholders. The first argument is MythicSeasons.getInstance() (from net.taiyou.mythicseasons). Call it only after MythicSeasons has finished starting.

Method Returns When no provider answers
isRaining(MythicSeasons main, Location loc) boolean world.hasStorm(), or false when the location has no world.
isSnowing(MythicSeasons main, Location loc) boolean world.hasStorm() and a biome temperature below 0.15 at the block, or false when the location has no world.
isThundering(MythicSeasons main, Location loc) boolean world.isThundering(), or false when the location has no world.
isInCloud(MythicSeasons main, Location loc) boolean false.
airTemperature(MythicSeasons main, Location loc) Integer The temperature system's air temperature, or null when that system is off (enabled: false in temperature.yml).
airTemperature(MythicSeasons main, Entity e) Integer Whether or not a provider answers: the Location form at the entity's position, plus, for a player, the warmth of their blockheat lines with air=true while the temperature system is on. null when the Location form is null.
surfaceWindSpeed(MythicSeasons main, Location loc) double 0.0.

With WorldGuard support loaded, isRaining and isThundering throw a NullPointerException for a location without a world, because the permanent spot provider is asked first.

boolean raining = WeatherState.isRaining(MythicSeasons.getInstance(), player.getLocation());
Integer air = WeatherState.airTemperature(MythicSeasons.getInstance(), player.getLocation());

Where the answers are used

Question Used by
isRaining The raining test of the Atmosphere condition, the MythicMobs conditions raining and sunny, the weather each player sees, and the atmosphere-rain-start and atmosphere-rain-stop triggers.
isSnowing The snowing test of atmosphere, the MythicMobs condition snowing, and the atmosphere-snow-start and atmosphere-snow-stop triggers.
isThundering The storm test of atmosphere, the MythicMobs conditions thundering and stormy, the placeholders <mythicseasons.storm> and %ms_storm%, the thunder each player sees, and the atmosphere-storm-start and atmosphere-storm-stop triggers.
isInCloud The incloud test of atmosphere, the placeholders <mythicseasons.incloud> and %ms_in_cloud%, and the atmosphere-cloud-enter and atmosphere-cloud-exit triggers.
airTemperature The AtmosphereTemp condition and the placeholders <mythicseasons.airtemperature> and %ms_atmosphere_temperature%.
surfaceWindSpeed The AtmosphereWind condition and the placeholders <mythicseasons.windspeed> and %ms_wind_speed%.

Three of these differ:

  • The weather a player sees follows the providers only while the atmosphere is on (enabled: true in atmosphere.yml) and a skill with the atmosphereweather mechanic, such as the bundled MS_Atmosphere, runs for the player. Thunder shows only while it rains. Without an isRaining answer the player gets the server weather back, and with the atmosphere off the mechanic restores it for every player.
  • The skill triggers read the registry without the vanilla fallback of WeatherState. Without an answer, rain, snow, storm and cloud count as absent, so a player who was in one gets its stop or exit trigger.
  • The MythicMobs conditions raining, sunny, snowing and thundering follow the providers only on a MythicMobs build that lets plugins replace its built-in conditions. On other builds they read the vanilla weather, with a warning at startup.

While the simulation still loads the area around a player, the first two keep that player's last state for up to 30 seconds.

These skip the providers and read the simulation or the temperature system directly: wind direction, humidity, precipitation, cloud cover, cloud base and top, the wind push of the atmospherewind mechanic, and %ms_air_temperature%.

Threads

A provider is called on the thread that asks, never moved to the main thread:

  • The main thread, for the weather skill triggers.
  • The thread MythicMobs runs a skill on, for its conditions, placeholders and the atmosphereweather mechanic.
  • The thread PlaceholderAPI is called on.

The weather triggers and the skills under skill-triggers.player-tick, such as MS_Atmosphere, ask several times for each player in a world with a season, every performance.skill-trigger-interval ticks (default 5).

So keep it thread-safe and fast: no blocking, no file or network access, and no reading of blocks, chunks or entities through the Bukkit API. Answer from a field you replace as a whole, such as a volatile reference to an immutable object updated on the main thread.

Example

A provider that fixes the weather in chosen worlds, ranked between the simulation and permanent spots:

import net.taiyou.mythicseasons.api.weather.WeatherProvider;
import org.bukkit.Location;
import org.bukkit.World;

import java.util.Set;

public final class FixedWeatherProvider implements WeatherProvider {

    private final Set<String> worlds;

    public FixedWeatherProvider(Set<String> worlds) {
        this.worlds = Set.copyOf(worlds);
    }

    @Override
    public int priority() {
        return 200;
    }

    @Override
    public Boolean isRaining(Location loc) {
        return fixed(loc) ? Boolean.FALSE : null;
    }

    @Override
    public Boolean isSnowing(Location loc) {
        return fixed(loc) ? Boolean.FALSE : null;
    }

    @Override
    public Boolean isThundering(Location loc) {
        return fixed(loc) ? Boolean.FALSE : null;
    }

    @Override
    public Integer airTemperature(Location loc) {
        return fixed(loc) ? Integer.valueOf(22) : null;
    }

    @Override
    public Double surfaceWindSpeed(Location loc) {
        return fixed(loc) ? Double.valueOf(0.0) : null;
    }

    private boolean fixed(Location loc) {
        World world = loc.getWorld();
        return world != null && worlds.contains(world.getName());
    }
}

Other worlds, and isInCloud everywhere, keep the simulation's answers.

import net.taiyou.mythicseasons.api.SeasonsAPI;
import net.taiyou.mythicseasons.api.weather.WeatherProvider;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.Set;

public final class MyPlugin extends JavaPlugin {

    private WeatherProvider provider;

    @Override
    public void onEnable() {
        provider = new FixedWeatherProvider(Set.of("minigame"));
        SeasonsAPI.getInstance().getWeatherRegistry().register(provider);
    }

    @Override
    public void onDisable() {
        SeasonsAPI.getInstance().getWeatherRegistry().unregister(provider);
    }
}

The plugin names MythicSeasons in depend in its plugin.yml.

Updated Nov 11, 2026