콘텐츠로 이동

Unity Netcode for GameObjects RPC 패턴 완전 가이드

Netcode for GameObjects(NGO)의 RPC(Remote Procedure Call)는 네트워크를 통해 원격 메서드를 호출하는 메커니즘입니다. ServerRpc는 클라이언트에서 서버로, ClientRpc는 서버에서 클라이언트로 메서드를 호출합니다.


using Unity.Netcode;
public class PlayerController : NetworkBehaviour
{
// 클라이언트 → 서버 RPC
[ServerRpc]
public void FireServerRpc(Vector3 position, Vector3 direction)
{
// 서버에서만 실행
SpawnBullet(position, direction);
}
// 서버 → 모든 클라이언트 RPC
[ClientRpc]
public void PlaySoundClientRpc(string soundName)
{
// 모든 클라이언트에서 실행
AudioManager.Play(soundName);
}
void Update()
{
if (!IsOwner) return; // 소유자만 입력 처리
if (Input.GetMouseButtonDown(0))
{
FireServerRpc(transform.position, transform.forward);
}
}
}

명명 규칙: RPC 메서드는 반드시 ServerRpc 또는 ClientRpc로 끝나야 합니다.


기본적으로 ServerRpc는 해당 NetworkObject의 소유자만 호출할 수 있습니다.

// 기본: 소유자만 호출 가능
[ServerRpc]
void DefaultServerRpc() { }
// 누구나 호출 가능 (서버에서 발신자 검증 필요)
[ServerRpc(RequireOwnership = false)]
void OpenDoorServerRpc(ulong requestingClientId)
{
// 서버에서 권한 검증
if (CanOpenDoor(requestingClientId))
OpenDoor();
}

3. RpcParams — 특정 클라이언트 대상

섹션 제목: “3. RpcParams — 특정 클라이언트 대상”
// 특정 클라이언트에게만 RPC 전송
[ClientRpc]
void SendPrivateMessageClientRpc(string message, ClientRpcParams rpcParams = default)
{
// rpcParams에 지정된 클라이언트에서만 실행
UIManager.ShowMessage(message);
}
// 서버에서 특정 클라이언트에게 전송
void SendToSpecificClient(ulong clientId, string message)
{
var clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = new ulong[] { clientId }
}
};
SendPrivateMessageClientRpc(message, clientRpcParams);
}
// 서버에서 소유자에게만 전송
void SendToOwner(string message)
{
var ownerParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = new ulong[] { OwnerClientId }
}
};
SendPrivateMessageClientRpc(message, ownerParams);
}

public class GameEntity : NetworkBehaviour
{
// NetworkVariable: 상태 동기화 (지속적 값)
private NetworkVariable<float> _health = new(100f,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server);
// RPC: 일회성 이벤트
[ClientRpc]
void OnDamagedClientRpc(float damage, Vector3 hitPoint)
{
// 히트 이펙트, 사운드 재생
SpawnHitEffect(hitPoint);
PlayHurtSound();
}
[ServerRpc(RequireOwnership = false)]
void TakeDamageServerRpc(float damage, Vector3 hitPoint,
ServerRpcParams rpcParams = default)
{
// 서버에서 데미지 처리
_health.Value -= damage;
// 모든 클라이언트에 이펙트 요청
OnDamagedClientRpc(damage, hitPoint);
if (_health.Value <= 0)
DieServerRpc();
}
}
NetworkVariableRPC
상태 지속적 동기화일회성 이벤트
새 클라이언트 접속 시 자동 동기화새 클라이언트에 전송 안 됨
변경 시만 전송즉시 전송

// 기본 지원 타입
[ServerRpc]
void ExampleRpc(
int i, float f, bool b, string s, // 기본 타입
Vector3 v3, Quaternion q, // Unity 타입
NetworkObjectReference netRef, // NetworkObject 참조
ulong clientId) // 클라이언트 ID
{ }
// 커스텀 구조체 직렬화
public struct GameAction : INetworkSerializable
{
public int ActionType;
public Vector3 Position;
public ulong TargetId;
public void NetworkSerialize<T>(BufferSerializer<T> serializer)
where T : IReaderWriter
{
serializer.SerializeValue(ref ActionType);
serializer.SerializeValue(ref Position);
serializer.SerializeValue(ref TargetId);
}
}
[ServerRpc]
void ExecuteActionServerRpc(GameAction action) { }

public class ChatManager : NetworkBehaviour
{
public event Action<string, string> OnMessageReceived;
// 클라이언트 → 서버: 메시지 전송 요청
[ServerRpc(RequireOwnership = false)]
public void SendChatServerRpc(string playerName, string message,
ServerRpcParams rpcParams = default)
{
// 서버에서 검증 (도배 방지, 금칙어 필터링)
if (string.IsNullOrWhiteSpace(message)) return;
if (message.Length > 200) message = message[..200];
// 모든 클라이언트에 브로드캐스트
ReceiveChatClientRpc(playerName, message);
}
// 서버 → 모든 클라이언트: 메시지 수신
[ClientRpc]
private void ReceiveChatClientRpc(string playerName, string message)
{
OnMessageReceived?.Invoke(playerName, message);
}
}

// 기본: 신뢰성 있는 순서 보장 전송
[ServerRpc(Delivery = RpcDelivery.Reliable)]
void ReliableRpc() { }
// 빠른 전송 (순서 비보장, 손실 가능)
// 실시간 위치 업데이트에 적합
[ServerRpc(Delivery = RpcDelivery.Unreliable)]
void PositionUpdateRpc(Vector3 pos, Quaternion rot) { }

  • [ServerRpc]: 클라이언트 → 서버, 기본적으로 소유자만 호출
  • [ClientRpc]: 서버 → 클라이언트, ClientRpcParams로 대상 제한 가능
  • RequireOwnership = false: 비소유자도 ServerRpc 호출 가능
  • NetworkVariable = 상태 동기화, RPC = 일회성 이벤트
  • 커스텀 타입은 INetworkSerializable 구현 필요