提供: Minecraft Modding Wiki
移動先: 案内検索
(「周辺機器の追加」ページへのリンク修正)
 
(同じ利用者による、間の5版が非表示)
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/1.65/周辺機器の追加|MC1.7 周辺機器の追加]]」のソースコードを元にして、変更部分のみを解説します。
  
 
*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;
 
 
}
 
}
  
58行目: 49行目:
 
package mods.sample.peripheral;
 
package mods.sample.peripheral;
  
 +
import java.util.HashMap;
 
import java.util.HashSet;
 
import java.util.HashSet;
 +
import java.util.Map;
 
import java.util.Set;
 
import java.util.Set;
  
94行目: 87行目:
 
@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行目: 94行目:
 
@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行目: 108行目:
  
 
public void click() {
 
public void click() {
synchronized (this.m_computers) {
+
Map<String, Integer> pos = new HashMap<String, Integer>();
for (IComputerAccess computer : this.m_computers) {
+
pos.put("x", this.xCoord);
computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()} );
+
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} );
 
}
 
}
 
}
 
}
127行目: 126行目:
 
=== 解説 ===
 
=== 解説 ===
 
==== BlockSamplePeripheral.java ====
 
==== BlockSamplePeripheral.java ====
周辺機器ブロックが右クリックされた時の処理を追加する。
+
周辺機器ブロックが右クリックされたときの処理を追加します。
 
<source lang = "java">
 
<source lang = "java">
 
@Override
 
@Override
139行目: 138行目:
 
}
 
}
 
</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行目: 151行目:
 
}
 
}
 
</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行目: 165行目:
 
@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) {
+
Map<String, Integer> pos = new HashMap<String, Integer>();
for (IComputerAccess computer : this.m_computers) {
+
pos.put("x", this.xCoord);
computer.queueEvent("sample_click", new Object[] {computer.getAttachmentName()} );
+
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} );
 
}
 
}
 
}
 
}
 
}
 
}
 
</source>
 
</source>
↑周辺機器ブロックが右クリックされた時に、BlockSamplePeripheralから呼び出される。IComputerAccessインスタンスのリストにある全てのComputerやTurtleへIComputerAccess.queueEvent()で"sample_click"イベントを発生させる。前述の通り、リストへのアクセスは排他的に行っている。
+
m_computersに登録されているすべてのComputerへIComputerAccess.queueEvent()で"sample_click"イベントを発生させます。イベントのパラメータとして、一番目に周辺機器の接続名(文字列型)、二番目に周辺機器ブロックの座標(テーブル型)を渡しています。
 +
 
 +
(synchronizedによる排他制御については後述)
 +
 
 +
==== イベントの名前とパラメータ ====
 +
イベント名は、発生したイベントの内容が分かりやすいように"'''周辺機器の種類_イベントの内容'''"のような形にすることが'''推奨'''されています(APIのjavadoc参照)。
 +
 
 +
queueEvent()の引数はComputerのos.queueEvent()と同様です。ただし、イベントのパラメータはオブジェクト型の配列として渡します。値の型は[[ComputerCraft_API/メソッドの追加#引数や戻り値の型|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()を渡すとよい。
 

2015年12月27日 (日) 10:42時点における最新版

ComputerCraft API >

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