はじめに
1.18でマルチツールを作る際に躓いていたのになんかあっさり出来てしまったので、同じことをしたい方がいらっしゃれば自由に流用してください。
開発環境
今回は以下の環境でやっていきます。
- Windows 10
- Eclipse Temurin JDK with Hotspot 17.0.2
- Minecraft 1.18.2
- MinecraftForge 40.0.3
- IntelliJ IDEA 2021.3.2
BlockStateについて
BlockStateの中に「#minecraft:mineable/pickaxe」ってのがありますね。
最近のMinecraftはデータパックなるものに対応したので簡単なModならJavaの知識無しで作れるようになったわけです。それに対応するために「このブロックはツルハシで破壊できるよ」ってフラグを付けているのがこれです。バニラだと「BlockTags.MINEABLE_WITH_PICKAXE」のリストに入っているブロックにのみ適応されます。
ツールの処理の流れ
public class DiggerItem extends TieredItem implements Vanishable {
//ブロックのリスト
private final TagKey<Block> blocks;
//破壊速度
protected final float speed;
public DiggerItem(float p_204108_, float p_204109_, Tier p_204110_, TagKey<Block> p_204111_, Item.Properties p_204112_) {
super(p_204110_, p_204112_);
this.blocks = p_204111_;
this.speed = p_204110_.getSpeed();
}
//this.blocksの中で対応するブロックに対して任意の破壊速度を適用
public float getDestroySpeed(ItemStack p_41004_, BlockState p_41005_) {
return p_41005_.is(this.blocks) ? this.speed : 1.0F;
}
}
バニラのツール類の元になるソースを一部抜粋してきました。
getDestroySpeed()にてTagKeyで指定したブロックに対しての破壊速度を適用しています。
なので...
public class HammerItem extends DiggerItem {
public HammerItem(Tier tier, int attackDamage, float attackSpeed, Item.Properties properties) {
super(attackDamage, attackSpeed, tier, BlockTags.MINEABLE_WITH_PICKAXE, properties);
}
@Override
public float getDestroySpeed(ItemStack itemStack, BlockState blockState) {
if (blockState.is(BlockTags.MINEABLE_WITH_PICKAXE)) {
return this.speed;
}
if (blockState.is(BlockTags.MINEABLE_WITH_AXE)) {
return this.speed;
}
if (blockState.is(BlockTags.MINEABLE_WITH_SHOVEL)) {
return this.speed;
} else {
return 1F;
}
}
}
こうやってゴリ押しすればなんかいい感じに動きます。
ただしこの場合デフォルトでツルハシ、斧、シャベルで適正ツールが登録されていないブロックも破壊速度が適用されません。海外製ModのMekanismなんかは新たにTagKeyを作ってオリジナルのプロパティを追加してたりするのでソースコードがえげつないことになってます。個人用で軽く済ませたいならこれが一番手っ取り早いと思います。
参考 GitHub - mekanism/Mekanism ~~ tools/item/ItemMekanismPaxel.java
終わりに
1.18になってMinecraftの仕様やForgeの仕様も大幅に変更され、出来ることは増えましたが、昔は数行で動いたプログラムが今じゃ百行くらい書かないと動かなくなったり。
個人的には1.7.10のときの使用に戻してほしいです...。