細 (ComputerCraft API/イベントの発生をComputerCraft API/1.65/イベントの発生へ移動: CCのバージョンごとにチュートリアルページを作成できるようにするため) |
(「周辺機器の追加」ページへのリンク修正) |
||
9行目: | 9行目: | ||
=== ソースコード === | === ソースコード === | ||
− | 「[[ComputerCraft_API/周辺機器の追加|周辺機器の追加]]」のソースコードを元にして、変更部分のみを解説します。 | + | 「[[ComputerCraft_API/1.65/周辺機器の追加|MC1.7 周辺機器の追加]]」のソースコードを元にして、変更部分のみを解説します。 |
*BlockSamplePeripheral.java | *BlockSamplePeripheral.java |
2015年12月27日 (日) 10:42時点における最新版
この記事は"Minecraft Forge Universal 10.13.0.x~"及び"ComputerCraft 1.65~"を前提MODとしています。 |
目次
イベントの発生[編集]
右クリックされたとき接続されているComputerにイベントを発生させる周辺機器ブロックを追加します。
- IComputerAccessインスタンスの管理
- IComputerAccess.queueEvent()によるイベントの発生
ソースコード[編集]
「MC1.7 周辺機器の追加」のソースコードを元にして、変更部分のみを解説します。
- BlockSamplePeripheral.java
package mods.sample.peripheral; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; public class BlockSamplePeripheral extends BlockContainer { public BlockSamplePeripheral() { super(Material.ground); } @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) { TileEntity tile = world.getTileEntity(x, y, z); if (!world.isRemote && tile != null && tile instanceof TileSamplePeripheral) { ((TileSamplePeripheral)tile).click(); } return true; } @Override public TileEntity createNewTileEntity(World world, int a) { return new TileSamplePeripheral(); } }
- TileSamplePeripheral.java
package mods.sample.peripheral; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; 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 { private final Set<IComputerAccess> m_computers; public TileSamplePeripheral() { m_computers = new HashSet(); } @Override public String getType() { return "sample"; } @Override public String[] getMethodNames() { return new String[] {}; } @Override public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException { return null; } @Override public void attach(IComputerAccess computer) { synchronized (this) { m_computers.add(computer); } } @Override public void detach(IComputerAccess computer) { synchronized (this) { m_computers.remove(computer); } } @Override public boolean equals(IPeripheral other) { if ((other != null) && (other instanceof TileSamplePeripheral)) { return other == this; } return false; } public void click() { Map<String, Integer> pos = new HashMap<String, Integer>(); pos.put("x", this.xCoord); pos.put("y", this.yCoord); pos.put("z", this.zCoord); synchronized(this) { for (IComputerAccess computer : m_computers) { computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName(), pos} ); } } } }
解説[編集]
BlockSamplePeripheral.java[編集]
周辺機器ブロックが右クリックされたときの処理を追加します。
@Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) { TileEntity tile = world.getTileEntity(x, y, z); if (!world.isRemote && tile != null && tile instanceof TileSamplePeripheral) { ((TileSamplePeripheral)tile).click(); } return true; }
ブロックが右クリックされたら周辺機器のTileEntityを取得してTileSamplePeripheral.click()を呼び出しています。
TileSamplePeripheral.java[編集]
接続されているComputerのリストを管理する処理と、そのComputerにイベントを発生させる処理を追加します。
- Computerリストの初期化
private final Set<IComputerAccess> m_computers; public TileSamplePeripheral() { m_computers = new HashSet(); }
接続されているComputerのIComputerAccessインスタンスはHashSetのm_computersに格納します。
m_computersをコンストラクタで初期化します。
- IComputerAccessインスタンスの追加と削除
@Override public void attach(IComputerAccess computer) { synchronized(this) { m_computers.add(computer); } } @Override public void detach(IComputerAccess computer) { synchronized(this) { m_computers.remove(computer); } }
attach()で接続されたComputerのIComputerAccessインスタンスをm_computersへ追加、detach()で取り外されたComputerのComputerAccessインスタンスをm_computersから削除します。こうすることによってm_computersには常に接続されているComputerだけが登録されているようになっています。
(synchronizedによる排他制御については後述)
- click()
周辺機器ブロックが右クリックされたときにBlockSamplePeripheralから呼び出されます。
public void click() { Map<String, Integer> pos = new HashMap<String, Integer>(); pos.put("x", this.xCoord); pos.put("y", this.yCoord); pos.put("z", this.zCoord); synchronized(this) { for (IComputerAccess computer : m_computers) { computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName(), pos} ); } } }
m_computersに登録されているすべてのComputerへIComputerAccess.queueEvent()で"sample_click"イベントを発生させます。イベントのパラメータとして、一番目に周辺機器の接続名(文字列型)、二番目に周辺機器ブロックの座標(テーブル型)を渡しています。
(synchronizedによる排他制御については後述)
イベントの名前とパラメータ[編集]
イベント名は、発生したイベントの内容が分かりやすいように"周辺機器の種類_イベントの内容"のような形にすることが推奨されています(APIのjavadoc参照)。
queueEvent()の引数はComputerのos.queueEvent()と同様です。ただし、イベントのパラメータはオブジェクト型の配列として渡します。値の型はcallMethod()の戻り値と同様に適切なLuaの型へと自動的に変換されます。
Minecraftとの競合[編集]
callMethod()と同様に、attach()とdetach()もComputerCraftのLuaスレッドから呼び出されているため、attach()やdetach()の処理中に、Minecraftのスレッドからアクセスされる可能性のあるフィールドへアクセスすると競合が発生する可能性があります。従って、そのような処理では適宜synchronizedなどで排他制御する必要があります。
今回のサンプルでは、ComputerCraftのLuaスレッドから呼び出されるattach()/detach()のm_computersへの変更と、Minecraftのスレッドから呼び出されるclick()のm_computersからの取得が競合してしまう可能性があります。そのため、それぞれのm_computersへのアクセスはsynchronizedブロック内で排他的に行っています。