(Unity 5.1 からは UNET の使用を推奨しています。下記の情報は旧ネットワークシステムのものです。)
マスターサーバー( Master Server )はプレイヤークライアントがゲームインスタンスに接続するための出会いの場所です。ポート番号や IP アドレスは隠蔽され、ネットワーク接続を確立する際は、ファイアウォールのハンドリングや NAT パンチスルーなど、技術的なタスクを実行します。
各々の実行中のゲームインスタンスはマスターサーバーに Game Type を提供します。プレイヤーがマスターサーバーに接続すると、Game Type が一致するかクエリ実行して、サーバーは実行中のゲームの一覧とそれぞれのプレイヤー数、またプレイするためにパスワードが必要であるかを応答します。このデータ交換を行うための関数はサーバー向けの MasterServer.RegisterHost() とプレイヤークライアント向けの MasterServer.RequestHostList() です。
RegisterHost をコールするとき 3 つの引数が必要で、gameTypeName (さきほどの Game Type )、gameName、comment をもとにホスト登録を行います。RequestHostList は接続したいホスト gameTypeName を引数にとります。その Game Type で登録されているホストがリクエストクライアントに戻されます。これは非同期処理であり、完全に受信した後に PollHostList() により完全なリストを受信することができます。
マスターサーバーによる NAT プルスルーは Facilitator という別処理によりハンドリングされますが、Unity のマスターサーバーは両方のサービスを並列処理します。
Game Type は各々のゲームを一意に識別する名前であるべきです(ただし Unity はこれを保証する中央登録システムはもってません)。他で使用されることのない独自の名前を選択します。もしゲームに異なるバージョンがある場合、ユーザーに警告を行いクライアントが実行サーバーとバージョンが対応してないことを知らせます。バージョン情報は comment フィールドで渡します。(バイナリデータであるためバージョンは好みのフォーマットで渡せます)。ゲームの名前は単にセットアップした人が提供した特定のゲームインスタンスの名前です。
comment フィールドはマスターサーバーを適切に設定すればより高度な方法で使用することができます。(この詳細については 以下 を参照してください。)例えば、comment の最初の 10 バイトをパスワードにしてマスターサーバーでホスト更新が行われたときにホスト更新を受信したときにマスターサーバー上でパスワードを展開することができます。もしパスワードチェックに失敗した場合、ホスト更新を拒否することができます。
ゲーム登録の前にホストでサポートされているかによって NAT 機能を有効・無効にすることが大事です。これは Network.InitializeServer の useNat の引数で行うことができます。
サーバーは次のようなコードで始まるかもしれません:
using UnityEngine;
using UnityEngine.Network;
using System.Collections;
public class ExampleScript : MonoBehaviour {
void OnGUI() {
if (GUILayout.Button ("Start Server"))
{
// Use NAT punchthrough if no public IP present
Network.InitializeServer(32, 25002, !Network.HavePublicAddress());
MasterServer.RegisterHost("MyUniqueGameType", "JohnDoes game", "l33t game for all");
}
}
}
C# スクリプトの例
function OnGUI() {
if (GUILayout.Button ("Start Server"))
{
// Use NAT punchthrough if no public IP present
Network.InitializeServer(32, 25002, !Network.HavePublicAddress());
MasterServer.RegisterHost("MyUniqueGameType", "JohnDoes game", "l33t game for all");
}
}
JS スクリプトの例
ここでは NAT パンチスルーが必要であるかを、マシンにパブリック IP アドレスがあるかどうかをチェックして判断します。Network.TestConnection というより洗練された関数によりホストマシンが NAT をできるかどうか判断させることもできます。さらにパブリック IP アドレスに対して接続テストを行いゲームポートに対してファイアウォールがブロックしているかチェックします。パブリック IP アドレスのあるマシンはつねに NAT テストを通過しますが、接続テストに失敗した場合にホストは NAT クライアントに 接続できません 。そのようなケースでは、ゲームを動かすにはポートフォワーディングが必要であることがユーザーに知らされます。ローカルのブロードバンド接続は通常 NAT アドレスがありますが、ポートフォワーディングをセットアップすることができません(パブリック IP アドレスを持たないため)。これらのケースでは、NAT テストが失敗した場合、ローカルネットワークのクライアントしか接続することができないためサーバーを実行することが推奨されないことが、ユーザーに知らされます。
もしホストが NAT 機能を必要でないのに有効化した場合もアクセス可能となります。しかし、NAT パンチスルーできないクライアントはサーバーが NAT を有効化していないために接続できないと誤解する可能性があります。
HostData オブジェクトはホスト登録やクエリの際に送信されます。次のホストに関する情報を保持しています:
boolean | useNat | ホストが NAT パンチスルーを使用するか示します。 |
String | gameType | ホストのゲームタイプ |
String | gameName | ホストのゲーム名 |
int | connectedPlayers | プレイヤー/クライアントの同時接続数 |
int | playerLimit | プレイヤー/クライアントの最大同時接続数 |
String[] | IP | ホストの内部 IP アドレス。パブリック IP アドレスをもつサーバーにおいては内部、外部の IP アドレスは同じです。内部接続する場合に、すべての IP アドレスとマシンのすべての印 t フェースを紐付けてチェックする必要があるため、このフィールドは配列として定義されています。 |
int | port | ホストのポート |
boolean | passwordProtected | ホスト接続にパスワードが必要であるか |
String | comment | ホスト登録の際にセットされたコメント |
String | guid | ホストのネットワーク GUID。NAT パンチスルーで接続するために必要 |
この情報はクライアントにより、ホストが接続できるかどうかみるために使用されます。NAT が有効化された場合、接続する際にホストの GUID が必要です。これは接続する際に HostData が受信されたときに自動的にハンドリングされます。接続のルーチンは次のようなものになります:
using UnityEngine;
using UnityEngine.Network;
using System.Collections;
public class ExampleScript : MonoBehaviour {
void Awake() {
MasterServer.RequestHostList("MadBubbleSmashGame");
}
void OnGUI() {
HostData[] data = MasterServer.PollHostList();
// Go through all the hosts in the host list
foreach (var element in data)
{
GUILayout.BeginHorizontal();
var name = element.gameName + " " + element.connectedPlayers + " / " + element.playerLimit;
GUILayout.Label(name);
GUILayout.Space(5);
string hostInfo;
hostInfo = "[";
foreach (var host in element.ip)
hostInfo = hostInfo + host + ":" + element.port + " ";
hostInfo = hostInfo + "]";
GUILayout.Label(hostInfo);
GUILayout.Space(5);
GUILayout.Label(element.comment);
GUILayout.Space(5);
GUILayout.FlexibleSpace();
if (GUILayout.Button("Connect"))
{
// Connect to HostData struct, internally the correct method is used (GUID when using NAT).
Network.Connect(element);
}
GUILayout.EndHorizontal();
}
}
}
C# スクリプトの例
function Awake() {
MasterServer.RequestHostList("MadBubbleSmashGame");
}
function OnGUI() {
var data : HostData[] = MasterServer.PollHostList();
// Go through all the hosts in the host list
for (var element in data)
{
GUILayout.BeginHorizontal();
var name = element.gameName + " " + element.connectedPlayers + " / " + element.playerLimit;
GUILayout.Label(name);
GUILayout.Space(5);
var hostInfo;
hostInfo = "[";
for (var host in element.ip)
hostInfo = hostInfo + host + ":" + element.port + " ";
hostInfo = hostInfo + "]";
GUILayout.Label(hostInfo);
GUILayout.Space(5);
GUILayout.Label(element.comment);
GUILayout.Space(5);
GUILayout.FlexibleSpace();
if (GUILayout.Button("Connect"))
{
// Connect to HostData struct, internally the correct method is used (GUID when using NAT).
Network.Connect(element);
}
GUILayout.EndHorizontal();
}
}
JS スクリプトの例
このサンプルではマスターサーバーから戻される関連するすべてのホスト情報が出力されます。ping 情報やホストの地理情報のように便利な情報もこれに加えることができます。
NAT パンチスルーが可能であるかにより、特定のコンピューターがサーバーとして適切であるか示します。いくつかのクライアントは接続できる可能性があるものの、NAT サーバーへの接続で問題が発生するクライアントが出る可能性があります。
デフォルトでは、NAT パンチスルーはマスターサーバーの協力により提供されますが、必ずしもこの方法でなくとも問題ありません。NAT パンチスルーのサービスに使用されるファシリテータ( Facilitator )プロセスです。もし二つのマインがファシリテータで接続されている場合、外部 IP アドレスとポートが使用されるかぎり、両方とも互いに接続できるように見えます。マスターサーバーは、他の方法では判断することが難しい、この外部 IP とポート情報を提供するために使用されます。マスターサーバーとファシリテータが密接に統合されているのはこのためです。マスターサーバーはデフォルトで同一の IP アドレスであり、いずれかを変更するには、MasterServer.ipAddress、MasterServer.port、Network.natFacilitatorIP および Network.natFacilitatorPort のいずれかを使用します。
Unity Technologies ではテスト目的で、完全にデプロイされたマスターサーバーがあり、このサーバーが実際にデフォルトで使用されます。しかしソースコードは無償で提供されており Windows、Linux および Mac OS で使用可能です。プロジェクトをソースから構築する方法に加えて、マスターサーバーが情報のハンドリングする方法や、通信方法を修正したいケースがあるかもしれません。例えば、ホストデータのハンドリングを最適化したり、ホスト一覧に戻されるクライアントの数を限定することができます。このような変更はソースコードの変更を伴い、この方法の詳細については Unity ネットワーキングサーバーのカスタム構築(旧) を参照してください。