Version: 5.6
NetworkAnimator
NetworkClient

NetworkBehaviour

NetworkBehaviour는 NetworkIdentity 컴포넌트가 있는 오브젝트와 함께 작동하는 특별한 스크립트입니다. 이 스크립트는 Command, ClientRPC, SyncEvent 및 SyncVar 같은 HLAPI 함수를 수행할 수 있습니다.

Unity 네트워크 시스템의 서버 권한이 있는 시스템의 경우, NetworkIdentities가 있는 네트워크로 연결된 오브젝트는 NetworkServer.Spawn()을 사용하여 서버에서 “스폰”되어야 합니다. 그러면 오브젝트가 NetworkInstanceId를 할당 받고 서버에 연결된 클라이언트에서 생성됩니다.

프로퍼티

프로퍼티: 기능:
isLocalPlayer 이 오브젝트가 로컬 클라이언트의 플레이어 오브젝트인 경우 true입니다.
isServer 이 오브젝트가 서버에서 실행 중이고 스폰된 경우 true입니다.
isClient 이 오브젝트가 클라이언트에서 실행 중인 경우 true입니다.
hasAuthority 이 오브젝트가 오브젝트의 권한이 있는 버전인 경우 (서버에 있거나 localPlayerAuthority가 있는 클라이언트에 있는 경우) true입니다.
assetId 오브젝트 NetworkIdentity의 assetId입니다.
netId 오브젝트 NetworkIdentity의 netId입니다.
playerControllerId 오브젝트 NetworkIdentity의 playerControllerId입니다.
connectionToServer 서버로 전송하는 데 사용할 NetworkConnection 오브젝트입니다.
connectionToClient 클라이언트로 전송하는 데 사용할 NetworkConnection 오브젝트입니다.

NetworkBehaviour에는 아래에 설명된 다음과 같은 기능이 있습니다.

  • 동기화된 변수
  • 네트워크 콜백
  • Server 및 Client 함수
  • 커맨드 전송
  • 클라이언트 RPC 호출
  • 네트워크 이벤트

동기화된 변수

NetworkBehaviours의 멤버 변수를 서버에서 클라이언트까지 동기화할 수 있습니다. 이 시스템에서 서버에 권한이 있으므로, 동기화는 서버에서 클라이언트 방향으로만 이루어집니다. 클라이언트 작업 수행 요청은 클라이언트에서 동기화된 변수가 아닌 커맨드를 통해 처리됩니다.

SyncVar 속성은 멤버 변수에 동기화되었다는 태그를 적용하는 데 사용합니다. SyncVar는 기본 타입일 수 있으며, 클래스, 리스트 또는 기타 컬렉션일 수 없습니다.

public class SpaceShip : NetworkBehaviour
{
    [SyncVar]
    public int health;

    [SyncVar]
    public string playerName;
}

SyncVar의 값이 서버에서 변경되면 게임의 모든 준비된 클라이언트로 전송됩니다. 오브젝트가 스폰되면 서버에서 전송된 모든 SyncVar의 최신 상태와 함께 클라이언트에 생성됩니다.

네트워크 콜백

다양한 네트워크 이벤트에 대해 NetworkBehaviour 스크립트에서 호출되는 콜백 함수가 있습니다. 이 함수는 base 클래스의 가상 함수이므로 다음과 같이 사용 코드에서 오버라이드될 수 있습니다.

public class SpaceShip : NetworkBehaviour
{
    public override void OnStartServer()
    {
        // disable client stuff
    }

    public override void OnStartClient()
    {
        // register client events, enable effects
    }
}

OnStartServer 함수는 오브젝트가 서버에서 스폰되거나 서버가 씬에 있는 오브젝트를 위해 시작될 때 호출됩니다. OnStartClient 함수는 오브젝트가 클라이언트에 스폰되거나 클라이언트가 씬에 있는 오브젝트를 위해 서버에 연결될 때 호출됩니다. 이 함수는 서버에서 효과를 억제하거나 클라이언트 측 이벤트를 설정하는 등 클라이언트 또는 서버 중 하나에만 관련된 작업을 수행하는 데 유용합니다.

로컬 클라이언트가 사용 중인 경우 두 함수가 모두 같은 오브젝트에서 호출됩니다.

그 밖에 다음과 같은 콜백이 있습니다.

  • OnSerialize - 서버에서 클라이언트로 전송할 상태를 수집하기 위해 호출합니다.
  • OnDeSerialize - 클라이언트의 오브젝트에 상태를 적용하기 위해 호출합니다.
  • OnNetworkDestroy - 서버가 오브젝트 파괴를 지시한 경우에 클라이언트에서 호출합니다.
  • OnStartLocalPlayer- 로컬 클라이언트전용 플레이어 오브젝트의 클라이언트에서 호출합니다.
  • OnRebuildObservers - 오브젝트의 관찰자 세트가 다시 빌드되는 경우 서버에서 호출합니다.
  • OnSetLocalVisibility - 오브젝트의 가시성이 로컬 클라이언트에서 변경되는 경우 호스트에서 호출합니다.
  • OnCheckObserver- 새 클라이언트의 가시성 상태를 확인하기 위해 서버에서 호출합니다.

Server 및 Client 함수

NetworkBehaviours의 Member 함수를 커스텀 속성으로 태그하여 서버 전용 또는 클라이언트 전용 함수로 지정할 수 있습니다. 다음은 그 예입니다.

using UnityEngine;
using UnityEngine.Networking;

public class SimpleSpaceShip : NetworkBehaviour
{
    int health;

    [Server]
    public void TakeDamage( int amount)
    {
        // will only work on server
        health -= amount;
    }

    [Client]
    void ShowExplosion()
    {
        // will only run on client
    }

    [ClientCallback]
    void Update()
    {
        // engine invoked callback - will only run on client
    }
}

이런 특성으로 인해 클라이언트 또는 서버가 활성 상태가 아닐 때 함수가 호출될 경우 즉시 결과를 반환합니다. 이 때 컴파일 타임 오류는 발생하지 않지만, 함수가 잘못된 범위로 호출될 경우 경고 로그 메시지가 표시됩니다. ServerCallbackClientCallback 특성은 사용자 코드로 호출이 제어되지 않는 엔진 콜백 함수에 사용할 수 있습니다. 이 두 특성은 경고를 생성하지 않습니다.

커맨드 전송

커맨드는 클라이언트가 서버에 무언가를 요청하는 방법입니다. HLAPI가 서버 권한이 있는 시스템이므로, 클라이언트는 커맨드를 통해서만 작업을 수행할 수 있습니다. 커맨드는 커맨드를 보낸 클라이언트에 해당하는 서버의 플레이어 오브젝트에서 실행됩니다. 이 라우팅은 자동으로 수행되므로 클라이언트가 다른 플레이어에 대해 커맨드를 전송하는 것은 불가능합니다.

커맨드는 아래와 같이 “Cmd” 접두사로 시작하고 [Command] 커스텀 특성을 포함해야 합니다.

using UnityEngine;
using UnityEngine.Networking;

public class SpaceShip : NetworkBehaviour
{
    bool alive;
    float thrusting;
    int spin;

    [Command]
    public void CmdThrust(float thrusting, int spin)
    {   
        if (!alive)
        {
            this.thrusting = 0;
            this.spin = 0;
            return;
        }
            
        this.thrusting = thrusting;
        this.spin = spin;
    }

    [ClientCallback]
    void Update()
    {
        int spin = 0;
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            spin += 1;
        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            spin -= 1;
        }
        // this will be called on the server
        CmdThrust(Input.GetAxis("Vertical"), spin);
    }
}

커맨드는 클라이언트에서 해당 함수를 정상적으로 호출하기만 하면 호출됩니다. 하지만 클라이언트에서 실행되는 커맨드 함수가 아닌, 서버의 해당 클라이언트의 플레이어 오브젝트에서 호출됩니다. 따라서 커맨드는 타입세이프하고, 보안 및 플레이어 라우팅을 빌트인하고 있으며, 인수가 함수들을 신속하게 호출하기 위해 효율적인 직렬화 메커니즘을 사용합니다.

클라이언트 RPC 호출

클라이언트 RPC 호출은 서버 오브젝트가 클라이언트 오브젝트에서 모든 것이 수행되도록 하는 방법입니다. 이 방법은 커맨드에서 메시지를 전송하는 방법과 방향이 반대지만, 개념은 같습니다. 하지만 클라이언트 RPC 호출은 플레이어 오브젝트에서만 호출되지 않고 NetworkIdentity 오브젝트에서도 호출될 수 있습니다. 호출은 아래와 같이 “Rpc” 접두사로 시작되고 [ClientRPC] 커스텀 특성을 포함해야 합니다.

using UnityEngine;
using UnityEngine.Networking;

public class SpaceShipRpc : NetworkBehaviour
{
    [ClientRpc]
    public void RpcDoOnClient(int foo)
    {
        Debug.Log("OnClient " + foo);
    }

    [ServerCallback]
    void Update()
    {
        int value = UnityEngine.Random.Range(0,100);
        if (value < 10)
        {
            // this will be invoked on all clients
            RpcDoOnClient(value);
        }
    }
}

네트워크 이벤트

네트워크 이벤트는 클라이언트 RPC 호출과 유사하지만 단순히 클라이언트 오브젝트에서 함수를 호출하는 데 그치지 않고 클라이언트 오브젝트에서 이벤트를 트리거합니다. 그러면 이벤트에 대해 등록된 기타 스크립트가 서버의 인수와 함께 호출되므로, 클라이언트에서 네트워크로 연결된 스크립트 간 상호작용이 가능합니다. 이벤트는 “Event” 접두사로 시작하고 SyncEvent 커스텀 특성을 포함해야 합니다.

이벤트를 사용하여 다른 스크립트를 통해 확장할 수 있는 강력한 네트워크 게임 시스템을 빌드할 수 있습니다. 다음 예에는 클라이언트의 효과 스크립트가 서버에서 combat 스크립트를 통해 생성된 이벤트에 응답할 수 있는 방법이 나와 있습니다.

using UnityEngine;
using UnityEngine.Networking;

// Server script
public class MyCombat : NetworkBehaviour
{
    public delegate void TakeDamageDelegate(int amount);
    public delegate void DieDelegate();
    public delegate void RespawnDelegate();
    
    float deathTimer;
    bool alive;
    int health;

    [SyncEvent(channel=1)]
    public event TakeDamageDelegate EventTakeDamage;
    
    [SyncEvent]
    public event DieDelegate EventDie;
    
    [SyncEvent]
    public event RespawnDelegate EventRespawn;

    [Server]
    void EventTakeDamage(int amount)
    {
        if (!alive)
            return;
            
        if (health > amount) {
            health -= amount;
        }
        else
        {
            health = 0;
            alive = false;
            // send die event to all clients
            EventDie();
            deathTimer = Time.time + 5.0f;
        }
    }

    [ServerCallback]
    void Update()
    {
        if (!alive)
        {
            if (Time.time > deathTimer)
            {
                Respawn();
            }
            return;
        }
    }

    [Server]
    void Respawn()
    {
        alive = true;
        // send respawn event to all clients
        EventRespawn();
    }
}

힌트

  • 네트워크 이벤트는 커맨드와 ClientRpc 호출을 제공하는 베이스 클래스입니다.
NetworkAnimator
NetworkClient