PUN Classic(PUN1이라고도 불립니다)은 PUN의 첫 버전입니다.         현재는 리팩토링 및 기능 확장에 의해 PUN2로 새롭게 바뀌었습니다.          새 프로젝트에는 PUN2를 이용해 주시고, 기존의 프로젝트도 가능하면 PUN1에서 PUN2로 옮기는 것을 권장합니다.  자세한 내용은: "마이그레이션 노트". PUN Classic은 곧 점검이 시작됩니다.        중요한 버그의 수정과 Unity의 신버전의 지원 등을 예정하고 있습니다. 신기능의 추가는 PUN2에서만 이루어지므로 주의해 주십시오.

RPCs 와 RaiseEvent

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

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

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

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

[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 가 필요 합니다. 호출 예제:

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

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

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

Back To Top

타켓들과 파라미터들

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

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

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

[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" 으로 추가 매개 변수 없이 누군가 쏘는 것을 구현 할 수 있습니다. 누가 쏘았고 무엇이 맞았는지 알게 됩니다.

Back To Top

타켓,버퍼링과 순서

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

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

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

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

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

Back To Top

RPC 이름의 숏컷(Shortcuts)

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

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

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

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

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

Back To Top

RPC의 타이밍과 로딩 레벨

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

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

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

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

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

예제:

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

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

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

Back To Top

RaiseEvent

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

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

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 에서 이것을 구현하여 이벤트들을 제어 합니다:

// 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 를 사용 합니다.

Back To Top

RaiseEventOptions 과 캐싱

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

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

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

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

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

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

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

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

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

기술문서 TOP으로 돌아가기