Customizing AOneBlock Phases#
Everything a player mines out of the magic block comes from a phase file. This page explains how those files work, what every number in them means, and how to build your own phases.
The short answer
The numbers after a material or entity — COBBLESTONE: 900 — are weights, not counts and not percentages. A phase adds up every weight it has and picks one entry at random in proportion to its weight. blocks:, mobs: and custom-blocks: all draw from that same single pool.
Where the files live#
After the addon has run once, the files are in:
plugins/BentoBox/addons/AOneBlock/
├── config.yml
├── phases_index.yml ← which phases load, in what order, and how long each is
└── phases/
├── 0_plains.yml ← the blocks, mobs, holograms and settings of a phase
├── 0_plains_chests.yml ← the loot tables of that phase
├── 700_underground.yml
├── 700_underground_chests.yml
└── ...
Every phase is a pair of files: <name>.yml and <name>_chests.yml. The chest file is paired by file name, so if you rename one you must rename the other.
0_plains.yml is the reference file
The shipped 0_plains.yml is heavily commented and documents every option. If you only read one file, read that one. This page covers the same ground with worked examples.
After editing any of these files, reload the addon (/bbox reload) or restart the server.
The three kinds of number#
This is the part that trips people up. A phase file contains three completely different kinds of number, and which is which depends entirely on the section it is in.
| Where | What the number is |
|---|---|
blocks:, mobs:, custom-blocks: | A weight — this entry's share of the random pool. |
Keys in fixedBlocks: and holograms: | A position — how many blocks into this phase, counting from 0. |
The top-level key of the file ('0':, '2500':) | The phase's section name, historically its start block. Phase order and length now come from phases_index.yml. |
Weights — the blocks: and mobs: sections#
How the roll works#
Every time a player breaks the magic block, AOneBlock:
- Adds up every weight in the current phase — all of
blocks:, all ofmobs:, and all ofcustom-blocks:. - Picks a random number in that range and returns whichever entry it lands on.
So:
chance of an entry = its weight ÷ total of all weights in the phase
A weight is not a quantity. STONE: 1000 does not mean a thousand stone will be generated during the phase — it means stone gets 1000 tickets in the raffle, and it is rolled fresh on every single block break.
Worked example#
'2500':
name: Winter
firstBlock: SNOW_BLOCK
biome: SNOWY_TAIGA
blocks:
COBBLESTONE: 900
SAND: 100
DIRT: 200
STONE: 1000
SPRUCE_LEAVES: 500
The weights total 900 + 100 + 200 + 1000 + 500 = 2700, so:
| Block | Weight | Chance per break |
|---|---|---|
STONE | 1000 | 1000 / 2700 = 37.0% |
COBBLESTONE | 900 | 900 / 2700 = 33.3% |
SPRUCE_LEAVES | 500 | 500 / 2700 = 18.5% |
DIRT | 200 | 200 / 2700 = 7.4% |
SAND | 100 | 100 / 2700 = 3.7% |
Over a 1000-block phase you would expect about 370 stone, but every break is an independent roll, so the real count wobbles around that figure.
Only the ratio matters#
blocks:
STONE: 1000
DIRT: 200
behaves identically to
blocks:
STONE: 10
DIRT: 2
The shipped files use large numbers on purpose: with a total in the thousands you can add a rare entry at weight 5 without having to rescale everything else to keep the percentages sensible.
Blocks and mobs share one pool#
Mob weights count towards the same total as block weights
mobs: is not a separate roll. A mob entry is just another ticket in the same raffle, so CHICKEN: 200 is exactly as likely as a block with weight 200 — and adding mobs makes every block slightly rarer.
The shipped Plains phase makes this concrete. Its blocks: weights total 11450 and its mobs: weights total 665, for a phase total of 12115:
| Entry | Weight | Chance per break |
|---|---|---|
GRASS_BLOCK | 2000 | 16.5% |
OAK_LOG | 2000 | 16.5% |
CHEST | 200 | 1.7% |
CHICKEN (mob) | 200 | 1.7% |
COW (mob) | 150 | 1.2% |
DIAMOND_ORE | 30 | 0.25% |
VILLAGER (mob) | 15 | 0.12% |
EMERALD_ORE | 10 | 0.08% |
Tuning recipes#
| You want to… | Do this |
|---|---|
| Make something twice as common | Double its weight |
| Remove something | Delete the line (or comment it out) |
| Add a block at roughly X% | Weight ≈ X/100 × current total ÷ (1 − X/100) — or just take the current total, and for ~1% add an entry of weight ≈ total/100 |
| Rebalance a whole phase | Change one weight at a time — every change shifts every other percentage, because the total moves |
| Make mobs rarer without touching blocks | Lower the mobs: weights; the block percentages rise automatically |
Rules and gotchas#
- A weight must be a whole number of 1 or more.
0, a negative value or a decimal is rejected and logged asBad item weight for <phase>: <material>. - The material must be a real Bukkit Material that is a block. Items like
DIAMONDwill be logged asBad block material. - Mobs must be a live, spawnable EntityType. Invalid names log the full list of valid ones on startup.
- If a phase has no valid weights at all, it logs
has zero probability of generating blocksand falls back to a single block type — check the section name spelling.
CHEST is a special case#
When CHEST is rolled from the pool, AOneBlock fills it from that phase's _chests.yml file. So the CHEST weight is the chance of getting a chest; which chest you get is a second, separate roll on rarity:
| Rarity | Chance |
|---|---|
COMMON | 62% |
UNCOMMON | 25% |
RARE | 9% |
EPIC | 4% |
These rarity chances are fixed in code and are not configurable. If a rarity has no chests defined for the phase, the COMMON list is used instead; if there are no chests at all, a plain empty chest is placed.
Mobs#
When a mob is rolled, the magic block becomes STONE if it was empty and the mob spawns on top of it. With clear-blocks: true in config.yml, blocks in the way are cleared so large mobs fit.
mobs:
COW: 150
SPIDER: 75
SHEEP: 75
PIG: 150
VILLAGER: 15
CHICKEN: 200
Positions — fixedBlocks and holograms#
The keys in these two sections are positions within the phase, counting from 0. Position 0 is the first block of the phase, 1 the second, and so on. They are not the player's overall block count, and a position larger than the phase length is simply never reached.
fixedBlocks#
Fixed blocks are guaranteed — they bypass the weighted pool entirely. Use them for scripted moments.
fixedBlocks:
0: GRASS_BLOCK
1: GRASS_BLOCK
2: GRASS_BLOCK
3: OAK_LOG
4: OAK_LOG
5: OAK_LOG
700: CHEST_WITH_WATER_BUCKET
- Defining position
0here replacesfirstBlock, which is then no longer needed. CHEST_WITH_<ITEM>is a shorthand that places a chest holding a single item of that material — handy for giving players a water bucket before the Ocean phase.- Prefer blocks that do not need support. A torch, rail or sapling placed as the magic block just pops off.
- A fixed block entry can also be a custom block definition.
holograms#
Same numbering, but the value is the text to float above the magic block. & colour codes work.
holograms:
0: "&aFirst block is grass!"
1: "&aSecond block is grass!"
3: "&aGood Luck!"
The very first hologram — the one shown before phase 1 begins — lives in the addon's locale file, not here.
Phase order and length — phases_index.yml#
Since AOneBlock 1.26.0
Phase order and length are not taken from the file names or the top-level keys any more. phases_index.yml is the source of truth.
phases:
- file: 0_plains
section: '0'
name: Plains
length: 700
- file: 700_underground
section: '700'
name: Underground
length: 1300
gotoAtEnd: 0
| Field | Meaning |
|---|---|
file | Base name of the phase file, without .yml. The chest file is <file>_chests.yml. |
section | The top-level key inside that phase file. |
name | Display name, used in logs and in /[admin_command] phases. |
length | How many blocks this phase lasts. |
enabled | Optional, defaults to true. Set false to leave the phase out entirely. |
requiredMinecraftVersion | Optional. The phase is skipped on older servers, taking up no blocks at all. |
Start blocks are computed: each phase starts at the running total of the lengths of the enabled phases above it, beginning at 0. Reorder phases freely; a disabled or skipped phase collapses out of the progression. After the last phase the block count jumps to gotoAtEnd.
The easiest way to change all of this is in game with /[admin_command] phases, which edits the index for you. See the phase order editor notes. Once you edit a length there, adminLengths: true is written into the index and your lengths are never recomputed.
The number in a file name is only a hint
0_plains, 2500_winter and so on are historical. A custom phase can be my_phase.yml with a my_phase: top-level key and no numbers anywhere. The numbers are still useful for a brand-new file: they tell the index reconciler where the phase belongs in the running order.
Anatomy of a phase file#
'0': # section name (see phases_index.yml)
name: Plains # display name
icon: GRASS_BLOCK # icon in the phases GUI (BentoBox ItemParser)
firstBlock: GRASS_BLOCK # the block for position 0 (optional)
biome: PLAINS # biome at the magic block location
requiredMinecraftVersion: '1.21.6' # optional version gate
fixedBlocks: { ... } # guaranteed blocks at positions
holograms: { ... } # text at positions
blocks: { ... } # weighted pool of blocks
mobs: { ... } # weighted pool of mobs — same pool
custom-blocks: [ ... ] # weighted pool of custom entries — same pool
start-commands: [ ... ]
end-commands: [ ... ]
end-commands-first-time: [ ... ]
requirements: { ... }
The display name, shown in the phases GUI, the boss bar, log lines and the [phase] command placeholder.
The icon used in the phases GUI only. Parsed with the BentoBox ItemParser, so custom player heads and any displayable item work. A phase with no icon falls back to its first block.
The block placed at position 0 of the phase. Optional — defining 0: under fixedBlocks does the same job and takes precedence.
Changes the biome at the magic block location only, not the whole island. To rebiome a whole island on a phase change, call the Biomes addon from a start-commands entry. An invalid biome name logs the complete list of valid biomes on startup.
Gates entry to the phase. Until every requirement is met the player is held at the end of the previous phase.
economy-balance— minimum player balance (requires Vault and an economy plugin)bank-balance— minimum island bank balance (requires the Bank addon)level— minimum island level (requires the Level addon)permission— a permission string the player must havecooldown— seconds that must pass since the phase was last started
requirements:
bank-balance: 10000
level: 10
permission: ready.for.battle
cooldown: 60
Commands on phase change#
Commands run as the console unless prefixed with [SUDO], in which case they run as the player who triggered them.
| Section | When it runs |
|---|---|
start-commands | When the phase begins |
end-commands | Every time the phase is completed |
end-commands-first-time | Only the first time this island completes the phase |
Placeholders substituted into the command string:
| Placeholder | Value |
|---|---|
[island] | Island name |
[owner] | Island owner's name |
[player] | Name of the player who broke the block |
[phase] | Name of this phase |
[blocks] | Number of blocks broken |
[level] | Island level (requires the Level addon) |
[bank-balance] | Island bank balance (requires the Bank addon) |
[eco-balance] | Player's economy balance (requires Vault and an economy plugin) |
start-commands:
- 'give [player] WOODEN_AXE 1'
- 'broadcast [player] just started OneBlock!'
end-commands-first-time:
- 'broadcast &c&l[!] &b[player] &fhas completed the &d&n[phase]&f phase for the first time.'
Chests#
Chests live in the phase's _chests.yml file, under the same top-level section name:
'0':
chests:
'1':
rarity: COMMON
contents:
0: ==: org.bukkit.inventory.ItemStack ...
'2':
rarity: EPIC
contents:
...
- The number keying each chest (
'1','2') is just a unique id — it is neither a weight nor a position. When a chest of a given rarity is due, one of the chests of that rarity is picked at random with equal probability. contentskeys are inventory slot numbers.rarityisCOMMON,UNCOMMON,RAREorEPIC.
Build chests in game, not by hand
Fill a real chest with what you want, look at it, and run /[admin_command] setchest <phase> <rarity>. The chest is serialized straight into the phase's chest file, correctly, first time. Hand-editing serialized item YAML is error-prone; use /[admin_command] sanity [<phase>] afterwards to check your loot tables. Deleting a chest still means editing the file and reloading.
Custom blocks#
custom-blocks: is a list of entries that are not plain materials. Each entry has a probability: field which — despite the name — is a weight, in exactly the same pool as blocks: and mobs:. probability: 10 is as likely as a block with weight 10.
custom-blocks:
- type: block-data
data: minecraft:chest[waterlogged=true]
probability: 10
- type: mob
mob: ZOMBIE
underlying-block: STONE
probability: 5
- type: itemsadder
id: mypack:ruby_ore
probability: 10
type | What it does | Requires |
|---|---|---|
block / block-data | Runs /setblock with full block data — block states, NBT, and an optional destroy|keep|replace mode. Prefer block when using NBT. | — |
mob | Spawns a vanilla entity using the Spawn Entity API. | mob; optional underlying-block (default STONE) |
mob-data | Runs /summon with vanilla NBT/components. Blocks inside the mob's (scaled) bounding box are cleared a tick after spawn so it fits. | data |
mythic-mob | Spawns a MythicMob through BentoBox's hook. | MythicMobs plugin |
itemsadder | Block from ItemsAdder. | ItemsAdder plugin |
nexo | Block from Nexo. | Nexo plugin |
craftengine | Block from CraftEngine. | CraftEngine plugin, BentoBox 3.15.0+ |
Custom blocks can also be used in fixedBlocks, as an object instead of a material name:
fixedBlocks:
0:
type: block-data
data: minecraft:chest[waterlogged=true]
1: GRASS_BLOCK
Quote your data strings
Custom block data strings contain {, }, [, ] and double quotes. Wrap the whole value in single quotes so the inner double quotes do not clash with YAML's string delimiters.
- type: mob-data
data: 'breeze{CustomName:[{text:"Breezy",color:"#f90606"}],Glowing:1b}'
underlying-block: STONE
probability: 10
Spawner gotcha
A spawner placed without the timing fields is inactive in vanilla 1.21 (Delay:-1 means "never tick"). Set Delay, MinSpawnDelay, MaxSpawnDelay and friends explicitly, or the spawner appears and does nothing. Delay:0 makes the first spawn happen on the very next tick.
If a custom block's plugin is not installed, the block falls back to STONE and a line is written to the log.
Version gating#
A phase, an individual block or an individual mob can declare the minimum Minecraft version it needs. Anything the server is too old for is skipped with one info line in the log instead of a Tried to load invalid item error.
Whole phase — put requiredMinecraftVersion in phases_index.yml so the file is not even parsed on an old server. The phase then takes up no blocks and the phases after it collapse up.
A single block or mob — use the object form, which swaps the bare weight for a weight: field:
blocks:
NETHERRACK: 300
DRIED_GHAST:
weight: 25
requiredMinecraftVersion: '1.21.6'
mobs:
ZOMBIFIED_PIGLIN: 100
HAPPY_GHAST:
weight: 5
requiredMinecraftVersion: '1.21.6'
Chest files are read item by item, so an item your server version does not know is skipped on its own and the rest of the chest still loads.
Building a new phase#
- Copy an existing pair of files in the
phasesfolder — say4000_jungle.ymland4000_jungle_chests.yml— tovolcano.ymlandvolcano_chests.yml. - Change the top-level key in both files to something unique, e.g.
volcano:. It must match in both. - Set
name:andicon:, then editblocks:andmobs:with the weights you want. Remember the percentages are relative to the phase total. - Restart or reload. The addon notices the new file, adds it to
phases_index.ymlat the end of the order with the default length of 500, and logs:Phase index: added Volcano from volcano.yml at the end of the phase order. Move it with the admin phases GUI. - Position it with
/[admin_command] phases— left-click to pick it up, click where it should go, shift-left-click to set its length. - Test it with
/[admin_command] setcount <player> <number>to jump straight to the phase's start block.
Test on a scratch island
Break a couple of hundred blocks and see what actually comes out. Weights read very differently on paper than they play. /[player_command] count shows where you are in the phase.
Troubleshooting#
| Symptom | Likely cause |
|---|---|
Bad block material in <phase>: X | X is not a Bukkit material, or is an item rather than a block |
Bad item weight for <phase>: X. Must be positive number above 1 | The weight is 0, negative or not a whole number |
Bad entity type in <phase>: X | Not a valid EntityType; the log lists the valid ones |
<phase> has zero probability of generating blocks | The blocks: section is missing, empty, or under the wrong section key |
Phase name trying to be set to X but already set to Y. Duplicate phase file? | Two files use the same top-level section key |
| A phase never appears | It is enabled: false in phases_index.yml, or its requiredMinecraftVersion is newer than the server |
| Chests come out empty | The chest file's top-level key does not match the phase file's, or its items failed to load — run /[admin_command] sanity |
| Edits do nothing | The addon was not reloaded, or you edited the file in src/main/resources in the jar rather than plugins/BentoBox/addons/AOneBlock/phases/ |
Watch the server log at startup. Every phase file loaded is logged, as is every rejected block, mob and item, and every change the index reconciler makes (lines beginning Phase index:).