はじめに
Minecraft Java版のMod開発における「Mixin」をご存知ですか?
MixinはModdingをする上での必須技術と言っても過言ではありません。
この記事では、このMixinについて簡単にご紹介したいと思います。
対象読者
- ForgeまたはFabricのMod開発をしている
- Mixinについて知らない
この記事では扱わないこと
- Mixinの環境構築、コーディングの解説
- Forge、FabricなどのMod作成の解説
Mixinとは?
Minecraft Java版の既存のソースコードを、実行時に変更することができるフレームワークです。
- Mod開発で利用される
- SpongePoweredが開発
できるようになること
Mixinを使わない場合
Mixinを使わないでMod開発をする場合、
- イベントシステム
- タスクシステム
- イニシャライザー
などの、APIよりあらかじめ提供されているエントリーポイントに沿って、オリジナルの処理を加えていくことになるでしょう。
しかしながら、こんなときはどうすればいいでしょうか?
「○○の部分に処理を加えたいのに、いい感じのイベントがない!!」
「既存の○○を無効化したいのに、APIでサポートされてない!!」
このように、APIでサポートされていない機能に対してModを適用する場合、複雑な実装になりがちです。
Mixinで解決
Mixinはこれらの問題を解決します。
Mixinにより可能になる主なことを、まとめます。
-
ソースコードの任意の場所に、自由に処理を加えられる
-
ソースコード上のメソッドの呼び出しや、フィールド、変数へのアクセスを書き換えられる
-
privateなメソッド、フィールドへのアクセサーを追加できる
※正確には他にもあります
ひとつずつ簡単に説明します。
1. 【Inject】処理の追加する
MixinではInject
と呼ばれます。
これは、マインクラフト内部のmethod()
の中へ、オリジナルの処理injected()
を追加する例です。
// マインクラフト内部のメソッド
public void foo() {
// Modにより追加された処理
+ injected(new CallbackInfo("foo", false));
// 元からある処理
doSomething1();
doSomething2();
doSomething3();
}
// https://fabricmc.net/wiki/tutorial:mixin_examplesより引用
他にも、次のようなことも可能です。
- 任意の場所で
return;
する - メソッドの返し値を書き換える
2. 【Redirect】呼び出しを変更する
MixinではRedirect
と呼ばれます。
// マインクラフト内部のメソッド
public void foo() {
doSomething1();
Something something = new Something();
// 元からある処理は削除される
- int i = something.doSomething(10);
// Modにより定義された処理に置き換わる
+ int i = injected(something, 10);
doSomething2();
}
// https://fabricmc.net/wiki/tutorial:mixin_examplesより引用
正確には異なる機能ですが、似たようなもので次のものもあります。
-
int i = 4;
の4
といった定数の部分を置き換えるModifyConstant
-
doSomegthing(i);
のi
といったメソッドの引数を置き換えるModifyArg
ModifyArgs
- ローカル変数を書き換える
ModifyVariable
3. 【Accessor】privateへのアクセサーを追加する
MixinではInvoker
やAccessor
と呼ばれます。
privateなメソッドを呼び出せるようにする
EndermanEntity enderman = ...;
// EndermanEntityInvokerを経由して、通常では呼び出せないprivateメソッドを呼び出せる
((EndermanEntityInvoker) enderman).invokeTeleportTo(0.0D, 70.0D, 0.0D);
// https://fabricmc.net/wiki/tutorial:mixin_accessorsより引用
privateなフィールドにアクセスする
// 通常ではアクセス出来ないフィールド、itemUseCooldownにアクセス
int itemUseCooldown = ((MinecraftClientAccessor) MinecraftClient.getInstance()).getItemUseCooldown();
// https://fabricmc.net/wiki/tutorial:mixin_accessorsより引用
「リフレクションを使えばいいのでは?」
と言われそうですが、リフレクションにはない次のメリットがあります。
- リフレクションに比べて早い
- アクセサーの定義はコンパイル時なので型安全
最後に
Mixinを扱えるようになると、Modで作れるものが大幅に増えます。
まだまだ日本語の文献が少ない状況ですが、みなさんも是非学んでみてください。
おまけ
Mixinの実装はKotlin、Scalaなどで行えません;;
一度はJavaの沼から抜け出した皆さんも、再びJavaを書くチャンスです!やったね!
あと詳しくは知らないけど、Mixinはサーバープラグインにも適用できるらしい。
参考資料&補足資料
FabricMCによる解説
今すぐMixinを使いたいならこっちがおすすめ。
開発元SpongePoweredによるドキュメント
技術的な内容ばかりで、実践的なことは書かれてないかも。
数少ない日本語文献
宣伝
Youtubeチャンネル
自作Modを遊ぶゆっくり実況動画を投稿しています。
登録者は15万人ほどです。
X(旧Twitter)
技術に関する投稿をしています。
Discordサーバー
マイクラ技術系をメインに交流できるサーバーです。
多少内輪ノリがありますが、興味があればどうぞ。