BeforeItemUseOnEventは、エンティティ(プレイヤーを含む)がブロックに対してアイテムを使おうとしたときに発火するイベントです。実際にアイテムをブロックに対して使う前に何かしらの処理を挟むときなどに利用できます。
プロパティ
blockFace
read-only blockFace: Direction;
アイテムが使われているブロックの面に関する情報。
Type: Direction(公式サイト)
blockLocation
read-only blockLocation: BlockLocation;
アイテムを使われるブロック(影響を受けるブロック)の位置。
Type: BlockLocation(公式サイト)
cancel
cancel: boolean;
アイテム使用時の動作をキャンセルするかどうか。trueにセットするとアイテムの使用をキャンセルします。
Type: boolean
faceLocationX
read-only faceLocationX: number;
対象ブロックに対してアイテムが使われる際のX座標(カーソル位置のX座標)。
Type: number
faceLocationY
read-only faceLocationY: number;
対象ブロックに対してアイテムが使われる際のY座標(カーソル位置のY座標)。
Type: number
item
item: ItemStack;
ブロックに対して使用したアイテム(アイテムスタック)。
Type: ItemStack (公式サイト)
source
read-only source: Entity;
このイベントを発生させたエンティティ。エンティティはプレイヤーを含む。
Type: Entity (公式サイト)
サンプルコード
棒を持った状態でしかチェストを開けなくする
BeforeItemUseOnEventイベントは実際にアイテムが使われてその効果が出る「前」にイベントを挟み込むことができるのが特徴です。これにより「特定のアイテムを持っていない場合にイベントをキャンセルする」こともできます。
例えば以下のようなコードで「棒を持った状態でしかチェストを開けなくする」といった機能を実現できます。
import { world } from "@minecraft/server";
world.events.beforeItemUseOn.subscribe(ev => {
// アイテムを使ったのがプレイヤーの場合のみ
if (ev.source.typeId === "minecraft:player") {
// そのアイテムが棒(minecraft:stick)以外の場合、
if (ev.item.typeId !== "minecraft:stick") {
// アイテムを使った先のブロックの座標からブロックを取得し、
// そのブロックがチェスト(minecraft:chest)だったらイベントをキャンセルする。
// = 棒以外のアイテムではチェストが開かなくなる。
const block = ev.source.dimension.getBlock(ev.blockLocation);
if (block.typeId === "minecraft:chest") {
ev.cancel = true;
}
}
}
});
使ったアイテムのネームタグが特定の文字列の場合しかチェストを開けない、みたいにすればマルチで謎解きクエストみたいなことが実現できそうですね!
上のコードを定数クラスを使って書く場合は次の通り。こちらの方が打ち間違えが発生しにくくバグも少なくなるでしょう。
import { MinecraftBlockTypes, MinecraftEntityTypes, MinecraftItemTypes, world } from "@minecraft/server";
world.events.beforeItemUseOn.subscribe(ev => {
// アイテムを使ったのがプレイヤーの場合のみ
if (ev.source.typeId === MinecraftEntityTypes.player.id) {
// そのアイテムが棒(minecraft:stick)以外の場合、
if (ev.item.typeId !== MinecraftItemTypes.stick.id) {
// アイテムを使った先のブロックの座標からブロックを取得し、
// そのブロックがチェスト(minecraft:chest)だったらイベントをキャンセルする。
// = 棒以外のアイテムではチェストが開かなくなる。
const block = ev.source.dimension.getBlock(ev.blockLocation);
if (block.typeId === MinecraftBlockTypes.chest.id) {
ev.cancel = true;
}
}
}
});
関数型プログラミングではこんな感じでしょうか。慣れればこれの方が見やすいかも。
import { MinecraftBlockTypes, MinecraftEntityTypes, MinecraftItemTypes, world } from "@minecraft/server";
world.events.beforeItemUseOn.subscribe(ev => {
[ev]
.filter(e => e.source.typeId === MinecraftEntityTypes.player.id)
.filter(e => e.item.typeId !== MinecraftItemTypes.stick.id)
.map(e => e.source.dimension.getBlock(e.blockLocation))
.filter(block => block.typeId === MinecraftBlockTypes.chest.id)
.map(() => ev.cancel = true);
});
まとめ
BeforeItemUseOnEventイベントはアイテムをブロックに対して使った際に、その効果が表れる「前」に処理を挟むことができることを解説しました。特定の条件の時のみアイテムやブロックのイベントを続行できるようにできるとアドオンの幅が広がると思いますのでチャレンジしてみてください。