MOD開発講座

概要

TNT Moddersが作成した、MOD開発の始め方に関する解説です。Javaの基礎知識を前提とし、その解説は行っておりませんのでご了承ください。

準備から入門編までの各項目は、それまでのコードに追加する形になっており、「ビルド」まででMODを一つ完成させます。初級編以降の各項目は、入門編のコードを基準として追加を行います。

 

利用ライセンス

本開発講座は、本webページ上の他の記事と同様にTNT Moddersがすべての権利を留保しています。 但し、本開発講座上のコード部分のみ、ユーザーのMOD開発のために部分的に改変した上で組み込み、自由に利用することを許可します。

具体例

○本開発講座のコードをコピーし、実装したアイテムを自分のMODのものに置き換えた上で利用する
○本開発講座のコードを参考にし、自分のMODにエンティティを追加する処理を実装する

×本開発講座のテクスチャをそのまま利用し二次配布する
×本開発講座の内容を正当な引用ではなく無断で転載する

MODの開発は自己責任で行ってください。この講座により生じたいかなる損害についても、TNT Moddersは一切責任を負いません。

 

ページ一覧

最新の情報はForgeのフォーラムを確認してください。

1.19.4

入門編

  1. 環境構築
  2. アイテムの追加
  3. リソースの自動生成
  4. ブロックの追加
  5. イベントの追加
  6. ビルド

初級編

  1. レシピの追加
  2. クリエイティブタブの追加
  3. 進捗の追加
  4. タグの追加

1.18.2

入門編

  1. 環境構築

1.16.5

入門編

  1. 環境構築
  2. アイテムの追加
  3. ブロックの追加
  4. レシピの追加
  5. MODの情報の登録
  6. ビルド

初級編

1.16.4

入門編

  1. 環境構築
  2. アイテムの追加
  3. ブロックの追加
  4. レシピの追加
  5. MODの情報の登録
  6. ビルド

初級編

1.14.4

入門編

  1. 環境構築
  2. アイテムの追加
  3. ブロックの追加
  4. レシピの追加
  5. MODの情報の登録
  6. ビルド

1.12.2 (Forge 14.23.0.2491)

入門編

  1. 環境構築
  2. アイテムの追加
  3. ブロックの追加
  4. レシピの追加
  5. MODの情報の登録
  6. ビルド

初級編

1.7.10 (Forge 10.13.4.1558)

1.7.10の環境構築はGradleで問題が発生しており、動作を確認できていません。詳しくは「環境構築 2 (1.7.10)」のコメント欄をご覧ください。

準備

  1. 前提知識
  2. 環境構築 1
  3. 環境構築 2 (1.7.10)

入門編

  1. アイテムの追加
  2. ブロックの追加
  3. リソースの作成
  4. レシピの追加
  5. MODの情報の登録
  6. ビルド

初級編

中級編

上級編

解説の追加要望について

このページのコメント欄では追加要望を受け付けていますが、TNT Modders側の都合により断らせていただく場合があります。 また、要望を承った後、実際に追加するまで時間がかかる場合があります。 ご了承ください。

コメント欄

このページのコメント欄には、解説の追加要望や開発講座全体に関する意見などを投稿してください。個別の解説をご要望の際は、Minecraftのバージョンと求める動作の詳しい説明も記載してください。

解説ページのコメント欄には、それぞれの解説に関する質問などを投稿してください。また、解説の誤りや、より良い方法などがありましたら、お知らせください。

86件のコメント

  1. 1.16.5でアイテムに鉱石辞書を登録したいのですがどうすれば良いでしょうか
    "net.minecraftforge.oredict.OreDictionary"が存在しないので方法が分かりません
    ご教授お願いします

  2. ho9tocraft

    すみません、アイテムの表示サイズの変更方法をご教授願えないでしょうか。
    Minecraft1.7.10です

    • 赤砂蛇 凪浜

      「アイテムの表示サイズの変更」とは具体的にどのような動作でしょうか。アイテムが表示される状況には、以下のようなものがあります。

      • GUI内のアイテム欄
      • 手持ちアイテム(一人称視点と三人称視点)
      • 防具や頭装備なら装備表示
      • ドロップアイテム
      • 額縁

      これらのうち、通常のアイテムはGUIのみ2Dで、他は3Dで描画されます。

      カスタムモデルを持ったアイテムを追加したいということであれば、オファレンMODのレーザーピストルが参考になると思います。他に求める動作と似た要素を持つMODがあれば、その実装を参考にしてください。

  3. HashMapから座標取得は出来ました!
    ですが次の課題で、その座標を保持してValueの2を減らしていて消す処理なんですが、まず座標保持からでHashMapのキーとvalueのキーの部分が座標でvalueが常に2になっています。

    なので、座標が保持されません。
    HashMapから出た座標をHashSetに入れて格納したのですが、次はHashSetからvalueを減少の2秒後の処理が調べてもわかりませんでした。

    • 赤砂蛇 凪浜

      今のコードがどのような状態になっているのか、何をしようとしているのか、何を答えてほしいのかわかりません。MOD開発の知識や技術は私のできる限りお伝えしたいのですが、前提となるJavaの知識や技術が、実現したいことの難しさに対して足りていないように思います。

      もし思うようにMOD開発が進まなかったら、一旦手を止めて、Javaの入門講座を一通り習ってみてはいかがでしょうか。以前紹介したようにJavaの解説は豊富にあるので、費用や媒体など自分にあった方法で、コードを書いてその意味を理解する練習をするとよいと思います。

  4. またすいません。

    (ctrl + H)での購読とは何でしょうか?
    探しても出てきません。

    残り時間とコメントアウトされているところに、WorldTickEventと書いたら
    Ecpresion Exception とエラーが出てきてしまいました。
    エラー内容を調べてみると。異例の処理と出てきました。

    • 赤砂蛇 凪浜

      「Ctrl + H」はIntelliJ IDEAのショートカットで、この機能を使うとEventを継承しているクラスの一覧を表示できます。英語日本語でヘルプがあるので確認してください。イベントの利用の解説記事もご覧ください。

      また、該当のコメント部分にはintで残り時間を入れてください。クラス名を入れるとJavaの文法が間違っていると表示されるはずです。

      求める機能の実現にはもう少しJavaの基礎知識が必要になるでしょう。初心者向けに解説しているwebサイト(例:Let'sプログラミング)や動画、書籍などが豊富にあるので、特にクラスやオブジェクト、メソッドなどについて調べてください。

      • 基礎をもう一回見直しながらやったら、

        @SubscribeEvent public void TickEvent(EntityPlayer player, World world, TickEvent.WorldTickEvent e){}

        こうすればいいんじゃないかと思いました。

        このEventをTickArmor外に配置して、TickEventの中に

        world.setBlock(BPos.get(player.dimension),Blocks.air,3);

        を書いて、TickEventが実行されるたびに、HashMap内に収納されている座標たちがairで置換されていくと思ったのですが、メソッドが解決しないと言われまして、

        BPosがHashMapだからかなと思ってHashMapからintへの変換方法を探したら、
        HashMapはオブジェクト型でintに変換するにはStringでvalueOfをしてHashMapをStringの文字列にして、Stringをintに変換するためにInteger.parseIntをしてあげるとできると書いてあったのですが、そのintをsetBlockの座標として書くとメソッドが解決しませんと出ます。

        なので、System.out.printでBPosのintを出力してみたところ出力されませんでした。

        出力されないのはTickArmorで繰り返しされているからだと思うんですけど、どうやったらTickArmor内に@SubscribeEvent
        public void TickEvent(EntityPlayer player, World world, TickEvent.WorldTickEvent e){}
        を入れられるのでしょうか?

        そして、HashMapからどのようにしてint(座標)に変換すればよいのでしょうか?

        教えて頂きたいです。

        • 赤砂蛇 凪浜

          まず、onArmorTickメソッドはその種類の防具がプレイヤーに装備されている間しか呼ばれません。ブロックの破壊処理をこのメソッド内に書いてしまうと、防具が外されたらブロックが消えなくなってしまいます。そのため、ワールドが読み込まれている間は常に呼ばれるよう、TickEventを利用する必要があるのです。

          イベントの利用の記事で解説されているように、@SubscribeEventがついていて引数がEventを継承したクラス一つのみのメソッドは、Forgeに登録することでイベントが発生したときに呼ばれるようになります。Worldのインスタンスは引数のWorldTickEventから取得できるはずです。以前説明したように、WorldからもディメンションIDを取得できるので、EntityPlayerのインスタンスは必要ありません。

          BPosHashMap<Integer, HashMap<BlockPos, Integer>>なので、BPos.getによって返されるのはHashMap<BlockPos, Integer>のインスタンスです。HashMapとその使い方については調べてください。今回は座標と残り時間のそれぞれの組(Entry)について、値(Value)にあたる残り時間を減らし、0になったら対象座標のブロックを破壊するという処理を書きます。BlockPosは三つのintで表現されるブロック座標をまとめて扱うためのクラスなので、x, y, zを取得してsetBlockに渡す必要があります。

          「メソッドが解決しない」など、IntelliJ IDEAで赤く警告表示されるのはコンパイルエラーです。カーソルを合わせると理由が表示されるので、今回はsetBlockの引数が間違っているとわかるはずです。できれば英語を機械翻訳なども活用して読んでほしいのですが、日本語化も可能です。

          • @SubScribeEventのTickEventはなんとかできました。

            ですが、次の段階の

            ""BPosはHashMap<Integer, HashMap<BlockPos, Integer>>なので、BPos.getによって返されるのはHashMap<BlockPos, Integer>のインスタンスです。HashMapとその使い方については調べてください。今回は座標と残り時間のそれぞれの組(Entry)について、値(Value)にあたる残り時間を減らし、0になったら対象座標のブロックを破壊するという処理を書きます。BlockPosは三つのintで表現されるブロック座標をまとめて扱うためのクラスなので、x, y, zを取得してsetBlockに渡す必要があります。""

            この部分が、わかりません。

            HashMapの使い方は改めてみてわかりましたが、BPosからの(X・Y・Z)の取得方法がわかりません。

            試したことは、
            BlockPosのようなまとまったクラスからint値を抽出する方法を検索してみましたが、ヒットせず
            BlockPosのjavaファイルを見ながらequalsやcopy()をやってみましたが駄目でした。
            次に、BPosでequalsをBPos.equals(X)このようにして、書いてみてエラーが出ず実行してみたらfalseが出力されて、オブジェクト?がないと言われたと思います(プログラムの解釈)

            BPos.get(null) //null
            BPos.get(BPos) //null
            BPos.get(map) //null
            BPos.size //1

            上記の4つも試してみましたが、座標らしきものは表示されず
            唯一BPosだけで実行してみたところ、

            @fffe797e=2

            という出力され、16進数みたいだったので変換してみたら、絶対座標ではない桁の数が出てきました。

            どのようにしたら、座標をBlockPosから抽出すればよいのでしょうか?

          • 赤砂蛇 凪浜

            そもそもHashMapが何か理解できていますか? これもJavaの知識なので自分で詳しく調べてほしいのですが、HashMap<K, V>は、それぞれのKのインスタンス(鍵)に対応させてVのインスタンス(値)を保持します。今回はディメンションごとに座標と残り時間を管理しなければならないので、外側のHashMapであるBPosの鍵はディメンションID、値はHashMap<BlockPos, Integer>になっています。

            HashMap.getHashMap.putの意味がわかったら、HashMap.entrySetや、Javaのコレクション(今回はSet)の使い方についても調べてみてください。次に進むためには、BlockPosIntegerの組(Entry)でループする操作が必要です。

            確認したところ、オファレンMODのBlockPosHashMapの鍵として使うには不完全でした。HashMapの鍵には不変性が要求されるので、以下のようにBlockPosx, y, zfinalにしてください。今回の変更の有無にかかわらず、x, y, zpublicなメンバ変数なので、外部から直接アクセスできます。

            public final class BlockPos {
                // 定数の定義に変更なし。
                public final int x, y, z;
            
                // 以下、コンストラクタとメソッドに変更なし。
            }
            

starmineouji へ返信するコメントをキャンセル

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください