Skip to content

Information

OptimalGifts features, the daily cycle, commands, permissions, tokens and formatting in one reference.

BattleStudio plugin

OptimalGifts

Players unlock daily gifts by playing, then claim each one once a day for a weighted random reward. Everything resets at midnight in your timezone.

Requires
Paper / FoliaMC 1.21.11+Java 21+OptimalLibrary

OptimalGifts gives players a menu of daily gifts. Each gift has a Required-Playtime; once the player has been online that long today, the gift unlocks and can be claimed once for a weighted random reward. Everything resets at midnight in your configured timezone and the cycle starts again.

Gifts live in one file (gifts.yml) and each one carries its own Locked / Claimable / Claimed icon, so a gift can look completely different in each state. There is no global rarity table: the colors and lore are per gift.

OptimalGifts runs on top of OptimalLibrary, a free shared plugin that must be installed alongside it. See Installation.

  • Playtime counts only while online. A player’s daily playtime is what was banked earlier today plus the current session.
  • The day is the calendar day in Settings.Timezone. When it changes, today’s playtime and every claim are wiped. There is no midnight task: the reset is picked up the next time the player’s data is used (opening the menu, the unlock check, an admin command).
  • Unlock happens when today’s playtime reaches the gift’s Required-Playtime. A check runs every second and sends the GIFT-UNLOCKED message (and its title) plus the GIFT-UNLOCKED sound the moment a gift becomes claimable.
  • Claim once per day by clicking the gift. The claim is saved to the database immediately, so a crash can never let a player claim the same gift twice.
  • The reward is one weighted pick from the gift’s Rewards list. Its Commands run from console with {player} replaced by the player’s name.

Unlock notifications are not saved. On join, every gift that is already claimable is marked as notified, so relogging never re-sends old unlocks.

  • Any number of daily gifts, each at its own menu slot with its own playtime requirement
  • Fully independent Locked / Claimable / Claimed icons per gift (material, amount, head, name, lore, glow and more)
  • Weighted reward rolls: each reward is a Chance and a list of console commands
  • Live menu: icons, countdowns and states update every second while the menu is open
  • Unlock notifications with a chat message, a screen title and a sound
  • Daily reset at midnight in any timezone
  • Optional automatic glow on claimable gifts
  • Temporary feedback icons and a deny sound on blocked clicks
  • Configurable menu layout with click actions (commands, messages, titles, sounds and more)
  • SQLite storage with write-behind saving, claims saved instantly
  • PlaceholderAPI support in messages, titles, icons and menu actions
  • Paper and Folia support
Command Aliases Permission Description
/gifts /gift, /dailygifts optimalgifts.use Open the daily gifts menu. Players only.

All admin commands use /giftsadmin (alias /giftadmin) and need optimalgifts.admin.

Command Description
/giftsadmin Show the admin help panel (GIFTS-ADMIN-HELP). Also shown for an unknown or incomplete subcommand.
/giftsadmin reset <player> Clear the player’s claims and playtime for today. Works on offline players the server has seen before: their stored data is deleted.
/giftsadmin addtime <player> <duration> Add playtime to an online player’s current day. <duration> uses the duration syntax, for example 10m, 1h30m or 2h.
/giftsadmin reload Reload config.yml, messages.yml, guis/gifts-menu.yml and gifts.yml, and restart the save timer.

Tab completion suggests subcommands, online player names and a few durations (10m, 30m, 1h, 2h).

Permission Default Grants
optimalgifts.use everyone /gifts and the menu
optimalgifts.admin op every /giftsadmin command

Gifts themselves have no permission nodes. Every player sees every enabled gift; playtime is the only gate.

OptimalGifts does not register a PlaceholderAPI expansion, so there are no %optimalgifts_...% placeholders.

With PlaceholderAPI installed, %...% placeholders from other plugins are resolved for the viewing player in messages, message titles, gift icons, menu items, the menu title and menu action arguments.

These are the plugin’s own {...} tokens.

Token Value Where
{gift} The gift’s Name. Gift icons, GIFT-LOCKED, GIFT-ALREADY-CLAIMED, GIFT-CLAIMED, GIFT-UNLOCKED
{number} The gift’s 1-based position in the daily order (sorted by required playtime). Same as {gift}
{required-playtime} The gift’s Required-Playtime, formatted. Gift icons
{playtime} The player’s playtime today. Gift icons
{unlocks-in} Playtime still needed. 0s once unlocked. Gift icons, GIFT-LOCKED
{refreshes-in} Countdown to the next midnight in Settings.Timezone. Gift icons, every menu item, temporary icons, menu actions, GIFT-ALREADY-CLAIMED
{reward} The rolled reward’s Name. GIFT-CLAIMED
{player} A player name. Reward commands, menu actions, admin messages
{uuid} The clicking player’s UUID. Menu actions
{duration}, {ms} The rejected duration / reload time in milliseconds. INVALID-DURATION / RELOAD

In PLAYTIME-ADDED, {playtime} is the amount that was added, not the day’s total. The full per-message list is on the messages.yml page.

Required-Playtime and /giftsadmin addtime accept one or more <number><unit> parts. Units are w, d, h, m and s; spaces are ignored. Spelled-out units such as 1 hour 30 minutes or 45 secs are shortened automatically.

"10m" -> 10 minutes
"1h 30m" -> 90 minutes
"2h" -> 2 hours
"1d 6h 30m" -> 30 hours 30 minutes
"0s" -> unlocked from the start of the day

A bare number without a unit (90), a number left without a unit at the end (1h30) or any other character makes the value invalid.

Durations are shown back as comma-separated units with zero parts dropped, for example 1h, 15m, 30s, 10m or 59s. Hours never roll over into days, so 30 hours shows as 30h.

Every text field supports legacy & codes, &#RRGGBB hex, MiniMessage (<gradient:a,b,c>, <rainbow>, <bold>, <#RRGGBB>, …) and <SOLID:RRGGBB>. <gradient> accepts comma-separated hex stops. With PlaceholderAPI installed, %...% placeholders are resolved as well. Italics are removed from item names and lore automatically.