유니티 Netcode for GameObject, Serialization

NGO 에서는 INetworkSerializable 인터페이스를 network serialization를 위한 유저가 정의한 type을 실행시킬 수 있습니다! 유저가 정의한 type외에도 기본적으로 C#과 Unity Primitive을 지원합니다!

 


C# Primitives

bool, char, sbyte, byte, short, ushort, int, uint, long, ulong, float, double, string타입을 지원합니다.
 
 

Unity Primitives

Color, Color32, Vector2, Vector3, Vector4, Quaternion, Ray, Ray2D을 지원합니다!


유저가 정의한 Type

Enum Types

Arrays 

int[] 같은 배열 형태를 처리하기 위해서는 Unity primitive type이나 Vector3 같이 사용하면 되지만, 

string[]같은 배열 형태를 처리하기 위해서는 구조체나 함수같은 컨테이너가 필요합니다. 그 컨테이너에는 반드시 INetworkSerializable 를 상속받아야 합니다

더보기

[ClientRpc]
void SendMessagesClientRpc(StringContainer[] messages) 

    foreach (var stringContainer in stringContainers)
    {
        Debug.Log($"{stringContainer.SomeText}");
    }
}

public class StringContainer : INetworkSerializable
{
    public string SomeText;
    public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        if (serializer.IsWriter)
        {
            serializer.GetFastBufferWriter().WriteValueSafe(SomeText);
        }
        else
        {
            serializer.GetFastBufferReader().ReadValueSafe(out SomeText);
        }
    }
}

Example: Move

public struct MyMoveStruct : INetworkSerializable
{
    public Vector3 Position;
    public Quaternion Rotation;

    public bool SyncVelocity;
    public Vector3 LinearVelocity;
    public Vector3 AngularVelocity;

    void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        // Position & Rotation
        serializer.SerializeValue(ref Position);
        serializer.SerializeValue(ref Rotation);
        
        // LinearVelocity & AngularVelocity
        serializer.SerializeValue(ref SyncVelocity);
        if (SyncVelocity)
        {
            serializer.SerializeValue(ref LinearVelocity);
            serializer.SerializeValue(ref AngularVelocity);
        }
    }
}

 

 

NetworkObject & NetworkBehaviour

GameObjects, NetworkObjects, NetworkBehaviour은 직렬화될 수 없는 Type입니다, 그레서 기본적으로 RPC나 NetworkVariable을 사용할 순 없습니다!

 

위와 같은 Type을 사용하기 위해선 2가지 Wrapper가 있습니다

NetworkObjectReference

NetworkObjectReferenceNetworkObject를 위해 사용될 수 있으며 NetworkObjects가 미리 Spawn되어 있는 상태에서만 가능합니다!

public class Weapon : NetworkBehaviour
{
    public void ShootTarget(GameObject target)
    {
        var targetObject = target.GetComponent<NetworkObject>();
        ShootTargetServerRpc(targetObject);
    }

    [ServerRpc]
    public void ShootTargetServerRpc(NetworkObjectReference target)
    {
        if (target.TryGet(out NetworkObject targetObject))
        {
            // deal damage or something to target object.
        }
        else
        {
            // Target not found on server, likely because it already has been destroyed/despawned.
        }
    }
}

 

 

위 코드를 더 쉽게 사용하는 방법이 있습니다

public class Weapon : NetworkBehaviour
{
    public void ShootTarget(GameObject target)
    {
        ShootTargetServerRpc(target);
    }

    [ServerRpc]
    public void ShootTargetServerRpc(NetworkObjectReference target)
    {
        NetworkObject targetObject = target;
    }
}

NetworkBehaviourReference

NetworkBehaviourReference 는 NetworkObjectReference 와 비슷하게 작동합니다!

하지만 생성된 NetworkObject에 구체적인 NetworkBehaviour 컴포넌트를 참조하는데 사용됩니다!

public class Health : NetworkBehaviour
{
    public NetworkVariable<int> Health = new NetworkVariable<int>();
}

public class Weapon : NetworkBehaviour
{
    public void ShootTarget(GameObject target)
    {
        var health = target.GetComponent<Health>();
        ShootTargetServerRpc(health, 10);
    }

    [ServerRpc]
    public void ShootTargetServerRpc(NetworkBehaviourReference health, int damage)
    {
        if (health.TryGet(out Health healthComponent))
        {
            healthComponent.Health.Value -= damage;
        }
    }
}