-
Notifications
You must be signed in to change notification settings - Fork 0
build a custom tool
This lesson shows how the Chisel is built and how you can use the same pattern to invent another tool. It is written for young programmers, but it uses the real files and code from STEMCraft.
A custom tool has several parts that cooperate:
- Item data tells the server its name, durability and texture.
- A recipe tells Minecraft how players obtain it.
- A texture tells Java and Bedrock what it looks like.
- A feature class listens for a player action and changes the game.
- Tests check the rules without needing a person to try every block.
- Documentation teaches players how to use it.
Think of these as members of a robot team. The texture is the costume, the recipe is the assembly plan, and the Java class is the brain.
Create a branch before editing anything:
git switch -c feature/my-toolChoose a small first version. Write down these answers before coding:
- What item does the player hold?
- What exact action activates it?
- Which blocks or creatures may it affect?
- What must it never affect?
- Does one use cost durability?
- How will a player know that it worked?
For the Chisel, the action is “right-click a supported block”. It never rotates complicated blocks such as doors, beds, chests, rails or redstone machinery.
Open plugin/src/main/resources/data-packs/stemcraft-survival/configs/custom-items.yml. The Chisel begins like this:
custom-items:
chisel:
material: FLINT
name: "<gray>Chisel"
texture: "stemcraft_survival:item/chisel"
lore:
- "<dark_gray>Right-click a supported block to rotate it"
placement: DENY
max-stack-size: 1
max-damage: 256Here is what each line means:
-
chiselis the logical ID. Code uses this ID even if the name or picture changes. -
materialis the harmless vanilla item Minecraft uses underneath the custom appearance. -
nameandloreare the words a player sees. The colour tags use MiniMessage. -
texturepoints to the image inside the data pack. -
placement: DENYstops an item with block-like backing data from being placed accidentally. -
max-stack-size: 1makes it behave like a tool. -
max-damagecreates its durability bar. Set this only on non-stackable tools.
When inventing your tool, pick a unique lowercase ID with hyphens. Keep the description short enough to read on a phone or tablet.
The Chisel recipe is in the same YAML file:
recipes:
shaped:
chisel:
result: "stemcraft:chisel"
amount: 1
shape:
- " I "
- " S "
ingredients:
I: IRON_INGOT
S: STICKEvery character in shape is one crafting-table square. Spaces are empty squares. Every letter must have a matching material under ingredients. The result uses the custom item ID, with stemcraft: in front and underscores in place of hyphens when necessary.
Good recipes tell a tiny story. Iron is the cutting edge and the stick is the handle. Avoid making a simple building helper cost diamonds or rare treasure unless the tool is extremely powerful.
The Chisel texture lives at:
plugin/src/main/resources/data-packs/stemcraft-survival/
contents/stemcraft_survival/textures/item/chisel.png
Use a 16×16 PNG with transparency. Keep the outline strong and use only a few colours so the picture is readable in a hotbar slot. The resource-pack builder uses the YAML metadata to generate the Java model and the Bedrock/Geyser item mapping from this single source.
If the item appears as flint, first check the texture path and then rebuild and accept the resource pack. A working behavior with the wrong picture usually means the Java code is fine and the resource-pack data needs attention.
Feature classes live in plugin/src/main/java/dev/stemcraft/feature. STEMCraft discovers classes that extend BaseFeature, so no giant registration list is needed.
The Chisel registers a PlayerInteractEvent listener in onEnable(). Its handler follows a guard-clause pattern:
player action
↓
Is it a main-hand right-click on a block?
↓ yes
Is the held item really stemcraft:chisel?
↓ yes
Is this block safe and meaningful to rotate?
↓ yes
Rotate → cancel normal use → sound/particles → damage tool
Guard clauses are early if (...) return; checks. They keep unrelated actions out of the feature and make the successful path easy to read.
Never identify a custom item only by its vanilla material or display name. Players can rename things, and several custom items may share one backing material. Use:
api.items().isCustomItemId("chisel", event.getItem())For Bedrock compatibility, react to normal Bukkit events and let Geyser translate the player's input. Avoid instructions that require a Java-only key. Also check event.getHand() so one tap is not processed twice.
A block's Material says what it is. Its BlockData stores details such as direction, axis, stair half and waterlogging.
The Chisel changes only one suitable property:
-
Directionalblocks move north → east → south → west. -
Orientableblocks move through the X, Y and Z axes. -
Rotatabledecorations move one of sixteen small steps.
Because the code changes the existing BlockData, a stair keeps unrelated properties such as its top/bottom half and waterlogged state. Minecraft may recalculate a corner shape when its new direction meets neighbouring stairs. Do not replace a stair with a new default stair just to change its direction; that would throw useful state away.
Some blocks need special care. A door has two halves, a bed has two blocks, a chest may be paired, and redstone can activate machines. Leave those out until you have designed and tested the whole rule. “Do nothing” is a good safe answer when a tool does not understand a block.
The Chisel cancels the normal interaction only after it knows a rotation is possible. It then plays a quiet grindstone sound and creates three particles. Durability is spent only after success, and Creative players do not spend durability.
This order matters. If you cancel too early, players may be unable to use an ordinary block even though the tool did nothing. If you damage too early, failed attempts waste the tool.
The event listener runs at high priority and ignores already-cancelled events. This lets protection plugins stop the edit before the Chisel acts. Your tools must respect protected builds too.
Tests live in plugin/src/test/java. ChiselFeatureTest asks four focused questions:
- Does a north-facing stair turn east?
- Does a vertical log move to the next axis?
- Does a standing decoration move one rotation step?
- Are unsafe directional blocks and plain terracotta rejected?
Run the focused tests while working:
./gradlew :plugin:test --tests dev.stemcraft.feature.ChiselFeatureTestThen run the whole project suite:
./gradlew testA test is not proof that no bug exists. It is a repeatable experiment that protects rules you already understand.
Before release, try both Java and Bedrock:
- Craft the tool and confirm the recipe-book result has the right name and image.
- Rotate every supported block family in all starting directions.
- Try unsupported blocks and confirm nothing happens or wears down.
- Try main hand and off hand.
- Try Survival and Creative mode.
- Try a protected area where building is denied.
- Use the tool until it breaks and watch the durability bar.
- Reconnect and confirm the item still has its identity and damage.
Touch controls can feel different from a mouse, so a Bedrock test is a real requirement, not an optional extra.
Once you understand this pattern, try a carefully limited tool such as a painter that cycles safe colours, a survey tool that reports block facts, or a gardener's tool that changes one crop-related state. Begin with one action and a short allow-list. Add powerful behavior only after tests explain its boundaries.
Before opening a pull request, check that your branch contains the item YAML, recipe, texture, feature code, tests, public instructions and developer notes. Another person should be able to understand both what your tool does and what it deliberately refuses to do.
- Home
- Architecture
- Services
- Features
- Build a Custom Tool
- Agriculture and Cooking
- Survival quality of life
- Custom items
- Slime and Magma Buckets
- Comets
- Rotten Flesh Uses
- Iron Golem Poppy Luring
- Gifts
- Mailboxes
- Notice boards
- Named regions
- Interactive guide callbacks
- Quests
- Commands
- API
- Minigames
- Minigame placeholders
- Tab completion
- Configuration
- Entitlements and badges
- Player reset service