PhoenixCrates Lite
collector-phoenixcrates · version 0.6.0 · registers as crate · CI 2026-09-25
PhoenixCrates metrics — and above all: does the randomness keep its promises?
That's the one thing you can't see in-game. A player who opens a hundred crates can sense that the reward advertised at 2% never comes up, but can't prove it; neither can an admin. Two metrics settle it:
<pre># OBSERVED probability over 30 days, against the CONFIGURED one sum by (crate,reward) (increase(mc_crate_rewards_total{alternative="false"[30d])) / ignoring(reward) group_left sum by (crate) (increase(mc_crate_rewards_total{alternative="false"}[30d])) / mc_crate_reward_expected_ratio # 1.0 = matches, 0.5 = half as frequent as promised }</pre>
There is no way to measure the raw draw, which had to be learned the hard way on the server. This module originally declared a reward_draws counter fed by CrateRewardSelectionEvent — which never fires as its name suggests. The event fires BEFORE the draw, with the list of candidates and a null reward, to let a third-party plugin impose its own choice; only afterward, if nobody responded, does selectByWeight actually draw. So there's no draw outcome to listen for.
The fallback is rewards_total filtered on alternative="false": what gets handed out WITHOUT having been substituted. An acknowledged imprecision remains — win limits and permissions remove candidates before the draw, invisibly. Hence crate_reward_candidates, which says how many rewards were actually in play.
Two regimes live in one class. The counters are fed by events and cost nothing at scrape time: they're already current. The gauges — configuration and per-player state — require walking lists, hence #isBackground() being true. Both mechanics live here together because they describe the same object; splitting them would force sharing crate identifiers between two classes.
All handlers run at MONITOR and in O(1). PhoenixCrates' events fire on the main thread, in the call stack of the open itself — verified at the bytecode level. A handler that took a millisecond would take it out of the tick.
Install
Put vania-metrics-collector-phoenixcrates-0.6.0.jar in the plugins folder, next to the core and to PhoenixCrates Lite, then restart. The collector depends on both: without PhoenixCrates Lite it stays disabled, and the core keeps running.
- Target plugin: PhoenixCrates Lite 6.2.1 — latest for Minecraft 1.21.11: 6.2.1
- Built against: core v0.6.0
- Download: vania-metrics-collector-phoenixcrates-0.6.0.jar, with its SHA-512, from the v0.6.0 release
- Collects: in the background, every few s — reading the plugin's state never blocks a scrape
- Tested on: Java 21
- Latest CI: success · 2026-09-25 21:34 UTC · commit
717801e· run
Platforms
| Platform | Target plugin | Collector | Latest CI |
|---|---|---|---|
| Paper | yes | Passed | paper ✓ |
| Purpur | yes | Passed | purpur ✓ |
| Folia | yes | Passed | folia ✓ |
| Spigot | yes | Passed | spigot ✓ |
| CraftBukkit | unknown | Unknown | — |
| Sponge | no | n/a | — |
| Velocity | no | n/a | — |
| BungeeCord | no | n/a | — |
| Waterfall | no | n/a | — |
| Geyser | no | n/a | — |
See the compatibility matrix for every collector at once.
Metrics
mc_crate_deliveries_total
counter source
Item DELIVERIES, not items delivered: eight keys given at once count as one. "source" is key_grant, crate_grant or reward_grant. Only PHYSICAL keys go through here — granting a virtual key fires no event and only shows up as a jump in mc_crate_player_keys.
mc_crate_keys
gauge virtual
Keys declared.
mc_crate_open_attempts_total
counter crate
Opens REQUESTED, whether they completed or not. Checks the invariant attempts = opens + failures; a gap means the plugin opened a crate without going through the normal path.
mc_crate_open_cooldown_seconds
gauge crate
Delay imposed between two opens of the same crate.
mc_crate_open_cost
gauge crate currency
Price of an open. "currency" is the configured cost engine, which leaves the door open to multiple currencies, as with the economy module.
mc_crate_open_failures_total
counter crate reason
Opens refused. "reason" is INFERRED from the player's state at the time of the request, since the plugin only returns a translated message: cooldown, no_key, money, cancelled, other.
mc_crate_opens_total
counter crate
Opens completed, across all players.
mc_crate_placements_total
counter crate world
Physical crates placed in the world.
mc_crate_player_cooldown_seconds
gauge player uuid crate
Time REMAINING before a player can reopen a crate. Zero if they can open right away.
mc_crate_player_keys
gauge player uuid key
VIRTUAL keys in stock for a connected player. Physical keys are in their inventory and are not counted here.
mc_crate_player_opens
gauge player uuid crate
A player's opens EVER, by crate type. Persisted by the plugin: the only metric in this module that doesn't reset to zero on restart.
mc_crate_player_opens_total
counter player uuid crate
Opens completed, per player and per crate. Counts SINCE THE EXPORTER STARTED; for the all-time total, see mc_crate_player_opens, which the plugin persists.
mc_crate_player_reward_wins
gauge player uuid reward
How many times a player has won a given reward, ever. WITHOUT a "crate" label: the plugin indexes these wins by reward identifier ALONE, so two crates that both name a reward "diamond" share the counter. That's not a design choice, it's what the data allows.
mc_crate_previews_total
counter crate
Previews opened without opening the crate: interest that doesn't convert.
mc_crate_reward_candidates
gauge crate
Rewards actually in play at the last draw. Lower than crate_rewards_configured when win limits or permissions removed rewards: this is what explains why a player can no longer win a reward they already got.
mc_crate_reward_expected_ratio
gauge crate reward
EXPECTED probability of a reward, between 0 and 1, normalized BY US (weight / sum of weights). Describes the draw's configuration, not the effective odds: guaranteed rewards, win limits and permissions are applied on top of it.
mc_crate_reward_required_keys
gauge crate reward
Keys required to be eligible for a reward. This is the ONLY notion of rarity the plugin has: there is no getRarity() in its API.
mc_crate_reward_weight
gauge crate reward
Raw weight of a reward in the draw. This is NOT a percentage.
mc_crate_reward_win_limit
gauge crate reward
Maximum number of times a reward can be won. NEGATIVE means unlimited: -1 is what the plugin returns, observed on its sample crates, not 0 as one might assume.
mc_crate_rewards_configured
gauge crate
Rewards declared on a crate. The Lite edition caps this at 5: this gauge says when that cap is hit.
mc_crate_rewards_total
counter crate reward alternative
Rewards actually HANDED OUT. "alternative" distinguishes the consolation reward from the drawn one.
mc_crate_selective_confirms_total
counter crate reward
Choices confirmed in selective mode, where the player picks their reward.
mc_crate_types
gauge enabled
Crate types declared.
Configuration
In metrics.properties, or as environment variables. See Configuration.
| Key | Default | Environment variable |
|---|---|---|
collector.crate | true | VANIA_METRICS_COLLECTOR_CRATE |
collector.crate.interval | 30 | VANIA_METRICS_COLLECTOR_CRATE_INTERVAL |
collector.crate.player_reward_wins | true | VANIA_METRICS_COLLECTOR_CRATE_PLAYER_REWARD_WINS |