Unity Netcode for GameObjects RPC 패턴 완전 가이드
Netcode for GameObjects(NGO)의 RPC(Remote Procedure Call)는 네트워크를 통해 원격 메서드를 호출하는 메커니즘입니다. ServerRpc는 클라이언트에서 서버로, ClientRpc는 서버에서 클라이언트로 메서드를 호출합니다.
1. 기본 RPC 구조
섹션 제목: “1. 기본 RPC 구조”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로 끝나야 합니다.
2. RequireOwnership
섹션 제목: “2. RequireOwnership”기본적으로 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);}4. NetworkVariable vs RPC
섹션 제목: “4. NetworkVariable vs RPC”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(); }}| NetworkVariable | RPC |
|---|---|
| 상태 지속적 동기화 | 일회성 이벤트 |
| 새 클라이언트 접속 시 자동 동기화 | 새 클라이언트에 전송 안 됨 |
| 변경 시만 전송 | 즉시 전송 |
5. 직렬화 가능 타입
섹션 제목: “5. 직렬화 가능 타입”// 기본 지원 타입[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) { }6. 실전 패턴 — 채팅 시스템
섹션 제목: “6. 실전 패턴 — 채팅 시스템”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); }}7. 신뢰성 (Reliability)
섹션 제목: “7. 신뢰성 (Reliability)”// 기본: 신뢰성 있는 순서 보장 전송[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구현 필요