Get it on Google Play


Wm뮤 :: 'Unity/Photon' 카테고리의 글 목록

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
퇴직한 전자과 게임프로그래머
2020.3.48f1 , 2022.3.6f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2023. 8. 12. 18:50 Unity/Photon

 

 

 

또 오랫동안 안 쓰니 자꾸 까먹는다

기초를 까먹어서 나중에 찾는데 안 보임 ㅋㅋ;;

 

 

 

Photon Transform View

포톤판 ObjectSync이다

상위에 Photon View 있어야 함

 

'Unity > Photon' 카테고리의 다른 글

자주 쓰는 유니티 포톤챗 코드  (0) 2021.12.14
포톤 오류,에러 모음  (0) 2021.12.08
포톤 친구랑 같이 플레이  (0) 2021.11.24
posted by 모카쨩
2021. 12. 14. 08:40

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2021. 12. 8. 14:36 Unity/Photon

 

 

 

32752 - A server-side plugin (or webhook) failed to execute and reported an error. 
Check the OperationResponse.DebugMessage.

 

웹훅설정해서 그럼

 

 

 

 

 

 

 

 

 

OnJoinRoomFailed에러 모음


    public override void OnJoinRoomFailed(short returnCode, string message)
    {
        switch (returnCode)
        {
            case ErrorCode.GameFull:
                Debug.LogError("풀방임");
                break;
        }
    }

 

 

 

 

 

 

 

----------------------------------------------------------------------------------------------

 

 

NotSupportedException: StartBackgroundCalls() can run a maximum of 255 threads.

포톤챗을 과도하게 연결시도함

SupportClass.StopAllBackgroundCalls()로 기존 연결들을 삭제하면 해결된다

SupportClass.StopAllBackgroundCalls();
chatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, 
PhotonNetwork.AppVersion, new AuthenticationValues(PhotonNetwork.AuthValues.UserId));

 

 

 

 

 

 

 

----------------------------------------------------------------------------------------------

Can not Instantiate before the client joined/created a room.

 

방연결 안 됐는데 네트워크 오브젝트 생성하려고 해서 그럼

PhotonNetwork.InstantiateRoomObject(botPrefab.name, pos, rot);

이거를

if(PhotonNetwork.CurrentRoom != null)
{
	PhotonNetwork.InstantiateRoomObject(botPrefab.name, pos, rot);
}

이렇게 수정해주자

 

 

 

 

----------------------------------------------------------------------------------------------

InvalidCastException: Specified cast is not valid.
PhotonPlayerData.OnPhotonSerializeView (Photon.Pun.PhotonStream stream, Photon.Pun.PhotonMessageInfo info) 

 

 

얼핏 봐서는 캐스트 타입 잘못 지정해서 그런거 같아보이지만 전혀 아니다.

몰론 아~주 가끔 정말로 타입 미스나서 그럴수도 있겠지만

(가끔 구버전이랑 신버전끼리 연결할때도 뜨더라)

 

해결방법 v1

더보기

동일 게임오브젝트에 IPunObservable을 마구 넣은뒤에 인스펙터에서 값 확인하려고 할때 뜬다

해결법은

 

기존

 

병합후

 

IPunObservable 불필요하게 분산시키지 말고 병합시키면 된다

다른 게임오브젝트에 옮기는거도 생각해봤는데 이런경우는 보통 GetComponent로 서로 호출하는게 많아서

서로 연결시키기 귀찮으니 걍 병합함

어차피 GetComponent로 가져오면 되니 수리하는데 드는 작업량도 작다

근데 이렇게 병합하면 아래 오류가 뜰수도 있다

 

v2

v1을 다 써놓고 보니 어 잠깐 IPunObservable가 갱신 안 되어서 발생하는 문제라면 혹시...

예상이 맞았다. 그냥 PhotonView 플래그 문제였다.

개뻘짓함

리셋후 프리팹 저장해줘라

 

 

 

----------------------------------------------------------------------------------------------

Observed scripts have to implement IPunObservable. 

원래 있던 IPunObservable들이 사라져서 생긴거

왜냐하면 쟤내들이 Auto Find All을 할때 플래그를 안 세워서 프리팹에 저장 안 되어있음 (하?)

 

방법은 두가지

첫번째는 매뉴얼 사용이고

 

두번째는 Reset사용이다

후자가 더 편하니 후자를 씀

원리는 당연히 플래그를 강제로 세워서 컴포넌트를 저장시키는것

'Unity > Photon' 카테고리의 다른 글

자주 쓰는 유니티 포톤챗 코드  (0) 2021.12.14
포톤 친구랑 같이 플레이  (0) 2021.11.24
포톤 메신저  (0) 2021.11.15
posted by 모카쨩
2021. 11. 24. 10:53

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2021. 11. 15. 00:30

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2021. 7. 26. 16:23 Unity/Photon

 

여기 있는 코드들은 거의 개인작 할때 만들었던 코드들이다.

전부는 아니였던거 같아서 거의라고 적긴 했는데 기억이 가물해서 전부일수도 있고 한두개 정도는 포톤API 기본예제일수도 있다.

 

 

 

PUN2 콜백 : https://doc-api.photonengine.com/en/pun/v2/class_photon_1_1_pun_1_1_mono_behaviour_pun_callbacks.html#a5c82419bda5edcbc20997573b460b9c2

 

에러코드 : https://doc-api.photonengine.com/en/pun/v1/class_error_code.html

 

 

 

 

연결상태

Debug.Log($"PhotonNetwork.IsConnected: {PhotonNetwork.IsConnected}"); //false
PhotonNetwork.ConnectUsingSettings(); //접속시도
Debug.Log($"PhotonNetwork.IsConnected: {PhotonNetwork.IsConnected}"); //true
//IsConnected는 접속호출 즉시 True가됨

Debug.Log($"PhotonNetwork.IsConnectedAndReady: {PhotonNetwork.IsConnectedAndReady}"); 
//IsConnectedAndReady로 해야 ConnectedToMaster되었는지 체크가능

 

 

 

 

RPC 샘플

    public void SendChatMessage(string message)
    {
        photonView.RPC(nameof(ReceiveChatMessage), RpcTarget.Others, message);
    }

    [PunRPC]
    void ReceiveChatMessage(string message)
    {
        Debug.Log($"{nameof(ReceiveChatMessage)}:{message}");
    }

 

RPC 샘플 (발신자가 오너가 아닐경우, 자신포함 브로드캐스트)

이런경우 어차피 1줄짜리이므로 함수를 분리하기 보단

그냥 SendHealEffect를 칠자리에 RPC코드를 넣는게 낫다 


public void SendHealEffect()
{
    //발신자가 동작할 코드
    photonView.RPC(nameof(ReceiveHealEffect), RpcTarget.All);
}

[PunRPC]
public void ReceiveHealEffect()
{
    if (photonView.IsMine)
    {
        //오너가 동작할 코드
    }
    else
    {
        //오너제외
    }
    //모두가 동작할 코드
}

 

 

RPC샘플 V2


//브로드캐스트 (오너가 모두에게)
[PunRPC]
public void ChatMessage(string message)
{
    if (photonView.IsMine)
    {
        var methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
        photonView.RPC(methodName, RpcTarget.Others, message);
    }
    Debug.Log($"{nameof(ChatMessage)}:{message}");
}
    
    
    
    
    
    
//주인에게 보낼때
[PunRPC]
public void ChatMessage(string message)
{
    if (photonView.IsMine)
    {
        Debug.Log($"{nameof(ChatMessage)}:{message}");
    }
    else
    {
        var methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
        photonView.RPC(methodName, photonView.Controller, message);
    }
}

 

 

 

 

 

RPC샘플 이전버전들

더보기
    
//브로드캐스트(발신자가 오너가 아닐때)
//인자에 기본값이 들어있으므로 그냥 HealEffect(); 치면 된다.
//다만 이건 의미없이 네트워크 송신비용이 발생하므로 V1처럼 가급적 함수를 하나 더 만들자
[PunRPC]
public void HealEffect(bool isSender = true)
{
    if (photonView.IsMine || isSender)
    {
        //오너와 발신자가 작동할 코드
    }
    if (isSender)
    {
        var methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
        photonView.RPC(methodName, photonView.Controller, false);
        //발신자만 작동할 코드
        return;
    }
    if (photonView.IsMine)
    {
        var methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
        photonView.RPC(methodName, RpcTarget.Others, false);
        //오너만 작동할 코드
    }
    //모두가 작동할 코드
}

 

 

 

 

 

RPC 관련 코드

//오너에게 보낼때(Fixed타입이면 오너가 null이므로 주의)
photonView.RPC(nameof(ReceiveChatMessage), photonView.Owner, message); 

//Controller에게 보낼때(Fixed타입일때 실질적 오너)
photonView.RPC(nameof(ReceiveChatMessage), photonView.Controller, message);

 

 

 

 

변수동기화 샘플

using Photon.Pun;

[RequireComponent(typeof(PhotonView))]
public class GameSystem : MonoBehaviourPunCallbacks, IPunObservable
{
    float timer = 200;
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.IsWriting)
        {
            stream.SendNext(timer);
        }
        else
        {
            timer = (float)stream.ReceiveNext();
        }
    }
}


//클래스 교환
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.IsWriting)
        {
            string[] sampleclassJsons = System.Array.ConvertAll(sampleClass,x=> JsonUtility.ToJson(x));
            stream.SendNext(sampleclassJsons);
        }
        else
        {
            string[] sampleclassJsons = (string[])stream.ReceiveNext();
            sampleClass = System.Array.ConvertAll(sampleclassJsons, x => JsonUtility.FromJson<SampleClass>(x));
        }
    }

 

타이머 동기화

[RequireComponent(typeof(PhotonView))]
public class GameSystem : MonoBehaviourPunCallbacks, IPunObservable
{
    System.DateTime startTime = System.DateTime.UtcNow;
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.IsWriting)
        {
            stream.SendNext(startTime.Ticks);
        }
        else
        {
            startTime = new System.DateTime((long)stream.ReceiveNext());
        }
    }
    public void SetTimer()
    {
        timer = oneGameTime - ((System.DateTime.UtcNow.Ticks - startTime.Ticks) / 10000000);
        timer = Mathf.Clamp(0, timer, oneGameTime);
        timerUI.text = timer.ToString();
    }
    static readonly float oneGameTime = 200;
    float timer = oneGameTime;
    public Text timerUI;

 

 

로컬타이머

        if (PhotonNetwork.CurrentRoom == null)
        {
            localTimer = 0;
        }
        else
        {
            localTimer += Time.deltaTime;
        }

 

 

해당 오브젝트의 오너의 닉네임을 불러옴

textUI.text = photonView.Owner.NickName;

 

자신이 마스터인지 체크

public bool CheckRoomMaster()
{
    return (PhotonNetwork.IsMasterClient) || (PhotonNetwork.CurrentRoom == null);
}

 

 

 

닉네임 설정

Photon.Pun.PhotonNetwork.NickName = "Name";

 

타임아웃시간 설정

PhotonNetwork.KeepAliveInBackground = 3;

 

 

PhotonView들이 OnPhotonSerialize를 초당 몇회 호출할지

PhotonNetwork.SerializationRate=10;

 

서버시간

var serverTime = PhotonNetwork.Time;

 

 

 

방을 나가도 파괴 안되는 오브젝트

PhotonNetwork.InstantiateRoomObject(prefab.name, pos, rot, 0);

 

 

 

 

플레이어 관련

//플레이어 리스트
PhotonNetwork.PlayerList

//플레이어 리스트 (자기자신 제외)
PhotonNetwork.PlayerListOthers

//로컬플레이어 (자기자신)
PhotonNetwork.LocalPlayer

//액터넘버(근데 이건 플레이어로 한정되는 고유값이므로 잘 안 쓴다. photonView.ViewID를 쓰자)
PhotonNetwork.LocalPlayer.ActorNumber

//UserId 설정 (연결전에 설정되어야함)
var auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
PhotonNetwork.AuthValues = new Photon.Realtime.AuthenticationValues(auth.CurrentUser.UserId);

//userId to player
var player = System.Array.Find(PhotonNetwork.PlayerList,x=>x.UserId== userId);
if (player == null)
{
    Debug.LogError($"해당 id의 플레이어가 존재하지 않음{userId}");
    return;
}

//userIdList to playerList
var playerList = PhotonNetwork.PlayerList.ToList().FindAll(x=> userIdList.Contains(x.UserId));

 

 

룸관련

//룸옵션
var roomOptions=new Photon.Realtime.RoomOptions();
roomOptions.MaxPlayers = 0;

//방잠그기
PhotonNetwork.CurrentRoom.IsOpen = false;

 

 

 

특정상태의 플레이어 리스트 관리

Ready는 각자호출하고 리스트는 오너가 관리함

이 방식 해보니까 오프라인모드일때나 룸이동시에 처리도 번거롭고 해서 그냥 오브젝트 생성식이 나았다

데이터는 절감될거 같은데 굳~이 따지면 기계어가 낫냐 어셈블리어가 낫냐의 차이이므로 그냥 오브젝트 생성식을 쓴다

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {

        if (stream.IsWriting)
        {
            stream.SendNext(ReadReadyPlayerList().ConvertAll(x=>x.UserId).ToArray());
            
        }
        else
        {
            var userIdList = ((string[])stream.ReceiveNext()).ToList();
            readyPlayerList = PhotonNetwork.PlayerList.ToList().FindAll(x=> userIdList.Contains(x.UserId));
        }

    }


    List<Photon.Realtime.Player> readyPlayerList = new List<Photon.Realtime.Player>();

    void Ready()
    {
        Debug.Log("Ready()");
        photonView.RPC(nameof(AddReadyPlayerList), photonView.Controller, PhotonNetwork.LocalPlayer.UserId);
    }
    void ReadyOff()
    {
        photonView.RPC(nameof(RemoveReadyPlayerList), photonView.Controller, PhotonNetwork.LocalPlayer.UserId);
    }

    [PunRPC]
    void AddReadyPlayerList(string userId)
    {
        Debug.Log("AddReadyPlayerList()");
        var player = System.Array.Find(PhotonNetwork.PlayerList,x=>x.UserId== userId);
        if (player == null)
        {
            Debug.LogError($"해당 id의 플레이어가 존재하지 않음{userId}");
            return;
        }
        if (readyPlayerList.Find(x => x.UserId == userId) == null)
        {
            readyPlayerList.Add(player);
        }
    }

    [PunRPC]
    void RemoveReadyPlayerList(string userId)
    {
        var player = System.Array.Find(PhotonNetwork.PlayerList, x => x.UserId == userId);
        if (player==null)
        {
            Debug.LogError($"해당 id의 플레이어가 존재하지 않음{userId}");
            return;
        }
        readyPlayerList.Remove(player);
    }

    List<Photon.Realtime.Player> ReadReadyPlayerList()
    {
        //오프라인 유저 제거
        readyPlayerList=readyPlayerList.FindAll(x => PhotonNetwork.PlayerList.Contains(x));
        return readyPlayerList;
    }

 

 

 

커스텀서버

var appSettings = new Photon.Realtime.AppSettings();
PhotonNetwork.PhotonServerSettings.AppSettings.CopyTo(appSettings);
appSettings.AppVersion = serverName + appSettings.AppVersion;
PhotonNetwork.ConnectUsingSettings(appSettings, PhotonNetwork.PhotonServerSettings.StartInOfflineMode);

 

 

 

로비분리

Photon.Realtime.TypedLobby lobby;
public override void OnConnectedToMaster()
{
    Debug.Log("ConnectedToMaster");

    lobby = new Photon.Realtime.TypedLobby("loobyNameSample", Photon.Realtime.LobbyType.Default);
    PhotonNetwork.JoinLobby(lobby); //로비접속
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
    Debug.LogError("PhotonRandomJoinFailed");
    PhotonNetwork.CreateRoom(null,null, lobby);
}

 

룸리스트

    List<RoomInfo> roomList= new List<RoomInfo>();
    public override void OnRoomListUpdate(List<RoomInfo> roomList)
    {
        this.roomList.RemoveAll(x=>roomList.FindIndex(y=>y.Name== x.Name)>=0);
        this.roomList.AddRange(roomList);
        this.roomList.RemoveAll(x => x.MaxPlayers == 0 || x.PlayerCount == 0);
        
        textUI.text = string.Join("",roomList.ConvertAll(room => $"{room.Name}:{room.CustomProperties["RoomName"]}"));
    }

 

 

 

연결상태

    [System.Serializable]
    public class BoolEvent : UnityEngine.Events.UnityEvent<bool> { }
    public BoolEvent OnChangedConnectedEvent;
    
    
    public override void OnConnectedToMaster()
    {
        Debug.Log("ConnectedToMaster");
        OnChangedConnectedEvent.Invoke(true);
    }
    public override void OnDisconnected(DisconnectCause cause)
    {
        Debug.Log("OnDisconnected");
        OnChangedConnectedEvent.Invoke(false);
    }

 

 

연결오류 모음

    public override void OnDisconnected(DisconnectCause cause)
    {
        switch (cause)
        {
            case DisconnectCause.None:
                break;
            case DisconnectCause.ExceptionOnConnect:
                break;
            case DisconnectCause.DnsExceptionOnConnect:
                break;
            case DisconnectCause.ServerAddressInvalid:
                break;
            case DisconnectCause.Exception:
                break;
            case DisconnectCause.ServerTimeout:
                break;
            case DisconnectCause.ClientTimeout:
                Debug.LogError($"포톤 서버가 터짐. Dev Region과 Fixed Region을 공백으로 하세요");
                break;
            case DisconnectCause.DisconnectByServerLogic:
                break;
            case DisconnectCause.DisconnectByServerReasonUnknown:
                break;
            case DisconnectCause.InvalidAuthentication:
                break;
            case DisconnectCause.CustomAuthenticationFailed:
                break;
            case DisconnectCause.AuthenticationTicketExpired:
                break;
            case DisconnectCause.MaxCcuReached:
                break;
            case DisconnectCause.InvalidRegion:
                break;
            case DisconnectCause.OperationNotAllowedInCurrentState:
                break;
            case DisconnectCause.DisconnectByClientLogic:
                break;
            case DisconnectCause.DisconnectByOperationLimit:
                break;
            case DisconnectCause.DisconnectByDisconnectMessage:
                break;
            default:
                break;
        }
        Debug.LogError($"{cause}");
    }

 

 

 

 

 

 

 

 

 

 

포톤 프로퍼티


    //생성
    public override void OnJoinRoomFailed(short returnCode, string message)
    {
        Debug.LogWarning("JoinRoomFailed");
        Debug.LogWarning("CreateRoom");
        //PhotonNetwork.CreateRoom(roomName);


        RoomOptions roomOptions = new RoomOptions();
        var hashtable = new ExitGames.Client.Photon.Hashtable();
        hashtable.Add(key:"mapName", value: "testMap"); //mapName 프로퍼티
        hashtable.Add(key: "password", value: "testPW"); //testPW 프로퍼티
        roomOptions.CustomRoomProperties = hashtable;
        roomOptions.CustomRoomPropertiesForLobby = System.Array.ConvertAll(roomOptions.CustomRoomProperties.Keys.ToArray(), x => x.ToString());
        Debug.Log($"Properties : {string.Join(", ", roomOptions.CustomRoomPropertiesForLobby)}");

        TypedLobby sqlLobby = new TypedLobby("myLobby", LobbyType.SqlLobby);
        PhotonNetwork.CreateRoom(null, roomOptions,sqlLobby);
    }
    
    
    //수정
    public override void OnCreatedRoom()
    {
        var hashtable = PhotonNetwork.CurrentRoom.CustomProperties;
        hashtable["mapName"] = "testMap2"; //수정
        Debug.Log($"mapName : {PhotonNetwork.CurrentRoom.CustomProperties["mapName"]}");

        Debug.Log("CreatedRoom");
    }
    
    //접속
    public override void OnConnectedToMaster()
    {
        Debug.Log("ConnectedToMaster");

        TypedLobby sqlLobby = new TypedLobby("myLobby", LobbyType.SqlLobby); 
        string sqlLobbyFilter = "mapName = \"testMap\""; 
        // "C0 = 1"
        // "C0 = 1 AND C2 > 50"
        // "C5 = \"Map2\" AND C2 > 10 AND C2 < 20"
        PhotonNetwork.JoinRandomRoom(null, 2, MatchmakingMode.FillRoom, sqlLobby, sqlLobbyFilter);
        PhotonNetwork.JoinRoom(roomName);
    }

 

 

'Unity > Photon' 카테고리의 다른 글

포톤 메신저  (0) 2021.11.15
포톤 PUN -> PUN2 변경점  (0) 2021.07.10
포톤 보이스  (0) 2021.07.10
posted by 모카쨩
2021. 7. 10. 17:34 Unity/Photon

API들

 

https://doc-api.photonengine.com/en/pun/v2/index.html

 

Photon Unity Networking 2: Main Page

Introduction Photon is a real-time multiplayer game development framework that is fast, lean and flexible. Photon consists of a server and multiple client SDKs for major platforms. Photon Unity Network (PUN) is our is our take on a Unity specific, high-lev

doc-api.photonengine.com

 

 

 



추가해야할것들

 

using Photon.Pun;

 

변경되는 함수

public class PhotonInit : Photon.PunBehaviour 
-> 
public class PhotonInit : MonoBehaviourPunCallbacks 










PhotonNetwork.ConnectUsingSettings(serverName);
PhotonNetwork.ConnectToBestCloudServer(serverName);
->
PhotonNetwork.ConnectUsingSettings();
PhotonNetwork.ConnectToBestCloudServer();






public override void OnPhotonRandomJoinFailed(object[] codeAndMsg)
{
}
    
    ->
public override void OnJoinRandomFailed(short returnCode, string message)
{
}
    
    
    
    
    
    
    
public override void OnPhotonCreateRoomFailed(object[] codeAndMsg)
{
}

->

public override void OnCreateRoomFailed(short returnCode, string message)
{
}





photonView.isMine

->

photonView.IsMine





PhotonTargets.All
->
RpcTarget.All





PhotonNetwork.PhotonServerSettings.ChatAppID
->
Photon.Pun.PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat





public override void OnReceivedRoomListUpdate()
{
    RoomInfo[] rooms = PhotonNetwork.GetRoomList();
}
->
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
}

 

 

 

삭제된 함수

    public override void OnConnectedToPhoton()
    {
    }

 

 

'Unity > Photon' 카테고리의 다른 글

자주 쓰는 유니티 포톤 코드  (0) 2021.07.26
포톤 보이스  (0) 2021.07.10
포톤 챗  (0) 2021.07.07
posted by 모카쨩
2021. 7. 10. 16:17

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.


  • total
  • today
  • yesterday

Recent Post

저사양 유저용 블로그 진입