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에는 아래에 설명된 다음과 같은 기능이 있습니다.
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 함수는 오브젝트가 클라이언트에 스폰되거나 클라이언트가 씬에 있는 오브젝트를 위해 서버에 연결될 때 호출됩니다. 이 함수는 서버에서 효과를 억제하거나 클라이언트 측 이벤트를 설정하는 등 클라이언트 또는 서버 중 하나에만 관련된 작업을 수행하는 데 유용합니다.
로컬 클라이언트가 사용 중인 경우 두 함수가 모두 같은 오브젝트에서 호출됩니다.
그 밖에 다음과 같은 콜백이 있습니다.
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
}
}
이런 특성으로 인해 클라이언트 또는 서버가 활성 상태가 아닐 때 함수가 호출될 경우 즉시 결과를 반환합니다. 이 때 컴파일 타임 오류는 발생하지 않지만, 함수가 잘못된 범위로 호출될 경우 경고 로그 메시지가 표시됩니다. ServerCallback 및 ClientCallback 특성은 사용자 코드로 호출이 제어되지 않는 엔진 콜백 함수에 사용할 수 있습니다. 이 두 특성은 경고를 생성하지 않습니다.
커맨드는 클라이언트가 서버에 무언가를 요청하는 방법입니다. 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 호출은 플레이어 오브젝트에서만 호출되지 않고 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();
}
}