API > Rednet & GPS

「API/Rednet & GPS」の編集履歴(バックアップ)一覧に戻る

API/Rednet & GPS - (2013/06/24 (月) 19:53:15) のソース

このページでは Rednet API と GPS API について解説する。

参考資料:
-[[Rednet API>http://computercraft.info/wiki/index.php?title=Rednet_%28API%29]]
-[[GPS API>http://computercraft.info/wiki/index.php?title=Gps_%28API%29]]
執筆時のバージョン:
-ComputerCraft 1.53 for Minecraft 1.5.2

----
#contents
----

*Rednet API
Rednet APIを使うと、離れた場所にあるコンピュータ同士で文字列データを送受信することができる。

Wireless Modemを使った無線通信と、Wired Modemを使った有線通信(CC1.51-)、RedPowerのBundled Cablesを使った有線通信がある。これらの内、Bundled Cablesを使った有線通信は現在ほぼ使われていない。また、このAPIはMineFactoryReloadedのRedNet Cableとは一切関係なく、RedNet Cableを通信に利用することもできない。
このページでの解説は、Wireless Modemを使った無線通信と、Wired Modemを使った有線通信を前提として進める。

※RedPowerのBundled Cablesを使った有線通信について
#region
通信速度が遅く(16bits/2ticks)、GPSも使えず、配線コストもかかるなど何かと不便なので現在は使われない。
Redstone信号で利用するときと同じように、コンピュータの側面に直接Bundled Cablesを接続する。そして、ケーブルを接続した方向をrednet.openで通信可能にする。後はRednet APIの各関数を利用して通信する。
ComputerCraftで扱える文字コードはASCIIの7ビット文字である。この7ビット文字を詰めて16ビットずつ送信する。Bundled Cablesの各色ワイヤーが各ビットのデータを伝送する。16ビットのデータ(2と2/7文字分)1個分の送信には2tickかかる(文字列データに1tick、セパレータに1tick)。
#endregion

**無線通信の通信可能範囲
通信可能範囲は通信するComputerやTurtleを中心とした半径が最大通信距離の球の内側である。
最大通信距離は64~384m(デフォルト設定)で、ComputerやTurtleのある高度によって変化する。以下の式によって求められる。
 if y >= 96 then
     range = (y - 96) * (modem_highAltitudeRange - modem_range) / ( WorldHeight - 98 ) + modem_range
 else
     range = modem_range
 end
デフォルト設定なら更に以下のようにも簡略化できる。
 range = y >= 96 and (y - 96) * 320 / 158 + 64 or 64
CC1.42では、CC1.41の「最高高度でもConfigで設定した最大通信距離に達しない不具合」が修正された。

デフォルト設定の通信可能距離
|CENTER:BGCOLOR(#DDD):&bold(){高度}|CENTER:BGCOLOR(#DDD):&bold(){最大通信距離}|
|RIGHT:1|RIGHT:64|
|CENTER:&bold(){...}|RIGHT:64|
|RIGHT:96|RIGHT:64|
|RIGHT:97|RIGHT:66.0253...|
|CENTER:&bold(){...}|CENTER:高度+1毎に+2.0253...|
|RIGHT:254|RIGHT:384|

雷雨時には modem_range の代わりに modem_rangeDuringStorm が、 modem_highAltitudeRange の代わりに modem_highAltitudeRangeDuringStorm が計算に使われることによって、最大通信距離が大幅に縮む。デフォルトの場合、 64m~384m が 16m~64m になる。

実際に到達判定に使われる最大通信距離は、送信側と受信側の最大通信距離のうち長い方である。
このため、例えば地上(低高度)にあるコンピュータと高高度にあるコンピュータは、高高度にあるコンピュータの通信範囲内なら互いに送受信が可能。通信の中継やGPSホストなどは、ワールドの限界高度付近に設置したWirless Turtleで行うとよい。

なお、送信側または受信側がロードされていないチャンク(プレイヤーのいるチャンクを中心とした21*21チャンクの範囲の外。いわゆる凍結チャンク)にある場合は、距離的に通信可能範囲内であっても通信を行うことができない。

**チャンネル
【1.5-】
従来の仕様では、送信時に指定できる送信先は特定のIDを持つコンピュータか、全てのコンピュータのみであった。CC1.5よりWireless Modemの機能が刷新され、コンピュータIDに替わり、通信対象の指定にチャンネルが使われるようになった。通信は、送信時に指定されたチャンネルと同じチャンネルをopenしている全てのコンピュータで受信可能である。また、一つのコンピュータは同時に127個のチャンネルまでopenすることができる。

なお、&b(){通信をRednet APIで行う限りにおいては、この仕様変更を気にする必要はない。}なぜならば、Rednet APIではチャンネル番号としてコンピュータIDが用いられており、rednet.broadcast()にも特定のチャンネル番号が用いられている(後述)ためである。受信に関しても、rednet.receive()およびrednet_messageイベントは従来通りこれら2つのチャンネルからのみ受信が可能である。

チャンネルは番号により識別され、チャンネルに使用できる番号は0~65535の整数である。ただし、65534はGPS用に、65535はrednet.broadcast用に使われている。

 gps.CHANNEL_GPS = 65534
 rednet.CHANNEL_BROADCAST = 65535

任意のチャンネル番号を指定して通信を行うには、[[Peripheral API>API/Peripheral]]を用いて、直接[[Wireless Modemのメソッド>API/Peripheral#id_2a62c87f]]を呼び出して通信する必要がある。また、受信するためには[[os.pullEvent()>API/OS#id_12ecb1d0]]でmodem_messageイベントを捕捉する。この方法で他者の利用しているチャンネルをopenして受信すると、他者のコンピュータ宛ての通信を見る事が出来てしまうので注意。

**open
-rednet.open( &italic(){side} )
-&italic(){side}(文字列)方向を通信可能な状態にする
-戻り値:nil

&italic(){side} は "left", "right", "top", "bottom", "front", "back" のいずれか(以下同様)。

【1.5-】コンピュータIDと同じ番号のチャンネル及び、rednet.CHANNEL_BROADCASTのチャンネルから受信可能な状態にする。

例:
 rednet.open( "left" )
左側を通信可能な状態にする。

**close
-rednet.close( &italic(){side} )
-&italic(){side}(文字列)方向を通信不可能な状態にする。
-戻り値:nil

【1.5-】コンピュータIDと同じ番号のチャンネル及び、rednet.CHANNEL_BROADCASTのチャンネルからの受信を不可能な状態にする。

**isOpen
【1.5-】
-rednet.close( &italic(){side} )
-&italic(){side}(文字列)方向が通信可能な状態か調べる。
-戻り値:ブーリアン型。通信可能状態ならtrue、不可能状態ならfalse。

コンピュータIDと同じ番号のチャンネルとrednet.CHANNEL_BROADCASTのチャンネルの両方から受信可能な状態かを返す。

**broadcast
-rednet.broadcast( &italic(){message} )
-すべての通信可能なComputer/Turtleへ&italic(){message}(文字列)を送信する
-戻り値:ブーリアン型。送信に成功したらtrue、失敗したらfalse。ただし受信の成否については保証しない

【1.5-】rednet.CHANNEL_BROADCASTのチャンネルに&italic(){message}を送信する。

例:
 rednet.broadcast("ComputerCraft")
すべての通信可能なComputer/Turtleへ文字列"ComputerCraft"を送信する。

**announce
【-1.481】
-rednet.announce()
-すべての通信可能なコンピュータに空のメッセージを送信する。 rednet.broadcast("") と同等
-戻り値:ブーリアン型。送信に成功したらtrue、失敗したらfalse。ただし受信の成否については保証しない

【1.5-】この関数は削除された。

**send
-rednet.send( &italic(){receiverID} , &italic(){message} [ , &italic(){waitUntilPortOpen}] )
-&italic(){receiverID}(数値)のIDを持つComputer/Turtleへ&italic(){message}(文字列)を送信する。&italic(){waitUntilPortOpen}(ブーリアン)にtrueを指定した場合は、サーバのポートが開くまで待つ(省略可)。
-戻り値:ブーリアン型。送信に成功したらtrue、失敗したらfalse。ただし受信の成否については保証しない

【1.5-】&italic(){receiverID}と同じ番号のチャンネルに&italic(){message}を送信する。rednet.openではコンピュータIDをチャンネル番号としてopenしているため、結果的にIDが&italic(){receiverID}のコンピュータに送信することになる。

例:
 rednet.send(22,"ComputerCraft", true)
IDが22のComputer/Turtleへ文字列"ComputerCraft"を送信する(ポートが利用可能になるまで待つ)。

**receive
-rednet.receive( &italic(){timeout} )
-他のComputer/Turtleからの通信を待ち、通信があれば受信する。&italic(){timeout}(数値)で待つ最大時間を指定できる。
-戻り値:数値型(&italic(){senderID}), 文字列型(&italic(){message}), 数値型(&italic(){distance})。通信を受信すると、送信者ID(&italic(){senderID})とメッセージ(&italic(){message})、送信者までの距離(&italic(){distance})が返る。ただしRedPowerの有線通信の場合は距離を取得できない。タイムアウトした場合はnilが返る。

【1.5-】通信可能なチャンネルからの通信を待ち、通信があれば受信する。rednet.openでは自身のコンピュータIDとrednet.CHANNEL_BROADCASTのチャンネルを通信可能な状態にするため、結果的に従来のrednet.receiveと同じ働きをする。なお、内部的にはrednet_messageイベントで受信しているため、前述の2つのチャンネル以外からはopenに関わらず受信できない。

【1.51-】Wired Modemを用いた有線通信の場合、&italic(){distance}は送信者までのケーブルの長さが返る。

例:
 senderId, message, distance = rednet.receive()
 print(message)
メッセージを受信し、それを表示する。

*GPS API
**GPSとは
GPSホストに記憶させた座標と、無線通信時に取得できるGPSホストまでの距離を元に、三次元測位の原理で位置を知りたいコンピュータの座標を計算するシステム(現実のGPSとはあまり関係ない)。ゲーム内から直接座標を取得するのではなく、Rednet APIの機能をフル活用して座標を求めている。

***GPSホストの設置
最低限必要なもの:
-GPSホストにする「Wireless Modemを接続したComputer」または「Wireless Turtle」を計4つ
(当然ながらWired Modemでは利用できない)

GPSホスト4つをそれぞれが同じ平面上にならない位置(つまり三角錐の各頂点の位置)に設置する。GPSホストは、なるべく広範囲から利用できるように、設置限界高度ギリギリに設置するとよい。そして、gps host <x> <y> <z>コマンドでGPSホストの座標を指定してGPSホストプログラムを起動する。GPSホストの座標は、GPSホストとするComputer/Turtleを設置した座標である(※Wireless Modemブロックの座標ではないので注意)。

GPSホストのComputer/Turtleがチャンク凍結・リロードで再起動しても自動で復帰できるようにするため、GPSホストプログラムはstartupプログラム内で起動するとよい。

startupの例:
 shell.run("gps", "host", "100", "254", "-200")
GPSホストプログラムを座標(100, 254, -200)に設定して起動する。


CC1.4からWireless Turtleでもgps hostコマンドが使えるように修正された。これにより、Wireless Turtleをプログラムによって設置位置まで移動させGPSホストプログラムを起動することが可能となった(ただし、自力で登って設置するならComputerの方が低コスト)。

***ホスト設置座標の例
※以下の例の「有効範囲」はWireless Modemの通信距離によるもの。実際には、GPSホストがプレイヤーからxまたはz座標で160mくらい離れた(正確にはプレイヤーのいるチャンクを中心とした21*21チャンクの範囲から出た)時点でGPSホストのあるチャンクが凍結され、利用できなくなってしまう(他のmodのチャンクローダーで回避可能)。

例1:
[[CC公式フォーラム>http://www.computercraft.info/forums2/index.php?/topic/9528-/]]で紹介されていたもの。平面上の有効範囲はy1で半径約270m、y64で半径約320mの大体円形。
+(x, 254, z - 9)
+(x + 9, 251, z)
+(x, 254, z + 9)
+(x - 9, 251, z)

ただし上の例では、y240~250付近で通信範囲内であっても座標を特定できないエリアがわずかに存在する(山岳~地下で利用する分には特に問題ない)。

例2:
GPSホストを一辺が約12mの正四面体の各頂点に配置した例。平面上の有効範囲はy1で半径約270m、y64で半径約315m、y128で半径約340mの円形。
+(x - 6, 254, z - 4)
+(x + 6, 254, z - 4)
+(x, 254, z + 7)
+(x, 244, z)

4機目の高度を下げているのは、4機目が1~3機目と同じ平面上の位置にならないようにするため。
#region
ホスト3機で2つに絞れた座標(片方が正しい)を4機目で1つに絞るためには、【《計算で求められた正しい座標と4機目間の距離》と《Rednetによる4機目までの正確な距離》の差の絶対値】と【《計算で求められた正しくない座標と4機目間の距離》と《Rednetによる4機目までの正確な距離》の差の絶対値】の差の絶対値が0.05以上である必要がある。これはGPS APIによる制約で、この値がGPS利用予定範囲内のすべての位置で0.05以上になるように4機目の高度を下げるのだが、高度を下げ過ぎると今度は通信可能範囲が縮小してGPS全体の利用可能範囲が狭くなってしまう。双方のバランスをとった結果、4機目のy座標、そして2~4機目のx, z座標つまりGPSの利用可能範囲が決まることになる。 
#endregion

***GPSの利用
4つ以上のGPSホストが利用可能な位置にある「Wireless Modemを接続したComputer」や「Wireless系 Turtle」でgps locateコマンドやgps.locate関数を使用する。

***GPSの仕組み
※【1.5】からWireless Modemの通信仕様変更により、GPS API及びgpsプログラムは、GPSホスト側の受信にはgps.CHANNEL_GPSのチャンネルを、GPSで座標を求めるコンピュータ側の受信には自身のコンピュータIDのチャンネルを用いるように変更されている。そのため、GPS APIやgpsプログラムを使わずにGPSネットワークを利用する場合は、[[Peripheral API>API/Peripheral]]を用いて、直接Wireless Modemのメソッドを呼び出して通信する必要がある。詳しくは ComputerCraft\lua\rom\apis\gps 及び ComputerCraft\lua\rom\programs\gps のLuaスクリプトを参照。なお、&bold(){GPS API及びgpsプログラムからのみGPSを利用する限りは、この仕様変更を特に気にする必要はない。}

+GPSホストには事前にGPSホストのある座標を記憶させておく(gps hostコマンドを使用。GPSホストはCHANNEL_GPSチャンネル宛ての通信が受信可能になる)
+gps locateコマンドまたはgps.locate関数によって、現在位置を知りたいコンピュータから文字列"PING"がCHANNEL_GPSチャンネルへ送信される
+文字列"PING"を受信したGPSホストは、1.で設定した自身の座標を"PING"を送信したコンピュータ(2.の位置を知りたいコンピュータ)へ返信する
+位置を知りたいコンピュータは各GPSホストからGPSホストの座標とGPSホストまでの距離(位置を求める計算に使われる)を得る。
+位置を知りたいコンピュータ側に、同一平面上にない4つ以上のGPSホストから返信があれば位置を計算できる。&br()同一直線上にない3つのGPSホストの場合、gps locateコマンドや、デバッグモードを指定したgps.locate関数は2つの座標(片方が正しい)を画面に表示するが、gps.locate関数の戻り値から結果を得ることはできない。

**locate
-gps.locate( &italic(){timeout} [ , &italic(){debug} ] )
-GPSシステムを利用してコンピュータやタートルの座標を求める。&italic(){timeout}(数値)はGPSホストからの返信を待つ時間(秒)。&italic(){debug}(ブーリアン)にtrueを指定すると画面にデバッグ情報を表示する。
-戻り値:数値型(&italic(){x}), 数値型(&italic(){y}), 数値型(&italic(){z})。座標が求められた場合は各座標の数値が返る。求められなかった場合はnilが返る

***locate関数の改造
3つのGPSホストで座標が求められるようにする。上の「GPSホスト設置座標の例」での4台目がいらなくなる。
ただし、すべてのGPSホストは高度254にあり、ブロック設置可能高度は254以下であるとする。
(改造は自己責任でお願いします)

.minecraft\mods\ComputerCraft\lua\rom\apis\gps の一部、138行目以降

 	-- Return the response
 	if pos1 and pos2 then
 		-- if _bDebug then  -- 以下 return nil までコメントアウト
 		-- 	print( "Ambiguous position" )
 		-- 	print( "Could be "..pos1.x..","..pos1.y..","..pos1.z.." or "..pos2.x..","..pos2.y..","..pos2.z )
 		-- end
 		-- return nil
 		if pos1.y > 254 then pos1 = pos2 end  -- 追加
 	end  -- 追加
 	if pos1 then  -- elseif を if に変更
 		if _bDebug then