Skip to content
RockPunkMC edited this page Sep 11, 2026 · 1 revision

EventClockRK Wiki

Version 1.0.0 · English documentation

A configurable event clock for Paper/Spigot, with cooldowns, five-field UNIX CRON, optional PlaceholderAPI, and YAML persistence. No database, GUI, permission nodes, or global polling loop.

Contents

Upgrading to 1.0.0

Stop the server, remove the previous plugin jar, install EventClockRK-1.0.0.jar, then start again. Keep the entire plugins/EventClockRK folder, including event definitions, schedules, and data. The alias is now /ecrk; /eventclock remains available and /ec is no longer registered.

Text timers now hide leading zero units by default: 0d 0h 5m 0s becomes 5m 0s, while 2h 0m 15s keeps its intermediate zero. time-units.hide-leading-zero defaults to true even in existing configurations where the key is absent. Set it to false to restore leading zeros. Keep time-units.hide-zero: false to preserve intermediate/trailing zeros; true still hides all zero units. Numeric seconds and fixed clock format are unchanged.

Installation

  1. Use a server runtime compatible with Java 17 or newer. Recent Minecraft versions can require Java 21; follow your server's Java requirement. This plugin's bytecode targets Java 17.
  2. Put EventClockRK-1.0.0.jar in the server's plugins folder and start the server.
  3. Edit the generated YAML files in plugins/EventClockRK/. The example is disabled by default.
  4. Run /ecrk reload from the server console or as an OP player. Use /ecrk list and /ecrk info <id> to inspect events.
  5. Optional: install PlaceholderAPI on your server. EventClockRK registers its own placeholders automatically; no expansion download is needed for EventClockRK itself. Other plugins' placeholders need their own integrations/expansions.

The compatibility target is Paper/Spigot 1.16–1.21.x, using the Spigot 1.16.5 API without NMS or version-specific code. This release has automated tests against that API and a simulated Bukkit adapter; it has not been run on a live server for every version. Folia is outside this compatibility target. Older server builds must themselves support the chosen Java runtime.

Quick start: a fortnightly KeyAll

This example runs every two weeks on Friday at 1:15 AM in Lima, anchored to September 11, 2026.

Create the event

Create plugins/EventClockRK/events/keyall.yml:

keyall:
  enabled: true
  repeat: true
  duration: 0
  cooldown: 0
  worlds: []
  min-players-online: 1
  alerts: [300, 60]
  broadcast-message: '&aThe scheduled event has started!'
  actions:
    - 'say Hello from EventClockRK!'
  end-actions: []
  end-broadcast-message: ''
  cancel-broadcast-message: ''

The action above is a test message, not a key reward. Replace it with your reward plugin's actual command. EventClockRK does not include a crate or key system.

Configure the schedule

In plugins/EventClockRK/schedulers.yml:

timezone: America/Lima

keyall-fortnightly:
  times:
    - '15 1 * * 5'
  interval-weeks: 2
  reference-date: '2026-09-11'
  random: false
  events:
    - keyall

Keep one top-level timezone setting when adding more schedules. The event's cooldown: 0 is valid because this scheduler references it.

The sequence includes September 11, September 25, October 9, and so on. Loading this configuration later uses the next future occurrence; missed dates are not replayed.

Load and test

/ecrk reload
/ecrk info keyall
/ecrk forcetrigger keyall

The force command immediately executes the configured actions. It does not change the fortnightly CRON calendar.

With PlaceholderAPI installed, test the countdown and next date in-game:

/papi parse me %keyall_time%
/papi parse me %keyall_next_datetime%

At least one eligible player must be online for the automatic occurrence in this example. If no eligible player is online, that occurrence is skipped.

Files

plugins/EventClockRK/
  config.yml          # Global display settings; English defaults
  messages.yml        # Internal messages, statuses, and time-unit labels
  schedulers.yml      # One timezone and any number of CRON schedules
  events/
    example.yml       # Generated only when the directory is empty
    anything.yml      # Each top-level key defines a separate event ID
  data/
    event-id.yml      # Automatically generated state; do not edit

Event IDs use lowercase letters, numbers, _ and -, up to 64 characters, starting with a letter or number. File-reserved names are rejected. IDs are case-sensitive. Event filenames do not determine IDs. Duplicate IDs are logged with their file; the first declaration in sorted filename order wins.

Malformed events and broken scheduler references are reported individually, and valid entries load. Invalid global YAML or timezone aborts reload before replacing the running engine. A malformed data file disables its event instead of silently resetting its history. Removing an event definition removes its data on successful reload; invalid declarations preserve their data, and an unreadable event file suppresses orphan cleanup.

Event example

keyall:
  enabled: true
  repeat: true
  duration: 0
  cooldown: 259200
  worlds: []
  min-players-online: 1
  alerts: [600, 300, 60]
  broadcast-message: '<green>A key for everyone!'
  actions:
    - 'your-key-plugin give %player% vote 1'
  end-actions: []
  end-broadcast-message: ''
  cancel-broadcast-message: ''

Replace the example action with your key plugin's actual command. enabled, repeat, duration, cooldown, worlds, min-players-online, alerts, broadcast-message, and actions are required with the types shown. Empty action/message lists are allowed. End/cancellation fields are optional. Time fields contain integer seconds. Duration 0 means instantaneous; cooldown must be positive unless a valid CRON scheduler controls the event.

Scheduling and lifecycle

  • Cooldowns run from the start of one event to the next due start, including offline time. An overdue cooldown fires once on return; it does not replay every missed interval.
  • If a due cooldown lacks players, it waits without polling. Joining or changing worlds rechecks waiting events. If a CRON occurrence lacks players, that occurrence is skipped.
  • Any valid scheduler reference overrides the event's cooldown. CRON missed while the plugin was stopped or the event was paused is skipped.
  • An already active event ignores every additional start attempt, including forced attempts. A skipped cooldown attempt schedules the next full interval; a skipped CRON occurrence waits for its next occurrence.
  • pause freezes remaining cooldown time and suppresses automatic CRON starts, while an active duration keeps running. resume restores the frozen cooldown or waits for the next future CRON occurrence.
  • repeat: false persists completion after its first start, including across reloads/restarts. resetcooldown does not clear completion. A force command can explicitly run it again.
  • forcetrigger bypasses disabled, paused, completed, and minimum-player restrictions. It retains pause/disabled settings and resets a cooldown from that forced start. It still respects world scope and active conflicts.
  • Active durations resume after a restart. If one expired offline, its end actions run once when loading; they are not replayed on subsequent restarts.
  • Cancel runs end-actions with %cancelled% = true, plus cancel-broadcast-message. An empty cancellation message uses the internal event-cancelled message. It never broadcasts the natural completion text. Natural endings use %cancelled% = false and end-broadcast-message, falling back to event-ended when empty.
  • State is saved on transitions using a temporary YAML file and atomic replacement where supported. Like external console commands generally, actions cannot provide a transactional exactly-once guarantee across a sudden process crash. State is committed before dispatch to avoid blindly duplicating rewards after a crash.

Every cooldown or CRON schedule uses a one-shot scheduled wakeup; durations and advance alerts have their own one-shot tasks. There is no repeating tick/second scan. Bukkit timers have tick resolution and depend on server TPS, so lag can delay execution. An early wake caused by a backward clock change is rescheduled. No real-time precision beyond the server scheduler is promised.

CRON

timezone: America/Lima

keyall-thursday:
  times: ['0 14 * * 4']
  random: false
  events: [keyall]

fortnightly-raid:
  times: ['0 20 * * 0']
  interval-weeks: 2
  reference-date: '2026-09-13'
  random: false
  events: [raidboss]

Create raidboss in an event file before enabling that schedule. Fields are minute, hour, day of month, month, weekday (0 Sunday–6 Saturday). Numeric values, *, lists, ranges, and steps are supported, e.g. */15 8-20 * * 1-5. When both day-of-month and weekday are restricted, UNIX OR matching is used. Named weekdays/months, 7 for Sunday, Quartz ?, L, W, and # are not accepted.

interval-weeks and quoted reference-date must be supplied together. Seven-day blocks are counted from that exact date, with no occurrences before it; matching blocks have an index divisible by the interval. Intervals range from 1 to 5200 weeks. Search is bounded to 400 years to reject impossible calendars. In DST zones, nonexistent local times are skipped and each instant of a repeated local time is a separate occurrence.

random: true chooses one entry from the full configured valid event list. If that entry is disabled, paused, completed, active, or lacks players, that occurrence is skipped without rerolling. random: false attempts all entries. Identical expressions within a scheduler cause one occurrence, while separate schedulers are independent. Time/progress/date placeholders and pre-start alerts are suppressed for any event referenced by a random scheduler; its status remains available.

World scope and actions

worlds: [] means all loaded worlds. Otherwise, only online players in named worlds count toward the minimum, appear in online variables, receive messages, and participate in player actions.

Variable Meaning
%event% Internal event ID
%player% Execute the command once per eligible online player
%world% With %player%: the player's world. Without it: execute once per eligible loaded world
%online_players% Eligible player names separated by spaces
%online_count% Number of eligible players
%cancelled% true on cancellation, false on natural ending/start

A command with neither %player% nor %world% runs once total, including a command with %online_players%. Messages are resolved separately for each eligible recipient, so %player%/%world% identify that recipient. Player-dependent external placeholders in a once-total or per-world command receive a null player context; use %player% when a per-player external value is required.

Own variables resolve first, then PlaceholderAPI. External placeholders remain untouched if it is absent. All actions use the server console on the main server thread through Bukkit's synchronous scheduler. A command that reloads/disables EventClockRK ends the remainder of its old action batch.

Internal messages automatically receive config.yml's prefix. Event broadcast fields do not. Messages support mixed legacy &a, hex &#FF5500, and MiniMessage colors/gradients. Editing messages.yml changes language; language: en identifies the bundled English defaults and does not download translations.

Placeholders

For ID keyall, use %keyall_time%, etc. Supported suffixes:

time            time_seconds    time_short
time_dh         time_dhm        time_dhms
time_hms        time_ms         next_datetime
progress_percent                progress_bar
status

While active, time/progress describe the active duration; otherwise they describe the cooldown or next scheduled start. Paused cooldowns display frozen time. Disabled/completed inactive events and random-scheduled time/progress/date values display placeholders.not-active. Paused or completed events have no displayed next date. Status precedence is active, completed, paused, inactive; enabled waiting events use inactive.

timer-format selects generic time: 1 = total HH:MM:SS, 2 = largest unit, 3 = full text. time-units controls which units appear in text formats and whether zero values are hidden; omitted larger units roll into the next shown unit. Numeric seconds and fixed clock format remain numeric. Unit labels live in messages.yml under time. The progress bar's length/characters and the SimpleDateFormat-style date format live in config.yml. Cooldown dates use the system timezone; scheduled dates use schedulers.yml's timezone.

PlaceholderAPI splits the identifier at the first underscore. EventClockRK groups IDs such as raid and raid_boss under one raid expansion while preserving %raid_boss_time%. If another expansion owns that prefix (e.g. vault), EventClockRK logs the conflict and skips its own placeholders for that prefix without taking over the existing expansion. Choose unique event prefixes.

Commands

Only OP players and local/remote server console may use these. There are no permission nodes in plugin.yml. Command blocks are not server console and are excluded.

/ecrk list
/ecrk info <id>
/ecrk forcetrigger <id>
/ecrk resetcooldown <id>
/ecrk pause <id>
/ecrk resume <id>
/ecrk cancel <id>
/ecrk reload

/eventclock is the full command. Subcommands and IDs have tab completion. Create/edit events only through YAML files.

Build and validation

Requires JDK 17+ and Maven 3.9+. Run mvn clean verify; the installable shaded artifact is target/EventClockRK-1.0.0.jar. Adventure color libraries are bundled and relocated to avoid server/plugin conflicts. Bukkit and PlaceholderAPI are provided by the server, not bundled.

Automated tests cover CRON/Lima/fortnight/DST cases, persistence, pause/resume/force/cancel, one-shot completion, offline recovery, random scheduling, world scoping, command authorization, invalid YAML, placeholder formatting, mixed colors, and PlaceholderAPI registration conflicts. The Bukkit integration tests use a deterministic simulated adapter, not an actual Minecraft process. Before production, test the jar on your exact server build with your real reward/end commands and installed PlaceholderAPI expansions.

Implementation references: Spigot API Maven repository, PlaceholderAPI expansion documentation.

Display settings

These global settings belong in config.yml:

timer-format: 3
time-units:
  days: true
  hours: true
  minutes: true
  seconds: true
  hide-zero: false
  hide-leading-zero: true
next-datetime-format: 'yyyy-MM-dd HH:mm:ss z'
progress-bar:
  length: 10
  filled: ''
  empty: ''

With these defaults:

Remaining time Display
Two days, three hours, fifteen minutes, twenty seconds 2d 3h 15m 20s
Two hours, zero minutes, fifteen seconds 2h 0m 15s
Five minutes 5m 0s
Twenty seconds 20s
No remaining time 0s

Keep hide-zero: false to retain intermediate and trailing zeros. hide-leading-zero: true only removes leading zero units. This default also applies when an existing configuration does not contain the new key.

Placeholder reference

Replace keyall with your event ID.

Placeholder Output
%keyall_time% Remaining time using the configured generic format
%keyall_time_seconds% Numeric remaining seconds
%keyall_time_short% Largest unit, such as 2d
%keyall_time_dh% Days and hours
%keyall_time_dhm% Days, hours and minutes
%keyall_time_dhms% Days, hours, minutes and seconds
%keyall_time_hms% Total hours, minutes and seconds
%keyall_time_ms% Total minutes and seconds
%keyall_next_datetime% Next start date and time
%keyall_progress_percent% Number from 0 to 100, without a percent sign
%keyall_progress_bar% Configurable visual progress bar
%keyall_status% Configurable status text

An enabled event waiting for its next occurrence may show Inactive: it means no active duration is running, not necessarily that the event is disabled.

Timed event example

Create an event that stays active for five minutes, with one hour between starts:

timed-event:
  enabled: true
  repeat: true
  duration: 300
  cooldown: 3600
  worlds: []
  min-players-online: 1
  alerts: [60]
  broadcast-message: '&aThe five-minute event has started!'
  actions: []
  end-actions: []
  end-broadcast-message: '&aThe event finished!'
  cancel-broadcast-message: '&cThe event was cancelled.'

Leave this ID out of schedulers.yml to use its cooldown.

/ecrk forcetrigger timed-event
/ecrk cancel timed-event

Cancellation executes end actions and the cancellation announcement. It never sends the natural completion announcement.

Troubleshooting

Problem What to check
/ec opens EnderChest Use /ecrk or /eventclock. Version 1.0.0 does not register /ec.
Event missing from list Check console errors, required fields, YAML indentation and duplicate IDs.
cooldown: 0 is rejected A valid scheduler must reference that exact ID. Otherwise use a positive cooldown.
A scheduled occurrence did not run Check timezone, online players, enabled/paused/completed/active state and whether the server was online.
Placeholder remains unchanged Check PlaceholderAPI, the ID, expansion conflicts and support in the displaying plugin.
Placeholder shows --- Check for a disabled/completed event or a random scheduler reference.
Leading zeros are still visible Use hide-leading-zero: true, retain hide-zero: false, and reload. Confirm the server is running the new jar.
Reward command fails Test its exact syntax from the console using your reward plugin.
Command access denied Use an OP player or server console. No permission nodes are available.

World filtering does not override an external command's scope. A global broadcast command from another plugin may still reach every player even when EventClockRK's own announcements are world-filtered.

To suspend an event while preserving its history, leave it defined and disable or pause it. Removing its definition and reloading also removes its saved state.

Release notes: 1.0.0

  • Removed the beta version suffix.
  • Replaced /ec with /ecrk; /eventclock remains available.
  • Added default suppression of leading zero time units while retaining intermediate zeros.
  • Preserved compatibility with existing event configuration and saved data.
  • Passed 53 automated tests, including simulated Bukkit integration tests.

The administrator reported successful KeyAll announcements, command execution and restart persistence on the preceding beta. A complete live Paper/Spigot version matrix has not been validated.