Monthly Crate

A physical crate you right-click, then pick tiles from a face-down grid to reveal what's inside.

groovyminecraft
On this page 6 sections
  1. Opening one
  2. The two pools
  3. The parts people ask about
  4. What the grid buys
  5. Architecture
  6. Trade-offs

The Monthly Crate is the top-tier crate on the Prisons server, and it doesn’t open into a spin animation or a predetermined reward. It opens into a 5×5 grid of face-down tiles. You pick four. Once you’ve picked, the unpicked tiles flip face-up so you can see what you missed. Then a single centred row of five jackpot tiles appears and you pick one more.

Every tile is rolled up front the moment you open the crate. When the grid flips, what you see is what was actually there, not a fabricated after-the-fact list. So “the four Legendaries I passed over” is a real thing, not a UI trick.

The crate itself is a physical ender chest item you hold in your hotbar and right-click. Two right-clicks can’t open two menus on the same crate, and any unclicked picks are paid out when the menu closes. Closing early never eats a key.

Opening one

  1. Right-click your Monthly Crate key. A glowing ender chest in your inventory.
  2. Pick four tiles from the 5×5 grid. The face-down panes cycle through colours while you decide.
  3. See what you missed. The remaining 21 tiles flip face-up for a beat so you can see the whole board.
  4. Pick one jackpot tile. A centred row of five appears with a separate high-value pool. Pick one.
  5. Collect. Rewards are handed to you as you pick, and the header updates to tell you what phase you’re in.

If you close the menu partway through, whatever picks you still had coming get paid out from the tiles that were already rolled.

The two pools

PoolWhere it shows upTuning
MainThe 5×5 grid, 4 picksBroader pool, moderate chases.
JackpotThe centred row of 5, 1 pickSeparate pool, richer rewards. Big wins can announce.

Really rare jackpot hits broadcast to the whole server (behind their own flag), so a truly lucky pull is a public event rather than a private silent line.

The parts people ask about

  • The tiles are pre-rolled. What you see when the grid flips up is what was there. The crate doesn’t re-decide after the fact.
  • One crate, one menu. You can’t hoard several open menus by mashing right-click; the physical crate is consumed atomically before the menu opens.
  • Closing the menu doesn’t waste your key. Unclicked picks settle at close, and the jackpot pays from its pool if you closed before it opened.
  • Duplicate rewards are possible. Each tile is an independent weighted draw, so the same reward can show up twice in one open. That’s intentional.
  • Announced wins don’t spam. Only rewards flagged announce: true broadcast, so the chat isn’t buried in every small win.

What the grid buys

  • Player agency. You choose which tiles to reveal instead of watching a spin. Nothing’s decided by clicking faster.
  • Meaningful “misses.” Seeing the four Legendaries you passed over is the whole feeling of the crate, and it only works because the tiles were rolled before you started clicking.
  • Cheat-proof physical items. Crates go through the anti-dupe pipeline (a per-crate id that can only be spent once), so duplicated copies just don’t open.
  • Live-ops without touching code. Rewards and jackpot pools live in a config file that hot-reloads on script recompile, so the monthly refresh is a config PR rather than a deploy.

Architecture

The crate is an item, not a command

The physical crate is an ender chest with a monthly_crate persistent-data tag and a unique per-item id (a UUID). Right-click routes through the standard interact handler → AntiDupeUtils.useId(...), which fires its callback for exactly one caller: the one whose INSERT for that id wins. A duplicated crate loses the race and its right-click reports “no longer usable, contact staff for a replacement.” A double-click on the real crate can’t open two menus either, because the item is consumed before the menu opens. Subtle rule, but opening first is how the crate dupe from an earlier system worked.

Everything is rolled up front

openCrate rolls all 25 main tiles right away and stores them on the session. Picks then just look up session.tiles[i], and the reveal phase can show every unpicked tile as its real reward because there’s nothing left to decide. Rolling at click time would work for the picks but would need a whole separate mechanism for “what were the other 21,” and the two paths would drift.

One shared animation task for every open crate

The shimmering face-down panes are re-randomised by a single sync-scheduler task, not per-crate tasks. When nobody has a crate open the task no-ops, so the packet cost is proportional to how many players are actually playing rather than to how many have logged in today. The panes themselves are built once (11 reusable ItemStack instances, one per glass colour) because inventory.setItem copies to NMS anyway. Sharing an instance is safe and cheap.

The phase machine advances on clicks, never on timers

The session has four phases (PICKING, AWAITING_JACKPOT, JACKPOT, FINISHED) and the only scheduled step is the ~1-second beat between finishing the main picks and the jackpot grid appearing. Everything else transitions on a click, so there’s no scheduled work that outlives the player and no window where a disconnect leaves a task holding a stale Player.

Close means settle, not lose

settle(player) runs when the menu closes, when the player quits, and at plugin unload. It looks at what phase the session is in and pays out whatever’s still owed. Remaining picks from the main pool if the player closed early, or the jackpot from its own pool if they closed during the reveal window before it opened. Only one path pays per phase (main pays from tiles, jackpot pays via the jackpotTaken flag) so closing at exactly the wrong moment doesn’t double up.

Two pools parsed with real chance percentages

parsePool walks each pool twice: once to sum weights, once to build entries with their computed displayed percentages baked in. The parser uses explicit null checks instead of Groovy’s Elvis for chance values, because a configured chance of 0 is falsy and would silently become weight 1, quietly re-enabling a reward someone had deliberately switched off.

Trade-offs

  • Grid, not spin. A spin is faster to show off in a video but has no “misses I can see.” The whole design is about the moment the unpicked tiles flip.
  • Same reward can show twice. The tiles are drawn with replacement. A no-replacement pool would guarantee five distinct rewards but at the cost of an unnatural “wait, that one is already up” bias in the roll, and it’d make the pool-vs-picks arithmetic weird when the pool is smaller than the grid.
  • Physical crate item, not a virtual counter. A counter is one less thing to carry, but a counter can’t be gifted, traded, or laid on a plot as a display. The item form gives the crate a life outside the menu.
  • Config hot-reload rebuilds pools, doesn’t rebuild sessions. Editing rewards while someone has a crate open won’t reroll their session. That would silently change what they thought they were picking. The next open sees the new pool.