この記事は"Minecraft Forge Universal 10.13.0.x~"及び"ComputerCraft 1.65~"を前提MODとしています。 |
目次
周辺機器メソッドの追加[編集]
Computerからperipheral.call()でメソッドを呼び出せる周辺機器ブロックを追加します。
- IPeripheral.getMethodNames()とIPeripheral.callMethod()の実装
ソースコード[編集]
「MC1.7 周辺機器の追加」または「MC1.8 周辺機器の追加」のソースコードを元にして、変更部分のみを解説します。
- TileSamplePeripheral.java
package mods.sample.peripheral; import net.minecraft.tileentity.TileEntity; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; public class TileSamplePeripheral extends TileEntity implements IPeripheral { @Override public String getType() { return "sample"; } @Override public String[] getMethodNames() { return new String[] {"fn1", "fn2"}; } @Override public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException { switch(method) { case 0: // fn1 return new Object[] {"fn1 called!"}; case 1: // fn2 if ( arguments.length < 1 ) { throw new LuaException("Expected argument"); } if ( arguments[0] == null ) { throw new LuaException("Illegal argument"); } return new Object[] {arguments[0], arguments[0].getClass().getName()}; } return null; } @Override public void attach(IComputerAccess computer) { } @Override public void detach(IComputerAccess computer) { } @Override public boolean equals(IPeripheral other) { if ((other != null) && (other instanceof TileSamplePeripheral)) { return other == this; } return false; } }
解説[編集]
TileSamplePeripheral.java[編集]
周辺機器のメソッドの名前を返すgetMethodNames()と、呼び出されたメソッドを実際に処理するcallMethod()を実装します。
- getMethodNames()
接続されたComputerから呼出し可能なメソッドの名前をString型の配列として返します。
@Override public String[] getMethodNames() { return new String[] {"fn1", "fn2"}; }
この配列内でのメソッド名の順番は、callMethod()で重要な意味を持ちます。また、この戻り値は常に同じ内容を返すようにします。
今回はfn1とfn2という2つのメソッドを実装します。
- callMethod()
Computerからメソッドが呼び出されたときの処理を実装します。
@Override public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException { switch(method) { case 0: // fn1が呼び出された時の処理 case 1: // fn2が呼び出された時の処理 } return null; }
引数computerにはメソッドを呼び出したComputerのIComputerAccessインスタンスが渡されます。
引数mothodは呼び出されたメソッドの番号で、これはgetMethodNames()で返した配列のインデックスに対応しています。
今回の例では、fn1が呼び出されたときにはmethod = 0、fn2が呼び出されたときにはmethod = 1となります。
methodの値をswitch文で分岐させれば各メソッドの処理を簡潔に書くことができます。
引数argumentsにはメソッド呼出し時に指定された引数がオブジェクト型配列で渡されます。
メソッドの戻り値はオブジェクト型の配列です。もしも返すべき値がなかった場合は空のオブジェクト型配列を返します。
サンプルのfn1では、単純に"fn1 called!"という文字列を返しています。
case 0: // fn1 return new Object[] {"fn1 called!"};
サンプルのfn2では引数の取得、例外のthrow、変数のreturnを行っています。
case 1: // fn2 if ( arguments.length < 1 ) { throw new LuaException("Expected argument"); } if ( arguments[0] == null ) { throw new LuaException("Illegal argument"); } return new Object[] {arguments[0], arguments[0].getClass().getName()};
まず、メソッドが引数なしで呼び出されたなら例外LuaException("Expected argument")を発生させ、第一引数にJava側で受け取れない値が指定されていたなら例外LuaException("Illegal argument")を発生させています。そして、戻り値として呼出し時に指定した第一引数と、その引数のJava側での型名を返しています。
引数や戻り値の型[編集]
メソッドの引数や戻り値の型はComputerCraftによって自動的に変換されます。
引数 L→J | 戻り値 J→L | ||
---|---|---|---|
Lua | Java | Java | Lua |
boolean | Boolean | Boolean | boolean |
number | Double | Number | number |
string | String | String | string |
table | HashMap | HashMap | table |
ILuaObject | table | ||
その他 | null | その他 | nil |
Luaのtable型はJava側ではHashMapになります。キーおよび値の型もそれぞれ上表に従って変換されます。
Luaのtableを使った配列は1オリジンです。キー0に値を代入することは可能ですが、キー0はLuaのipairs()や#演算子の対象にはなりません。
例外 LuaException[編集]
callMethod()の処理中で例外LuaExceptionをthrowすると、そこで処理を中止してComputerの画面にエラーメッセージを表示します。ComputerCraftの周辺機器では主にメソッドの引数の不備を指摘する時に用いられているようです。
throw new LuaException("Expected argument");
この例外が発生した場合、その時点でプログラムの処理は中止され、Computerの画面上には、
lua:1: Expected argument
のように表示されます。表示されるフォーマットは、プログラム名:行番号:内容
です。
この例では"lua"というLuaプログラム内の1行目のperipheral.call()で呼ばれた周辺機器メソッドの処理中にLuaException("Expected argument")がthrowされたことを表します。
Minecraftとの競合[編集]
※今回のサンプルでは問題ありません
callMethod()はComputerCraftのLuaスレッドから呼び出されているため、callMethod()の処理中に、Minecraftのスレッドからアクセスされる可能性のあるフィールドへアクセスすると、競合が発生する可能性があります。従って、そのような処理では適宜synchronizedなどで排他制御する必要があります。