ComputerCraftに周辺機器を追加するModの製作について解説する。 &color(red){対象:Minecraft Forgeを利用して独自のブロック、アイテムを追加できるModding初級者以上。} 参考資料: -[[Minecraft Midding Wiki>http://minecraftjp.info/modding/index.php/Minecraft_Modding_Wiki]] --[[チュートリアル一覧: MinecraftForgeUniversal>http://minecraftjp.info/modding/index.php/%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E4%B8%80%E8%A6%A7#MinecraftForgeUniversal]] -[[ComputerCraft Forums: Peripherals and Turtle Upgrades>http://www.computercraft.info/forums2/index.php?/forum/17-]] --[[Creating Peripherals and Turtle Upgrades>http://www.computercraft.info/forums2/index.php?/topic/606-]] --[[Very Basic Framework (Your First Peripheral)>http://www.computercraft.info/forums2/index.php?/topic/613-]] ※Minecraft 1.2.5時のもの -[[Minecraft Forge: Tutorials>http://www.minecraftforge.net/wiki/Category:Tutorials]] 執筆時のバージョン: -ComputerCraft 1.47 for Minecraft 1.4.4 ---- #contents ---- *周辺機器追加Modの概要 周辺機器とは、Disk DriveやMonitorのように隣接したComputerやTurtle(以下まとめて「Computer」)から呼び出されて、様々な機能を提供するブロックである。 周辺機器はブロックとして実装し、ブロックのTileEntityに[[IPeripheral>Modding/Peripheral/API]]インターフェイスを実装することで、ComputerCraftから呼び出された時の動作を実装する。そのため、Minecraft Forgeを利用して独自のブロックを追加できる人なら、誰でも簡単に周辺機器追加Modを作ることができる。 *基本的な周辺機器追加Modの例 このサンプルは以下の3クラスからなる。 -TileEntityBasicPeripheral -BlockBasicPeripheral -BasicPeripheral 簡略化のため[[Proxyシステム>http://minecraftjp.info/modding/index.php/%E3%83%97%E3%83%AD%E3%82%AD%E3%82%B7%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6]]は利用していない。 **TileEntityBasicPeripheral.java TileEntityのサブクラスにIPeripheralを実装することで、周辺機器としての機能を実装する。IPeripheralの各メソッドについては[[IPeripheral>Modding/Peripheral/API]]を参照。 #highlight(java){{ package sample.peripheral; import net.minecraft.src.TileEntity; import dan200.computer.api.IComputerAccess; import dan200.computer.api.IPeripheral; public class TileEntityBasicPeripheral extends TileEntity implements IPeripheral { @Override public String getType() { return "basicPeripheral"; } @Override public String[] getMethodNames() { return new String[] { "test" }; } @Override public Object[] callMethod( IComputerAccess computer, int method, Object[] arguments ) throws Exception { switch( method ) { case 0: if( arguments.length < 1 ) { throw new Exception("Expected argument"); } return new Object[] { arguments[0] }; } return null; } @Override public boolean canAttachToSide(int side) { return true; } @Override public void attach( IComputerAccess computer, String computerSide ) { System.out.printf("[BasicPeripheral] %s was attached to Computer #%d (side: %s)\n", this.getBlockType().getBlockName(), computer.getID(), computerSide ); } @Override public void detach( IComputerAccess computer ) { System.out.printf("[BasicPeripheral] %s was detached from Computer #%d\n", this.getBlockType().getBlockName(), computer.getID() ); } } }} このサンプルでは、周辺機器のタイプ名として&bold(){basicPeripheral}を返し、Computerによってゲーム内で呼び出せる周辺機器のメソッド(以下「周辺機器のメソッド」)として&bold(){test}を実装している。また、周辺機器がComputerと接続(attach)・接続解除(detach)された時に、デバッグ情報として接続・接続解除されたComputerのIDなどを出力している(Minecraftをコマンドラインから実行すると見ることができる)。 Computerから呼び出せる周辺機器の各メソッドの名前は、getMethodNamesの戻り値で指定する。周辺機器の各メソッドの処理は、callMethodで第二引数の値をswitch構文などで分岐させて実装する。周辺機器のメソッドが呼び出された時にComputerから呼び出されるcallMethodの第二引数の値と、呼び出された周辺機器のメソッドの、getMethodNamesの戻り値の配列でのインデックス番号は一致する。 このサンプルの&bold(){test}の場合はgetMethodNamesの戻り値の配列でのインデックス番号が&bold(){0}であるため、ゲーム内で&bold(){test}を呼び出した時にComputerから呼ばれるcallMethodの第二引数の値(int method)は&bold(){0}になる。したがって、methodが&bold(){0}のときに&bold(){test}の処理を実行するように実装すればよい。&bold(){test}の処理の内容は、呼び出し時に引数がなかった場合はComputerにエラーメッセージを表示し、引数があった場合は最初の引数の値を返すというもの。 **BlockBasicPeripheral.java 周辺機器ブロック本体。 BlockContainerのサブクラスとし、createNewTileEntityでIPeripheralを実装したTileEntityのサブクラスのインスタンスを返す。 #highlight(java){{ package sample.peripheral; import net.minecraft.src.BlockContainer; import net.minecraft.src.Material; import net.minecraft.src.TileEntity; import net.minecraft.src.World; public class BlockBasicPeripheral extends BlockContainer { protected BlockBasicPeripheral( int blockId, int terrainId, Material material ) { super(blockId, terrainId, material); } @Override public TileEntity createNewTileEntity( World world ) { return new TileEntityBasicPeripheral(); } } }} このサンプルでは、createNewTileEntityで前述のTileEntityBasicPeripheralのインスタンスを返している。 **BasicPeripheral.java @ModアノテーションによりForge Mod Loaderにロードされるクラス。 #highlight(java){{ package sample.peripheral; import net.minecraft.src.*; import net.minecraftforge.common.Configuration; import net.minecraftforge.common.Property; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.network.NetworkMod; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.LanguageRegistry; @Mod(modid="BasicPeripheral", name="BasicPeripheral", version="0.0.0", dependencies="after:CCTurtle") @NetworkMod(clientSideRequired=true, serverSideRequired=false) public class BasicPeripheral { public int blockIdBasicPeripheral; public static Block blockBasicPeripheral; @Mod.PreInit public void preInit(FMLPreInitializationEvent event) { Configuration cfg = new Configuration(event.getSuggestedConfigurationFile()); cfg.load(); Property Prop = cfg.getBlock("basicPeripheralBlockID", 1211); blockIdBasicPeripheral = Prop.getInt(); cfg.save(); } @Mod.Init public void init(FMLInitializationEvent event) { blockBasicPeripheral = (new BlockBasicPeripheral(blockIdBasicPeripheral, 6, Material.ground)) .setBlockName("basicPeripheral").setCreativeTab(CreativeTabs.tabBlock); GameRegistry.registerBlock(blockBasicPeripheral); GameRegistry.registerTileEntity(TileEntityBasicPeripheral.class, "TileEntityBasicPeripheral"); LanguageRegistry.addName(blockBasicPeripheral, "Basic Peripheral"); GameRegistry.addRecipe( new ItemStack(blockBasicPeripheral, 1), new Object[] { "XXX", "XYX", "XXX", Character.valueOf('X'), Block.stone, Character.valueOf('Y'), Block.dirt }); CreativeTabs[] tabs = CreativeTabs.creativeTabArray; for( int i = 0; i < tabs.length; i++ ) { if( tabs[i].getTabLabel().equals("ComputerCraft") || tabs[i].getTabLabel().equals("BatComputerCraft") ) { blockBasicPeripheral.setCreativeTab(tabs[i]); } } System.out.printf("[BasicPeripheral] Set %s (ID: %d) in Creative Tab: %s\n", blockBasicPeripheral.getBlockName(), blockBasicPeripheral.blockID, blockBasicPeripheral.getCreativeTabToDisplayOn().getTranslatedTabLabel() ); } } }} @Modアノテーションを付加したクラスがForge Mod Loaderにロードされる。ここでModの情報も登録している。特筆すべきは&bold(){dependencies="after:CCTurtle"}という値で、これはこのModをComputerCraftよりも後に読み込ませる効果がある。 @Mod.PreInitアノテーションを付加したメソッド(@Mod.Initメソッドの前に呼び出される)preInitでコンフィグファイルを読み込み、サンプル周辺機器のブロックIDを取得している。ブロックIDのデフォルト値は&bold(){1211}。 @Mod.Initアノテーションを付加したメソッド(初期化時に呼び出される)initで周辺機器ブロックやTileEntity、ブロックのレシピを登録している。サンプルの周辺機器ブロックはブロックIDが前述のコンフィグから取得した値で、テクスチャは6面とも石ハーフブロックの上下面と同じ。ゲーム内での表示名は&bold(){Basic Peripheral}。レシピは中央に土ブロックを置き周囲を石ブロックで囲った形。最後に周辺機器ブロックをクリエイティブ・インベントリに登録している。全てのクリエイティブ・タブの中からComputerCraftのタブを検索し、見つかった場合はそこに登録、見つからなかった場合は最初に指定したバニラのBlockタブに登録される。 周辺機器は基本的にComputerから呼び出されて動くため、ここで何かをComputerCraft側に登録するような処理は存在しない。