3-1. 서버, 클라이언트


- MonobehaviourPuncallbacks를 사용하는 경우는, 위 함수들을 필요로 할때(요청을 받을 때), 즉 이벤트를 필요로 할때만
상속 받으면 됨.
- 요청을 할때는 using Photon.Pun; 만 사용 하면 됨.

- CreateRoom함수의 경우 2번째 인자로 방 Option설정가능.

- JoinRandomOrCreateRoom 함수도 존재하며, 비어 있는 방이 없으면 새로 방을 만들어 들어가는 함수.




- OnRoomListUpdate(List roomList)의 roomList 자체가 처음 로비 입장을 제외하고, 그 다음 부턴 변경된 사항들만 전달.
- 로비에서 나가는 경우 모든 방 목록을 초기화당하고 / 다시 로비 입장시 처음에는 모든 방목록을 받는다

- OnMasterClientSwitched함수는 방장이 바뀌면 호출됨.

- PhotonNetwork.Instantiate: Resources 폴더의 프리펩을 생성, object타입의 Data또한 매개변수로 사용 가능.
- photonView.InstantiationData를 통해 생성한 인스턴스에서 Data를 가져올 수 있음.
- 삭제할때는 PhotonNetwork.Destroy를 사용.
3-2. Custom Property


- 룸과 플레이어에 추가적인 정보를 원하는 경우, 커스텀 프로퍼티를 이용해서 구성 가능.
-> ex) Room의 경우, 이름, 최대 참여가능 인원, 현재 참여인원, 공개여부
-> ex) Player의 경우, 닉네임, 아이디, 방장여부 등
- 커스텀 프로퍼티는 추가하고자 하는 정보의 이름과 값을 설정하여 같은 게임을 플레이하는 구성원들에게 정보를 공유하고 동기화 가능.
- ExitGames.Client.Photon.hashTable은 포톤에서 구현한 자료로, c#의 Dictionary와 사용방법 일치.
-> 네트워크 동기화를 위해서 직렬화가 가능한 위의 HashTable 사용이 필요.

- 커스텀 프로퍼티는 위처럼, 확장메서드를 활용하는 것이 추후 활용면에서 편리.
- using을 사용하여 Photonhashtable을 간략히 사용하면 편리.
3-3. Photon View, MonoBehaviourPun

- Photon View: 동기화 해야하는 게임오브젝트를 관리하기 위한 컴포넌트
-> ViewId, 객체의 소유자, 네트워크 변경사항 등을 읽고 쓰기 위한 스크립트를 보유.

- MonoBehaviourPun: Photon View는 게임오브젝트를 동기화 하기 위한 기준이 되며, 보통의 경우 포톤 뷰를 포함하는 게임오브젝트의 스크립트는 포톤 뷰를참조하기 위한 변수를 가진 MonoBehaviourPun클래스를 상속하는 것을 추천.
3-4. IPunObservable
- 그냥 MonoBehaviour를 사용해도 상관 x.



- IPunObservable이 있어야 Photon View에서 Observed Components에 자동으로 동기화 될 스크립트로 구성.
- OnPhotonSerializeView()함수에서 동기화할 변수를 지정 가능.
- 보내고 받을때 꼭 보내는 순서와 개수를 일치시켜줘야함.
- 참조타입은 불가능하고, 값타입 변수만 가능.
-> 참조타입은 어떻게 동기화 할까?
-> PhotonView 변수 사용하면 된다.


- PhotonView를 통해 소유권자는 ID를 보내고, 받는 쪽에선 ID를 통해 참조타입을 가져올 수 있다.
(또 다른 예시)



- viewId가 달린 GameObject의 Id를 넘겨주어서, 그 Id를 찾은후, 넣어주기도 가능.
3-5.함수의 동기화 RPC


- photon ServerSettings에서 Rpc List확인가능.

- 함수의 경우 PunRPC를 통해, 동기화 가능하다.
- PunRPC함수 생성 자체는 MonoBehaviourPun을 상속받은 클래스에서만 가능.
- 호출 조건은 RPC함수가 구현된 클래스가 붙어있는 객체에 Photonview가 있어야함.
-> 호출하는 클래스는 Pun을 굳이 상속받을 필요없이 pun을 상속받은 클래스의 photonview를 가져와 RPC함수호출이 가능**.
-> 또한, 호출하는 클래스는 photonview없어도 Photonview가 달린 클래스를 찾아와 RPc호출 가능.

- 위의 경우 FindObjectOfType으로 예시를 들긴했지만, 원하는 객체의 PHotonview를 참조할 때, 인스펙터창에서 public변수 또는 GetComponent로 참조 가능.


3-6. 지연보상

- 서버에서 RPC를 보낸시간을 현재시간에서 빼서 지연시간을 계산.
- 지연시간 만큼 미리 position을 앞으로 보내고 그자리에서 생성하는 식의 지연보상처리가 가능.

- 물리 지연 처리 방법.
private Vector3 networkPosition;
private float deltaPosition;
private Quaternion networkRotation;
private float deltaRotation;
private void Update()
{
if (photonView.IsMine == false)
{
transform.position = Vector3.MoveTowards(transform.position, networkPosition, deltaPosition * Time.deltaTime * PhotonNetwork.SerializationRate);
transform.rotation = Quaternion.RotateTowards(transform.rotation, networkRotation, deltaRotation * Time.deltaTime * PhotonNetwork.SerializationRate);
}
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
stream.SendNext(transform.position);
stream.SendNext(transform.rotation);
}
else if (stream.IsReading)
{
networkPosition = (Vector3)stream.ReceiveNext();
networkRotation = (Quaternion)stream.ReceiveNext();
deltaPosition = Vector3.Distance(transform.position, networkPosition);
deltaRotation = Quaternion.Angle(transform.rotation, networkRotation);
}
}
- 물리 객체가 아닌 지연 보상은 Transform 컴포넌트를 사용하여 동기화, 이전 시점데이터와 현재 시점의 데이터의 차이에서 계산을 진행하고 조정.
3-7. 마이그레이션, RoomObject


- 마이그레이션: 온라인 멀티플레이어 게임의 개념으로 방장이 연결이 해제되는 경우에도 다른 클라이언트가 호스트 권한을 승계하고 게임을 자연스럽고 끊임없이 전이 하는 기법.
- 마스터 클라이언트가 변경 되며, 기존의 마스터 클라이언트가 생성한 게임 씬에 필요한 게임오브젝트들은 소유자가 사라지면서 같이 사라지게 되는 상황이 있을 수 있음.
- 게임에서 소유자와 무관하게 계속해서 유지되기 원하는 공용으로 사용할 게임오브젝트는 RoomObject로 생성하고, 이는 마스터 클라이언트만 컨트롤 권한을 가지고 동작가능.
-> 마스터클라이언트가 트랜스폼뷰가달린 룸오브젝트를 이동시키면 동기화 됨.
-> is.mine이나, Masterclient 조건 사용시 룸오브젝트 다루기 가능.
-> 마스터 클라이언트가 교체될 경우 권한을 승계하는 방식으로 동작.
3-8. RigidbodyView, TransformView
- 포톤에는 이미 Rigidbody 또는 Transform만 동기화하도록 View를 제공.
- 절대 두가지 View를 동시에 사용 x.
- TransformView는 다른Pc에서 부드러운 이동이 가능하지만,
만약 순간이동 느낌을 원한다면 OnPhotonSerializeView를 통해 위치를 변수로 동기화.
3-9. 서버 세팅

- Photon - PhotonUnityNetworking - Resources - Photon Server Settings.
- Window - PhotonUnityNetworking - HighlightServer Settings.
3-10. PlayerNumbering
using Photon.Pun;
using Photon.Pun.UtilityScripts;
using Photon.Realtime;
public class PlayerInfoDisplay : MonoBehaviour
{
void Start()
{
foreach (Player player in PhotonNetwork.PlayerList)
{
int number = PlayerNumbering.GetPlayerNumber(player);
Debug.Log($"Player {player.NickName} has number {number}");
}
}
}

- PlayerNumbering 스크립트가 존재해야 GetPlayerNumber 제대로 사용가능.
- 없으면, -1만 계속 출력.
- customProperty의 설정도 확인 가능.
- Playerindex 즉 numbering은 그대로 유지.
-> Player0 입장, Player1입장.
-> Player0퇴장해도 Player1의 인덱스는 1로 그대로 유지.
-> 다시 새로운 Player들어오면 0번 입장 받음.