提供: Minecraft Modding Wiki
移動先: 案内検索
(解説を見やすく編集)
1行目: 1行目:
{{Stb}}
+
[[ComputerCraft_API|ComputerCraft API]] >
 
{{前提MOD|reqmod="Minecraft Forge Universal 10.13.0.x~"及び"ComputerCraft 1.65~"}}
 
{{前提MOD|reqmod="Minecraft Forge Universal 10.13.0.x~"及び"ComputerCraft 1.65~"}}
  
== 周辺機器からイベントを発生させる ==
+
== イベントの発生 ==
右クリックされたとき、接続されたComputerやTurtleに対してイベントを発生させる周辺機器ブロックを追加する。
+
右クリックされたとき接続されているComputerにイベントを発生させる周辺機器ブロックを追加します。
 +
 
 +
*IComputerAccessインスタンスの管理
 +
*IComputerAccess.queueEvent()によるイベントの発生
  
 
=== ソースコード ===
 
=== ソースコード ===
「[[ComputerCraft_API/周辺機器の追加|周辺機器の追加]]」のソースコードを元にして、変更部分のみを解説する。
+
「[[ComputerCraft_API/周辺機器の追加|周辺機器の追加]]」のソースコードを元にして、変更部分のみを解説します。
  
 
*BlockSamplePeripheral.java
 
*BlockSamplePeripheral.java
 
<source lang = "java">
 
<source lang = "java">
 
package mods.sample.peripheral;
 
package mods.sample.peripheral;
 
import java.util.Random;
 
  
 
import net.minecraft.block.BlockContainer;
 
import net.minecraft.block.BlockContainer;
34行目: 35行目:
 
}
 
}
 
return true;
 
return true;
}
 
 
@Override
 
public int quantityDropped(int meta, int fortune, Random random){
 
return quantityDroppedWithBonus(fortune, random);
 
}
 
 
@Override
 
public int quantityDropped(Random random){
 
return 1;
 
 
}
 
}
  
94行目: 85行目:
 
@Override
 
@Override
 
public void attach(IComputerAccess computer) {
 
public void attach(IComputerAccess computer) {
synchronized (this.m_computers) {
+
synchronized (this) {
this.m_computers.add(computer);
+
m_computers.add(computer);
 
}
 
}
 
}
 
}
101行目: 92行目:
 
@Override
 
@Override
 
public void detach(IComputerAccess computer) {
 
public void detach(IComputerAccess computer) {
synchronized (this.m_computers) {
+
synchronized (this) {
this.m_computers.remove(computer);
+
m_computers.remove(computer);
 
}
 
}
 
}
 
}
115行目: 106行目:
  
 
public void click() {
 
public void click() {
synchronized (this.m_computers) {
+
synchronized (this) {
for (IComputerAccess computer : this.m_computers) {
+
for (IComputerAccess computer : m_computers) {
computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()} );
+
computer.queueEvent("sample_click",
 +
new Object[] {computer.getAttachmentName()});
 
}
 
}
 
}
 
}
127行目: 119行目:
 
=== 解説 ===
 
=== 解説 ===
 
==== BlockSamplePeripheral.java ====
 
==== BlockSamplePeripheral.java ====
周辺機器ブロックが右クリックされた時の処理を追加する。
+
周辺機器ブロックが右クリックされたときの処理を追加します。
 
<source lang = "java">
 
<source lang = "java">
 
@Override
 
@Override
139行目: 131行目:
 
}
 
}
 
</source>
 
</source>
ブロックが右クリックされたらTileEntity(周辺機器)を取得してclick()を呼び出す。
+
ブロックが右クリックされたら周辺機器のTileEntityを取得してTileSamplePeripheral.click()を呼び出しています。
  
 
==== TileSamplePeripheral.java ====
 
==== TileSamplePeripheral.java ====
イベント発生の処理と、イベントを発生させるための接続されたComputerやTurtleのリストの管理を追加する。
+
接続されているComputerのリストを管理する処理と、そのComputerにイベントを発生させる処理を追加します。
 +
 
 +
*Computerリストの初期化
 
<source lang = "java">
 
<source lang = "java">
 
private final Set<IComputerAccess> m_computers;
 
private final Set<IComputerAccess> m_computers;
150行目: 144行目:
 
}
 
}
 
</source>
 
</source>
↑コンストラクタで接続されたComputerやTurtleへイベントを発生させるのに必要なIComputerAccessインスタンスのリストを初期化する。
+
接続されているComputerのIComputerAccessインスタンスはHashSetのm_computersに格納します。<br>
 +
m_computersをコンストラクタで初期化します。
 +
 
 +
*IComputerAccessインスタンスの追加と削除
 
<source lang = "java">
 
<source lang = "java">
 
@Override
 
@Override
 
public void attach(IComputerAccess computer) {
 
public void attach(IComputerAccess computer) {
synchronized(this.m_computers) {
+
synchronized(this) {
this.m_computers.add(computer);
+
m_computers.add(computer);
 
}
 
}
 
}
 
}
161行目: 158行目:
 
@Override
 
@Override
 
public void detach(IComputerAccess computer) {
 
public void detach(IComputerAccess computer) {
synchronized(this.m_computers) {
+
synchronized(this) {
this.m_computers.remove(computer);
+
m_computers.remove(computer);
 
}
 
}
 
}
 
}
 
</source>
 
</source>
↑attach()で接続されたComputerやTurtleのIComputerAccessインスタンスをリストへ追加、detach()で取り外されたComputerやTurtleのComputerAccessインスタンスをリストから削除。<br>
+
attach()で接続されたComputerのIComputerAccessインスタンスをm_computersへ追加、detach()で取り外されたComputerのComputerAccessインスタンスをm_computersから削除します。こうすることによってm_computersには常に接続されているComputerだけが登録されているようになっています。<br>
attach()とdetach()はComputerCraftのLuaスレッドから呼び出されている。このリストはMinecraftスレッドから呼び出されるclick()からもアクセスされるのでsynchronizedで排他制御している。
+
 
 +
(synchronizedによる排他制御については後述)
 +
 
 +
*click()
 +
周辺機器ブロックが右クリックされたときにBlockSamplePeripheralから呼び出されます。
 
<source lang = "java">
 
<source lang = "java">
 
public void click() {
 
public void click() {
synchronized (this.m_computers) {
+
synchronized (this) {
for (IComputerAccess computer : this.m_computers) {
+
for (IComputerAccess computer : m_computers) {
computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()} );
+
computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()});
 
}
 
}
 
}
 
}
 
}
 
}
 
</source>
 
</source>
↑周辺機器ブロックが右クリックされた時に、BlockSamplePeripheralから呼び出される。IComputerAccessインスタンスのリストにある全てのComputerやTurtleへIComputerAccess.queueEvent()で"sample_click"イベントを発生させる。前述の通り、リストへのアクセスは排他的に行っている。
+
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ブロック内で排他的に行っています。
イベント名は、発生したイベントの内容が分かりやすいように"'''周辺機器の種類_イベントの内容'''"のような形にする事が'''推奨'''されている。(APIのjavadoc参照)<br>
 
queueEvent()の引数はos.queueEvent関数と同様。ただし、イベントのパラメータはオブジェクト型配列として渡す。値の型はcallMethod()の戻り値と同様に適切なLuaの型へと変換される。イベントのパラメータの一番目には、ComputerやTurtleからどの周辺機器で発生したイベントなのかが分かるように、IComputerAccess.getAttachmentName()を渡すとよい。
 

2014年11月14日 (金) 02:39時点における版

ComputerCraft API >

この記事は"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ブロック内で排他的に行っています。