INetworkSerializableを実装して自作の型を同期可能にする【MLAPI】
MLAPI で同期可能な型
MLAPI でデフォルトで NetworkVariable や RPC で同期可能な型は C# プリミティブ型,Unity プリミティブ型,Enum型です.
C# Primitives | Unity Multiplayer Networking
Unity Primitives | Unity Multiplayer Networking
Enum Types | Unity Multiplayer Networking
上記以外,例えば自作したクラスや構造体をNetworkVariableやRPCで同期させたい場合はどうすればよいでしょうか.
INetworkSerializable
MLAPI v0.1.0 から INetworkSerializable インタフェースが実装されました. このインタフェースを実装すれば,自作の型の同期が出来るようです.
INetworkSerializable | Unity Multiplayer Networking
サンプル
早速やってみましょう.以前私が作ったMLAPI-QuickStartを利用します.
名前がstringになっていますが,FirstName,LastNameを定義した構造体FullNameに変更してみましょう.
using MLAPI.Serialization; namespace MLAPIQuickStart { public struct FullName : INetworkSerializable { public string FirstName => _firstName; public string LastName => _lastName; private string _firstName; private string _lastName; public FullName(string firstName, string lastName) { _firstName = firstName; _lastName = lastName; } public void NetworkSerialize(NetworkSerializer serializer) { serializer.Serialize(ref _firstName); serializer.Serialize(ref _lastName); } } }
作成したので,PlayerScript.cs を変えます.変更した箇所のみ記載.
/// <summary> /// プレイヤー名の同期変数 /// </summary> private readonly NetworkVariable<FullName> _networkPlayerName = new NetworkVariable<FullName> (new NetworkVariableSettings {WritePermission = NetworkVariablePermission.OwnerOnly}); private void Start() { // ローカルプレイヤーの場合,カメラを一人称視点に設定し,プレイヤー名のテキストを画面下に表示する if (IsOwner) { _sceneScript.PlayerScript = this; var thisTransform = transform; // thisTransform.position = new Vector3(Random.Range(-5, 5), 0, Random.Range(-5, 5)); _cameraTransform.transform.SetParent(thisTransform); _cameraTransform.localPosition = new Vector3(0, 0, 0); floatingInfo.transform.localPosition = new Vector3(0, -0.3f, 0.6f); floatingInfo.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); var playerName = new FullName("Player", Random.Range(100, 999).ToString()); var color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)); SubmitPlayerNameServerRpc(playerName); SubmitPlayerColorServerRpc(color); SubmitJoinedMessageServerRpc(); } } /// <summary> /// プレイヤー名を設定する /// </summary> /// <param name="playerName">playerName</param> /// <param name="serverRpcParams">ServerRpcParams</param> [ServerRpc(RequireOwnership = true)] private void SubmitPlayerNameServerRpc(FullName playerName, ServerRpcParams serverRpcParams = default) => _networkPlayerName.Value = playerName; /// <summary> /// 入室時メッセージを表示する /// </summary> /// <param name="serverRpcParams">ServerRpcParams</param> [ServerRpc(RequireOwnership = true)] private void SubmitJoinedMessageServerRpc(ServerRpcParams serverRpcParams = default) { if (_sceneScript != null) { // 一応ここでは LastName のみ表示するようにしてみます _sceneScript.SetMessage($"{_networkPlayerName.Value.LastName} joined"); } }
これで入室してみると以下のようになりました.
ちなみに INetworkSerializable をインタフェースに持たない状態で RPC や NetworkVariable に当てはめようとすると, コンパイル後に以下のエラーが出ます.