Configとは、ハードコーディングを避け利用者側で設定を変更する手段を提供するための機能である。
ここでは、Forgeによって提供されるConfig機能について説明する。
基本
旧来のConfig生成について解説する。
簡易的なサンプルを以下に示す。
package com.example.config; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.Mod; @Mod(modid = ConfigSample.MODID, name = "ConfigSample", version = "1.0", acceptableRemoteVersions = "*") public class ConfigSample { public static final String MODID = "config_sample"; @EventHandler public void preInit(FMLPreInitializationEvent event) { Configuration cfg = new Configuration(event.getSuggestedConfigurationFile()); cfg.load();//コンフィグをロード /*ここでConfigの値の取得。*/ cfg.save();//セーブ } }
Configurationクラスを通してPropertyにアクセスすることで値を取得できる。
Propertyや値は各種getメソッドを利用して取得できるので場合に応じたメソッドを使えばよいだろう。
Configuration#loadでは非検査例外が投げられる可能性があるが、ファイル操作はこの時点で行われていないためハンドルする必要はない。(むしろハンドルすると中途半端に読み込まれ挙動がおかしくなる)
この方法ではConfigファイルは自由な場所に生成できるが、通常はFMLPreInitializationEvent#getSuggestedConfigurationFileを利用するのが良いだろう。
アノテーション利用
1.10.2-12.18.2.2103からConfigアノテーションが追加され、かつてあったModLoaderというModの機能の一つであるMLPropと同じ感覚でConfigシステムを利用することができるようになった。
すべてのプリミティブ型(とラッパークラス)、String、それらの配列、さらに付随してEnumとカテゴリーとして通常のクラスまで扱うことができる。
Configアノテーションが付与されたクラスごとにConfigファイルが生成される。
サンプル
Minecraft ForgeによるDebug用サンプルを改変したものを用いて示す。
コード
package com.example.config; import net.minecraftforge.common.config.Config; import net.minecraftforge.common.config.Config.*; import net.minecraftforge.fml.common.Mod; @Mod(modid = ConfigSample.MODID, name = "ConfigSample", version = "1.0", acceptableRemoteVersions = "*") public class ConfigSample { public static final String MODID = "config_sample"; @Config(modid = MODID, type = Type.INSTANCE, name = MODID + "_types") public static class CONFIG_TYPES { public static boolean bool = false; public static boolean[] boolA = {false, true}; public static Boolean Bool = false; public static Boolean[] BoolA = {false, true}; public static float flt = 1.0f; public static float[] fltA = {1.0f, 2.0f}; public static Float Flt = 1.0f; public static Float[] FltA = {1.0f, 2.0f}; public static double dbl = 1.0d; public static double[] dblA = {1.0d, 2.0d}; public static Double Dbl = 1.0D; public static Double[] DblA = {1.0D, 2.0D}; public static byte byt = 1; public static byte[] bytA = {1, 2}; public static Byte Byt = 1; public static Byte[] BytA = {1, 2}; public static char chr = 'a'; public static char[] chrA = {'a', 'b'}; public static Character Chr = 'A'; public static Character[] ChrA = {'A', 'B'}; public static short srt = 1; public static short[] srtA = {1, 2}; public static Short Srt = 1; public static Short[] SrtA = {1, 2}; public static int int_ = 1; public static int[] intA = {1, 2}; public static Integer Int = 1; public static Integer[] IntA = {1, 2}; public static String Str = "STRING!"; public static String[] StrA = {"STR", "ING!"}; public static TEST enu = TEST.BIG; public static NestedType Inner = new NestedType(); public enum TEST { BIG, BAD, WOLF; } public static class NestedType { public String HeyLook = "I'm Inside!"; } } @Config(modid = MODID) public static class CONFIG_ANNOTATIONS { @RangeDouble(min = -10.5, max = 100.5) public static double DoubleRange = 10.0; @RangeInt(min = -10, max = 100) public static double IntRange = 10; @LangKey("this.is.not.a.good.key") @Comment({"This is a really long", "Multi-line comment"}) public static String Comments = "Hi Tv!"; } }
解説
@Config(modid = MODID, type = Type.INSTANCE, name = MODID + "_types") public static class CONFIG_TYPES { public static boolean bool = false; public static boolean[] boolA = {false, true}; public static Boolean Bool = false; public static Boolean[] BoolA = {false, true}; public static float flt = 1.0f; public static float[] fltA = {1.0f, 2.0f}; public static Float Flt = 1.0f; public static Float[] FltA = {1.0f, 2.0f}; public static double dbl = 1.0d; public static double[] dblA = {1.0d, 2.0d}; public static Double Dbl = 1.0D; public static Double[] DblA = {1.0D, 2.0D}; public static byte byt = 1; public static byte[] bytA = {1, 2}; public static Byte Byt = 1; public static Byte[] BytA = {1, 2}; public static char chr = 'a'; public static char[] chrA = {'a', 'b'}; public static Character Chr = 'A'; public static Character[] ChrA = {'A', 'B'}; public static short srt = 1; public static short[] srtA = {1, 2}; public static Short Srt = 1; public static Short[] SrtA = {1, 2}; public static int int_ = 1; public static int[] intA = {1, 2}; public static Integer Int = 1; public static Integer[] IntA = {1, 2}; public static String Str = "STRING!"; public static String[] StrA = {"STR", "ING!"}; public static TEST enu = TEST.BIG; public static NestedType Inner = new NestedType(); public enum TEST { BIG, BAD, WOLF; } public static class NestedType { public String HeyLook = "I'm Inside!"; } }
Configにおいて扱えるすべての型である。
生成されるConfigファイルは以下の通り。
- config_sample_types.cfg
# Configuration file general { B:Bool=false B:BoolA < false true > I:Byt=1 I:BytA < 1 2 > I:Chr=65 I:ChrA < 65 66 > D:Dbl=1.0 D:DblA < 1.0 2.0 > D:Flt=1.0 D:FltA < 1.0 2.0 > I:Int=1 I:IntA < 1 2 > I:Srt=1 I:SrtA < 1 2 > S:Str=STRING! S:StrA < STR ING! > B:bool=false B:boolA < false true > I:byt=1 I:bytA < 1 2 > I:chr=97 I:chrA < 97 98 > D:dbl=1.0 D:dblA < 1.0 2.0 > S:enu=BIG D:flt=1.0 D:fltA < 1.0 2.0 > I:intA < 1 2 > I:int_=1 I:srt=1 I:srtA < 1 2 > inner { S:HeyLook=I'm Inside! } }
Configアノテーションで指定したnameがそのままファイル名になっている。(nameを指定しない場合はModidとなる。)
各プロパティ名はフィールド名に基づいており、初期化時の値がConfigの既定値に設定される。
また、カテゴリ名に大文字を使用できないためInnerという名前のフィールドで生成されたカテゴリはinnerという名前となる。
@Config(modid = MODID) public static class CONFIG_ANNOTATIONS { @RangeDouble(min = -10.5, max = 100.5) public static double DoubleRange = 10.0; @RangeInt(min = -10, max = 100) public static double IntRange = 10; @LangKey("this.is.not.a.good.key") @Comment({"This is a really long", "Multi-line comment"}) public static String Comments = "Hi Tv!"; }
Configにさらなる付加情報を与えるために利用できるアノテーションの利用サンプルである。
RangeDouble/RangeIntアノテーションではdouble/int型のプロパティに対し範囲を定めることができ、コメントも添えられる。
LangKeyアノテーションでは、ConfigGUIで用いられるツールチップ等の翻訳キーを指定できる。ConfigGUIを利用しないのであれば必要ない。
Commentアノテーションでは、プロパティに添えるコメントを指定できる。
生成されるConfigファイルは以下の通り。
- config_sample.cfg
# Configuration file general { # This is a really long # Multi-line comment S:Comments=Hi Tv! # Min: -10.5 # Max: 100.5 D:DoubleRange=10.0 # Min: -10 # Max: 100 D:IntRange=10.0 }
ConfigGUI利用
ModアノテーションのguiFactoryにおいてIModGuiFactory実装クラスを指定することで利用可能になる機能である。
Mod一覧の各ModのページからConfigGUIは開くことができる。
FMLConfigGuiFactoryがサンプルとなっているので参考にすると良いだろう。