MonoBehaviourPun 상속
게임 오브젝트 동기화 Photon View
네트워크 생성 및 삭제
원격 함수 호출 RPC
방장 변경 이벤트 처리 (OnMasterClientSwitched)
채팅 기능 구현

MonoBehaviourPun 클래스는 MonoBehaviour를 상속받고 있고
이 게임오브젝트에 있는 PhotonView를 찾고 캐싱해두는 클래스

Photon View는 네트워크에서 동기화가 필요한 오브젝트에 추가하여
오브젝트의 소유권, 상태 동기화, RPC 연결 등의 역할을 하는 컴포넌트
View ID : 서버에서 오브젝트를 식별할 수 있는 고유 ID
IsMine : 해당 Photon View를 내 클라이언트가 소유한 오브젝트인지 여부
Observables : IPunObservable 인터페이스를 구현한 컴포넌트 목록
Observed Components : 동기화할 컴포넌트 리스트
그 외로 UI View들도 있음
Friend List View
Player List View
Room List View
Player Overview Panel
Region List View
Tab View Manager

동기화할 컴포넌트에
IPunObservable인터페이스를 추가 후,OnPhotonSerializeView를 구현해야함
// 게임 오브젝트 위치 동기화
if (stream.IsWriting)
{
stream.SendNext(transform.position);
stream.SendNext(_moveSpeed);
}
else if (stream.IsReading)
{
_networkPosition = (Vector3)stream.ReceiveNext();
_moveSpeed = (float)stream.ReceiveNext();
}
ex) bool, byte, short, int, long, float, double, string, Vector2, Vector3, Quaternion, Player(int PhotonPlayer.ID)
stream.SendNext() 는 값 타입만 전송 가능
stream.ReceiveNext() 데이터를 받을 때는 보낸 순서대로 받고, 형변환을 해야함
stream.IsWriting 은 내가 데이터를 보낼 때
stream.IsReading 은 다른 클라이언트의 데이터를 받을 때
그 외의 데이터는 RPC로 보내야 함
게임 오브젝트는 각 클라이언트마다 메모리 주소가 다르기 때문에 전송할 수 없다.
대신, 모든 클라이언트에서 동일한 값을 가지는ViewID를 전송하여 오브젝트를 식별할 수 있다.
int id = photonView.ViewID;
보내는 쪽에서 객체 대신 ID를 전송하고
PhotonView target = PhotonView.Find(id);
받는 쪽에서 ID로 객체를 찾는 방식이다.

기존의
Instantiate()가 아닌PhotonNetwork.Instantiate()를 사용해야함
PhotonNetwork.Instantiate("프리팹 이름", new Vector3(0, 0, 0), Quaternion.identity);
프리팹 이름은 Resources 폴더에 있는 프리팹 이름을 뜻한다.
룸에 상주하고 있는 오브젝트는
PhotonNetwork.InstantiateRoomObject("프리팹 이름", new Vector3(0, 0, 0), Quaternion.identity);
를 사용하여 인스턴스화해야 한다.
방장 클라이언트에서만 호출할 수 있음
새로 입장한 유저들도 자동으로 인식
룸에 남아 있는 동안 유지됨

PhotonNetwork.Destroy(photonView);
PhotonView 컴포넌트를 기준으로 오브젝트를 파괴하고,
PhotonNetwork.Instantiate() 로 생성된 오브젝트만 파괴할 수 있다.
RPC는 Photon View가 있는 오브젝트에 네트워크를 통해 함수를 실행시킬 수 있는 기능
photonView.RPC("Shoot", RpcTarget.AllBufferedViaServer);
[PunRPC]
public void Shoot(PhotonMessageInfo info)
{
float lag = Mathf.Abs((float)(PhotonNetwork.Time - info.SentServerTime));
Debug.Log($"서버 시간 - 보낸 서버 시간 = {lag}");
GameObject newBullet = Instantiate(_bulletPrefab, _muzzlePoint.position, _muzzlePoint.rotation);
newBullet.GetComponent<Bullet>().ApplyLagCompensation(lag);
}
RPC("함수명", RpcTarget.실행할 대상들, 매개변수~)
실행할 함수는 public 이어야 하며, [PunRPC] 어트리뷰트를 추가해야 함
RpcTarget
| 이름 | 대상 |
|---|---|
| All | 자신 포함 모든 클라이언트에 전송 |
| Others | 자신 제외 모든 클라이언트에 전송 |
| MasterClient | 방장 클라이언트에 전송 |
| AllBuffered | All과 같지만 호출을 누적, 새로 입장한 클라이언트에 순차적 전송 |
| OthersBuffered | Others와 같지만 호출을 누적, 새로 입장한 클라이언트에 순차적 전송 |
| AllViaServer | 자신 포함 모든 클라이언트에게 서버를 경유하여 전송 |
| AllBufferedViaServer | AllViaServer + Buffered |
실행할 함수에 PhotonMessageInfo 매개변수를 추가하여 보낸 플레이어, 보낸 서버 시간 등을 알 수 있음
매개변수는 직렬화 가능한 타입만 보낼 수 있음
쌓인 Buffered 함수들은 PhotonNetwork.RemoveBufferedRPCs(); 로 지울 수 있다.