Unity 6000.0.51f 환경에서 진행했고 멀티를 테스트할 수 있는 에셋은 ParrelSync를 사용했습니다.
RPC
RPC(Remote Procedure Call)는 서로 물리적으로 떨어져 있는 두 컴퓨터가 있을 때 한 컴퓨터가 다른 컴퓨터의 프로시저를 호출하는 기능을 말합니다.
모든 RPC는 NetworkBehaivour를 상속받아야 사용할 수 있습니다.
ServerRpc
ServerRpc는 클라이언트가 서버의 함수를 실행시키기 위한 속성입니다.
클라이언트가 ServerRpc 속성이 붙어 있는 함수를 실행시키면 서버에 ServerRpc 속성이 붙어 있는 이 함수를 실행하라고 요청합니다.
그러면 서버는 요청을 받고 해당 함수를 실행하게 됩니다.
간단한 예시를 통해 어떤 결과가 나오는 지 직접 확인해 보겠습니다.
public class RpcTest : NetworkBehaviour
{
private void Update()
{
if (IsOwner && Input.GetKeyDown(KeyCode.Space))
{
Server_Rpc("ServerRPC");
}
}
[ServerRpc]
private void Server_Rpc(string message, NetworkConnection conn = null)
{
Debug.Log($"{message} : {conn}");
}
}
우선 NetworkBehaviour를 상속받아야 합니다.
그리고 반환 값이 있으면 안 되며 클라이언트가 해당 오브젝트의 Owner를 가지고 있어야 합니다.
Update 에선 Owner 인지 확인하고 스페이스바를 누르면 Server_Rpc가 실행되게끔 했습니다.
Server_Rpc 함수에선 ServerRpc 속성을 사용하고 매개변수로 string를 받았는데 여러 개도 받을 수 있습니다.
그리고 NetworkConnection은 서버에 함수 실행 요청을 하면 요청한 클라이언트의 정보가 담기게 됩니다.
기본 값을 null로 해둔 이유는 자동으로 클라이언트의 정보를 할당해 주기 때문입니다.
클라이언트에서 위 스크립트를 실행하고 스페이스바를 누르면 위 사진처럼 서버에서 Server_Rpc 함수가 실행되는 걸 볼 수 있습니다.
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Server_Rpc("ServerRPC");
}
}
[ServerRpc(RequireOwnership = false)]
private void Server_Rpc(string message, NetworkConnection conn = null)
{
Debug.Log($"{message} : {conn}");
}
RequireOwnership 여부에 따라 Owner 없이 ServerRpc를 실행할 수 있습니다.
다만, Owner가 없을 때 예를 들어 n개 클라이언트 중 누군가 위 스크립트 기준으로 스페이스바를 누르면 서버에서 Server_Rpc 함수가 n번 실행되게 됩니다.
ObserversRpc
ObserversRpc는 서버가 모든 클라이언트들의 함수를 실행시키기 위한 속성입니다.
public class RpcTest : NetworkBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && IsOwner)
{
Server_Rpc("ObserverRPC");
}
}
[ServerRpc]
private void Server_Rpc(string message)
{
Observer_Rpc(message);
}
[ObserversRpc]
private void Observer_Rpc(string message)
{
Debug.Log($"{message}");
}
}
위 RpcTest 스크립트를 Player 오브젝트에 넣고 스페이스바를 눌렀을 때 결과입니다.
코드를 보면 ServerRpc를 먼저 실행하고 ObserversRpc를 실행했습니다.
그 결과 모든 클라이언트들의 ObserversRpc가 실행되는 걸 볼 수 있습니다.
ServerRpc를 거치는 이유는 아까 ObserversRpc는 서버에서 실행된다고 했습니다.
근데 ServerRpc를 없애고 그냥 ObserversRpc만 실행하면?
호스트가 아닌 클라이언트에선 ObserversRpc가 실행이 안됩니다.
호스트가 아닌 클라이언트는 그냥 서버에 연결되어 있을 뿐 서버 그 자체는 아니기 때문입니다.
저는 ObserversRpc가 MMORPG 에서 확성기랑 비슷하다는 느낌을 받았습니다.
public class RpcTest : NetworkBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && IsOwner)
{
Observer_Rpc("ObserverRPC");
}
}
[ObserversRpc]
private void Observer_Rpc(string message)
{
Debug.Log($"{message}");
}
}
ObserversRpc를 직접 썼을 때 또 다른 기능이 생깁니다.
호스트에서 ObserversRpc를 쓰면 모든 클라이언트에서 ObserversRpc가 실행되고 호스트가 아닌 클라이언트에서 실행하면 실행이 안됩니다.
이를 잘 활용하면 호스트가 공지사항? 같은 거 유저 전체에게 뿌릴 때 사용할 수도 있겠네요.
근데 왜 이름이 ClinetsRpc가 아니라 ObserversRpc일까요?
Unity Fishnet[3] Observer
Unity 6000.0.51f 환경에서 진행했고 멀티를 테스트할 수 있는 에셋은 ParrelSync를 사용했습니다.ObserverObserver는 특정 조건 (오브젝트 거리, 같은 씬에 있는지, owner 인지 등)에 만족해야 네트워크 오브
gamecoke.tistory.com
일단 Observer가 무엇인지 알아야 합니다.
위 사진을 보면 이해가 될 텐데 내가 소유한 네트워크 오브젝트가 관찰하고 있는 네트워크 오브젝트들에게만 ObserversRpc 함수가 실행됩니다.
만약 관찰이 안된다면 서버는 관찰이 안 되는 오브젝트에겐 ObserversRpc 함수 실행을 안 시켜줍니다.
호스트만 다른 클라이언트가 보이는 이유는 서버는 모든 클라이언트에 대한 정보를 항상 가지고 있어야 하기 때문입니다.
이에 대한 정보는 위에 Observer 페이지를 참고해 주세요.
TargetRpc
public class RpcTest : NetworkBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && IsOwner)
{
Target_Rpc(base.Owner, "TargetRpc");
}
}
[TargetRpc]
private void Target_Rpc(NetworkConnection conn, string message)
{
Debug.Log($"Connection: {conn}, message: {message}");
}
}
가장 간단한 Rpc로 서버에서 특정 클라이언트에게만 TargetRpc 함수를 실행하라고 신호를 보냅니다.
부가 옵션
Multi-Purpose Rpc
[ObserversRpc][TargetRpc]
private void DisplayChat(NetworkConnection target, string sender, string message)
{
Debug.Log($"{sender}: {message}.");
}
[Server]
private void SendChatMessage()
{
//Owner에게만 메세지 전송
DisplayChat(base.Owner, "Bob", "Hello world");
//모든 클라이언트에게 메시지 전송
DisplayChat(null, "Bob", "Hello world");
}
Rpc를 중첩시키는 기능입니다.
중첩시켜 놓으면 마치 오버로딩된 함수처럼 작동하게 됩니다.
Channels
private bool _reliable;
private void FixedUpdate()
{
_reliable = !_reliable;
Channel channel = (_reliable) ? Channel.Reliable : Channel.Unreliable;
RpcTest("Anything", channel);
}
/* 어떤 Rpc든지 사용이 가능합니다.
* 기본 값은 Reliable 이기 때문에,
* 굳이 매개변수에 추가 안 해도 됩니다. */
[ServerRpc]
private void RpcTest(string txt, Channel channel = Channel.Reliable)
{
if (channel == Channel.Reliable)
Debug.Log("Message received! I never doubted you.");
else if (channel == Channel.Unreliable)
Debug.Log($"Glad you got here, I wasn't sure you'd make it.");
}
모든 Rpc에서 사용 가능합니다.
Channels는 Reliable, Unreliable로 나뉩니다.
Reliable은 데이터를 신뢰하고 Unreliable은 데이터를 신뢰하지 않습니다.
그래서 Unreliable은 데이터를 잃을 수도 있지만 속도가 빠르고
Reliable은 속도가 느린 대신 도착 보장이 됩니다.
공식 문서에 자세히 안 나와 있는 거 같아서 코드 까보니까 TCP, UDP 개념이 맞는 거 같습니다.
RunLocally
[ServerRpc(RunLocally = true)]
private void RpcTest()
{
Debug.Log("Rpc Test!");
}
모든 Rpc에서 사용가능한 기능입니다.
ServerRpc에서 실행하면 서버와 클라이언트 모두 실행되고 ObserversRpc에서 실행하면 관찰된 오브젝트와 서버 모두 실행됩니다.
TargetRpc 마찬가지로 특정 클라이언트와 서버에서 함수가 실행됩니다.
DataLength
[ServerRpc(DataLength = 3500)]
private void ServerSendBytes(byte[] data) {}
모든 Rpc에서 사용 가능한 기능입니다.
교환하려는 데이터 크기의 최댓값을 정합니다.
만약 최대값을 넘어서면 크기 조정이 발생하기 때문에 가비지 컬렉션이 실행됩니다.
'유니티 > Tutorial' 카테고리의 다른 글
Unity Fishnet[3] Observer (0) | 2025.07.21 |
---|---|
Unity Fishnet[2] Ownership과 Player Move (2) | 2025.07.08 |
Unity Fishnet[1] 네트워크 연결 및 플레이어 스폰 (2) | 2025.06.30 |
Unity Fishnet[0] 소개 및 설치 (0) | 2025.06.24 |
Unity 디자인 패턴 Command (2) | 2025.05.28 |