介绍
Custom-Block — custom blocks for BONE:MSD, one line each
This project was built with the help of Claude Code, Anthropic’s AI coding assistant. That covers the generator, the port of the BONE:MSD engine to Minecraft 26.3, the tests and this documentation.
Describe your blocks as a list in blocks.json, like enum values: full blocks, slabs and stairs. The generator builds everything else: the block item, loot tables, the creative-menu entry, models, translations, and the vanilla overrides. The output is a single pack for Minecraft 26.3 that already includes the BONE:MSD engine.
Custom-Block/
├── blocks.json ← your block "enum" (edit this)
├── textures/ ← 16×16 PNG textures (put them here)
├── slots.lock.json ← which slab each full block occupies (auto-generated, do NOT delete)
├── generator/build.py ← the generator
├── engine-patches/26.3/ ← fixes that port the [BONE:MSD](https://www.planetminecraft.com/data-pack/bone-cb-bhex-s-over-named-engine-for-custom-blocks/) engine to Minecraft 26.3
├── tests/ ← build check on a real 26.3 server, no client needed
├── build/ ← output: custom_blocks.zip (recreated on every build)
└── extension/ ← original [BONE:MSD](https://www.planetminecraft.com/data-pack/bone-cb-bhex-s-over-named-engine-for-custom-blocks/) engine, author's example and PDF (reference, do not edit)
Quick start
- Put a texture into
textures/, e.g.textures/marble.png. - Add an entry to
blocks.json:
{ "id": "marble", "name": { "en_us": "Marble", "ru_ru": "Мрамор" }, "material": "stone", "texture": "marble" }
A slab or stairs of the same texture is one more line each, with shape:
{ "id": "marble_slab", "name": "Marble Slab", "material": "stone", "shape": "slab", "texture": "marble" },
{ "id": "marble_stairs", "name": "Marble Stairs", "material": "stone", "shape": "stairs", "texture": "marble" }
- Build and install into a world:
python3 generator/build.py --install "<path to the world folder>"
- Rejoin the world.
/reloadis not enough: new creative-menu entries (paintings) are registered only when a world loads. If you only changed textures or models, F3+T is enough.
To get the blocks: /function custom_blocks:give_all or /function custom_blocks:give/<id>. In creative they are among the paintings in the Functional Blocks tab.
Requires Python 3.9+ (standard library only). Generator messages are in Russian.
Block fields
| Field | Required | Meaning |
|---|---|---|
id |
yes | Block name: a-z, 0-9, _. Renaming it loses blocks already placed in worlds. |
name |
no | A string (en_us) or { "en_us": "...", "ru_ru": "..." }. Derived from id by default. |
title |
no | Creative-menu caption. Only A-Z a-z 0-9 and space, because the engine font has nothing else. Defaults to name.en_us. |
material |
no | wood · stone (default) · copper · wool · concrete. Sets sound, hardness, required tool and flammability. |
shape |
no | full (default) · slab · stairs. Slabs and stairs are drawn by item_display (see below); for them model can only be cube_all, cube_column or cube_bottom_top. |
texture |
* | One texture on all sides (model cube_all). |
model + textures |
* | cube_column (side, end) · cube_bottom_top (side, top, bottom) · cube (up, down, north, south, east, west, optional particle). |
model_file |
no | Full blocks only. Path to your own JSON model (e.g. from Blockbench), relative to Custom-Block/. Entries from textures are merged into it. The model must still be a full cube (see Limitations). |
drop |
no | Another loot table to drop instead, e.g. minecraft:blocks/oak_planks. By default the block drops itself. |
creative |
no | false hides the block from the creative menu. |
slab / waterlogged |
no | Full blocks only. Pin the block to a specific slab, e.g. "slab": "cherry_slab". Rarely needed. |
* either texture or textures is required. For slabs and stairs, texture goes on every face; with cube_column the end texture goes on top and bottom; with cube_bottom_top the top, bottom and side textures go where their names say.
A texture value without : is the file textures/<name>.png. You can put a .png.mcmeta next to it for animation. A value with : is an existing texture, e.g. minecraft:block/calcite.
Global settings in blocks.json:
namespace— namespace of the generated content (custom_blocks);description— pack description;minecraft_version— only26.3for now. It selects the pack format numbers and the data syntax: 26.3 changed loot tables and predicates a lot (modifier,condition,match_block);use_waterlogged_slots— also use the second, waterlogged state of each slab. Off by default: the PDF lists bugs for these states;reserved_slabs— slabs the generator must not touch because another pack uses them.
How it works
Slots. Every block occupies the <slab>[type=double] state of one vanilla slab. The BONE:MSD engine turns player-made double slabs into full blocks, so this state is free in the world. The resource pack draws your model on it, and the data pack replaces its drop. The block has no entity: it is fast, can be pushed by pistons and does not desync.
Available slots per material: wood 12, stone 44, copper 3, wool 15, concrete 15. With use_waterlogged_slots there are twice as many. One slab per material is kept out of the pool: it is the base of custom slabs (see below).
Stable slots. A slot is assigned once and stored in slots.lock.json, so the order of blocks.json does not matter. When a block is removed, its slot is retired and never given to a new block; otherwise blocks already placed in worlds would turn into the new one. To reuse retired slots anyway: python3 generator/build.py --free-retired.
Placing. The block item is a barrier carrying bone_cb data. The engine catches the barrier being placed, puts a command block in its spot, and on the next tick that command block places the real block.
Slabs and stairs ("shape", new in 1.1.0). A slab or stairs block cannot be a free block state: there are no free slab or stairs states of the right shape. So these blocks are a real vanilla base block with an item_display on top of it:
| material | slab base | stairs base |
|---|---|---|
| wood | oak_slab |
oak_stairs |
| stone | stone_slab |
stone_stairs |
| copper | waxed_cut_copper_slab |
waxed_cut_copper_stairs |
| wool | white_wool_slab |
white_wool_stairs |
| concrete | white_concrete_slab |
white_concrete_stairs |
- The block item is the base item (e.g.
oak_slab) with your model andbone_csdata. The game places it as usual, so top/bottom, facing, stair corners and waterlogging all work. An advancement catches the placement, a ray from the player’s eyes finds the block, and anitem_displaywith a copy of the item is summoned in the block. The base gives the hitbox, sound and hardness. - The model is the vanilla
slab/stairsmodel with your textures, 1% larger than the base so the base texture does not show through. For stairs the display reads the block state every tick and switches the model (straight/inner/outer) and rotation, so corners follow neighbours like vanilla. - Breaking: when the base disappears, the display looks for the base item that has just dropped, takes one and drops your item instead. No drop (creative,
/setblock), nothing extra. - Two custom slabs can be stacked in one block (two displays). The engine does not turn such a double slab into planks.
Engine port. The original engine (extension/bone-msd-26-5) does not load in 26.3: the world opens in safe mode with Failed to parse bone_msd:block_engine/placed_block. The generator copies the engine and applies engine-patches/26.3/ on top:
- the new
placed_blockadvancement format; - placement fix: the original engine reacted to any placed barrier and turned every barrier within 7 blocks into a command block. Ordinary barriers became stray command blocks, and barriers near a placed custom block became copies of it. Now the advancement fires only for items with
bone_cb, and only the barrier the player is looking at is converted; - the new
item modifysyntax inupdate_slot; - five redstone block tags that were missing from the author’s archive;
- a check in the engine’s ray (
raycast/trigger): a double slab that holds Custom-Block slabs is not turned into a full vanilla block.
Only files the engine actually uses go into the pack: font textures the font does not reference and the author’s demo strings stay out.
One pack, both roles. Data packs and resource packs have different format numbers in 26.3 (121 and 97), but the pack has one pack.mcmeta. So it declares the range min_format: 97, max_format: 121. The game’s own code reports the pack as compatible in both roles; this was checked.
Upgrading from 1.0.x
Blocks you already placed keep working; their slots do not change. The difference: five slabs are now the base of custom slabs and are no longer given to full blocks: oak_slab, stone_slab, waxed_cut_copper_slab, white_wool_slab, white_concrete_slab. If your slots.lock.json gives one of them to a full block, the build stops with an error that names the block. Pin that block to another slab with "slab"; blocks of it already placed will then look like a plain double slab. With the default order this can only happen once a material has almost no free slots left.
Installation
build/custom_blocks.zip is the only file you need: one zip with data/ and assets/.
Automatic: --install (see Quick start) copies the zip into <world>/datapacks/ and into the resourcepacks/ folder of the same game instance. It also removes older versions of these packs and warns if the author’s originals are still there. Enable the resource pack once in the game settings.
Manual: copy custom_blocks.zip into <world>/datapacks/ and into resourcepacks/.
Do not install the original bone-msd-26-5 or the author’s bone-msd-example-pack together with this pack. The original engine breaks 26.3 worlds, and the example overrides the same items/painting.json.
If something does not work, check the instance’s logs/latest.log. Lines with Missing data pack, Failed to load function, Failed to parse or Missing block model point to the cause.
Creative-menu tooltip (omg_font)
omg_font is a font from the engine’s resource pack. Its “characters” are pictures:
…— 47-pixel-tall background pieces that look like a vanilla tooltip (dark fill, purple border);…— spaces, including negative ones;A-Z a-z 0-9— large letters.
In creative a block is a painting, and its tooltip is: Painting / variant title / author / size. The variant title is written in this font. Its background reaches upward, covers the Painting line and draws a fake tooltip with the block name. The background width is fitted to the name (painting_title in the generator).
Lines after the title are drawn later, i.e. on top of the fake tooltip:
- Painting size (“16×16”). The engine blanked it for English only, so in other languages it showed through. The generator now blanks it for every language, which hides the size of vanilla paintings too.
- Advanced tooltips (F3+H):
minecraft:paintingand the component count. A pack cannot remove them; turn F3+H off for a clean tooltip.
Testing without the game client
python3 tests/run_gametest.py
The script takes Java and the 26.3 jar from Prism Launcher and starts Minecraft’s built-in GameTest server with the pack from build/ plus the test pack tests/cbtest. In about 15 seconds it checks:
- that the pack loads without errors or warnings;
- that the block item carries
bone_cb; - barrier → command block → placed block, without touching a nearby ordinary barrier;
- drops of custom blocks and of ordinary slabs;
- painting → block item conversion;
- slabs and stairs: display placement, stairs following a shape change, a double slab made of two custom slabs, its drop when broken (16 checks in total).
The test targets the example blocks split_oak, engraved_copper, split_oak_slab and split_oak_stairs. The resource pack cannot be checked this way; only the game client renders it.
Limitations
- Full blocks are double slabs, so their hitbox, collision and occlusion are always a full cube. A non-cube
model_fileonly changes the picture and leaves see-through gaps in the world. - Slabs and stairs (new in 1.1.0; the logic passes the server test, but how they look has not been checked in the game client yet):
- every block is an entity (two for a double slab) checked every tick, so thousands of them cost more than full blocks;
- rotated stairs rotate their texture with the model (vanilla stairs keep it aligned,
uvlock), so directional textures look different from vanilla; - break particles and cracks are those of the base block (e.g. oak);
- a piston moves only the base: the block turns into a plain base block;
- a double custom slab takes its light from the block above;
- middle-click picks the vanilla base block.
- Textures must be opaque: slabs render as solid blocks.
- Middle-click in creative picks the vanilla slab, not your block.
- When a player builds a double slab of the same type, the custom block flashes for 1 tick (a known engine issue).
- Double slabs that already exist in a world, or that world generation creates, become custom blocks. That is why rare slabs (pale_oak, bamboo_mosaic, resin_brick…) are used first.
- The engine places blocks through command blocks: a server needs
enable-command-block=true. - The engine keeps the block being placed in one shared storage. If two players place custom blocks in the very same tick, both get the second one.
Credits
BONE:MSD is by Bhex. The original engine, its example pack and documentation are in extension/. The only changes there: the author’s drafts (*-old functions) and unused font textures were removed, and the pack icon and description were replaced. The textures in textures/ come from that example pack. They are third-party work and are not covered by this project; all rights belong to their author. They will be removed on the author’s request.
常见问题
Custom Block 支持哪些 Minecraft 版本?
Custom Block 支持 Minecraft Java 版 26.3。下载时注意选择和你游戏版本一致的文件。
Custom Block 怎么安装?
新建世界时在「数据包」里把下载的 .zip 拖进去;已有的存档,把文件放进存档目录下的 datapacks 文件夹,进游戏输入 /reload 即可生效。服务器同样放在世界目录的 datapacks 里。
评论
登录后评论和评分