シンプルなUnityネットワーク同期エンジンを実現
6693 ワード
シンプルなUnityネットワーク同期エンジンNetgoを実現
現在、GOLANGは特にネットワークプログラミングの面で大きなトレンドを持っています.c/c++と比較すると、GCは一部の機器性能を占有しているが、エラー確率が小さく、開発効率が大幅に向上し、そのオリジナルサポートのコラボレーションを応用することで、高同時性のサービスエンドプログラムを開発することが容易になる.筆者はVR業界に2年余り接触し、いくつかのビジネスunityネットワークエンジンに接触し、いつも使っているものが時代遅れだと感じ、自分で簡単なエンジンを書いた.現在実装されている基本的な機能:は部屋のコンセプトをサポートしています. は、フレーム同期およびRPCを含む柔軟なデータ同期方式をサポートする. は、カスタムイベントの送信をサポートします.
簡単なdemoも実現しましたが、同期効果は下図を参照してください.後で詳しく説明します.
プロジェクトのアドレス:https://github.com/harlanc/netgo-unity-client次は簡単なプロジェクトの複盤です.
データ通信フォーマット
データ通信フォーマットの定義は、プロジェクト全体の基盤です.ここのクライアントとサービス側は、プラットフォーム間、言語間通信です.そのため、言語に関係なく、プラットフォームに関係なく、簡単で使いやすく、効率的でトラフィックを費やさないデータフォーマットを定義します.ここではGoogleのProtobufを選び、この投稿を参考に詳しく紹介します.
ProtobufのC#コードライブラリには2つの選択肢があります.1つはprotobuf-net、1つはprotobuf-csharp-portです.前者のインタフェースの書き方はC#文法の規範に合っており、より快適に見えます.プラットフォームをまたぐ必要がある場合は、後者を使うことをお勧めします.異なる言語のインタフェースが似ているので、開発が容易になります.原作者の返事を見てみましょう.
protoファイルの定義
protobufをどのように使用するかは、まずprotoファイルを書き、独自の構造化データを定義します.netgoでは、netgoで定義されたメッセージ・ボディの一部を次に示します.
参照を完全に定義します.
c#とgolang APIインタフェースファイルの生成
ネーミングスペースを更新したら、次のコマンドを実行してAPIファイルを生成します. golang protoc --go_out=. *.proto c# protoc --csharp_out=. *.proto
サービス側ネットワークモデル
Unityネットワーク同期エンジンの実装には、サービス側とクライアントの2つの部分が含まれます.NegoはUnityネットワーク同期エンジンのサービス端であり、golangを用いて実現され、その原生的な協程を十分に利用して高同時性を実現している.そのネットワークモデルはgotcpに基づいて実現される.
上図を参照すると、netgoはsocketリンクごとに1つのコヒーレンスを確立し、1つのsocketコヒーレンス内部に3つのコヒーレンスを確立します. ReadLoopは、ネットワーク側からデータを読み出し、チャネルに格納するために使用される. HandleLoopは、アプリケーション層のデータを解析し、対応する処理を完了し、処理後のデータをChannelを介してWriteLoopに送信するために使用される. WriteLoopは、処理結果forwardを他のクライアントまたはresponseに本クライアントに渡す責任を負う.
参照コード:
クライアントコード構造
APIを書くのは基本的にユーザー向けのプログラミングで、筆者は、はっきりしたコード構造、良い命名方式は大部分の注釈を省くことができて、コードの書く乱れは注釈によって救うことしかできなくて、コード構造は下図を見ます:
ネーミングスペースによって、Library、ネットワーク層とアプリケーション層に分けられる(後でユーザインタフェース層が分けられる).
関連概念
データ同期
ここでの同期とは、1つの部屋のデータの同期であり、1つの部屋にはネットワーク上の複数の端末ユーザーが存在し、各Clientは部屋内の他の人のデータをローカルでCloneし、データの同期とはあなた自身のデータを他のCientの自分のCloneに同期することであり、送信範囲は他のユーザーが受信する.
データの同期は次の2つに分けられます. View Sync
ViewSyncはミリ秒レベルのデータ同期です.仮想キャラクタアクションの同期に使用できます. RPC
同期はユーザーによって手動でトリガーされます.交換などの同期に使用できます.
Custom Event
Custom Eventは、同期メッセージを他のすべてのClientエンティティに送信するのではなく、1つまたは複数の指定されたClientに送信します.
インタフェースの紹介
ルーム関連インタフェース
リクエストインタフェース
コールバックインタフェース
Player関連インタフェース
CustomEventインタフェース
リクエストインタフェース
コールバックインタフェース
View Sync
ビューの同期には、コンポーネントスクリプトを独自に実装し、シーケンス化逆シーケンス化インタフェースを実装し、物体にマウントする必要があります.
Cloneエンティティは、データの逆シーケンス化を受けた後、Updateでリアルタイムに更新すればよい.
RPC
RPCを使用するには、ビュースクリプトにRPC関数を書く必要があります.
次のインタフェースを呼び出して、RPC呼び出しを他のCloneエンティティに送信します.
RPC、View Sync、およびCustom Eventの詳細な使用方法については、ソースコードを参照してください.
デモ
サービス・エンドの導入
Cloneコード
インストール依存
リスニングIPの更新
mainを開きます.go
サービスの開始
クライアントコンパイルインストール
クライアントはwindows/MacOS/Andorid/IOSマルチプラットフォームをサポートします.以下、AndroidとMacOSでテストします.
IPとポートの構成
Androidプラットフォームの切り替え
コンパイル生成APK
APKインストール後の初期化画面は以下の通りです.
機能テスト
2つのClientが同じ部屋に入ると、各Clientは2つのCubeをインスタンス化し、1つはネイティブエンティティ(Mine Cube)、1つは相手エンティティ(Clone Cube)となる.
View SYnc
ボタンMoveをクリックすると、ビュー同期でpostionとrotationの同期が行われます.つまり、文章が始まったばかりの動図の展示の様子です.
RPC
Mine Cubeをクリックすると、Cubeの色が変化し、他のマシンに同期します.ここでの色同期はRPCで実現されます.
Custom Event
Clone Cubeをクリックすると、相手エンティティにメッセージが送信され、効果は相手のMine Cube Scaleが増加します.
Road Map
次に、最適化が必要な機能が追加されるか、または追加されることを考慮します.ホール機能 をサポートは負荷等化 をサポートする. UDP等のネットワーク伝送プロトコルをサポートする を追加する. jsonなどの複数種類のデータ符号化フォーマットをサポートする を追加する. View Syncデータ転送最適化 ルーム間Custom Event 対応 .....
現在、GOLANGは特にネットワークプログラミングの面で大きなトレンドを持っています.c/c++と比較すると、GCは一部の機器性能を占有しているが、エラー確率が小さく、開発効率が大幅に向上し、そのオリジナルサポートのコラボレーションを応用することで、高同時性のサービスエンドプログラムを開発することが容易になる.筆者はVR業界に2年余り接触し、いくつかのビジネスunityネットワークエンジンに接触し、いつも使っているものが時代遅れだと感じ、自分で簡単なエンジンを書いた.現在実装されている基本的な機能:
簡単なdemoも実現しましたが、同期効果は下図を参照してください.後で詳しく説明します.
プロジェクトのアドレス:https://github.com/harlanc/netgo-unity-client次は簡単なプロジェクトの複盤です.
データ通信フォーマット
データ通信フォーマットの定義は、プロジェクト全体の基盤です.ここのクライアントとサービス側は、プラットフォーム間、言語間通信です.そのため、言語に関係なく、プラットフォームに関係なく、簡単で使いやすく、効率的でトラフィックを費やさないデータフォーマットを定義します.ここではGoogleのProtobufを選び、この投稿を参考に詳しく紹介します.
ProtobufのC#コードライブラリには2つの選択肢があります.1つはprotobuf-net、1つはprotobuf-csharp-portです.前者のインタフェースの書き方はC#文法の規範に合っており、より快適に見えます.プラットフォームをまたぐ必要がある場合は、後者を使うことをお勧めします.異なる言語のインタフェースが似ているので、開発が容易になります.原作者の返事を見てみましょう.
protoファイルの定義
protobufをどのように使用するかは、まずprotoファイルを書き、独自の構造化データを定義します.netgoでは、netgoで定義されたメッセージ・ボディの一部を次に示します.
enum CacheOptions{
AddToRoomCache = 0;
RemoveFromRoomCache = 1;
}
message NGVector3{
float x = 1;
float y = 2;
float z = 3;
}
message NGQuaternion{
float x = 1;
float y = 2;
float z = 3;
float w = 4;
}
message NGColor{
float r = 1;
float g = 2;
float b = 3;
float a = 4;
}
参照を完全に定義します.
c#とgolang APIインタフェースファイルの生成
ネーミングスペースを更新したら、次のコマンドを実行してAPIファイルを生成します.
サービス側ネットワークモデル
Unityネットワーク同期エンジンの実装には、サービス側とクライアントの2つの部分が含まれます.NegoはUnityネットワーク同期エンジンのサービス端であり、golangを用いて実現され、その原生的な協程を十分に利用して高同時性を実現している.そのネットワークモデルはgotcpに基づいて実現される.
上図を参照すると、netgoはsocketリンクごとに1つのコヒーレンスを確立し、1つのsocketコヒーレンス内部に3つのコヒーレンスを確立します.
参照コード:
func (c *Conn) Do() {
if !c.srv.callback.OnConnect(c) {
return
}
asyncDo(c.handleLoop, c.srv.waitGroup)
asyncDo(c.readLoop, c.srv.waitGroup)
asyncDo(c.writeLoop, c.srv.waitGroup)
}
クライアントコード構造
APIを書くのは基本的にユーザー向けのプログラミングで、筆者は、はっきりしたコード構造、良い命名方式は大部分の注釈を省くことができて、コードの書く乱れは注釈によって救うことしかできなくて、コード構造は下図を見ます:
ネーミングスペースによって、Library、ネットワーク層とアプリケーション層に分けられる(後でユーザインタフェース層が分けられる).
関連概念
データ同期
ここでの同期とは、1つの部屋のデータの同期であり、1つの部屋にはネットワーク上の複数の端末ユーザーが存在し、各Clientは部屋内の他の人のデータをローカルでCloneし、データの同期とはあなた自身のデータを他のCientの自分のCloneに同期することであり、送信範囲は他のユーザーが受信する.
データの同期は次の2つに分けられます.
ViewSyncはミリ秒レベルのデータ同期です.仮想キャラクタアクションの同期に使用できます.
同期はユーザーによって手動でトリガーされます.交換などの同期に使用できます.
Custom Event
Custom Eventは、同期メッセージを他のすべてのClientエンティティに送信するのではなく、1つまたは複数の指定されたClientに送信します.
インタフェースの紹介
ルーム関連インタフェース
リクエストインタフェース
//
public static void JoinOrCreateRoom(string roomid,uint maxnumber)
//
public static void CreateRoom(string roomid, uint maxnumber)
//
public static void JoinRoom(string roomid)
//
public static void LeaveRoom()
コールバックインタフェース
//
void OnGreatedRoom();
//
void OnGreateRoomFailed(string errmsg);
//
void OnJoinedRoom();
//
void OnJoinRoomFailed();
//
void OnLeftRoom();
Player関連インタフェース
//
public static void Instantiate(string prefabname, Vector3 position, Quaternion rotation, uint[] viewids)
//
void OnOtherPlayerEnteredRoom(NGPlayer player);
//
void OnOtherPlayerLeftRoom(NGPlayer player);
CustomEventインタフェース
リクエストインタフェース
//
public static void SendCustomEvent(uint eventid, uint[] targetpeerids, NGAny[] customdata)
コールバックインタフェース
//
void OnCustomEvent(uint eventID, NGAny[] data);
View Sync
ビューの同期には、コンポーネントスクリプトを独自に実装し、シーケンス化逆シーケンス化インタフェースを実装し、物体にマウントする必要があります.
public interface INGSerialize
{
void SerializeViewComponent(NGViewStream stream);
void DeserializeViewComponent(NGViewStream stream);
}
public class CubeViewComponent : NGIncomingEvent, INGSerialize
{
public void SerializeViewComponent(NGViewStream stream)
{
stream.Send(this.transform.position);
stream.Send(this.transform.rotation);
}
public void DeserializeViewComponent(NGViewStream stream)
{
mCorrentPosition = (NGVector3)stream.Receive();
mCorrentRotation = (NGQuaternion)stream.Receive();
}
}
Cloneエンティティは、データの逆シーケンス化を受けた後、Updateでリアルタイムに更新すればよい.
void Update()
{
if (!view.IsMine)
{
transform.position = mCorrentPosition;//Vector3.Lerp(transform.position, mCorrentPosition, Time.deltaTime * 5);
transform.rotation = mCorrentRotation;//Quaternion.Lerp(transform.rotation, mCorrentRotation, Time.deltaTime * 5);
}
}
RPC
RPCを使用するには、ビュースクリプトにRPC関数を書く必要があります.
[NGRPCMethod]
public void OnColor(NGAny[] c)
{
mMat.color = c[0].NgColor;
}
次のインタフェースを呼び出して、RPC呼び出しを他のCloneエンティティに送信します.
public static void SendRPC(uint viewID, string methodname, RPCTarget target, params NGAny[] parameters)
RPC、View Sync、およびCustom Eventの詳細な使用方法については、ソースコードを参照してください.
デモ
サービス・エンドの導入
Cloneコード
git clone https://github.com/netgo-framework/netgo.git
インストール依存
go get -d ./...
リスニングIPの更新
mainを開きます.go
tcpAddr, err := net.ResolveTCPAddr("tcp", "192.168.0.104:8686")
サービスの開始
go run main.go
クライアントコンパイルインストール
クライアントはwindows/MacOS/Andorid/IOSマルチプラットフォームをサポートします.以下、AndroidとMacOSでテストします.
IPとポートの構成
Androidプラットフォームの切り替え
コンパイル生成APK
APKインストール後の初期化画面は以下の通りです.
機能テスト
2つのClientが同じ部屋に入ると、各Clientは2つのCubeをインスタンス化し、1つはネイティブエンティティ(Mine Cube)、1つは相手エンティティ(Clone Cube)となる.
View SYnc
ボタンMoveをクリックすると、ビュー同期でpostionとrotationの同期が行われます.つまり、文章が始まったばかりの動図の展示の様子です.
RPC
Mine Cubeをクリックすると、Cubeの色が変化し、他のマシンに同期します.ここでの色同期はRPCで実現されます.
Custom Event
Clone Cubeをクリックすると、相手エンティティにメッセージが送信され、効果は相手のMine Cube Scaleが増加します.
Road Map
次に、最適化が必要な機能が追加されるか、または追加されることを考慮します.