この記事は"Minecraft Forge"を前提MODとしています。 |
目次
はじめに
IResourcePackインターフェースは、本来リソースパックのように機能する動的クラスを作成するためのものである。 この使い方次第で、ビルドパス(出力したMODのjarファイル)外にあるリソースを参照できるため、MODの利用者がリソースパックを使わずにリソースを変更することも可能。
以下は基本的にMinecraft 1.7.x/1.8を対象に解説する。1.8ではFML関連クラスのパッケージが変更となっているので、注意されたし。 なお、FML上には予めIResourcePackを実装したFileResourcePackやFolderResourcePack等のクラスが存在するが、ここでは扱わない。
ソースコード
package、import等は省略
SampleMod.java
@Modクラスでの書き方
@Mod(id="samplemod",name="samplemod") public class SampleMod{ /*略*/ @EventHandler public void init(FMLInitializationEvent event){ /*略*/ //defaultResourcePacksはprivateのため、リフレクションが必要。 //難読化名は1.7.10のもの。1.8では難読化されていない List<IResourcePack> defaultResourcePacks = ObfuscationReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "field_110449_ao"); defaultResourcePacks.add(new SampleResourcePack()); /*略*/ } /*略*/ }
SampleResourcePack.java
public class SampleResourcePack implements IResourcePack{ public SampleResourcePack(){ //コンストラクタは基本的に空で良い } @Override public InputStream getInputStream(ResourceLocation par1ResourceLocation) throws IOException { //参照されたリソースに対し、InputStreamを返す。 return new FileInputStream(… } @Override public boolean resourceExists(ResourceLocation resource) { //参照されたリソースが存在するかの指定。 return true; } @Override @SuppressWarnings("rawtypes") public Set getResourceDomains() { //IResourcePackが処理するリソースのドメインを指定。複数指定可能。 return ImmutableSet.of("samplemod"); } @Override public IMetadataSection getPackMetadata(IMetadataSerializer par1MetadataSerializer, String par2Str){ //メタデータを持たせないならnullでよい return null; } @Override public BufferedImage getPackImage() { //パック画像も用意しないのであればnullでよい return null; } @Override public String getPackName() { //パックの名前。メタデータやパック画像を用意しないのであれば、プレイ中ユーザから見えることはない //空やnullを返すとクラッシュする return "SampleResourcePack"; } }
解説
リソースパックの登録
List<IResourcePack> defaultResourcePacks = ObfuscationReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "field_110449_ao"); defaultResourcePacks.add(new SampleResourcePack());
IResourcePackを実装したクラスを実際にリソースパックとして認識させるために、Minecraft.defaultResourcePacksフィールドを参照する。 privateのため、リフレクションを利用して取得する。
リソースの取得
@Override public InputStream getInputStream(ResourceLocation par1ResourceLocation) throws IOException { return new FileInputStream(… } @Override public boolean resourceExists(ResourceLocation resource) { return true; }
基本的にリソースはInputStreamで取得される。getInputStream(ResourceLocation)は、参照されたリソース(第1引数に渡されるResourceLocation)に対しInputStreamを取得させるための必須メソッド。 このメソッドで、FileInputStreamなり何なりを使用すれば、ビルドパスの外部にあるファイルをリソースとして取得させることが可能。
resourceExists(ResourceLocation)は、参照されたリソースがSampleResourcePackに存在するか(SampleResourcePackがリソースを返すか)を指定する必須メソッド。ビルドパスに用意したリソースを参照する場合は、falseを返せばよい。
例では簡略化してあるが、引数に渡されるResourceLocationをチェックして、適切な値を返すようにすること。 特にgetInputStreamでは、誤って存在しないファイルへのFileInputStreamを返すなどといったことが無いようにしたい。
後は、通常通りResourceLocationを使用するだけでよい。
補足
上記の例は、リソースのInputStreamをFileInputStreamを使用して直接渡すような記述であるが、実際の実装ではClassLoaderを用意しgetResourceAsStream()する方が良い。(特にMinecraft 1.8にてZip内からリソースを読み取ろうとする際、挙動が不安定になりやすい?)