Minecraft Modding

コードが書きたい。

雛形を更新したのでもうちょっと入門らしく

今日の目次

動作確認

プロジェクトのセットアップが完了している前提で始めます。
まずは正常にプロジェクトが実行出来ること、modが読み込まれることを確認しましょう。
f:id:atushi-info:20170913022704p:plain

実行の仕方

f:id:atushi-info:20170913034226p:plain

プロジェクトの設定

確認が出来れば早速コーディングに移りたいですが、その前にちょっとだけプロジェクトの設定を変更したいと思います。
「メニューバー -> ウインドウ -> 設定」から下記のスクリーンショットのようにしましょう。
この設定では日本語のコメントを書いた時に文字化けしない為の設定です。
※UIが真っ黒なのは別途テーマをインストールしているからです(黒いとかっこいい!)。
f:id:atushi-info:20170913024745p:plain

Modのパッケージ構成を変更

あまり行う必要がないと言えばないのですが、個人的な趣向になってしまいますが階層を浅くしたい為変更します。
現在は「com.example.examplemod」となっていると思いますが「com.example」を削除し、「examplemod」にします。基本的にはMod名にあたるパッケージ名で十分重複するようなことはないと思ったのでこのようにしました。

パッケージ名の変更

一応方法が分からない方のために手順を載せます。
パッケージ・エクスプローラーに表示されているパッケージ「com.example.examplemod」を右クリックします。
「表示されたメニュー -> リファクタリング -> 名前変更」で下記のスクリーンショットのように編集し、OKボタンを押せば反映されます。
※名前変更は「com.example.examplemod」をクリックし、F2を押しても行うことが出来ます。
f:id:atushi-info:20170913032302p:plain

Mod本体の処理を定義

やって参りましたようやくコーディングです。
何も手を付けていなければExampleModクラスではinitメソッドが以下のように定義されていると思います。
※ちなみに@Modが宣言されているクラスがMod本体になります。
ExampleMod.java

   @EventHandler
    public void init(FMLInitializationEvent event)
    {
        // some example code
        System.out.println("DIRT BLOCK >> "+Blocks.DIRT.getUnlocalizedName());
    }

この定義を次のコードで上書きします。

    // ログ出力で使います
    public static Logger logger;

    /***
     * Mod本体のメソッド中最初に呼ばれます。<br>
     * 変数の初期化など後続の処理に影響のあることを済ませます。
     * 
     * @param event
     */
    @Mod.EventHandler
    public void preInit(FMLPreInitializationEvent event) {
        logger = event.getModLog();
    }

    /***
     * preinitの後に呼ばれます。<br>
     * 言わばこのModの本体とも言える主要なメソッドです。<br>
     * とにかく主要なことはここで処理します。
     * 
     * @param event
     */
    @Mod.EventHandler
    public void init(FMLInitializationEvent event) {
    }

    /***
     * initの後に呼ばれます。つまりMod本体の中では最後に呼ばれます。<br>
     * リソースの開放や不要なデータの削除などお片付け的なことをします。
     * 
     * @param event
     */
    @Mod.EventHandler
    public void postInit(FMLPostInitializationEvent event) {
    }

編集出来ればエラーにならないか一度実行してみましょう。
最初に実行したときのように問題なく動作すれば大丈夫です。

クライアントとサーバーで処理を分岐

サーバーではテクスチャやモデルと言った画面表示周りの処理が不要である為、それらの処理を書き分けられるようにします。
まずはパッケージ・エクスプローラーよりexamplemodパッケージ配下にproxyパッケージを作りましょう。
「examplemodパッケージを右クリック -> 新規 -> パッケージ」を選択すると下記のようにウインドウが出るので名前をexamplemod.proxyにします。
f:id:atushi-info:20170913041749p:plain

次に同じ要領で「proxyパッケージを右クリック -> 新規 -> クラス」で表示されたウインドウに下記のように入力してCommonProxy、ClientProxy、ServerProxyクラスをそれぞれ作ります。
f:id:atushi-info:20170913042616p:plain

各クラスは次のように書きましょう。
CommonProxy.java

package examplemod.proxy;

import examplemod.ExampleMod;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

/***
 * クライアントとサーバー共通でアイテム、ブロック、ツールの読み込みます。
 * 
 * @author youname
 *
 */
@Mod.EventBusSubscriber
public class CommonProxy {
    public void preInit(FMLPreInitializationEvent event) {
        ExampleMod.logger.info("CommonProxy.preInit");
    }

    public void init(FMLInitializationEvent event) {
        ExampleMod.logger.info("CommonProxy.init");
    }

    public void postInit(FMLPostInitializationEvent event) {
        ExampleMod.logger.info("CommonProxy.postInit");
    }

    @SubscribeEvent
    public static void registerBlocks(RegistryEvent.Register<Block> event) {
        ExampleMod.logger.info("CommonProxy.registerBlocks");
    }

    /***
     * Modで追加したいアイテムを読み込みます。<br>
     * 勿論アイテムのクラスは自分で定義する必要があります。
     * 
     * @param event
     */
    @SubscribeEvent
    public static void registerItems(RegistryEvent.Register<Item> event) {
        ExampleMod.logger.info("CommonProxy.registerItems");
    }
}

ClientProxy.java

package examplemod.proxy;

import examplemod.ExampleMod;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;

/***
 * クライアント側でリソースを読み込みます。
 * 
 * @author youname
 *
 */
@Mod.EventBusSubscriber(Side.CLIENT)
public class ClientProxy extends CommonProxy {
    @Override
    public void preInit(FMLPreInitializationEvent event) {
        super.preInit(event);
        ExampleMod.logger.info("ClientProxy.preInit");
    }

    /***
     * ブロックやアイテムのモデル(テクスチャは何を使うとかテクスチャの向きとか定義したファイル)を読み込みます。<br>
     * 
     * @param event
     */
    @SubscribeEvent
    public static void registerModels(ModelRegistryEvent event) {
        ExampleMod.logger.info("ClientProxy.registerModels");
    }
}

ServerProxy.java

package examplemod.proxy;

import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.relauncher.Side;

/***
 * サーバー側で行う処理。
 * 
 * @author youname
 *
 */
@Mod.EventBusSubscriber(Side.SERVER)
public class ServerProxy extends CommonProxy {
}

プロキシクラスが定義出来たらExampleModクラスから呼び出しましょう。
次のようになります。
ExampleMod.java

package examplemod;

import org.apache.logging.log4j.Logger;

import examplemod.proxy.CommonProxy;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

/***
 * Modの本体で、@Modを宣言することで本体として認識されます。<br>
 * modidの文字列はmcmod.infoのmodidと同一にしなければ、mcmod.infoが読み込まれないので設定値を合わせる必要があります。<br>
 * このクラスでMinecraftにブロックやアイテムの登録を行います。<br>
 * 
 * @author myname
 * @version forge-1.12-14.21.1.2426
 */
@Mod(modid = ExampleMod.MODID, version = ExampleMod.VERSION)
public class ExampleMod {

    // Modの識別やリソースのドメイン名に利用されます
    public static final String MODID = "examplemod";
    // Modのバージョン
    public static final String VERSION = "0.0.1";

    // プロキシ(読み込み処理)のパッケージ階層
    public static final String CLIENT_PROXY = "examplemod.proxy.ClientProxy";
    public static final String SERVER_PROXY = "examplemod.proxy.ServerProxy";

    // サーバー、クライアントを識別しインスタンスを保持します
    @SidedProxy(clientSide = CLIENT_PROXY, serverSide = SERVER_PROXY)
    public static CommonProxy proxy;

    // いまいち必要性が分からない
    @Mod.Instance
    public static ExampleMod instance;

    // ログ出力で使います
    public static Logger logger;

    /***
     * Mod本体のメソッド中最初に呼ばれます。<br>
     * 変数の初期化など後続の処理に影響のあることを済ませます。
     * 
     * @param event
     */
    @Mod.EventHandler
    public void preInit(FMLPreInitializationEvent event) {
        logger = event.getModLog();
        proxy.preInit(event);
    }

    /***
     * preinitの後に呼ばれます。<br>
     * 言わばこのModの本体とも言える主要なメソッドです。<br>
     * とにかく主要なことはここで処理します。
     * 
     * @param event
     */
    @Mod.EventHandler
    public void init(FMLInitializationEvent event) {
        proxy.init(event);
    }

    /***
     * initの後に呼ばれます。つまりMod本体の中では最後に呼ばれます。<br>
     * リソースの開放や不要なデータの削除などお片付け的なことをします。
     * 
     * @param event
     */
    @Mod.EventHandler
    public void postInit(FMLPostInitializationEvent event) {
        proxy.postInit(event);
    }
}

それではこれで実行してみましょう。
無事に実行出来ればコンソールに出力されるログの中から下記のような出力を見つけることが出来るはずです。

[05:07:21] [main/INFO] [examplemod]: CommonProxy.preInit
[05:07:21] [main/INFO] [examplemod]: ClientProxy.preInit
~~~
[05:07:21] [main/INFO] [examplemod]: CommonProxy.registerBlocks
~~~
[05:07:21] [main/INFO] [examplemod]: CommonProxy.registerItems
~~~
[05:07:21] [main/INFO] [examplemod]: ClientProxy.registerModels
~~~
[05:07:50] [main/INFO] [examplemod]: CommonProxy.init
~~~
[05:07:50] [main/INFO] [examplemod]: CommonProxy.postInit

出力されていれば雛形の完成です。長々とお付き合いありがとうございました。
コードはGithubで公開しています。

Github

github.com