Events

MythicSeasons fires five Bukkit events, see API for setup. Calendar events are named periods such as Christmas, set up in plugins/MythicSeasons/events/.

Overview

Event Package Cancellable Fires
SeasonChangeEvent net.taiyou.mythicseasons.api Yes Before a world changes season.
SeasonRefreshChunkEvent net.taiyou.mythicseasons.event Yes Before a chunk is sent again to a player after a season or sub-season change.
DayChangeEvent net.taiyou.mythicseasons.calendar No Before the in-game date of a world changes.
SeasonEventStart net.taiyou.mythicseasons.api Yes Before a calendar event starts in a world.
SeasonEventEnd net.taiyou.mythicseasons.api No When a calendar event ends in a world.

Common to all events

  • All five fire on the server main thread, never asynchronously, so listeners may use the Bukkit API.
  • They extend org.bukkit.event.Event, with the static getHandlerList() and the getHandlers() method. The cancellable ones implement org.bukkit.event.Cancellable (isCancelled(), setCancelled(boolean)).
  • Date, Season and SeasonCustomEvent are listed under Supporting types.

What MythicSeasons does with its own events

Event What happens Priority Cancelled events
SeasonChangeEvent Runs the old season's season-end skill triggers, and one tick later the new season's season-start triggers, cast by the first player in the world. Needs MythicMobs and a player in the world, see Triggers. MONITOR Skipped
DayChangeEvent Updates the base temperature (temperature system on), the season (automatic-season-cycling on) and the calendar events, then checks the sub-season one tick later. NORMAL Not cancellable
SeasonEventStart Sends the MythicMobs signal startEvent_<id> to every active mob in the world. NORMAL Not skipped
SeasonEventEnd Sends the MythicMobs signal endEvent_<id> to every active mob in the world. NORMAL Not applicable
SeasonRefreshChunkEvent No listener. The chunk is sent after the event unless a listener cancelled it. none none

Season events

SeasonChangeEvent

Cancellable. Also fires for a change to or from no season.

new SeasonChangeEvent(World w, Season newSeason, Season oldSeason)
new SeasonChangeEvent(World w, Season newSeason, Season oldSeason, String newSeasonId, String oldSeasonId)

MythicSeasons always uses the second constructor. The first leaves both ids null.

Method Returns Description
getWorld() World The world that changes season.
getNewSeason() Season ACTIVE, or DISABLED when the world ends up with no season.
getOldSeason() Season ACTIVE, or DISABLED when the world had no season.
getNewSeasonId() String The new season's id, disabled for none.
getOldSeasonId() String The old season's id, disabled for none.
isCancelled() boolean Whether a listener cancelled the change.
setCancelled(boolean) void Cancels the change or restores it.

It fires when:

  • The calendar moves the world into another season (needs automatic-season-cycling in config.yml and an enabled calendar).
  • /ms set, /ms nextseason, /ms disable or SeasonsAPI.setSeason(world, Season.DISABLED) runs.
  • A world gets its starting season from on-new-world-creation.default-season in config.yml (at startup for loaded worlds with no saved season, and on world creation) or on-new-world-creation.sync-with-other-worlds (the calendar's season for a new world).

It does not fire when the new id equals the current one. Inside the listener SeasonsAPI.getSeasonId(world) still returns the old id.

SeasonRefreshChunkEvent

Cancellable. Fires before MythicSeasons sends a chunk again so the player sees the new seasonal colours.

new SeasonRefreshChunkEvent(Chunk chunk, Player player)
Method Returns Description
getChunk() Chunk The chunk about to be sent again.
getPlayer() Player The player who receives it.
isCancelled() boolean Whether a listener cancelled the refresh.
setCancelled(boolean) void Cancels the refresh or restores it.

Each player in the world gets the loaded chunks within the server view distance again, one chunk every 2 ticks per world. A cancelled chunk keeps the old colours until it is sent to that player again.

Calendar events

DayChangeEvent

Not cancellable. Fires before the new date is stored.

new DayChangeEvent(World w, Date from, Date to)
Method Returns Description
getWorld() World The world whose date changes.
getFrom() Date The date before the change.
getTo() Date The date after the change.

It fires when:

  • A world with a season passes in-game midnight (world time 18000). This is the default and needs enabled: true in calendar.yml.
  • A real-life day ends with calendar-is-real-life-days: true in calendar.yml. After a stop of several days, to can be several days after from.
  • A real-life day ends with sync-time-with-real-world: true in calendar.yml: once per world with a season entry, while modify-daynight-length or modify-weather-cycle in config.yml is true (both default to true).
  • A date is set by SeasonsAPI.setDate, /ms setdate, /ms nextseason (first day of the next season), /ms set (middle of the season, only while sub-seasons.enabled is on and the calendar is enabled), or the copy between the worlds under synced-worlds in calendar.yml.

A world's first date fires no event. Inside the listener SeasonsAPI.getDate(world) still returns from, except with sync-time-with-real-world: true, where it reads the real date. Check getFrom() and getTo() for null.

SeasonEventStart

Cancellable. Fires before the calendar event becomes active.

new SeasonEventStart(World w, SeasonCustomEvent e, String eventId)
Method Returns Description
getWorld() World The world where the event starts.
getEventId() String The id of the event file, in lower case.
getCustomEvent() SeasonCustomEvent The calendar event: display name, display flag, start and stop lines.
isCancelled() boolean Whether a listener cancelled the start.
setCancelled(boolean) void Cancels the start or restores it.

It fires on a day change, once for each event file that starts in the world, see Events.

It never fires in worlds under disabled-worlds in the event file. Worlds under worlds-without-events in calendar.yml get it and the event becomes active, but its start lines do not run. An event already running at server start or /ms reload becomes active again without SeasonEventStart.

Cancelling keeps the event inactive: it is missing from getActiveEvents, the isevent condition stays false and the start lines do not run. Mobs still receive startEvent_<id>, and when the schedule ends SeasonEventEnd still fires and the stop lines run.

Inside the listener the event is not active yet, so SeasonsAPI.getActiveEvents(world) does not list it. SeasonCustomEvent.getCommands(boolean) is the event's own list: copy it before you change it, or the change stays until the next reload.

SeasonEventEnd

Not cancellable. Fires when the calendar event ends.

new SeasonEventEnd(World w, SeasonCustomEvent e, String eventId)
Method Returns Description
getWorld() World The world where the event ends.
getEventId() String The id of the event file, in lower case.
getCustomEvent() SeasonCustomEvent The event that ends.

It fires on the day change that ends the event's schedule, and never for a daily event, which does not end. The disabled-worlds and worlds-without-events rules are those of SeasonEventStart.

Inside the listener the event is still active (isevent is true, and SeasonsAPI.getActiveEvents(world) lists it when it has display-event: true), unless its start was cancelled.

Example listener

import net.taiyou.mythicseasons.api.SeasonChangeEvent;
import net.taiyou.mythicseasons.api.SeasonEventStart;
import net.taiyou.mythicseasons.calendar.DayChangeEvent;
import net.taiyou.mythicseasons.calendar.Date;
import net.taiyou.mythicseasons.event.SeasonRefreshChunkEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

import java.util.logging.Logger;

public final class SeasonsListener implements Listener {

    private final Logger logger;

    public SeasonsListener(Logger logger) {
        this.logger = logger;
    }

    @EventHandler
    public void onSeasonChange(SeasonChangeEvent event) {
        logger.info(event.getWorld().getName() + ": " + event.getOldSeasonId() + " to " + event.getNewSeasonId());
    }

    @EventHandler
    public void onEventStart(SeasonEventStart event) {
        logger.info(event.getWorld().getName() + ": event " + event.getEventId()
                + " (" + event.getCustomEvent().getName() + ") starts");
    }

    @EventHandler
    public void onDayChange(DayChangeEvent event) {
        Date to = event.getTo();
        if (to != null) {
            logger.info(event.getWorld().getName() + ": day " + to.getDay() + " of month " + to.getMonth());
        }
    }

    @EventHandler
    public void onRefresh(SeasonRefreshChunkEvent event) {
        if (event.getPlayer().hasPermission("myserver.noseasonrefresh")) {
            event.setCancelled(true);
        }
    }
}

Players with myserver.noseasonrefresh keep the old colours until their chunks are sent again.

Register it from your plugin's onEnable:

getServer().getPluginManager().registerEvents(new SeasonsListener(getLogger()), this);
Updated Nov 11, 2026