(解説を見やすく編集) |
(→イベントの発生: リンク追加) |
||
185行目: | 185行目: | ||
イベント名は、発生したイベントの内容が分かりやすいように"'''周辺機器の種類_イベントの内容'''"のような形にすることが'''推奨'''されています(APIのjavadoc参照)。 | イベント名は、発生したイベントの内容が分かりやすいように"'''周辺機器の種類_イベントの内容'''"のような形にすることが'''推奨'''されています(APIのjavadoc参照)。 | ||
− | queueEvent()の引数はComputerのos.queueEvent() | + | queueEvent()の引数はComputerのos.queueEvent()と同様です。ただし、イベントのパラメータはオブジェクト型の配列として渡します。値の型は[[ComputerCraft_API/メソッドの追加#引数や戻り値の型|callMethod()の戻り値と同様]]に適切なLuaの型へと自動的に変換されます。 |
==== Minecraftとの競合 ==== | ==== Minecraftとの競合 ==== |
2014年11月14日 (金) 02:48時点における版
この記事は"Minecraft Forge Universal 10.13.0.x~"及び"ComputerCraft 1.65~"を前提MODとしています。 |
目次
イベントの発生
右クリックされたとき接続されているComputerにイベントを発生させる周辺機器ブロックを追加します。
- IComputerAccessインスタンスの管理
- IComputerAccess.queueEvent()によるイベントの発生
ソースコード
「周辺機器の追加」のソースコードを元にして、変更部分のみを解説します。
- 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.HashSet; 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() { synchronized (this) { for (IComputerAccess computer : m_computers) { computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()}); } } } }
解説
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() { synchronized (this) { for (IComputerAccess computer : m_computers) { computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()}); } } }
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ブロック内で排他的に行っています。