2

For some time, the item component "on_dig" has not been working correctly, and now the Bedrock Wiki displays a warning that the component has been officially removed.

Source: https://wiki.bedrock.dev/items/tool-durability.html

Is there any way to implement a working durability bar for custom tools in addons made for the most recent versions of Minecraft Bedrock?

Custom tools' durabilities automatically decrease (as is expected) when they are used to damage an entity, but nothing happens when they are used to mine a block. I would like the durability for custom tools to work the same as for vanilla tools when they are used to break blocks, too.

1

2 Answers 2

3

UPDATE: This now requires the latest beta version of @minecraft/server, 1.10.0-beta, to be specified in the manifest.json file. Otherwise, it will not work.


Here is a solution using server-side scripting: it seems to work well in the current Bedrock version (last tested with 1.20.71). The code below is taken from /scripts/main.js from the behavior pack of a template addon I've developed (free to download) with "min_engine_version" 1.20.30. The module uses server version 1.10.0-beta.

Refer to the code comments for implementation details. Note that you'll have to specify your custom tools' durabilities both in the tools' .json files and in the script file, as well as their identifiers.


Script File:

import { world, system, ItemStack } from "@minecraft/server"

// Useful Reference: https://learn.microsoft.com/en-us/minecraft/creator/scriptapi/minecraft/server/minecraft-server?view=minecraft-bedrock-stable

// The item identifiers for all the block-breaking (left click functionality) custom tools in this addon
const blockBreakingTools = [
    "tooltest:copper_pickaxe", "tooltest:copper_axe", "tooltest:copper_sword", "tooltest:copper_shovel",
    "tooltest:examplium_pickaxe", "tooltest:examplium_axe", "tooltest:examplium_sword", "tooltest:examplium_shovel",
];
// Custom tools which can be used BOTH to break blocks AND to cause an interact (i.e. right click) event, and should take durability damage in both cases, should go in BOTH arrays.
// Any custom tools which take durability damage ONLY ON INTERACT (right click) EVENTS, and NOT when used to break a block, should go here and NOT in the 'customTools' array above!
const interactionTools = [
    "tooltest:copper_hoe", "tooltest:copper_axe", "tooltest:copper_shovel",
    "tooltest:examplium_hoe", "tooltest:examplium_axe", "tooltest:examplium_shovel"
];
// Store custom tools' durabilities here, since the .maxDurability property doesn't seem to work
// IMPORTANT: Add a new property: value pair to the below object for each new custom tool material you add to this pack.
// Choose your custom tools' names such that the material's name is a SUBSTRING of the tool's name. Otherwise, the script will not work.
const customToolDurabilities = {
    "copper": 100,
    "examplium": 500
};

const strippableLogs = [
    "minecraft:oak_log", "minecraft:jungle_log", "minecraft:spruce_log", "minecraft:birch_log", "minecraft:dark_oak_log", "minecraft:acacia_log", "minecraft:mangrove_log", "minecraft:cherry_log",
    "minecraft:oak_wood", "minecraft:jungle_wood", "minecraft:spruce_wood", "minecraft:birch_wood", "minecraft:dark_oak_wood", "minecraft:acacia_wood", "minecraft:mangrove_wood", "minecraft:cherry_wood",
    "minecraft:crimson_stem", "minecraft:warped_stem", "minecraft:crimson_hyphae", "minecraft:warped_hyphae", "tooltest:examplewood_log"
];

// Utility function: avoids duplicated code between the playerBreakBlock and playerInteractWithBlock event listeners
function decrementToolDurability(event, toolTypeArray) {
    if (event.player.getGameMode() !== "creative") {
        // This is immutable, which means we can't decrement its durability directly. Instead, we'll have to make a clone
        // of the item stack, decrement that new stack's durability, and set the item in the correct slot to the new stack.
        var tool;
        if (toolTypeArray === blockBreakingTools) {
            tool = event.itemStackAfterBreak;
        } else {
            tool = event.itemStack;
        }
        
        // Only perform additional actions if the tool used to break the block was one of the custom block-breaking tools
        if (tool !== undefined && toolTypeArray.includes(tool.typeId)) {
            const player = event.player;
            const inventory = player.getComponent("minecraft:inventory").container;
            
            // Find the correct durability value for the material of the tool being used
            var toolDurability;
            for (var material in customToolDurabilities) {
                if (tool.typeId.includes(material)) {
                    toolDurability = customToolDurabilities[material];
                    break;
                }
            }
            // If tool is at 1 remaining durability, replace it with an empty slot.
            if (tool.getComponent("minecraft:durability").damage === toolDurability - 1) {
                inventory.setItem(player.selectedSlot, undefined);
                (async () => {
                    await player.dimension.runCommandAsync("playsound random.break " + player.name);
                })();
            }
            // Otherwise, make a mutable clone of the item, decrement its durability, then replace the original item in the slot with the duplicate
            else {
                var newTool = inventory.getItem(player.selectedSlot).clone();
                newTool.getComponent("minecraft:durability").damage++;
                inventory.setItem(player.selectedSlot, newTool);
            }
        }
    }
}

// Decrement custom tools' durability when they are used to break blocks outside of Creative Mode
world.afterEvents.playerBreakBlock.subscribe(event => {
    decrementToolDurability(event, blockBreakingTools);
});

// Properties are player names, as strings
// Values are objects of the form { tillingCooldown: Boolean, tilledCoarseDirtCooldown: Boolean, makePathCooldown: Boolean, stripLogCooldown: Boolean }
var forAllPlayers = {};

// Initialize active players' entries in the forAllPlayers object, to keep track of their tool interaction cooldowns
world.afterEvents.playerSpawn.subscribe(event => {
    const playerName = event.player.name;
    // Set up the entry for the given player the first time they spawn
    if (forAllPlayers[playerName] === undefined) {
        forAllPlayers[playerName] = { tillingCooldown: false, tilledCoarseDirtCooldown: false, makePathCooldown: false, stripLogCooldown: false };
    }
});

// Decrement custom tools' durabilities when they are used to perform interact events (i.e. log stripping; tilling dirt; forming grass paths) and the player is not in Creative Mode
world.beforeEvents.playerInteractWithBlock.subscribe(event => {
    const tool = event.itemStack;
    const block = event.block;
    const player = event.player;
    
    // Only perform additional actions if the tool used in the block interaction was one of the custom interaction tools
    if (tool !== undefined && interactionTools.includes(tool.typeId)) {
        // This will be set to true if the item-block interaction had an effect, and will stay false otherwise
        var shouldDecreaseDurability = false;
        // For custom hoes
        // Note that it's checking for a substring consisting of the tool's type -preceded by an underscore-. This avoids the possibility of false matches with the tool's -material- should
        // that material happen to contain the same substring. For example, comparing to "_hoe" instead of "hoe" avoids a false match with "example:shoe_leather_axe" (although why would that be a thing... XD)
        if (!forAllPlayers[player.name].tillingCooldown && tool.typeId.includes("_hoe")) {
            // Convert coarse dirt or rooted dirt to regular dirt, and set a 0.5-second cooldown to prevent it from being instantly converted to farmland afterwards
            if ((block.typeId === "minecraft:dirt" && block.permutation.getState("dirt_type") === "coarse") || block.typeId === "minecraft:dirt_with_roots") {
                (async () => {
                    // If rooted dirt is tilled, also drop a hanging roots item. This must be done BEFORE setting the block to plain dirt, or else the conditional statement will evaluate to false.
                    if (block.typeId === "minecraft:dirt_with_roots") {
                        system.run(function() { player.dimension.spawnItem(new ItemStack("minecraft:hanging_roots"), {x: block.x, y: block.y + 1, z: block.z}); });
                    }
                    await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " minecraft:dirt");
                    await player.dimension.runCommandAsync("playsound dig.grass " + player.name);
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].tillingCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].tillingCooldown = false;}, 5);
                forAllPlayers[player.name].tilledCoarseDirtCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].tilledCoarseDirtCooldown = false;}, 10);
            }
            // Convert regular dirt, grass, dirt path, or mycelium to farmland
            else if (!forAllPlayers[player.name].tilledCoarseDirtCooldown && block.typeId === "minecraft:dirt" || block.typeId === "minecraft:grass_block" || block.typeId === "minecraft:mycelium" || block.typeId === "minecraft:grass_path") {
                (async () => {
                    await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " minecraft:farmland");
                    await player.dimension.runCommandAsync("playsound dig.grass " + player.name);
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].tillingCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].tillingCooldown = false;}, 5);
            }
        }
        // For custom shovels
        else if (!forAllPlayers[player.name].makePathCooldown && tool.typeId.includes("_shovel")) {
            // Convert grass, dirt, podzol, rooted dirt or mycelium to dirt path block
            if (block.typeId === "minecraft:grass_block" || block.typeId === "minecraft:dirt" || block.typeId === "minecraft:podzol" || block.typeId === "minecraft:dirt_with_roots" || block.typeId === "minecraft:mycelium") {
                (async () => {
                    await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " minecraft:grass_path");
                    await player.dimension.runCommandAsync("playsound dig.grass " + player.name);
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].makePathCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].makePathCooldown = false;}, 5);
            }
        }
        // For custom axes
        else if (!forAllPlayers[player.name].stripLogCooldown && tool.typeId.includes("_axe")) {
            // Strip any type of log/wood
            if (strippableLogs.includes(block.typeId)) {
                (async () => {
                    // In order for the log-stripping functionality to work with custom logs, their block ids must be added to the strippableLogs array, and their names must adhere to the same naming scheme used for vanilla logs.
                    // For example, if a custom log is named "example:pine_log", then there must be another custom block in the resource pack named "example:stripped_pine_log".
                    if (block.typeId.includes("_stem") || block.typeId.includes("_hyphae")) {
                        await player.dimension.runCommandAsync("playsound dig.stem " + player.name);
                    } else {
                        await player.dimension.runCommandAsync("playsound dig.wood " + player.name);
                    }
                    // Preserve the orientation of the original block, since vanilla logs/wood have the pillar geometry
                    var logOrientation = block.permutation.getState("pillar_axis");
                    // Custom logs use "minecraft:facing_direction" instead of "pillar_axis"
                    if (logOrientation === undefined) {
                        logOrientation = block.permutation.getState("minecraft:facing_direction");
                        await player.dimension.runCommandAsync('setblock ' + block.x + " " + block.y + " " + block.z + ' ' + block.typeId.slice(0, block.typeId.indexOf(":")) + ':stripped_' + block.typeId.slice(block.typeId.indexOf(":") + 1, block.typeId.length) + ' ["minecraft:facing_direction" = "' + logOrientation + '"]');
                    } else {
                        await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " " + block.typeId.slice(0, block.typeId.indexOf(":")) + ":stripped_" + block.typeId.slice(block.typeId.indexOf(":") + 1, block.typeId.length) + ' ["pillar_axis" = "' + logOrientation + '"]');
                    }
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].stripLogCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].stripLogCooldown = false;}, 5);
            }
        }
        
        // Decrement tool's durability if the tool was used successfully
        if (shouldDecreaseDurability) {
            system.run(function() { decrementToolDurability(event, interactionTools); });
        }
    }
});

And, one of the custom pickaxes' item.json files from the same pack, for reference:

{  
  "format_version": "1.20.30",  
  "minecraft:item": {  
        "description": {  
            "identifier": "tooltest:examplium_pickaxe",  
            "menu_category": {  
                "group": "itemGroup.name.pickaxe",
                "category": "equipment"
            }  
        },  
        "components": {  
            "minecraft:is_tool": {},
            "minecraft:is_pickaxe": {},
            "tag:iron_tier": {},
            "minecraft:damage": 6,
            "minecraft:max_stack_size": 1,
            "minecraft:icon": {  
                "texture": "examplium_pickaxe"  
            },  
            "minecraft:hand_equipped": true,  
            "minecraft:display_name": {  
                "value": "Examplium Pickaxe"  
            },
            "minecraft:hover_text_color": "aqua",
            "minecraft:digger": {
                "destroy_speeds": [
                    {
                        "block": {"tags":"q.any_tag('stone','metal')"},
                        "speed": 7
                    },
                    {
                        "block": "minecraft:copper_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:coal_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:tuff",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:lapis_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_coal_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_copper_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_lapis_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:cobbled_deepslate",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:chiseled_deepslate",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_bricks",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:cracked_deepslate_bricks",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_tiles",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:cracked_deepslate_tiles",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:quartz_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:end_stone",
                        "speed": 7
                    }
                ],
                "use_efficiency": true
            },
            "minecraft:durability": { 
                "max_durability": 500
            },
            "minecraft:repairable": {
                "repair_items": [
                    {
                        "items": ["tooltest:examplium"],
                        "repair_amount": 165 // Repair ~1/3 of item's total durability per examplium block
                    }
                ]
            },
            "minecraft:enchantable": {
                "slot": "pickaxe",
                "value": 10
            }
        }
    }
}

And, here is manifest.json for the behavior pack, showing how to add the script module, and the server module as a dependency:

{
    "format_version": 2,
    "header": {
        "description": "Custom tool template behavior pack",
        "name": "ToolTemplateBP",
        "uuid": "96ed5d4c-af36-46e5-945e-fe88425b24e2",
        "version": [1, 0, 0],
        "min_engine_version": [1, 20, 30]
    },
    "modules": [
        {
            "description": "Complete tool sets from vanilla and custom materials, for reference",
            "type": "data",
            "uuid": "92d20d62-11e8-4212-bdbd-a3a44c6c6aeb",
            "version": [1, 0, 0]
        },
        {
            "description": "Custom tool template script",
            "type": "script",
            "uuid": "2897fa00-259b-41fd-84c3-23b76b5f4c48",
            "version": [1, 0, 0],
            "entry": "scripts/main.js"
        }
    ],
    "dependencies": [
        {
            "uuid": "e004fca2-73b9-425e-bb72-941ba09a6caf",
            "version": [1, 0, 0]
        },
        {
            "module_name": "@minecraft/server",
            "version": "1.10.0-beta"
        }
    ]
}
3
  • 1
    Hi Quack, does this solution still work for you? We received a similar question saying it doesn't, and I would like to rule out client-side problems first.
    – Joachim
    Feb 25 at 10:54
  • 1
    @Joachim Server version 1.8.0-beta no longer exists: it will have to be changed either to the latest stable version or to 1.9.0-beta. I will try both and then update the answer. Thanks for the update! Feb 25 at 16:32
  • 1
    @Joachim I have confirmed it will still work if you update the version number to 1.9.0-beta. Trying to use 1.8.0 gives an error. Feb 25 at 16:39
0

As of @minecraft/server version 1.10.0 (stable), it is possible to include working custom tools in your addons without requiring any experimental features.

Here is a downloadable template addon which can be used as a reference for designing your own custom tools: refer in particular to the code comments in main.js for how to integrate your new blocks/items with the script functionality.

Planet Minecraft Download

Unfortunately, it seems like fewer block tags work in conjunction with the tool tier tags in this version. This means that for blocks which require the correct tool to drop, it is necessary to manually add a list of mineable blocks inside the "destroy_speeds" array inside the "minecraft:digger" component in your custom tool's behavior pack .json file. Otherwise, the tool will not speed up mining time or obtain a drop for the block. (I will be updating the template addon with a complete list of blocks which should be mineable at each tool tier [wood, stone, iron and diamond] in the near future.)


For now, here are the new manifest.json, main.js, and a selected .item.json file, for reference:

BP/manifest.json

{
    "format_version": 2,
    "header": {
        "description": "Custom tool template behavior pack",
        "name": "ToolTemplateBP",
        "uuid": "d12be1f0-9246-4eb9-bf2c-7ebb15f3db8b",
        "version": [1, 0, 0],
        "min_engine_version": [1, 20, 50]
    },
    "modules": [
        {
            "description": "Complete tool sets from vanilla and custom materials, for reference",
            "type": "data",
            "uuid": "23306f6d-3569-43d6-a49b-122a0f3df9e1",
            "version": [1, 0, 0]
        },
        {
            "description": "Custom tool template script",
            "type": "script",
            "uuid": "e4b5fc0c-00e8-430e-8952-570cc64b5703",
            "version": [1, 0, 0],
            "entry": "scripts/main.js"
        }
    ],
    "dependencies": [
        {
            "uuid": "47805301-8411-4243-90b6-f2ca79545bb9",
            "version": [1, 0, 0]
        },
        {
            "module_name": "@minecraft/server",
            "version": "1.10.0"
        }
    ]
}

BP/scripts/main.js

import { world, system, ItemStack } from "@minecraft/server"

// Useful Reference: https://learn.microsoft.com/en-us/minecraft/creator/scriptapi/minecraft/server/minecraft-server?view=minecraft-bedrock-stable

// The item identifiers for all the block-breaking (left click functionality) custom tools in this addon
const blockBreakingTools = [
    "tooltest:copper_pickaxe", "tooltest:copper_axe", "tooltest:copper_sword", "tooltest:copper_shovel",
    "tooltest:examplium_pickaxe", "tooltest:examplium_axe", "tooltest:examplium_sword", "tooltest:examplium_shovel",
];
// Custom tools which can be used BOTH to break blocks AND to cause an interact (i.e. right click) event, and should take durability damage in both cases, should go in BOTH arrays.
// Any custom tools which take durability damage ONLY ON INTERACT (right click) EVENTS, and NOT when used to break a block, should go here and NOT in the 'customTools' array above!
const interactionTools = [
    "tooltest:copper_hoe", "tooltest:copper_axe", "tooltest:copper_shovel",
    "tooltest:examplium_hoe", "tooltest:examplium_axe", "tooltest:examplium_shovel"
];
// Store custom tools' durabilities here, since the .maxDurability property doesn't seem to work
// IMPORTANT: Add a new property: value pair to the below object for each new custom tool material you add to this pack.
// Choose your custom tools' names such that the material's name is a SUBSTRING of the tool's name. Otherwise, the script will not work.
const customToolDurabilities = {
    "copper": 100,
    "examplium": 500
};

const strippableLogs = [
    "minecraft:oak_log", "minecraft:jungle_log", "minecraft:spruce_log", "minecraft:birch_log", "minecraft:dark_oak_log", "minecraft:acacia_log", "minecraft:mangrove_log", "minecraft:cherry_log",
    "minecraft:oak_wood", "minecraft:jungle_wood", "minecraft:spruce_wood", "minecraft:birch_wood", "minecraft:dark_oak_wood", "minecraft:acacia_wood", "minecraft:mangrove_wood", "minecraft:cherry_wood",
    "minecraft:crimson_stem", "minecraft:warped_stem", "minecraft:crimson_hyphae", "minecraft:warped_hyphae", "tooltest:examplewood_log"
];

// Utility function: avoids duplicated code between the playerBreakBlock and itemUseOn event listeners
function decrementToolDurability(event, toolTypeArray) {
    //if (event.player.getGameMode() !== "creative") { ---------------------------------------------  This can be uncommented once player.getGameMode is taken out of experimental
        // This is immutable, which means we can't decrement its durability directly. Instead, we'll have to make a clone
        // of the item stack, decrement that new stack's durability, and set the item in the correct slot to the new stack.
        // Since we can't tell which item the player is actually holding (player.selectedSlot is still experimental), we'll have to
        // make an "educated guess" based on whether its durability is equal to that of the item which was used to break the block.
        var tool; var player;
        if (toolTypeArray === blockBreakingTools) {
            tool = event.itemStackAfterBreak;
            player = event.player;
        } else {
            tool = event.itemStack;
            player = event.source;
        }
        
        // Only perform additional actions if the tool used to break the block was one of the custom tools
        if (tool !== undefined && toolTypeArray.includes(tool.typeId)) {
            const inventory = player.getComponent("minecraft:inventory").container;
            
            // Find the correct durability value for the material of the tool being used
            var toolDurability;
            for (var material in customToolDurabilities) {
                if (tool.typeId.includes(material)) {
                    toolDurability = customToolDurabilities[material];
                    break;
                }
            }
            
            // Find the slot index of the first item with the right type and durability to be the one the player used.
            // We know that any item which was used to interact with or break a block *must* be in the player's hotbar, and so have a slot index value between 0 and 9 inclusive.
            var equivalentItemSlotIndex = 0;
            for (var s = 0; s < 10; s++) {
                const item = inventory.getItem(s);
                if (item !== undefined && item.typeId === tool.typeId && item.getComponent("minecraft:durability").damage === tool.getComponent("minecraft:durability").damage) {
                    equivalentItemSlotIndex = s;
                    break;
                }
            }
            
            // If tool is at 1 remaining durability, replace it with an empty slot.
            if (tool.getComponent("minecraft:durability").damage === toolDurability - 1) {
                inventory.setItem(equivalentItemSlotIndex, undefined);
                player.playSound("random.break");
            }
            // Otherwise, make a mutable clone of the item, decrement its durability, then replace the original item in the slot with the duplicate
            else {
                var newTool = inventory.getItem(equivalentItemSlotIndex).clone();
                newTool.getComponent("minecraft:durability").damage++;
                inventory.setItem(equivalentItemSlotIndex, newTool);
            }
        }
    //} --------------------------------------  Uncomment this once player.getGameMode is added to the stable version
}

// Properties are player names, as strings
// Values are objects of the form { tillingCooldown: Boolean, tilledCoarseDirtCooldown: Boolean, makePathCooldown: Boolean, stripLogCooldown: Boolean }
var forAllPlayers = {};

// Initialize active players' entries in the forAllPlayers object, to keep track of their tool interaction cooldowns
world.afterEvents.playerSpawn.subscribe(event => {
    const playerName = event.player.name;
    // Set up the entry for the given player the first time they spawn
    if (forAllPlayers[playerName] === undefined) {
        forAllPlayers[playerName] = { tillingCooldown: false, tilledCoarseDirtCooldown: false, makePathCooldown: false, stripLogCooldown: false };
    }
});

// Decrement custom tools' durability when they are used to break blocks (once player.getGameMode() is out of experimental status, we should have tools take damage only outside of Creative Mode)
world.afterEvents.playerBreakBlock.subscribe(event => {
    decrementToolDurability(event, blockBreakingTools);
});

// Decrement custom tools' durabilities when they are used to perform interact events (i.e. log stripping; tilling dirt; forming grass paths)
world.beforeEvents.itemUseOn.subscribe(event => {
    const tool = event.itemStack;
    const block = event.block;
    const blockID = block.getItemStack().typeId;
    const player = event.source;
    
    // Only perform additional actions if the tool used in the block interaction was one of the custom interaction tools
    if (tool !== undefined && interactionTools.includes(tool.typeId)) {
        // This will be set to true if the item-block interaction had an effect, and will stay false otherwise
        var shouldDecreaseDurability = false;
        // For custom hoes
        // Note that it's checking for a substring consisting of the tool's type -preceded by an underscore-. This avoids the possibility of false matches with the tool's -material- should
        // that material happen to contain the same substring. For example, comparing to "_hoe" instead of "hoe" avoids a false match with "example:shoe_leather_axe" (although why would that be a thing... XD)
        if (!forAllPlayers[player.name].tillingCooldown && tool.typeId.includes("_hoe")) {
            // Convert coarse dirt or rooted dirt to regular dirt, and set a 0.5-second cooldown to prevent it from being instantly converted to farmland afterwards
            if ((blockID === "minecraft:dirt" && block.permutation.getState("dirt_type") === "coarse") || blockID === "minecraft:dirt_with_roots") {
                (async () => {
                    // If rooted dirt is tilled, also drop a hanging roots item. This must be done BEFORE setting the block to plain dirt, or else the conditional statement will evaluate to false.
                    if (blockID === "minecraft:dirt_with_roots") {
                        system.run(function() { player.dimension.spawnItem(new ItemStack("minecraft:hanging_roots"), {x: block.x, y: block.y + 1, z: block.z}); });
                    }
                    await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " minecraft:dirt");
                    player.playSound("dig.grass");
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].tillingCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].tillingCooldown = false;}, 5);
                forAllPlayers[player.name].tilledCoarseDirtCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].tilledCoarseDirtCooldown = false;}, 10);
            }
            // Convert regular dirt, grass, dirt path, or mycelium to farmland
            else if (!forAllPlayers[player.name].tilledCoarseDirtCooldown && blockID === "minecraft:dirt" || blockID === "minecraft:grass_block" || blockID === "minecraft:mycelium" || blockID === "minecraft:grass_path") {
                (async () => {
                    await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " minecraft:farmland");
                    player.playSound("dig.grass");
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].tillingCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].tillingCooldown = false;}, 5);
            }
        }
        // For custom shovels
        else if (!forAllPlayers[player.name].makePathCooldown && tool.typeId.includes("_shovel")) {
            // Convert grass, dirt, podzol, rooted dirt or mycelium to dirt path block
            if (blockID === "minecraft:grass_block" || blockID === "minecraft:dirt" || blockID === "minecraft:podzol" || blockID === "minecraft:dirt_with_roots" || blockID === "minecraft:mycelium") {
                (async () => {
                    await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " minecraft:grass_path");
                    player.playSound("dig.grass");
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].makePathCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].makePathCooldown = false;}, 5);
            }
        }
        // For custom axes
        else if (!forAllPlayers[player.name].stripLogCooldown && tool.typeId.includes("_axe")) {
            // Strip any type of log/wood
            if (strippableLogs.includes(blockID)) {
                // In order for the log-stripping functionality to work with custom logs, their block ids must be added to the strippableLogs array, and their names must adhere to the same naming scheme used for vanilla logs.
                // For example, if a custom log is named "example:pine_log", then there must be another custom block in the resource pack named "example:stripped_pine_log".
                (async () => {
                    // Preserve the orientation of the original block, since vanilla logs/wood have the pillar geometry
                    var logOrientation = block.permutation.getState("pillar_axis");
                    // Custom logs use "minecraft:facing_direction" instead of "pillar_axis"
                    if (logOrientation === undefined) {
                        logOrientation = block.permutation.getState("minecraft:facing_direction");
                        await player.dimension.runCommandAsync('setblock ' + block.x + " " + block.y + " " + block.z + ' ' + blockID.slice(0, blockID.indexOf(":")) + ':stripped_' + blockID.slice(blockID.indexOf(":") + 1, blockID.length) + ' ["minecraft:facing_direction" = "' + logOrientation + '"]');
                    } else {
                        await player.dimension.runCommandAsync("setblock " + block.x + " " + block.y + " " + block.z + " " + blockID.slice(0, blockID.indexOf(":")) + ":stripped_" + blockID.slice(blockID.indexOf(":") + 1, blockID.length) + ' ["pillar_axis" = "' + logOrientation + '"]');
                    }
                    if (blockID.includes("_stem") || blockID.includes("_hyphae")) {
                        player.playSound("dig.stem");
                    } else {
                        player.playSound("dig.wood");
                    }
                })();
                shouldDecreaseDurability = true;
                forAllPlayers[player.name].stripLogCooldown = true;
                system.runTimeout(function() {forAllPlayers[player.name].stripLogCooldown = false;}, 5);
            }
        }
        
        // Decrement tool's durability if the tool was used successfully
        if (shouldDecreaseDurability) {
            system.run(function() { decrementToolDurability(event, interactionTools); });
        }
    }
});

BP/items/examplium_pickaxe.item.json

{  
  "format_version": "1.20.50",  
  "minecraft:item": {  
        "description": {  
            "identifier": "tooltest:examplium_pickaxe",  
            "menu_category": {  
                "group": "itemGroup.name.pickaxe",
                "category": "equipment"
            }  
        },  
        "components": {  
            "minecraft:is_tool": {},
            "minecraft:is_pickaxe": {},
            "tag:iron_tier": {},
            "minecraft:damage": 6,
            "minecraft:max_stack_size": 1,
            "minecraft:icon": {  
                "texture": "examplium_pickaxe"  
            },  
            "minecraft:hand_equipped": true,  
            "minecraft:display_name": {  
                "value": "item.tooltest:examplium_pickaxe.name"  
            },
            "minecraft:hover_text_color": "aqua",
            "minecraft:digger": {
                "destroy_speeds": [ // TODO: add quartz, sandstone, diamond/gold blocks, and other stone/metal-type blocks this item should be able to mine
                    {
                        "block": {"tags":"q.any_tag('stone','metal')"},
                        "speed": 7
                    },
                    {
                        "block": "minecraft:copper_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:iron_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:coal_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:lapis_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:gold_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:diamond_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:redstone_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:lit_redstone_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:emerald_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:tuff",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:pointed_dripstone",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_coal_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_copper_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_lapis_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_gold_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_iron_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_diamond_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_redstone_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:lit_deepslate_redstone_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_emerald_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:cobbled_deepslate",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:chiseled_deepslate",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_bricks",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:cracked_deepslate_bricks",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:deepslate_tiles",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:cracked_deepslate_tiles",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:quartz_ore",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:end_stone",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:basalt",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:smooth_basalt",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:polished_basalt",
                        "speed": 7
                    },
                    {
                        "block": "minecraft:calcite",
                        "speed": 7
                    }
                ],
                "use_efficiency": true
            },
            "minecraft:durability": { 
                "max_durability": 500
            },
            "minecraft:repairable": {
                "repair_items": [
                    {
                        "items": ["tooltest:examplium"],
                        "repair_amount": 165 // Repair ~1/3 of item's total durability per examplium block
                    }
                ]
            },
            "minecraft:enchantable": {
                "slot": "pickaxe",
                "value": 10
            }
        }
    }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .