Skip to content

PokeLoot Weights

Lets staff set the drop chance of each item in Pixelmon PokeLoot chests. Pixelmon picks chest loot evenly from a flat list; this mod picks by weight from a config file instead.

What it does

  • Replaces the item a PokeLoot chest gives with a weighted pick from pokeloot_weights.json. Example: Master Ball at weight 1, Rare Candy at weight 40.
  • One table per chest type, using Pixelmon's own tier names:
Tier Chest
tier1 Poke Ball chest
tier2 Ultra Ball chest
tier3 Master Ball chest
ultraSpace Beast Ball chest
  • Hidden chests roll across tiers. By default the split is 51/34/15 (tier1/2/3), the same as Pixelmon, and it can be changed, including letting hidden chests reach the Beast Ball table.
  • Everything else stays Pixelmon's: claim tracking, one-time or timed chests, the "found" chat line, the sound.
  • Never touched: owner-set chests and special-event chests with custom drops.
  • If anything goes wrong, the chest falls back to a normal Pixelmon drop, never an empty chest.

Server-side only.

How players use it

Players open PokeLoot chests as usual. Only the odds are different.

Staff guide

All commands need pokelootweights.command.admin (off by default; ops and console have it).

Task Command
Summary of every tier: entries, total weight, hidden split /pokelootweights info
The 20 heaviest entries in a tier, with their real drop chance /pokelootweights info <tier>
Roll a tier many times and compare to the expected chances /pokelootweights simulate <tier> <trials>
Apply config changes /pokelootweights reload

Recipe to change a chance: edit the entry's weight in the JSON, run /pokelootweights reload, then check it with /pokelootweights info <tier>. Reload warnings are shown in chat.

Configuration

config/pokelootweights/pokeloot_weights.json. /pokelootweights reload applies changes with no restart.

{
  "enabled": true,
  "hidden-chest-tier-weights": { "tier1": 51, "tier2": 34, "tier3": 15, "ultraSpace": 0 },
  "tiers": {
    "tier3": {
      "rolls": { "min": 1, "max": 2 },
      "entries": [
        { "weight": 1,  "item": { "id": "pixelmon:poke_ball",
                                  "components": { "pixelmon:poke_ball": "master_ball" } } },
        { "weight": 40, "item": "pixelmon:rare_candy", "count": { "min": 1, "max": 3 } },
        { "weight": 0,  "item": "pixelmon:ability_capsule" }
      ]
    }
  }
}
Field Meaning
enabled Master switch. false leaves every chest to Pixelmon
weight Relative within the tier, not a percent. Weight 3 in a tier totalling 60 is 5%. 0 keeps the entry in the file but it never drops
item An item id, or {"id": ..., "components": {...}}, the same format as Pixelmon's pokechestdrops.json
count Stack size, a number or {"min": n, "max": n}. Default 1
rolls How many items one chest gives. Default 1. Rolls are independent, so an item can repeat
hidden-chest-tier-weights Which tier a hidden chest rolls from

A bare string entry ("pixelmon:rare_candy") counts as weight 1, so a Pixelmon tier list can be pasted straight in. Adding weight to one entry makes every other entry in that tier rarer.

If the file does not exist, the mod writes one when the server starts, from the server's current PokeLoot lists, every item at weight 1. That keeps the odds exactly as they were.

Data and storage

Only the config file.

Troubleshooting

Symptom Cause Fix
Chests drop the old items Config unreadable, so the mod stood down; or enabled is false Run /pokelootweights reload and read the warnings
One tier uses stock Pixelmon loot That tier is missing or has no usable entries Fix the tier. Other tiers keep working
An item never drops Its id does not exist (entry skipped) or its weight is 0 Check the reload warnings
Hidden chests never give Beast Ball loot ultraSpace is 0 in hidden-chest-tier-weights Expected by default

Boot lines that show it loaded:

PokeLootWeights: listening for PokeLoot drops.
PokeLootWeights: tier1 loaded with <n> entries, total weight <n>, 1-1 roll(s).

Maintainer notes

  • The hook is Pixelmon's PokeLootEvent.GetDrops on Pixelmon.EVENT_BUS. It fires after Pixelmon has already picked a drop and before the player gets it, so every decline path keeps Pixelmon's pick. No mixin, no access transformer. Removing the jar restores stock behaviour.
  • Chests where PokeChestTileEntity.isCustomDrop() is true are skipped.
  • The config loads on ServerStartedEvent, because DropItemRegistry's lists only exist after datapacks load.
  • The permission node is mirrored into Bukkit at startup so it tab-completes in LuckPerms.
  • On main: the starting config came from the datapack pokechest_boss_raid_loot_table_adjustments. Its drops/pokechestdrops.json was renamed to .bak-20260803-194915 at cutover. The rest of that datapack (Ability Patch and Ability Capsule changes for raids and bosses) is still active and must stay. A full rollback means removing this mod and renaming the backup file back, then /reload.
  • The live main config was hand-tuned on the server (Beast Ball tier total 88 to 211). The deploy bundle still has the flat seed, so never push the bundle config over it. Bundle and live copy: manual_uploads/2026-08-03-pokeloot-weights/ in the ops repo.
  • scripts/convert_pokeloot_to_weighted.py in the ops repo turns a Pixelmon drops file into this format.

Building

./gradlew build

Output: build/libs/pokelootweights-<version>.jar.

Full command, permission and config tables: Reference.