たくさんの自由帳

自作 MOD の Minecraft 1.21.5 移行メモ

投稿日 : | 0 日前

文字数(だいたい) : 2407

どうもこんばんわ。

本題

Minecraft 1.21.5がリリースされたので自作MODを対応させました。
わんちゃんの柄が増えた?

Imgur

Imgur

Imgur

前回

https://takusan.negitoro.dev/posts/minecraft_mod_1_21_4_migration/

公式

今回も今回とてFabricチームがまとめてくれているので読みます

https://fabricmc.net/2025/03/24/1215.html

Gradle

FabricForge8.12.1になってます。NeoForge8.12

ツールチップを付けるメソッドが非推奨化

そして代替メソッドが見つからない、それっぽい名前のはあるんだけど全く引数が違う。。

データコンポーネントとツールチップ

https://wiki.fabricmc.net/tutorial:tooltip#adding_tooltips_in_1215

どうやらデータコンポーネント(耐久、付いているエンチャント、金床のコスト)の中にツールチップに関する処理が移動した?
その上、ツールチップの表示処理を見ると、バニラのデータコンポーネントだけが列挙されてて、自作した所でデータコンポーネントを差し込む所が見つけられなかった。。。

Fabric

Fabricの場合はFabric APIが独自のツールチップ追加イベントを飛ばしてくれるので、そのタイミングでやればいいらしい。
このイベントをMOD初期化時に一回呼べば良い(@Modがついてるクラスのコンストラクタとかで)

というわけで適当にイベント登録する関数を作って、

/** ツールチップイベントを拾う */
object ClickManaitaTooltipEventCallback {
 
    /** ツールチップ表示イベントを登録する */
    fun registerTooltipEventCallback() {
        // ツールチップの実装が変わってしまったので対応
        // https://wiki.fabricmc.net/tutorial:tooltip#adding_tooltips_in_1215
        ItemTooltipCallback.EVENT.register tooltipCallback@{ itemStack, _, _, list ->
            val tooltipText = when (val item = itemStack.item) {
                is ClickManaitaBaseItem -> item.getTooltipText()
                is ClickManaitaCustomItem -> item.getTooltipText(itemStack)
                else -> return@tooltipCallback
            }
            list.add(tooltipText)
        }
    }
}

@Modが付いたクラスのコンストラクタで呼び出す。
Kotlinで書いているので(Fabric Language Kotlinなので)コンストラクタじゃなくて関数だけど、、

@Suppress("unused")
fun init() {
    // 以下省略...
 
    // イベント登録
    ClickManaitaTooltipEventCallback.registerTooltipEventCallback() // これ
}

ちなみにgetTooltipText()はこれ。MutableTextを返している。

class ClickManaitaBaseItem(settings: Settings?, private val dropSize: Int = 2) : Item(settings) {
 
    /** ツールチップの文言を返す */
    fun getTooltipText(): MutableText {
        return MutableText.of(PlainTextContent.of("x$dropSize")).setStyle(Style.EMPTY.withColor(Formatting.AQUA))
    }
 
}

NeoForge

NeoForgeもソースコード見てたら見つけました。Fabricと同様にイベントを初期化時に一発購読すれば取れます。
まずはイベントを受け取るため、イベント受け取り用のクラスを作って、メソッドを作ります。

Fabricと違い、@SubscribeEventを付けると受け取れます。
どこからも呼び出されない関数なので、静的解析(IDEA)がこれ使ってないやん消せるって言ってきますが、実行中に呼び出されるので@SuppressWarnings("unused")を付けておきます。
警告が消えるとかのレベルなんですが。

ツールチップの上書きイベントを受け取る場合、引数の数、型 (シグネチャ) を合わせておく必要があります。名前は多分なんでも良い。
今回の場合はItemTooltipEventを一つだけ取るメソッドを用意しておけば良いはず。

public class ClickManaitaPlayerEvent {
 
    /**
     * ツールチップを出すメソッドが非推奨になってしまったので
     */
    @SuppressWarnings("unused")
    @SubscribeEvent
    public void onItemTooltip(ItemTooltipEvent event) {
        ItemStack itemStack = event.getItemStack();
        List<Component> toolTip = event.getToolTip();
 
        MutableComponent text = switch (itemStack.getItem()) {
            case ClickManaitaBaseItem baseItem -> baseItem.getHoverText(itemStack);
            case ClickManaitaBlockItem blockItem -> blockItem.getHoverText();
            default -> null;
        };
        if (text != null) {
            toolTip.add(text);
        }
    }
}

このクラスを、MOD初期化時に一発呼べば良いはず。
@Modが付いたクラスのコンストラクタが良いかな。

@Mod(ClickManaita.MOD_ID)
public class ClickManaita {
 
    /**
     * MODのID
     */
    public static final String MOD_ID = "clickmanaita";
 
    /**
     * コンストラクタ
     */
    public ClickManaita(IEventBus modEventBus, ModContainer modContainer) {
        // 省略...
 
        NeoForge.EVENT_BUS.register(new ClickManaitaPlayerEvent()); // これ
    }
}

ちなみにgetHoverText()MutableComponentを返しているだけです。

public MutableComponent getHoverText(ItemStack itemStack) {
    MutableComponent text = Component.literal(toolTipText);
    text.setStyle(Style.EMPTY.withColor(TextColor.parseColor(toolTipColor).getOrThrow()));
    return text;
}

Imgur

Forge

Forgeも同様にイベントがあります。ので購読すれば良さそう。
NeoForgeとほぼ同じなのでコードだけ貼ります。NeoForgeで書いたものを、IDEAのブランチ間差分でForge側にコピペしただけなので、、、

Imgur

public class ClickManaitaPlayerEvent {
 
    /**
     * ツールチップを出すメソッドが非推奨になってしまったので
     */
    @SuppressWarnings("unused")
    @SubscribeEvent
    public void onItemTooltip(ItemTooltipEvent event) {
        ItemStack itemStack = event.getItemStack();
        List<Component> toolTip = event.getToolTip();
 
        MutableComponent text = switch (itemStack.getItem()) {
            case ClickManaitaBaseItem baseItem -> baseItem.getHoverText(itemStack);
            case ClickManaitaBlockItem blockItem -> blockItem.getHoverText();
            default -> null;
        };
        if (text != null) {
            toolTip.add(text);
        }
    }
}
@Mod(ClickManaita.MOD_ID)
public class ClickManaita {
 
    /**
     * MODのID
     */
    public static final String MOD_ID = "clickmanaita";
 
    /**
     * コンストラクタ
     */
    public ClickManaita(FMLJavaModLoadingContext context) {
        // 以下省略...
 
        // プレイヤーイベント
        MinecraftForge.EVENT_BUS.register(new ClickManaitaPlayerEvent());
    }
}

道具アイテムのクラスが消えた?

つるはしクラスと、剣クラスが消えた。斧とかは残ってる。
代わりにnew Item()の際にItem.Settings().pickaxe()とかを付けるようになった?

onStateReplaced の引数変更

見た感じ引数を直して、中身はItemScatterer.onStateReplaced(state, world, pos)を呼び出すだけ?

差分

はい

おわりに

Kotlinの言語レベルのnull安全に慣れすぎてOptional<T>が何もわからない。。。
Optional#mapするくらいなら早期returnしてく、、れ。nullable を引き回すのは、、、