This document is about: PUN 1
SWITCH TO

PUN Classic (v1), PUN 2, Bolt는 휴업 모드입니다. Unity2022에 대해서는 PUN 2에서 서포트하지만, 신기능의 추가는 없습니다. 현재 이용중인 고객님의 PUN 및 Bolt 프로젝트는 중단되지 않고, 퍼포먼스나 성능이 떨어지는 일도 없습니다. 앞으로의 새로운 프로젝트에는 Photon Fusion 또는 Quantum을 사용해 주십시오.

RPCs 와 RaiseEvent

다른 Photon 패키지를 제외하고 PUN의 특징 중 하나는 Remote Procedure Calls (RPCs)를 지원한다는 것 입니다.

원격 프로시져 호출(Remote Procedure Calls)

원격 프로시져 호출은 이름대로 (같은 룸에 있는)원격 클라이언트에 있는 메소드를 호출 하는 것 입니다.

메소드에 대해서 원격 호출을 사용하려면 [PunRPC] 속성을 적용 해야 합니다.

Unknown

[PunRPC]
void ChatMessage(string a, string b)
{
    Debug.Log("ChatMessage " + a + " " + b);
}
Unity 5.1에서는 RPC 특성을 구식으로 취급하고 있기 때문에 나중에 삭제 될 것이 분명합니다. 따라서 PUN v1.56 과 새로운 버전에서는 `PunRPC`라는 다른 속성을 사용하고 있습니다. RPC와 "Remote Procedure Call" 다른 모든 사용에는 영향을 주지 않습니다.
RPC로 표기된 함수를 호출 하기 위해서 `PhotonView` 가 필요 합니다. 호출 예제:

Unknown

PhotonView photonView = PhotonView.Get(this);
photonView.RPC("ChatMessage", PhotonTargets.All, "jup", "and jup!");

프로 팁:스크립트가 Photon.MonoBehaviour 또는 Photon.PunBehaviour 에서 상속을 받은 것이라면(is a) this.photonView.RPC() 를 사용 할 수 있습니다.

그래서 호출하려는 메소드를 직접 호출하는 것 대신에 PhotonView 의 RPC() 에 호출 하려는 메소드 이름을 제공하여 호출 합니다.

타켓들과 파라미터들

PhotonView는 RPC 의 "타켓"과 같습니다: 모든 클라이언트들은 특정 PhotonView 가 있는 네트워크 게임오브젝트의 메소드만을 실행 합니다. 만약 특정 객체를 때렸다고 하면 "ApplyDamage" RPC 를 호출하여 수신 클라이언트가 동일한 객체에 피해를 적용시킬 것입니다!

복수개의 파라미터를 추가 할 수 있습니다(PUN 이 복수개 파라미터를 처리하기 위하여 직렬화를 제공합니다). 복수개의 파라미터를 추가 했을 때 메소드와 호출은 동일한 파라미터를 가지고 있어야 합니다. 만약 수신 클라이언트가 일치하는 메소드를 찾지 못하면 에러가 기록 됩니다.

이 규칙에 대해 한가지의 예외 사항이 있습니다: RPC 메소드의 마지막 파라미터는 PhotonMessageInfo 타입이 될 수 있는데 개별 호출에 대한 컨텍스트(context)를 제공 할 것입니다. 호출할 때 PhotonMessageInfo 를 설정하지 않습니다.

Unknown

[PunRPC]
void ChatMessage(string a, string b, `PhotonMessageInfo` info)
{
    // the photonView.RPC() call is the same as without the info parameter.
    // the info.sender is the player who called the RPC.
    Debug.Log(String.Format("Info: {0} {1} {2}", info.sender, info.photonView, info.timestamp));
}

PhotonMessageInfo의 sender 와 PhotonView의 "targetting" 으로 추가 매개 변수 없이 누군가 쏘는 것을 구현 할 수 있습니다. 누가 쏘았고 무엇이 맞았는지 알게 됩니다.

타켓,버퍼링과 순서

어떤 클라이언트가 RPC 를 실행할지 정의 할 수 있습니다. PhotonTargets 의 값을 사용하여 RPC를 실행할 클라이언트를 정의 합니다. 대부분의 경우에 모두 로 설정하여 모든 클라이언트가 RPC 호출할 수 있도록 합니다. 때로는 Others 로 일부분만 할 수 있도록 정의 하기도 합니다.

PhotonTargets은 Buffered 로 끝나는 몇 개의 값이 있습니다. 서버는 이러한 RPC들을 기억하고 있으며 새로운 플레이어가 참여했을 때 이전에 발생했던 것 까지 포함하여 RPC 를 얻습니다. 이러한 것을 사용할 때는 긴 버퍼 때문에 참여시간이 느려질 수 있다는 것에 주의 하시기 바랍니다.

PhotonTargets는 ViaServer 로 끝나는 값이 있습니다. 일반적으로 전송 클라이언트가 RPC를 실행해야만 할 때 서버로 RPC 전송 없이 즉시 실행 합니다. 이렇게 하면 로컬에서 메소드를 호출 할 때 지연이 없기 때문에 이벤트의 순서에 영향이 있습니다!

ViaServer 는 "모두" 숏컷을 사용할 수 없도록 합니다. RPC가 순서대로 실행되어야 할 때 매우 흥미로운 것입니다:RPC는 서버를 통하여 전송되고 모든 수신 클라이언트에 의해서 동일 순서로 실행됩니다. 순서는 서버에 도착하는 순서 입니다.

예제:레이싱 게임에서 "finished"를 AllViaServer로서 전송 할 수 있습니다. 첫번째 "완주" RPC 호출은 누가 이겼는지 알려 줍니다. 이후의 "완주" 호출은 누가 몇위인지 알려줄 것입니다.

RPC 이름의 숏컷(Shortcuts)

문자열은 네트워크를 통한 전송에서 가장 비효율적이기 때문에 PUN 은 문자열을 줄여서 전송하는 트릭을 사용 합니다. PUN은 에디터에 있는 RPC를 감지하고 목록을 컴파일 합니다. 각 메소드 이름은 리스트를 통해 ID 를 얻고 RPC 를 이름으로 호출 할 때 PUN 은 아무도 모르게 ID를 보낼 것 입니다.

짧게 전송하는 것 때문에 게임의 다른 빌드들은 RPC에 대해서 동일한 ID 를 사용할 수 없습니다. 이것이 문제가 된다면 숏컷을 사용할 수 없게 설정 할 수 있습니다. 동일 빌드의 클라이언트 경우에는 문제가 되지 않습니다.

RPC 목록은 PhotonServerSettings 를 통해서 저장되고 관리됩니다.

RPC 호출이 프로젝트의 다른 빌드로 인하여 이상이 발생하게되면 RPC 목록을 검토 하세요. Get HashCode 버튼은 해시코드를 계산하여 프로젝트 폴더를 쉽게 비교 할 수 있습니다.

필요하다면 리스트를 클리어(clear)할 수 있으며(Clear RPCs 버튼) Refresh RPC List 버튼을 클릭하여 리스트를 갱신할 수 있습니다.

RPC의 타이밍과 로딩 레벨

RPC는 특정 PhotonViews에서 호출 되며 수신측에서 매칭되는 하나의 클라이언트가 목표 지점 입니다. 만약 원격 클라이언트가 로드되지 않았거나 아직 매칭되는 PhotonView 생성을 하지 못했으면 RPC 는 손실 됩니다!

이 때문에 RPC 손실에 대한 전형적인 원인은 클라이언트가 새로운 신(scene)을 로드 할 때 입니다. 하나의 클라이언트는 새로운 게임오브젝트들과 함께 신을 로드 했으나 다른 클라이언트들이 신을 로드 하지 못했다면 이 클라이언트들은 RPC를 알 수가 없습니다(동일 신을 로드 하기 전까지)

PUN은 이것을 관리 할 수 있습니다. 접속 전에 PhotonNetwork.automaticallySyncScene = true 로 설정하고 룸의 마스터 클라이언트에게 PhotonNetwork.LoadLevel() 를 사용하시면 됩니다. 이 방식으로 하나의 클라이언트가 룸내의 모든 클라이언트들이 로드해야할 레벨을 정의합니다.

RPC 손실을 방지 하기 위해서 클라이언트는 수신 되는 메시지 처리를 멈출 수 있습니다(LoadLevel이 해줍니다).

RPC의 전송 실패를 방지하기 위해 클라이언트가 보내 오는 RPC의 실행을 중지 할 수 있습니다 (즉 LoadLevel이 할 것입니다). 신을 로드 하라는 RPC 요청을 받았을 때 내용이 모두 초기화 되기 전까지 즉시 isMessageQueueRunning = false 를 설정 합니다.

예제:

C#

private IEnumerator MoveToGameScene()
{
    // Temporary disable processing of futher network messages
    PhotonNetwork.isMessageQueueRunning = false;
    Application.LoadLevel(levelName);
}

메시지 큐를 사용하지 않도록 설정 해놓으면 큐가 잠금 해제 될 때까지는 메시지의 송수신이 지연 될 것입니다.

다음의 단계로 진행 할 때 큐를 잠금 해제하는 것은 매우 중요합니다.

RaiseEvent

일부 경우에서 RPC가 원하는 기능이 아닐 수 도 있습니다. RPC는 PhotonView와 호출할 메소드가 필요 합니다 .

PhotonNetwork.RaiseEvent 로 자신만의 이벤트를 구성할 수 있으며 네트워크 객체에 관계 없이 이벤트들을 전송할 수 있습니다. 코드와 내용을 구성하여 전송 합니다:

Unknown

byte evCode = 0;    // my event 0. could be used as "group units"
byte[] content = new byte[] { 1, 2, 5, 10 };    // e.g. selected unity 1,2,5 and 10
bool reliable = true;
PhotonNetwork.RaiseEvent(evCode, content, reliable, null);

컨텐츠는 PUN이 직렬화(serialization)할 수 있는 모든 것이 될 수 있습니다. object[] 와 선택된 유닛을 혼합하여 사용할 수 있습니다.

이벤트를 받기 위해서 , 스크립트는 EventCallback를 구현하고 등록해야 합니다. PUN은 성능 때문에 일반적인 콜백을 사용하지 않습니다. MonoBehaviour 에서 이것을 구현하여 이벤트들을 제어 합니다:

Unknown

// setup our OnEvent as callback:
void Awake()
{
    PhotonNetwork.OnEventCall += this.OnEvent;
}

// handle events:
private void OnEvent(byte eventcode, object content, int senderid)
{
    if (eventcode == 0)
    {
        PhotonPlayer sender = PhotonPlayer.Find(senderid);  // who sent this?
        byte[] selected = (byte[])content;
        foreach (byte unitId in selected)
        {
            // do something
        }
    }
}

예제 코드는 유용하지는 않지만 아이디어를 얻을 수 있습니다. 이벤트 코드들을 구성할 수 있고 다른 컨텐츠에 다른 방식으로 사용할 수 있습니다.

기본적으로 PUN은 모든 통신에서 꽤 많이 RaiseEvent 를 사용 합니다.

RaiseEventOptions 과 캐싱

RaiseEventOptions 파라미터로 만약 버퍼링 되어 있으면 이벤트를 받을 클라이언트를 정의 할 수 있습니다.

가장 흥미로운 옵션은 아마도 이벤트 캐시/버퍼링 일 것입니다. PUN은 인스턴스 생성에서 사용하며 새로운 플레이어(참여하는)가 룸에서 발생했던 이벤트를 받아야 할 때 유용 합니다.

RaiseEventOptions.EventCaching 은 3가지의 중요한 옵션이 있습니다: AddToRoomCache, AddToRoomCacheGlobalRemoveFromRoomCache 입니다. 이 옵션들은 이벤트에 해시테이블을 전송할 때 가장 잘 동작 합니다.

EventCaching.AddToRoomCache 로 RaiseEvent 가 발생되면 이 이벤트는 서버의 캐시에 놓여지게 됩니다. 이 의미는 나중에 참여하는 모든 플레이어가 이 이벤트를 받는 다는것 입니다. 새로운 플레이어는 캐시된 이벤트들을 서버에 도착한 순서대로 받습니다.

플레이어가 떠날 때 캐시된 이벤트들은 자동적으로 캐시에서 제거 됩니다. 특정 이벤트에 대해서 캐시에서 제거되는 것을 방지 하기 위해서는 EventCaching.AddToRoomCacheGlobal 로 RaiseEvent를 호출 하세요. 이렇게 하면 이벤트는 "룸의 이벤트 캐시"로 들어가게 됩니다.

캐시에 굉장히 많은 이벤트를 넣었다면 새로운 플레이어는 룸에 들어가 참여 했을 때 매우 많은 메시지들을 받게 될 것 입니다. 매우 많은 이벤트가 있기 때문에 시간이 걸릴 수 있으니 더이상 필요하지 않은 이벤트들은 EventCaching.RemoveFromRoomCache 를 통해서 제거 해야 합니다.

RemoveFromRoomCache 를 사용할 때 RaiseEvent 의 EventCode는 필터로서 사용 될 것 입니다. 따라서 몇개의 이벤트를 설정 하는 대신 이것의 모든 인스턴스를 제거 할 수 있습니다.

좀 더 세밀한 제어를 하기 위해서 이벤트의 컨텐츠는 필터링에 사용 될 수 있습니다. 이렇게 하려면 해시테이블을 컨텐츠 타입으로 사용 해야 합니다. 특정한 이벤트의 식별을 위해서 키/값의 쌍으로 설정 할 수 있으며 RemoveFromRoomCache 로 RaiseEvent 시에 컨텐츠 필터내에 키/값 쌍을 가진 것만을 갖게 됩니다.

이러한 방식으로 개별 이벤트들, 특정 객체에 속한 이벤트들 , 턴 등 무엇 이든지 식별할 수 있습니다.

Back to top