/** * @packageDocumentation * Add some useful custom components in Minecraft Bedrock Edition. * @license MIT * @author CTN Studios Contributors * @document */ import { Entity, EquipmentSlot, GameMode, ItemComponent, ItemComponentTypes, ItemDurabilityComponent, ItemStack, Player, world, } from "@minecraft/server"; /** * Dispose the item when entity use it. * @param durability The durability to reduce. * @param item The item to be used. * @param entity The entity that used the item. */ function disposeItem( durability: number, item: ItemStack, entity: Entity ): void { const newItem = consumeDurability(item, durability, entity); setEquipmentItem(entity, newItem); } /** * Damage an {@link ItemStack}. * @param item The {@link ItemStack} to be damaged. * @param value The durability to be removed. * @param entity The optional {@link Entity} which breaks this tool. * @returns the damaged {@link ItemStack}. */ function consumeDurability( item: ItemStack, value: number, entity?: Entity ): ItemStack | undefined { const durability: undefined | ItemComponent = item.getComponent( ItemComponentTypes.Durability ); if ( durability === undefined || !(durability instanceof ItemDurabilityComponent) ) return item; if (durability.damage + value >= durability.maxDurability) { if (entity instanceof Player) { entity.playSound("random.break"); } return undefined; } else { durability.damage += value; return item; } } /** * Replaces the item in the given EquipmentSlot. * @param entity The owner of the slot. * @param item The item to equip. If undefined, clears the slot. * @param slot The slot to set item stack, default is {@link EquipmentSlot.Mainhand}. */ function setEquipmentItem( entity: Entity, item?: ItemStack, slot: EquipmentSlot = EquipmentSlot.Mainhand ): boolean | undefined { return entity.getComponent("equippable")?.setEquipment(slot, item); } /** * Registry a `lazuli:custom_tool` component in game. * * You can use {@link CustomToolComponent.registry} method to registry it. * * The following code can be used to registry this component: * * ~~~ts * CustomToolComponent.registry(); * ~~~ * * After registied it, add following code your item JSON file: * ~~~json * "minecraft:custom_components": ["lazuli:custom_tool"] * ~~~ * * @remarks * Registry a `lazuli:custom_tool` component in game. */ export class CustomToolComponent { private constructor() {} static registry() { world.beforeEvents.worldInitialize.subscribe((event) => { const REGISTER = event.itemComponentRegistry; REGISTER.registerCustomComponent("lazuli:custom_tool", { onMineBlock(arg) { const item = arg.itemStack; if (item) { if (arg.source instanceof Player) { if ( arg.source.getGameMode() === GameMode.survival || arg.source.getGameMode() === GameMode.adventure ) disposeItem(1, item, arg.source); } else { disposeItem(1, item, arg.source); } } }, onHitEntity(arg) { const item = arg.itemStack; if (item) { if (arg.attackingEntity instanceof Player) { if ( arg.attackingEntity.getGameMode() === GameMode.survival || arg.attackingEntity.getGameMode() === GameMode.adventure ) disposeItem(2, item, arg.attackingEntity); } else { disposeItem(2, item, arg.attackingEntity); } } }, }); }); } } /** * Registry a `lazuli:custom_weapon` component in game. * * You can use {@link CustomWeaponComponent.registry} method to registry it. * * The following code can be used to registry this component: * * ~~~ts * CustomWeaponComponent.registry(); * ~~~ * * After registied it, add following code your item JSON file: * ~~~json * "minecraft:custom_components": ["lazuli:custom_weapon"] * ~~~ * * @remarks * Registry a `lazuli:custom_weapon` component in game. */ export class CustomWeaponComponent { private constructor() {} static registry() { world.beforeEvents.worldInitialize.subscribe((event) => { const REGISTER = event.itemComponentRegistry; REGISTER.registerCustomComponent("lazuli:custom_tool", { onMineBlock(arg) { const item = arg.itemStack; if (item) { if (arg.source instanceof Player) { if ( arg.source.getGameMode() === GameMode.survival || arg.source.getGameMode() === GameMode.adventure ) disposeItem(2, item, arg.source); } else { disposeItem(2, item, arg.source); } } }, onHitEntity(arg) { const item = arg.itemStack; if (item) { if (arg.attackingEntity instanceof Player) { if ( arg.attackingEntity.getGameMode() === GameMode.survival || arg.attackingEntity.getGameMode() === GameMode.adventure ) disposeItem(1, item, arg.attackingEntity); } else { disposeItem(1, item, arg.attackingEntity); } } }, }); }); } }