Photon PUN2 + Chat + Voice2 (APK)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Version : Unity 2021.3.5f1
Version : Unity 2021.3.5f1
Version : Unity 2021.3.5f1

Photon Chat은 PUN2 에 포함되어 있다.

처음 접속을 하면 로비로 이동하여 Room목록을 확인

Room에 접속하면 자동으로 채팅 및 음성이 연결되는 구조

포톤 기능 RND 목적으로 간단하게 만든 앱이라서 발생할 수 있는 모든 문제를 해결하지 않음

(예를 들어 채팅중 네트워크 오류, 입장 불가 등… )

무료 라이센스라서 20명 이상 동시 접속 시 터질 수 있음

Photon PUN2 + Chat

APP.CS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
using Newtonsoft.Json;
namespace Com.Lycos7560
{
public struct PlayerData
{
public string NickName;
public string UserGuid;
public PlayerData(string _nicknName, string _userGuid = null)
{
NickName = _nicknName;
UserGuid = _userGuid;
}
}
public class APP : SingletonMonobehaviour<APP>
{
protected override void Awake()
{
base.Awake();
if (CheckPlayerData()) {
PlayerPrefs.DeleteAll();
LoadPlayerNickName();
}
else {
PlayerPrefs.DeleteAll();
PlayerPrefs.SetString("NickName", string.Empty);
PlayerPrefs.SetString("UserGuid", Guid.NewGuid().ToString());
SavePlayerNickName();
}
}
// 로컬에 데이터가 존재하는지 확인
private bool CheckPlayerData()
{
bool exists = File.Exists(Application.persistentDataPath + "/PlayerInfo.json");
if (exists) Debug.Log("Existing User");
else Debug.Log("NewUser");
return exists;
}
// 플레이어의 정보를 로컬에 저장
public void SavePlayerNickName()
{
PlayerData _PlayerData = new (PlayerPrefs.GetString("NickName"), PlayerPrefs.GetString("UserGuid"));
var json = JsonConvert.SerializeObject(_PlayerData);
File.WriteAllText(Application.persistentDataPath + "/PlayerInfo.json", json);
}
// 로컬에 저장된 플레이어의 정보를 불러온다.
public void LoadPlayerNickName()
{
var _Json = File.ReadAllText(Application.persistentDataPath + "/PlayerInfo.json");
var _Info = JsonConvert.DeserializeObject<PlayerData>(_Json);
PlayerPrefs.SetString("NickName", _Info.NickName);
PlayerPrefs.SetString("UserGuid", _Info.UserGuid);
}
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.IO; using Newtonsoft.Json; namespace Com.Lycos7560 { public struct PlayerData { public string NickName; public string UserGuid; public PlayerData(string _nicknName, string _userGuid = null) { NickName = _nicknName; UserGuid = _userGuid; } } public class APP : SingletonMonobehaviour<APP> { protected override void Awake() { base.Awake(); if (CheckPlayerData()) { PlayerPrefs.DeleteAll(); LoadPlayerNickName(); } else { PlayerPrefs.DeleteAll(); PlayerPrefs.SetString("NickName", string.Empty); PlayerPrefs.SetString("UserGuid", Guid.NewGuid().ToString()); SavePlayerNickName(); } } // 로컬에 데이터가 존재하는지 확인 private bool CheckPlayerData() { bool exists = File.Exists(Application.persistentDataPath + "/PlayerInfo.json"); if (exists) Debug.Log("Existing User"); else Debug.Log("NewUser"); return exists; } // 플레이어의 정보를 로컬에 저장 public void SavePlayerNickName() { PlayerData _PlayerData = new (PlayerPrefs.GetString("NickName"), PlayerPrefs.GetString("UserGuid")); var json = JsonConvert.SerializeObject(_PlayerData); File.WriteAllText(Application.persistentDataPath + "/PlayerInfo.json", json); } // 로컬에 저장된 플레이어의 정보를 불러온다. public void LoadPlayerNickName() { var _Json = File.ReadAllText(Application.persistentDataPath + "/PlayerInfo.json"); var _Info = JsonConvert.DeserializeObject<PlayerData>(_Json); PlayerPrefs.SetString("NickName", _Info.NickName); PlayerPrefs.SetString("UserGuid", _Info.UserGuid); } } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
using Newtonsoft.Json;


namespace Com.Lycos7560
{
    public struct PlayerData
    {
        public string NickName;
        public string UserGuid;
        public PlayerData(string _nicknName, string _userGuid = null)
        {
            NickName = _nicknName;
            UserGuid = _userGuid;
        }
    }

    public class APP : SingletonMonobehaviour<APP>
    {

        protected override void Awake()
        {
            base.Awake();
            if (CheckPlayerData()) {
                PlayerPrefs.DeleteAll();
                LoadPlayerNickName();
            }
            else {
                PlayerPrefs.DeleteAll();
                PlayerPrefs.SetString("NickName", string.Empty);
                PlayerPrefs.SetString("UserGuid", Guid.NewGuid().ToString());
                SavePlayerNickName();
            }
        }

        // 로컬에 데이터가 존재하는지 확인 
        private bool CheckPlayerData()
        {
            bool exists = File.Exists(Application.persistentDataPath + "/PlayerInfo.json");
            if (exists) Debug.Log("Existing User");
            else Debug.Log("NewUser");
            return exists;
        }

        // 플레이어의 정보를 로컬에 저장
        public void SavePlayerNickName()
        {
            PlayerData _PlayerData = new (PlayerPrefs.GetString("NickName"), PlayerPrefs.GetString("UserGuid"));
            var json = JsonConvert.SerializeObject(_PlayerData);
            File.WriteAllText(Application.persistentDataPath + "/PlayerInfo.json", json);
        }

        // 로컬에 저장된 플레이어의 정보를 불러온다.
        public void LoadPlayerNickName()
        {
            var _Json = File.ReadAllText(Application.persistentDataPath + "/PlayerInfo.json");
            var _Info = JsonConvert.DeserializeObject<PlayerData>(_Json);
            PlayerPrefs.SetString("NickName", _Info.NickName);
            PlayerPrefs.SetString("UserGuid", _Info.UserGuid);
        }
    }
}

Connection.CS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Realtime;
namespace Com.Lycos7560
{
public class Connection : MonoBehaviourPunCallbacks
{
public GameObject _ConnetMain;
public TMP_InputField _InputFieldName;
public CanvasGroup ConnetGroup;
public Button ConnetBTN;
public TMP_Text ConnectionStatusText;
public override void OnEnable()
{
if (PlayerPrefs.GetString("NickName") != string.Empty)
_InputFieldName.text = PlayerPrefs.GetString("NickName");
else _InputFieldName.text = string.Empty;
}
private void Awake()
{
_InputFieldName.onValueChanged.AddListener((_value) =>
{
if (_value.Length > 0 || _value != string.Empty)
{
ConnetGroup.alpha = 1f;
ConnetGroup.interactable = true;
ConnetGroup.blocksRaycasts = true;
}
else
{
ConnetGroup.alpha = 0.3f;
ConnetGroup.interactable = false;
ConnetGroup.blocksRaycasts = false;
}
});
ConnetBTN.onClick.AddListener(() => {
ConnetGroup.alpha = 0.3f;
ConnetGroup.interactable = false;
ConnetGroup.blocksRaycasts = false;
_InputFieldName.interactable = false;
PlayerPrefs.SetString("NickName", _InputFieldName.text);
APP.Instance.SavePlayerNickName();
ConnectionStatusText.text = "Connecting . . .";
NetworkManager.Instance.Connect();
});
_ConnetMain.SetActive(true);
}
private void Start()
{
NetworkManager.Instance.OnDisconnectedAction += ConnectionOnDisconnected;
NetworkManager.Instance.OnJoinedLobbyAction += ConnectionOnJoinedLobby;
NetworkManager.Instance.OnChangeNetworkClientState += OnChangeNetworkClientState;
if (PlayerPrefs.GetString("NickName") != string.Empty)
_InputFieldName.text = PlayerPrefs.GetString("NickName");
else _InputFieldName.text = string.Empty;
}
// 액션 등록
private void ConnectionOnJoinedLobby()
{
Debug.Log("Connet OnJoinedLobby()");
_ConnetMain.SetActive(false);
}
// 액션 등록
public void ConnectionOnDisconnected()
{
Debug.Log("연결 종료");
_ConnetMain.SetActive(true);
ConnetGroup.alpha = 1f;
ConnetGroup.interactable = true;
ConnetGroup.blocksRaycasts = true;
_InputFieldName.interactable = true;
_InputFieldName.text = PlayerPrefs.GetString("NickName");
}
private void OnChangeNetworkClientState(ClientState _clientState)
{
ConnectionStatusText.text = _clientState.ToString();
}
}
}
using UnityEngine; using UnityEngine.UI; using TMPro; using Photon.Pun; using Photon.Realtime; namespace Com.Lycos7560 { public class Connection : MonoBehaviourPunCallbacks { public GameObject _ConnetMain; public TMP_InputField _InputFieldName; public CanvasGroup ConnetGroup; public Button ConnetBTN; public TMP_Text ConnectionStatusText; public override void OnEnable() { if (PlayerPrefs.GetString("NickName") != string.Empty) _InputFieldName.text = PlayerPrefs.GetString("NickName"); else _InputFieldName.text = string.Empty; } private void Awake() { _InputFieldName.onValueChanged.AddListener((_value) => { if (_value.Length > 0 || _value != string.Empty) { ConnetGroup.alpha = 1f; ConnetGroup.interactable = true; ConnetGroup.blocksRaycasts = true; } else { ConnetGroup.alpha = 0.3f; ConnetGroup.interactable = false; ConnetGroup.blocksRaycasts = false; } }); ConnetBTN.onClick.AddListener(() => { ConnetGroup.alpha = 0.3f; ConnetGroup.interactable = false; ConnetGroup.blocksRaycasts = false; _InputFieldName.interactable = false; PlayerPrefs.SetString("NickName", _InputFieldName.text); APP.Instance.SavePlayerNickName(); ConnectionStatusText.text = "Connecting . . ."; NetworkManager.Instance.Connect(); }); _ConnetMain.SetActive(true); } private void Start() { NetworkManager.Instance.OnDisconnectedAction += ConnectionOnDisconnected; NetworkManager.Instance.OnJoinedLobbyAction += ConnectionOnJoinedLobby; NetworkManager.Instance.OnChangeNetworkClientState += OnChangeNetworkClientState; if (PlayerPrefs.GetString("NickName") != string.Empty) _InputFieldName.text = PlayerPrefs.GetString("NickName"); else _InputFieldName.text = string.Empty; } // 액션 등록 private void ConnectionOnJoinedLobby() { Debug.Log("Connet OnJoinedLobby()"); _ConnetMain.SetActive(false); } // 액션 등록 public void ConnectionOnDisconnected() { Debug.Log("연결 종료"); _ConnetMain.SetActive(true); ConnetGroup.alpha = 1f; ConnetGroup.interactable = true; ConnetGroup.blocksRaycasts = true; _InputFieldName.interactable = true; _InputFieldName.text = PlayerPrefs.GetString("NickName"); } private void OnChangeNetworkClientState(ClientState _clientState) { ConnectionStatusText.text = _clientState.ToString(); } } }
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Realtime;

namespace Com.Lycos7560
{
    public class Connection : MonoBehaviourPunCallbacks
    {
        public GameObject _ConnetMain;

        public TMP_InputField _InputFieldName;

        public CanvasGroup ConnetGroup;
        public Button ConnetBTN;

        public TMP_Text ConnectionStatusText;

        public override void OnEnable()
        {
            if (PlayerPrefs.GetString("NickName") != string.Empty)
                _InputFieldName.text = PlayerPrefs.GetString("NickName");
            else _InputFieldName.text = string.Empty;
            

        }


        private void Awake()
        {
            _InputFieldName.onValueChanged.AddListener((_value) =>
            {
                if (_value.Length > 0 || _value != string.Empty)
                {
                    ConnetGroup.alpha = 1f;
                    ConnetGroup.interactable = true;
                    ConnetGroup.blocksRaycasts = true;
                }
                else
                {
                    ConnetGroup.alpha = 0.3f;
                    ConnetGroup.interactable = false;
                    ConnetGroup.blocksRaycasts = false;
                }
            });

            ConnetBTN.onClick.AddListener(() => {
                ConnetGroup.alpha = 0.3f;
                ConnetGroup.interactable = false;
                ConnetGroup.blocksRaycasts = false;
                _InputFieldName.interactable = false;
                PlayerPrefs.SetString("NickName", _InputFieldName.text);
                APP.Instance.SavePlayerNickName();
                ConnectionStatusText.text = "Connecting . . .";
                NetworkManager.Instance.Connect();
            });

            _ConnetMain.SetActive(true);
        }

        private void Start()
        {
            NetworkManager.Instance.OnDisconnectedAction += ConnectionOnDisconnected;
            NetworkManager.Instance.OnJoinedLobbyAction += ConnectionOnJoinedLobby;
            NetworkManager.Instance.OnChangeNetworkClientState += OnChangeNetworkClientState;

            if (PlayerPrefs.GetString("NickName") != string.Empty)
                _InputFieldName.text = PlayerPrefs.GetString("NickName");
            else _InputFieldName.text = string.Empty;
        }

        // 액션 등록
        private void ConnectionOnJoinedLobby()
        {
            Debug.Log("Connet OnJoinedLobby()");
            _ConnetMain.SetActive(false);

        }

        // 액션 등록
        public void ConnectionOnDisconnected()
        {
            Debug.Log("연결 종료");
            _ConnetMain.SetActive(true);
            ConnetGroup.alpha = 1f;
            ConnetGroup.interactable = true;
            ConnetGroup.blocksRaycasts = true;
            _InputFieldName.interactable = true;
            _InputFieldName.text = PlayerPrefs.GetString("NickName");
        }


        private void OnChangeNetworkClientState(ClientState _clientState)
        {
            ConnectionStatusText.text = _clientState.ToString();
        }
    }
}

Lobby.CS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Realtime;
namespace Com.Lycos7560
{
public class Lobby : MonoBehaviourPunCallbacks
{
public GameObject _LobbyMain;
public Button _ExitBtn;
public Button _CreateRoomBtn;
public TMP_Text LobbyPeopleCountText;
public Transform _Content;
public List<TypedLobbyInfo> _LobbyInfoList;
public GameObject RoomItemPrefab;
private List<RoomItem> _RoomItemList = new();
private TypedLobby _CntLobby => PhotonNetwork.CurrentLobby;
private List<RoomInfo> _CntRoomList;
private Dictionary<string, RoomInfo> _SachedRoomList = new();
private Coroutine _LobbyCoroutine;
public GameObject _RoomJoinPopUp;
public Button _PopUpCloseBtn;
public TMP_Text _RoomJoinFailText;
private void Awake()
{
_ExitBtn.onClick.AddListener(() => {
NetworkManager.Instance.DisconnectMainServer();
});
_CreateRoomBtn.onClick.AddListener(() => {
_RoomJoinPopUp.SetActive(true);
NetworkManager.Instance.CreateRoomWithNickName(false);
});
_PopUpCloseBtn.onClick.AddListener(() => {
_RoomJoinPopUp.SetActive(false);
});
for (int i = 0; i < 20; i++)
{
RoomItem _RoomItem = Instantiate<GameObject>(RoomItemPrefab, _Content).GetComponent<RoomItem>();
_RoomItem.ChangeRoomInfo("Defalut", 0, 0);
_RoomItemList.Add(_RoomItem);
_RoomItemList[i].gameObject.SetActive(false);
_RoomItem.JoinRoomBtn.onClick.AddListener(() => {
_RoomJoinPopUp.SetActive(true);
_RoomJoinFailText.text = "Try to access the chat room.";
_PopUpCloseBtn.gameObject.SetActive(false);
NetworkManager.Instance.JoinRoom(_RoomItem.RoomName.text);
});
}
_LobbyMain.SetActive(false);
}
private void Start()
{
// 액션 등록
NetworkManager.Instance.OnDisconnectedAction += LobbyOnDisconnected;
NetworkManager.Instance.OnJoinedLobbyAction += LobbyOnJoinedLobby;
NetworkManager.Instance.OnJoinRoomFailedAction += LobbyOnJoinRoomFailed;
NetworkManager.Instance.OnJoinedRoomAction += LobbyOnJoinedRoom;
NetworkManager.Instance.OnLeftRoomAction += LobbyOnLeftRoom;
}
#region ActionFuctions
private void LobbyOnJoinedLobby()
{
_LobbyMain.SetActive(true);
_RoomJoinFailText.text = "Attempt to connect . . .";
_PopUpCloseBtn.gameObject.SetActive(false);
_SachedRoomList.Clear();
if (_LobbyCoroutine != null)
{
StopCoroutine(_LobbyCoroutine);
_LobbyCoroutine = null;
}
_LobbyCoroutine = StartCoroutine(UpdateLobbyCoroutine());
LobbyPeopleCountText.text = string.Format($"Lobby People Count : {PhotonNetwork.CountOfPlayersOnMaster}");
}
private void LobbyOnDisconnected()
{
if (_LobbyCoroutine != null)
StopCoroutine(_LobbyCoroutine);
_LobbyCoroutine = null;
_LobbyMain.SetActive(false);
}
private void LobbyOnJoinedRoom()
{
_RoomJoinPopUp.SetActive(true);
_RoomJoinFailText.text = "Attempt to connect . . .";
_PopUpCloseBtn.gameObject.SetActive(false);
_LobbyMain.SetActive(false);
if (_LobbyCoroutine != null)
StopCoroutine(_LobbyCoroutine);
_LobbyCoroutine = null;
}
private void LobbyOnLeftRoom()
{
_LobbyMain.SetActive(true);
_RoomJoinFailText.text = "Attempt to connect . . .";
_PopUpCloseBtn.gameObject.SetActive(false);
_SachedRoomList.Clear();
if (_LobbyCoroutine != null) {
StopCoroutine(_LobbyCoroutine);
_LobbyCoroutine = null;
}
_LobbyCoroutine = StartCoroutine(UpdateLobbyCoroutine());
UpdateLobbyRoomList();
}
private void LobbyOnJoinRoomFailed(short returnCode, string message)
{
PhotonNetwork.JoinLobby(_CntLobby);
_RoomJoinPopUp.SetActive(true);
_PopUpCloseBtn.gameObject.SetActive(true);
_RoomJoinFailText.text = string.Format($"returnCode : {returnCode} , {message}");
UpdateLobbyRoomList();
}
#endregion
#region MonoBehaviourPunCallbacks
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
_CntRoomList = roomList;
UpdateLobbyRoomList();
}
public override void OnCreatedRoom()
{
// 카운트 리셋
NetworkManager.Instance.CreateRoomWithNickName(true);
}
public override void OnCreateRoomFailed(short returnCode, string message)
{
NetworkManager.Instance.CreateRoomWithNickName(false);
}
#endregion
/// <summary>
/// 일정 시간마다 로비에 Room과 있는 로비 인원을 업데이트
/// 목적이 Chatting을 사용 가능할 때까지 대기
/// </summary>
private IEnumerator UpdateLobbyCoroutine()
{
yield return new WaitUntil(() => NetworkManager.Instance._ChatClient != null && NetworkManager.Instance._ChatClient.CanChat);
_RoomJoinPopUp.SetActive(false);
_PopUpCloseBtn.gameObject.SetActive(true);
WaitForSeconds _Delay = new WaitForSeconds(10f);
yield return _Delay;
while (true)
{
LobbyPeopleCountText.text = string.Format($"Lobby People Count : {PhotonNetwork.CountOfPlayersOnMaster}");
PhotonNetwork.JoinLobby(_CntLobby);
UpdateLobbyRoomList();
yield return _Delay;
if (_LobbyMain.activeSelf == false) break;
}
_LobbyCoroutine = null;
}
private void UpdateLobbyRoomList()
{
for (int i = 0; i < _CntRoomList.Count; i++)
{
RoomInfo info = _CntRoomList[i];
if (info.RemovedFromList) _SachedRoomList.Remove(info.Name);
else _SachedRoomList[info.Name] = info;
}
for (int j = 0; j < _RoomItemList.Count; j++)
{
_RoomItemList[j].gameObject.SetActive(false);
_RoomItemList[j].ChangeRoomInfo("Defalut", 0, 0);
}
for (int j = 0; j < _CntRoomList.Count; j++)
{
RoomInfo info = _CntRoomList[j];
if (info.PlayerCount == 0) continue;
_RoomItemList[j].gameObject.SetActive(true);
_RoomItemList[j].ChangeRoomInfo(info.Name, info.PlayerCount, info.MaxPlayers);
}
}
}
}
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; using Photon.Pun; using Photon.Realtime; namespace Com.Lycos7560 { public class Lobby : MonoBehaviourPunCallbacks { public GameObject _LobbyMain; public Button _ExitBtn; public Button _CreateRoomBtn; public TMP_Text LobbyPeopleCountText; public Transform _Content; public List<TypedLobbyInfo> _LobbyInfoList; public GameObject RoomItemPrefab; private List<RoomItem> _RoomItemList = new(); private TypedLobby _CntLobby => PhotonNetwork.CurrentLobby; private List<RoomInfo> _CntRoomList; private Dictionary<string, RoomInfo> _SachedRoomList = new(); private Coroutine _LobbyCoroutine; public GameObject _RoomJoinPopUp; public Button _PopUpCloseBtn; public TMP_Text _RoomJoinFailText; private void Awake() { _ExitBtn.onClick.AddListener(() => { NetworkManager.Instance.DisconnectMainServer(); }); _CreateRoomBtn.onClick.AddListener(() => { _RoomJoinPopUp.SetActive(true); NetworkManager.Instance.CreateRoomWithNickName(false); }); _PopUpCloseBtn.onClick.AddListener(() => { _RoomJoinPopUp.SetActive(false); }); for (int i = 0; i < 20; i++) { RoomItem _RoomItem = Instantiate<GameObject>(RoomItemPrefab, _Content).GetComponent<RoomItem>(); _RoomItem.ChangeRoomInfo("Defalut", 0, 0); _RoomItemList.Add(_RoomItem); _RoomItemList[i].gameObject.SetActive(false); _RoomItem.JoinRoomBtn.onClick.AddListener(() => { _RoomJoinPopUp.SetActive(true); _RoomJoinFailText.text = "Try to access the chat room."; _PopUpCloseBtn.gameObject.SetActive(false); NetworkManager.Instance.JoinRoom(_RoomItem.RoomName.text); }); } _LobbyMain.SetActive(false); } private void Start() { // 액션 등록 NetworkManager.Instance.OnDisconnectedAction += LobbyOnDisconnected; NetworkManager.Instance.OnJoinedLobbyAction += LobbyOnJoinedLobby; NetworkManager.Instance.OnJoinRoomFailedAction += LobbyOnJoinRoomFailed; NetworkManager.Instance.OnJoinedRoomAction += LobbyOnJoinedRoom; NetworkManager.Instance.OnLeftRoomAction += LobbyOnLeftRoom; } #region ActionFuctions private void LobbyOnJoinedLobby() { _LobbyMain.SetActive(true); _RoomJoinFailText.text = "Attempt to connect . . ."; _PopUpCloseBtn.gameObject.SetActive(false); _SachedRoomList.Clear(); if (_LobbyCoroutine != null) { StopCoroutine(_LobbyCoroutine); _LobbyCoroutine = null; } _LobbyCoroutine = StartCoroutine(UpdateLobbyCoroutine()); LobbyPeopleCountText.text = string.Format($"Lobby People Count : {PhotonNetwork.CountOfPlayersOnMaster}"); } private void LobbyOnDisconnected() { if (_LobbyCoroutine != null) StopCoroutine(_LobbyCoroutine); _LobbyCoroutine = null; _LobbyMain.SetActive(false); } private void LobbyOnJoinedRoom() { _RoomJoinPopUp.SetActive(true); _RoomJoinFailText.text = "Attempt to connect . . ."; _PopUpCloseBtn.gameObject.SetActive(false); _LobbyMain.SetActive(false); if (_LobbyCoroutine != null) StopCoroutine(_LobbyCoroutine); _LobbyCoroutine = null; } private void LobbyOnLeftRoom() { _LobbyMain.SetActive(true); _RoomJoinFailText.text = "Attempt to connect . . ."; _PopUpCloseBtn.gameObject.SetActive(false); _SachedRoomList.Clear(); if (_LobbyCoroutine != null) { StopCoroutine(_LobbyCoroutine); _LobbyCoroutine = null; } _LobbyCoroutine = StartCoroutine(UpdateLobbyCoroutine()); UpdateLobbyRoomList(); } private void LobbyOnJoinRoomFailed(short returnCode, string message) { PhotonNetwork.JoinLobby(_CntLobby); _RoomJoinPopUp.SetActive(true); _PopUpCloseBtn.gameObject.SetActive(true); _RoomJoinFailText.text = string.Format($"returnCode : {returnCode} , {message}"); UpdateLobbyRoomList(); } #endregion #region MonoBehaviourPunCallbacks public override void OnRoomListUpdate(List<RoomInfo> roomList) { _CntRoomList = roomList; UpdateLobbyRoomList(); } public override void OnCreatedRoom() { // 카운트 리셋 NetworkManager.Instance.CreateRoomWithNickName(true); } public override void OnCreateRoomFailed(short returnCode, string message) { NetworkManager.Instance.CreateRoomWithNickName(false); } #endregion /// <summary> /// 일정 시간마다 로비에 Room과 있는 로비 인원을 업데이트 /// 목적이 Chatting을 사용 가능할 때까지 대기 /// </summary> private IEnumerator UpdateLobbyCoroutine() { yield return new WaitUntil(() => NetworkManager.Instance._ChatClient != null && NetworkManager.Instance._ChatClient.CanChat); _RoomJoinPopUp.SetActive(false); _PopUpCloseBtn.gameObject.SetActive(true); WaitForSeconds _Delay = new WaitForSeconds(10f); yield return _Delay; while (true) { LobbyPeopleCountText.text = string.Format($"Lobby People Count : {PhotonNetwork.CountOfPlayersOnMaster}"); PhotonNetwork.JoinLobby(_CntLobby); UpdateLobbyRoomList(); yield return _Delay; if (_LobbyMain.activeSelf == false) break; } _LobbyCoroutine = null; } private void UpdateLobbyRoomList() { for (int i = 0; i < _CntRoomList.Count; i++) { RoomInfo info = _CntRoomList[i]; if (info.RemovedFromList) _SachedRoomList.Remove(info.Name); else _SachedRoomList[info.Name] = info; } for (int j = 0; j < _RoomItemList.Count; j++) { _RoomItemList[j].gameObject.SetActive(false); _RoomItemList[j].ChangeRoomInfo("Defalut", 0, 0); } for (int j = 0; j < _CntRoomList.Count; j++) { RoomInfo info = _CntRoomList[j]; if (info.PlayerCount == 0) continue; _RoomItemList[j].gameObject.SetActive(true); _RoomItemList[j].ChangeRoomInfo(info.Name, info.PlayerCount, info.MaxPlayers); } } } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Realtime;

namespace Com.Lycos7560
{
    public class Lobby : MonoBehaviourPunCallbacks
    {
        public GameObject _LobbyMain;
        public Button _ExitBtn;
        public Button _CreateRoomBtn;
        public TMP_Text LobbyPeopleCountText;

        public Transform _Content;

        public List<TypedLobbyInfo> _LobbyInfoList;

        public GameObject RoomItemPrefab;
        private List<RoomItem> _RoomItemList = new();

        private TypedLobby _CntLobby => PhotonNetwork.CurrentLobby;
        private List<RoomInfo> _CntRoomList;

        private Dictionary<string, RoomInfo> _SachedRoomList = new();
        private Coroutine _LobbyCoroutine;

        public GameObject _RoomJoinPopUp;
        public Button _PopUpCloseBtn;
        public TMP_Text _RoomJoinFailText;

        private void Awake()
        {
          
            _ExitBtn.onClick.AddListener(() => {
                NetworkManager.Instance.DisconnectMainServer();
            });

            _CreateRoomBtn.onClick.AddListener(() => {
                _RoomJoinPopUp.SetActive(true);
                NetworkManager.Instance.CreateRoomWithNickName(false); 
            });

            _PopUpCloseBtn.onClick.AddListener(() => {
                _RoomJoinPopUp.SetActive(false);
            });

            for (int i = 0; i < 20; i++)
            {
                RoomItem _RoomItem = Instantiate<GameObject>(RoomItemPrefab, _Content).GetComponent<RoomItem>();
                _RoomItem.ChangeRoomInfo("Defalut", 0, 0);
                _RoomItemList.Add(_RoomItem);
                _RoomItemList[i].gameObject.SetActive(false);
                _RoomItem.JoinRoomBtn.onClick.AddListener(() => {
                    _RoomJoinPopUp.SetActive(true);
                    _RoomJoinFailText.text = "Try to access the chat room.";
                    _PopUpCloseBtn.gameObject.SetActive(false);
                    NetworkManager.Instance.JoinRoom(_RoomItem.RoomName.text);
                });
            }

            _LobbyMain.SetActive(false);
        }

        private void Start()
        {
            // 액션 등록
            NetworkManager.Instance.OnDisconnectedAction += LobbyOnDisconnected;
            NetworkManager.Instance.OnJoinedLobbyAction += LobbyOnJoinedLobby;
            NetworkManager.Instance.OnJoinRoomFailedAction += LobbyOnJoinRoomFailed;
            NetworkManager.Instance.OnJoinedRoomAction += LobbyOnJoinedRoom;
            NetworkManager.Instance.OnLeftRoomAction += LobbyOnLeftRoom;
        }



        #region ActionFuctions

        private void LobbyOnJoinedLobby()
        {
            _LobbyMain.SetActive(true);

            _RoomJoinFailText.text = "Attempt to connect . . .";
            _PopUpCloseBtn.gameObject.SetActive(false);
            _SachedRoomList.Clear();

            if (_LobbyCoroutine != null)
            {
                StopCoroutine(_LobbyCoroutine);
                _LobbyCoroutine = null;
            }
            _LobbyCoroutine = StartCoroutine(UpdateLobbyCoroutine());

            LobbyPeopleCountText.text = string.Format($"Lobby People Count : {PhotonNetwork.CountOfPlayersOnMaster}");
        }

        private void LobbyOnDisconnected()
        {
            if (_LobbyCoroutine != null)
                StopCoroutine(_LobbyCoroutine);
            _LobbyCoroutine = null;
            _LobbyMain.SetActive(false);
        }

        private void LobbyOnJoinedRoom()
        {
            _RoomJoinPopUp.SetActive(true);
            _RoomJoinFailText.text = "Attempt to connect . . .";
            _PopUpCloseBtn.gameObject.SetActive(false);
            _LobbyMain.SetActive(false);

            if (_LobbyCoroutine != null) 
                StopCoroutine(_LobbyCoroutine);
            _LobbyCoroutine = null;
        }

        private void LobbyOnLeftRoom()
        {
            _LobbyMain.SetActive(true);
            _RoomJoinFailText.text = "Attempt to connect . . .";
            _PopUpCloseBtn.gameObject.SetActive(false);
            _SachedRoomList.Clear();

            if (_LobbyCoroutine != null) {
                StopCoroutine(_LobbyCoroutine);
                _LobbyCoroutine = null;
            }
            _LobbyCoroutine = StartCoroutine(UpdateLobbyCoroutine());
            UpdateLobbyRoomList();
        }

        private void LobbyOnJoinRoomFailed(short returnCode, string message)
        {
            PhotonNetwork.JoinLobby(_CntLobby);
            _RoomJoinPopUp.SetActive(true);
            _PopUpCloseBtn.gameObject.SetActive(true);
            _RoomJoinFailText.text = string.Format($"returnCode : {returnCode} ,  {message}");
            UpdateLobbyRoomList();
        }

        #endregion


        #region  MonoBehaviourPunCallbacks
        public override void OnRoomListUpdate(List<RoomInfo> roomList)
        {
            _CntRoomList = roomList;
            UpdateLobbyRoomList();
        }

        public override void OnCreatedRoom()
        {
            // 카운트 리셋
            NetworkManager.Instance.CreateRoomWithNickName(true);
        }


        public override void OnCreateRoomFailed(short returnCode, string message)
        {
            NetworkManager.Instance.CreateRoomWithNickName(false);
        }


        #endregion



        /// <summary>
        /// 일정 시간마다 로비에 Room과 있는 로비 인원을 업데이트
        /// 목적이 Chatting을 사용 가능할 때까지 대기 
        /// </summary>
        private IEnumerator UpdateLobbyCoroutine()
        {
            yield return new WaitUntil(() => NetworkManager.Instance._ChatClient != null && NetworkManager.Instance._ChatClient.CanChat);
            _RoomJoinPopUp.SetActive(false);
            _PopUpCloseBtn.gameObject.SetActive(true);

            WaitForSeconds _Delay = new WaitForSeconds(10f);
            yield return _Delay;

            while (true)
            {
                LobbyPeopleCountText.text = string.Format($"Lobby People Count : {PhotonNetwork.CountOfPlayersOnMaster}");
                PhotonNetwork.JoinLobby(_CntLobby);
                UpdateLobbyRoomList();
                yield return _Delay;
                if (_LobbyMain.activeSelf == false) break;
            }

            _LobbyCoroutine = null;
        }

        private void UpdateLobbyRoomList()
        {
            for (int i = 0; i < _CntRoomList.Count; i++)
            {
                RoomInfo info = _CntRoomList[i];
                if (info.RemovedFromList) _SachedRoomList.Remove(info.Name);
                else _SachedRoomList[info.Name] = info;
            }

            for (int j = 0; j < _RoomItemList.Count; j++)
            {
                _RoomItemList[j].gameObject.SetActive(false);
                _RoomItemList[j].ChangeRoomInfo("Defalut", 0, 0);
            }

            for (int j = 0; j < _CntRoomList.Count; j++)
            {
                RoomInfo info = _CntRoomList[j];
                if (info.PlayerCount == 0) continue;
                _RoomItemList[j].gameObject.SetActive(true);
                _RoomItemList[j].ChangeRoomInfo(info.Name, info.PlayerCount, info.MaxPlayers);
            }
        }


    }
}

Chatting.CS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Chat;
using ExitGames.Client.Photon;
namespace Com.Lycos7560
{
public class Chatting : MonoBehaviourPunCallbacks, IChatClientListener
{
public ChatClient _ChatClient;
public GameObject ChattingMain;
public Button _CloseChattingMainBtn;
public TMP_Text _ServerStateText;
public TMP_InputField _ChatInputField;
public Button _ChatSendBtn;
public TMP_Text _ChattingContentText;
public TMP_Text SubscribeUsersText;
public ChatChannel _CntChatChannel;
#region IChatClientListener CallBacks
public void OnGetMessages(string channelName, string[] senders, object[] messages)
{
for (int i = 0; i < senders.Length; i++)
{
string sender = senders[i];
string message = messages[i].ToString();
string chatMessage = $"[{sender}]: {message}";
// 채팅 메시지 추가
_ChattingContentText.text += chatMessage + "\n";
}
}
// 개인 메시지(귓속말) 미구현
public void OnPrivateMessage(string sender, object message, string channelName)
{
Debug.Log("Private message from [" + sender + "]: " + message);
}
// 접속한 Room의 이름과 관련된 채널 구독이 성공 CallBack
public void OnSubscribed(string[] channels, bool[] results)
{
_ChattingContentText.text = string.Empty;
// 채널을 캐싱해준다. (구독 완료된 시점)
if (_ChatClient.TryGetChannel("Room_" + PhotonNetwork.CurrentRoom.Name, out _CntChatChannel))
// 나가기 버튼 활성화
_CloseChattingMainBtn.gameObject.SetActive(true);
// 첫 화면 출력
_ChattingContentText.text += " Welcome to Photon Chat. \n";
UpdateSubscribeUsersText();
/* 디버깅
for (int i = 0; i < channels.Length; i++)
Debug.Log("Subscribed to Channel: " + channels[i]);
*/
}
// 접속한 Room의 이름과 관련된 채널 구독을 해제 CallBack
public void OnUnsubscribed(string[] channels)
{
// 구독 해제와 동시에 Clear
_ChattingContentText.text = string.Empty;
_CntChatChannel = null;
/* 디버깅
for (int i = 0; i < channels.Length; i++)
Debug.Log("Unsubscribed from Channel: " + channels[i]);
*/
}
// 디버그 CallBack 미구현
public void DebugReturn(DebugLevel level, string message)
{
Debug.Log("Debug: " + level + " - " + message);
}
// 디버그 CallBack 미구현
public void OnDisconnected()
{
Debug.Log("Disconnected from Chat Server");
}
// 디버그 CallBack 미구현
public void OnChatStateChange(ChatState state)
{
_ServerStateText.text = string.Format($"Server State : {state}");
}
// 디버그 CallBack 미구현
public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
{
Debug.Log("Status Update - User: " + user + ", Status: " + status);
}
// 어떤 유저가 해당 채널을 구독 CallBack
public void OnUserSubscribed(string channel, string user)
{
// 메시지 창에 어떤 유저가 구독했는지 출력
string message = $"<color=#06FF00>'{user}' has joined '{channel}'</color>";
_ChattingContentText.text += message + "\n";
UpdateSubscribeUsersText();
}
// 어떤 유저가 해당 채널을 구독 해제 CallBack
public void OnUserUnsubscribed(string channel, string user)
{
// 메시지 창에 어떤 유저가 구독을 해제했는지 출력
string message = $"<color=#FF0000> '{user}' has left '{channel}'</color>";
_ChattingContentText.text += message + "\n";
UpdateSubscribeUsersText();
}
#endregion
#region MonoBehaviour
private void Awake()
{
ChattingMain.SetActive(false);
_CloseChattingMainBtn.onClick.AddListener(() => {
PhotonNetwork.LeaveRoom();
});
_ChatSendBtn.onClick.AddListener(() => {
if (_ChatInputField.text == string.Empty) return;
else {
SendRoomMessage(_ChatInputField.text);
_ChatInputField.text = string.Empty;
}
});
}
private void Start()
{
// 액션 등록
NetworkManager.Instance.OnJoinedRoomAction += ChattingOnJoinedRoom;
NetworkManager.Instance.OnLeftRoomAction += ChattingOnLeftRoom;
NetworkManager.Instance.OnJoinedLobbyAction += ChattingOnJoinedLobby;
}
private void Update()
{
// !!필수!!
// ChatClient의 콜백 처리를 위해 주기적으로 호출
if (_ChatClient != null)
_ChatClient.Service();
}
#endregion
#region ActionFuctions
/// <summary>
/// 로비에 접속하면 Chatting Server를 활성화 시킨다.
/// </summary>
private void ChattingOnJoinedLobby()
{
// 구독 전에 나가는 것을 방지
_CloseChattingMainBtn.gameObject.SetActive(false);
if (_ChatClient == null) {
// 로비에 접속한 후 ChatClient 초기화 및 연결
_ChatClient = new ChatClient(this);
_ChatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new Photon.Chat.AuthenticationValues(PhotonNetwork.NickName));
Debug.LogFormat($"Chatting Server 초기화 및 연결 시작");
}
}
/// <summary>
/// Room에 접속하면 실행되는 함수
/// Room의 이름과 관련된 채팅 서버에 접속한다.
/// </summary>
private void ChattingOnJoinedRoom()
{
_ChattingContentText.text = string.Empty;
ChattingMain.SetActive(true);
string _Channel = "Room_" + PhotonNetwork.CurrentRoom.Name; // 가입할 채널 이름 배열
_ChatClient.Subscribe(_Channel, 0, -1, new ChannelCreationOptions { PublishSubscribers = true } ); // 채널에 구독
Debug.LogFormat($"{"Room_" + PhotonNetwork.CurrentRoom.Name} :: 구독");
}
/// <summary>
/// Room에서 나갈 경우 실행되는 함수
/// </summary>
private void ChattingOnLeftRoom()
{
string[] _Channels = new string[] { _CntChatChannel.Name };
_ChatClient.Unsubscribe(_Channels);
_CntChatChannel = null;
ChattingMain.SetActive(false);
}
#endregion
/// <summary>
/// 구독한 Channel에 메시지를 보냅니다.
/// </summary>
/// <param name="message"></param>
private void SendRoomMessage(string message)
{
if (_ChatClient != null && _ChatClient.CanChat) {
// _ChatClient가 구독한 방에 메시지를 보냅니다.
_ChatClient.PublishMessage("Room_" + PhotonNetwork.CurrentRoom.Name, message);
}
}
/// <summary>
/// 체널의 있는 유저들의 정보를 갱신합니다.
/// </summary>
private void UpdateSubscribeUsersText()
{
if (_ChatClient != null && _CntChatChannel != null) {
var _Users = _CntChatChannel.Subscribers;
SubscribeUsersText.text = string.Empty;
foreach (var _user in _Users)
SubscribeUsersText.text += _user + " ";
}
else SubscribeUsersText.text = "There is a problem with the network.";
}
}
}
using UnityEngine; using UnityEngine.UI; using TMPro; using Photon.Pun; using Photon.Chat; using ExitGames.Client.Photon; namespace Com.Lycos7560 { public class Chatting : MonoBehaviourPunCallbacks, IChatClientListener { public ChatClient _ChatClient; public GameObject ChattingMain; public Button _CloseChattingMainBtn; public TMP_Text _ServerStateText; public TMP_InputField _ChatInputField; public Button _ChatSendBtn; public TMP_Text _ChattingContentText; public TMP_Text SubscribeUsersText; public ChatChannel _CntChatChannel; #region IChatClientListener CallBacks public void OnGetMessages(string channelName, string[] senders, object[] messages) { for (int i = 0; i < senders.Length; i++) { string sender = senders[i]; string message = messages[i].ToString(); string chatMessage = $"[{sender}]: {message}"; // 채팅 메시지 추가 _ChattingContentText.text += chatMessage + "\n"; } } // 개인 메시지(귓속말) 미구현 public void OnPrivateMessage(string sender, object message, string channelName) { Debug.Log("Private message from [" + sender + "]: " + message); } // 접속한 Room의 이름과 관련된 채널 구독이 성공 CallBack public void OnSubscribed(string[] channels, bool[] results) { _ChattingContentText.text = string.Empty; // 채널을 캐싱해준다. (구독 완료된 시점) if (_ChatClient.TryGetChannel("Room_" + PhotonNetwork.CurrentRoom.Name, out _CntChatChannel)) // 나가기 버튼 활성화 _CloseChattingMainBtn.gameObject.SetActive(true); // 첫 화면 출력 _ChattingContentText.text += " Welcome to Photon Chat. \n"; UpdateSubscribeUsersText(); /* 디버깅 for (int i = 0; i < channels.Length; i++) Debug.Log("Subscribed to Channel: " + channels[i]); */ } // 접속한 Room의 이름과 관련된 채널 구독을 해제 CallBack public void OnUnsubscribed(string[] channels) { // 구독 해제와 동시에 Clear _ChattingContentText.text = string.Empty; _CntChatChannel = null; /* 디버깅 for (int i = 0; i < channels.Length; i++) Debug.Log("Unsubscribed from Channel: " + channels[i]); */ } // 디버그 CallBack 미구현 public void DebugReturn(DebugLevel level, string message) { Debug.Log("Debug: " + level + " - " + message); } // 디버그 CallBack 미구현 public void OnDisconnected() { Debug.Log("Disconnected from Chat Server"); } // 디버그 CallBack 미구현 public void OnChatStateChange(ChatState state) { _ServerStateText.text = string.Format($"Server State : {state}"); } // 디버그 CallBack 미구현 public void OnStatusUpdate(string user, int status, bool gotMessage, object message) { Debug.Log("Status Update - User: " + user + ", Status: " + status); } // 어떤 유저가 해당 채널을 구독 CallBack public void OnUserSubscribed(string channel, string user) { // 메시지 창에 어떤 유저가 구독했는지 출력 string message = $"<color=#06FF00>'{user}' has joined '{channel}'</color>"; _ChattingContentText.text += message + "\n"; UpdateSubscribeUsersText(); } // 어떤 유저가 해당 채널을 구독 해제 CallBack public void OnUserUnsubscribed(string channel, string user) { // 메시지 창에 어떤 유저가 구독을 해제했는지 출력 string message = $"<color=#FF0000> '{user}' has left '{channel}'</color>"; _ChattingContentText.text += message + "\n"; UpdateSubscribeUsersText(); } #endregion #region MonoBehaviour private void Awake() { ChattingMain.SetActive(false); _CloseChattingMainBtn.onClick.AddListener(() => { PhotonNetwork.LeaveRoom(); }); _ChatSendBtn.onClick.AddListener(() => { if (_ChatInputField.text == string.Empty) return; else { SendRoomMessage(_ChatInputField.text); _ChatInputField.text = string.Empty; } }); } private void Start() { // 액션 등록 NetworkManager.Instance.OnJoinedRoomAction += ChattingOnJoinedRoom; NetworkManager.Instance.OnLeftRoomAction += ChattingOnLeftRoom; NetworkManager.Instance.OnJoinedLobbyAction += ChattingOnJoinedLobby; } private void Update() { // !!필수!! // ChatClient의 콜백 처리를 위해 주기적으로 호출 if (_ChatClient != null) _ChatClient.Service(); } #endregion #region ActionFuctions /// <summary> /// 로비에 접속하면 Chatting Server를 활성화 시킨다. /// </summary> private void ChattingOnJoinedLobby() { // 구독 전에 나가는 것을 방지 _CloseChattingMainBtn.gameObject.SetActive(false); if (_ChatClient == null) { // 로비에 접속한 후 ChatClient 초기화 및 연결 _ChatClient = new ChatClient(this); _ChatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new Photon.Chat.AuthenticationValues(PhotonNetwork.NickName)); Debug.LogFormat($"Chatting Server 초기화 및 연결 시작"); } } /// <summary> /// Room에 접속하면 실행되는 함수 /// Room의 이름과 관련된 채팅 서버에 접속한다. /// </summary> private void ChattingOnJoinedRoom() { _ChattingContentText.text = string.Empty; ChattingMain.SetActive(true); string _Channel = "Room_" + PhotonNetwork.CurrentRoom.Name; // 가입할 채널 이름 배열 _ChatClient.Subscribe(_Channel, 0, -1, new ChannelCreationOptions { PublishSubscribers = true } ); // 채널에 구독 Debug.LogFormat($"{"Room_" + PhotonNetwork.CurrentRoom.Name} :: 구독"); } /// <summary> /// Room에서 나갈 경우 실행되는 함수 /// </summary> private void ChattingOnLeftRoom() { string[] _Channels = new string[] { _CntChatChannel.Name }; _ChatClient.Unsubscribe(_Channels); _CntChatChannel = null; ChattingMain.SetActive(false); } #endregion /// <summary> /// 구독한 Channel에 메시지를 보냅니다. /// </summary> /// <param name="message"></param> private void SendRoomMessage(string message) { if (_ChatClient != null && _ChatClient.CanChat) { // _ChatClient가 구독한 방에 메시지를 보냅니다. _ChatClient.PublishMessage("Room_" + PhotonNetwork.CurrentRoom.Name, message); } } /// <summary> /// 체널의 있는 유저들의 정보를 갱신합니다. /// </summary> private void UpdateSubscribeUsersText() { if (_ChatClient != null && _CntChatChannel != null) { var _Users = _CntChatChannel.Subscribers; SubscribeUsersText.text = string.Empty; foreach (var _user in _Users) SubscribeUsersText.text += _user + " "; } else SubscribeUsersText.text = "There is a problem with the network."; } } }
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Chat;
using ExitGames.Client.Photon;

namespace Com.Lycos7560
{
    public class Chatting : MonoBehaviourPunCallbacks, IChatClientListener
    {
        public ChatClient _ChatClient;

        public GameObject ChattingMain;

        public Button _CloseChattingMainBtn;

        public TMP_Text _ServerStateText;

        public TMP_InputField _ChatInputField;

        public Button _ChatSendBtn;

        public TMP_Text _ChattingContentText;
        public TMP_Text SubscribeUsersText;

        public ChatChannel _CntChatChannel;

        #region IChatClientListener CallBacks

        public void OnGetMessages(string channelName, string[] senders, object[] messages)
        {
            for (int i = 0; i < senders.Length; i++)
            {
                string sender = senders[i];
                string message = messages[i].ToString();

                string chatMessage = $"[{sender}]: {message}";

                // 채팅 메시지 추가
                _ChattingContentText.text += chatMessage + "\n";
            }
        }

        // 개인 메시지(귓속말) 미구현
        public void OnPrivateMessage(string sender, object message, string channelName)
        {
            Debug.Log("Private message from [" + sender + "]: " + message);
        }

        // 접속한 Room의 이름과 관련된 채널 구독이 성공 CallBack
        public void OnSubscribed(string[] channels, bool[] results)
        {
            _ChattingContentText.text = string.Empty;
            // 채널을 캐싱해준다. (구독 완료된 시점)
            if (_ChatClient.TryGetChannel("Room_" + PhotonNetwork.CurrentRoom.Name, out _CntChatChannel))  

            // 나가기 버튼 활성화
            _CloseChattingMainBtn.gameObject.SetActive(true); 

            // 첫 화면 출력
            _ChattingContentText.text += " Welcome to Photon Chat. \n";
            UpdateSubscribeUsersText();
            /* 디버깅
            for (int i = 0; i < channels.Length; i++)
                Debug.Log("Subscribed to Channel: " + channels[i]); 
            */
        }

        // 접속한 Room의 이름과 관련된 채널 구독을 해제 CallBack
        public void OnUnsubscribed(string[] channels)
        {
            // 구독 해제와 동시에 Clear
            _ChattingContentText.text = string.Empty;
            _CntChatChannel = null;
            /* 디버깅
            for (int i = 0; i < channels.Length; i++)
                Debug.Log("Unsubscribed from Channel: " + channels[i]);
            */
        }

        // 디버그 CallBack 미구현
        public void DebugReturn(DebugLevel level, string message)
        {
            Debug.Log("Debug: " + level + " - " + message);
        }

        // 디버그 CallBack 미구현
        public void OnDisconnected()
        {
            Debug.Log("Disconnected from Chat Server");
        }

        // 디버그 CallBack 미구현
        public void OnChatStateChange(ChatState state)
        {
            _ServerStateText.text = string.Format($"Server State : {state}");
        }

        // 디버그 CallBack 미구현
        public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
        {
            Debug.Log("Status Update - User: " + user + ", Status: " + status);
        }

        //  어떤 유저가 해당 채널을 구독 CallBack
        public void OnUserSubscribed(string channel, string user)
        {
            // 메시지 창에 어떤 유저가 구독했는지 출력
            string message = $"<color=#06FF00>'{user}' has joined '{channel}'</color>";
            _ChattingContentText.text += message + "\n";
            UpdateSubscribeUsersText();
        }

        //  어떤 유저가 해당 채널을 구독 해제 CallBack
        public void OnUserUnsubscribed(string channel, string user)
        {
            // 메시지 창에 어떤 유저가 구독을 해제했는지 출력
            string message = $"<color=#FF0000> '{user}' has left '{channel}'</color>";
            _ChattingContentText.text += message + "\n";
            UpdateSubscribeUsersText();
        }


        #endregion


        #region MonoBehaviour

        private void Awake()
        {         
            ChattingMain.SetActive(false);
            _CloseChattingMainBtn.onClick.AddListener(() => { 
                  PhotonNetwork.LeaveRoom();
            });
            _ChatSendBtn.onClick.AddListener(() => {
                if (_ChatInputField.text == string.Empty) return;
                else {
                    SendRoomMessage(_ChatInputField.text);
                    _ChatInputField.text = string.Empty;
                }
            });
        }

        private void Start()
        {
            // 액션 등록
            NetworkManager.Instance.OnJoinedRoomAction += ChattingOnJoinedRoom;
            NetworkManager.Instance.OnLeftRoomAction += ChattingOnLeftRoom;
            NetworkManager.Instance.OnJoinedLobbyAction += ChattingOnJoinedLobby;
        }

        private void Update()
        {
            // !!필수!!
            // ChatClient의 콜백 처리를 위해 주기적으로 호출
            if (_ChatClient != null)
                _ChatClient.Service();
        }

        #endregion



        #region ActionFuctions

        /// <summary>
        /// 로비에 접속하면 Chatting Server를 활성화 시킨다.
        /// </summary>
        private void ChattingOnJoinedLobby()
        {
            // 구독 전에 나가는 것을 방지
            _CloseChattingMainBtn.gameObject.SetActive(false); 

            if (_ChatClient == null) {
                // 로비에 접속한 후 ChatClient 초기화 및 연결
                _ChatClient = new ChatClient(this);
                _ChatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new Photon.Chat.AuthenticationValues(PhotonNetwork.NickName));
                Debug.LogFormat($"Chatting Server 초기화 및 연결 시작");
            }
        }

        /// <summary>
        ///  Room에 접속하면 실행되는 함수
        ///  Room의 이름과 관련된 채팅 서버에 접속한다.
        /// </summary>
        private void ChattingOnJoinedRoom()
        {
            _ChattingContentText.text = string.Empty;
            ChattingMain.SetActive(true);
            string _Channel = "Room_" + PhotonNetwork.CurrentRoom.Name; // 가입할 채널 이름 배열
            _ChatClient.Subscribe(_Channel, 0, -1, new ChannelCreationOptions { PublishSubscribers = true } ); // 채널에 구독
            Debug.LogFormat($"{"Room_" + PhotonNetwork.CurrentRoom.Name} :: 구독");

        }

        /// <summary>
        /// Room에서 나갈 경우 실행되는 함수
        /// </summary>
        private void ChattingOnLeftRoom()
        {
            string[] _Channels = new string[] { _CntChatChannel.Name };
            _ChatClient.Unsubscribe(_Channels);
            _CntChatChannel = null;
            ChattingMain.SetActive(false);
        }

        #endregion

        /// <summary>
        /// 구독한 Channel에 메시지를 보냅니다.
        /// </summary>
        /// <param name="message"></param>
        private void SendRoomMessage(string message)
        {
            if (_ChatClient != null && _ChatClient.CanChat) {
                //  _ChatClient가 구독한 방에 메시지를 보냅니다.
                _ChatClient.PublishMessage("Room_" + PhotonNetwork.CurrentRoom.Name, message);
            }
        }

        /// <summary>
        /// 체널의 있는 유저들의 정보를 갱신합니다.
        /// </summary>
        private void UpdateSubscribeUsersText()
        {
            if (_ChatClient != null && _CntChatChannel != null) {
                var _Users = _CntChatChannel.Subscribers;
                SubscribeUsersText.text = string.Empty;
                foreach (var _user in _Users)
                    SubscribeUsersText.text += _user + "  ";               
            }
            else SubscribeUsersText.text = "There is a problem with the network.";
           
        }
    }






}

NetworkManager.CS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using UnityEngine;
using UnityEngine.Events;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using Photon.Chat;
namespace Com.Lycos7560
{
public class NetworkManager : MonoBehaviourPunCallbacks
{
public static NetworkManager Instance;
public Connection _Connection;
public Chatting _Chatting;
public Lobby _Lobby;
public ChatClient _ChatClient { get { return _Chatting._ChatClient; } }
#region Private Serializable Fields
#endregion
#region Private Fields
/// <summary>
/// 이 클라이언트의 버전 번호입니다.
/// 사용자는 gameVersion에 의해 서로 분리되어 있습니다
/// (이를 통해 변경 사항을 변경할 수 있습니다).
/// </summary>
string gameVersion = "1";
/// <summary>
/// 룸당 최대 플레이어 수입니다.
/// 방이 꽉 차면 새로운 플레이어가 참여할 수 없기 때문에 새로운 방이 만들어집니다.
/// </summary>
[Tooltip("방이 꽉 차면 새로운 플레이어가 참여할 수 없기 때문에 새로운 방이 만들어집니다.")]
[SerializeField]
private byte maxPlayersPerRoom = 5;
/// <summary>
/// 현재 NetworkClientState의 상태를 나타냅니다.
/// </summary>
[Tooltip("현재 NetworkClientState의 상태를 나타냅니다. NetworkClientStateCheck 함수를 통하여 업데이트 됩니다")]
[SerializeField]
private ClientState _CntNetworkClientState = ClientState.PeerCreated;
public ClientState CntNetworkClientState
{
get => _CntNetworkClientState;
set
{
if (_CntNetworkClientState != value)
OnChangeNetworkClientState?.Invoke(value);
_CntNetworkClientState = value;
}
}
[Tooltip("방생성을 시도한 횟수입니다.")]
[SerializeField]
private int _CreateRoomCnt = 1;
#endregion
#region public Fields
#endregion
public UnityAction<ClientState> OnChangeNetworkClientState;
public UnityAction OnDisconnectedAction;
public UnityAction OnJoinedLobbyAction;
public UnityAction OnJoinedRoomAction;
public UnityAction<short, string> OnJoinRoomFailedAction;
public UnityAction OnLeftRoomAction;
#region MonoBehaviour CallBacks
/// <summary>
/// MonoBehavior 메서드는 초기 초기화 단계에서 Unity에 의해 GameObject에 호출되었습니다.
/// </summary>
void Awake()
{
Instance = this;
// #Critical
// 이렇게하면 PhotonNetwork를 사용할 수 있습니다.
// 마스터 클라이언트의 LoadLevel()과 동일한 룸에 있는 모든 클라이언트의 LoadLevel이 자동으로 동기화됩니다
PhotonNetwork.AutomaticallySyncScene = true;
UpdateCntNetworkClientState();
}
/// <summary>
/// 마스터 서버에 진입한 후에 바로 실행
/// </summary>
public override void OnConnectedToMaster()
{
UpdateCntNetworkClientState();
PhotonNetwork.JoinLobby();
PhotonNetwork.NickName = PlayerPrefs.GetString("NickName");
}
/// <summary>
/// 접속이 종료되었을 경우 실행된다.
/// </summary>
/// <param name="cause"></param>
public override void OnDisconnected(DisconnectCause cause)
{
if (cause == DisconnectCause.DisconnectByServerLogic)
{
// 로비 입장 실패
Debug.LogFormat($"<color=red> Failed to enter lobby : {cause} </color>");
}
else
{
// 기타 연결 끊김 원인(예: 인터넷 연결 끊김)
Debug.Log($"<color=red> Disconnected from server : {cause} </color>");
}
UpdateCntNetworkClientState();
OnDisconnectedAction?.Invoke();
}
public override void OnJoinedLobby()
{
UpdateCntNetworkClientState();
OnJoinedLobbyAction?.Invoke();
}
public override void OnJoinedRoom()
{
string userId = PhotonNetwork.LocalPlayer.UserId;
Debug.Log("Joined Room - User ID: " + userId);
OnJoinedRoomAction?.Invoke();
}
public override void OnJoinRoomFailed(short returnCode, string message)
{
OnJoinRoomFailedAction?.Invoke(returnCode, message);
}
public override void OnLeftRoom()
{
OnLeftRoomAction?.Invoke();
}
public void CreateRoomWithNickName(bool _CntReset)
{
if (!_CntReset)
{
string _RoomStringBase = PlayerPrefs.GetString("NickName");
string _UserGuid = PlayerPrefs.GetString("UserGuid");
if (_UserGuid.Length >= _CreateRoomCnt)
PhotonNetwork.CreateRoom(_RoomStringBase + "_#" + _UserGuid[.._CreateRoomCnt++], new RoomOptions { MaxPlayers = maxPlayersPerRoom, CleanupCacheOnLeave = true, PlayerTtl = 1000 });
else Debug.Log("방생성 실패(너무 많은 생성 실패)");
}
else _CreateRoomCnt = 1;
}
#endregion
#region Public Methods
/// <summary>
/// 연결 프로세스를 시작합니다.
/// </summary>
public void Connect()
{
// 연결되었다면 로비에 참여
if (PhotonNetwork.IsConnected) PhotonNetwork.JoinLobby(new TypedLobby("MainLobby", LobbyType.Default));
else
{
PhotonNetwork.GameVersion = gameVersion;
PhotonNetwork.ConnectUsingSettings();
}
}
public void JoinRoom(string _roomName)
{
PhotonNetwork.JoinRoom(_roomName);
}
public void DisconnectMainServer()
{
PhotonNetwork.Disconnect();
}
public void UpdateCntNetworkClientState()
{
CntNetworkClientState = PhotonNetwork.NetworkClientState;
}
#endregion
}
}
using UnityEngine; using UnityEngine.Events; using Photon.Pun; using Photon.Realtime; using TMPro; using Photon.Chat; namespace Com.Lycos7560 { public class NetworkManager : MonoBehaviourPunCallbacks { public static NetworkManager Instance; public Connection _Connection; public Chatting _Chatting; public Lobby _Lobby; public ChatClient _ChatClient { get { return _Chatting._ChatClient; } } #region Private Serializable Fields #endregion #region Private Fields /// <summary> /// 이 클라이언트의 버전 번호입니다. /// 사용자는 gameVersion에 의해 서로 분리되어 있습니다 /// (이를 통해 변경 사항을 변경할 수 있습니다). /// </summary> string gameVersion = "1"; /// <summary> /// 룸당 최대 플레이어 수입니다. /// 방이 꽉 차면 새로운 플레이어가 참여할 수 없기 때문에 새로운 방이 만들어집니다. /// </summary> [Tooltip("방이 꽉 차면 새로운 플레이어가 참여할 수 없기 때문에 새로운 방이 만들어집니다.")] [SerializeField] private byte maxPlayersPerRoom = 5; /// <summary> /// 현재 NetworkClientState의 상태를 나타냅니다. /// </summary> [Tooltip("현재 NetworkClientState의 상태를 나타냅니다. NetworkClientStateCheck 함수를 통하여 업데이트 됩니다")] [SerializeField] private ClientState _CntNetworkClientState = ClientState.PeerCreated; public ClientState CntNetworkClientState { get => _CntNetworkClientState; set { if (_CntNetworkClientState != value) OnChangeNetworkClientState?.Invoke(value); _CntNetworkClientState = value; } } [Tooltip("방생성을 시도한 횟수입니다.")] [SerializeField] private int _CreateRoomCnt = 1; #endregion #region public Fields #endregion public UnityAction<ClientState> OnChangeNetworkClientState; public UnityAction OnDisconnectedAction; public UnityAction OnJoinedLobbyAction; public UnityAction OnJoinedRoomAction; public UnityAction<short, string> OnJoinRoomFailedAction; public UnityAction OnLeftRoomAction; #region MonoBehaviour CallBacks /// <summary> /// MonoBehavior 메서드는 초기 초기화 단계에서 Unity에 의해 GameObject에 호출되었습니다. /// </summary> void Awake() { Instance = this; // #Critical // 이렇게하면 PhotonNetwork를 사용할 수 있습니다. // 마스터 클라이언트의 LoadLevel()과 동일한 룸에 있는 모든 클라이언트의 LoadLevel이 자동으로 동기화됩니다 PhotonNetwork.AutomaticallySyncScene = true; UpdateCntNetworkClientState(); } /// <summary> /// 마스터 서버에 진입한 후에 바로 실행 /// </summary> public override void OnConnectedToMaster() { UpdateCntNetworkClientState(); PhotonNetwork.JoinLobby(); PhotonNetwork.NickName = PlayerPrefs.GetString("NickName"); } /// <summary> /// 접속이 종료되었을 경우 실행된다. /// </summary> /// <param name="cause"></param> public override void OnDisconnected(DisconnectCause cause) { if (cause == DisconnectCause.DisconnectByServerLogic) { // 로비 입장 실패 Debug.LogFormat($"<color=red> Failed to enter lobby : {cause} </color>"); } else { // 기타 연결 끊김 원인(예: 인터넷 연결 끊김) Debug.Log($"<color=red> Disconnected from server : {cause} </color>"); } UpdateCntNetworkClientState(); OnDisconnectedAction?.Invoke(); } public override void OnJoinedLobby() { UpdateCntNetworkClientState(); OnJoinedLobbyAction?.Invoke(); } public override void OnJoinedRoom() { string userId = PhotonNetwork.LocalPlayer.UserId; Debug.Log("Joined Room - User ID: " + userId); OnJoinedRoomAction?.Invoke(); } public override void OnJoinRoomFailed(short returnCode, string message) { OnJoinRoomFailedAction?.Invoke(returnCode, message); } public override void OnLeftRoom() { OnLeftRoomAction?.Invoke(); } public void CreateRoomWithNickName(bool _CntReset) { if (!_CntReset) { string _RoomStringBase = PlayerPrefs.GetString("NickName"); string _UserGuid = PlayerPrefs.GetString("UserGuid"); if (_UserGuid.Length >= _CreateRoomCnt) PhotonNetwork.CreateRoom(_RoomStringBase + "_#" + _UserGuid[.._CreateRoomCnt++], new RoomOptions { MaxPlayers = maxPlayersPerRoom, CleanupCacheOnLeave = true, PlayerTtl = 1000 }); else Debug.Log("방생성 실패(너무 많은 생성 실패)"); } else _CreateRoomCnt = 1; } #endregion #region Public Methods /// <summary> /// 연결 프로세스를 시작합니다. /// </summary> public void Connect() { // 연결되었다면 로비에 참여 if (PhotonNetwork.IsConnected) PhotonNetwork.JoinLobby(new TypedLobby("MainLobby", LobbyType.Default)); else { PhotonNetwork.GameVersion = gameVersion; PhotonNetwork.ConnectUsingSettings(); } } public void JoinRoom(string _roomName) { PhotonNetwork.JoinRoom(_roomName); } public void DisconnectMainServer() { PhotonNetwork.Disconnect(); } public void UpdateCntNetworkClientState() { CntNetworkClientState = PhotonNetwork.NetworkClientState; } #endregion } }
using UnityEngine;
using UnityEngine.Events;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using Photon.Chat;

namespace Com.Lycos7560
{
    public class NetworkManager : MonoBehaviourPunCallbacks
    {
        public static NetworkManager Instance;

        public Connection _Connection;
        public Chatting _Chatting;
        public Lobby _Lobby;


        public ChatClient _ChatClient { get { return _Chatting._ChatClient; } }

        #region Private Serializable Fields
        #endregion

        #region Private Fields

        /// <summary>
        /// 이 클라이언트의 버전 번호입니다.
        /// 사용자는 gameVersion에 의해 서로 분리되어 있습니다 
        /// (이를 통해 변경 사항을 변경할 수 있습니다).
        /// </summary>
        string gameVersion = "1";

        /// <summary>
        /// 룸당 최대 플레이어 수입니다. 
        /// 방이 꽉 차면 새로운 플레이어가 참여할 수 없기 때문에 새로운 방이 만들어집니다.
        /// </summary>
        [Tooltip("방이 꽉 차면 새로운 플레이어가 참여할 수 없기 때문에 새로운 방이 만들어집니다.")]
        [SerializeField]
        private byte maxPlayersPerRoom = 5;


        /// <summary>
        /// 현재 NetworkClientState의 상태를 나타냅니다.
        /// </summary>
        [Tooltip("현재 NetworkClientState의 상태를 나타냅니다. NetworkClientStateCheck 함수를 통하여 업데이트 됩니다")]
        [SerializeField]
        private ClientState _CntNetworkClientState = ClientState.PeerCreated;

        public ClientState CntNetworkClientState
        {
            get => _CntNetworkClientState;
            set
            {
                if (_CntNetworkClientState != value)
                    OnChangeNetworkClientState?.Invoke(value);
                _CntNetworkClientState = value;
            }
        }

        [Tooltip("방생성을 시도한 횟수입니다.")]
        [SerializeField]
        private int _CreateRoomCnt = 1;

        #endregion

        #region public Fields

        #endregion

        public UnityAction<ClientState> OnChangeNetworkClientState;

        public UnityAction OnDisconnectedAction;

        public UnityAction OnJoinedLobbyAction;

        public UnityAction OnJoinedRoomAction;

        public UnityAction<short, string> OnJoinRoomFailedAction;

        public UnityAction OnLeftRoomAction;



        #region MonoBehaviour CallBacks

        /// <summary>
        /// MonoBehavior 메서드는 초기 초기화 단계에서 Unity에 의해 GameObject에 호출되었습니다.
        /// </summary>
        void Awake()
        {
            Instance = this;
            // #Critical
            // 이렇게하면 PhotonNetwork를 사용할 수 있습니다.
            // 마스터 클라이언트의 LoadLevel()과 동일한 룸에 있는 모든 클라이언트의 LoadLevel이 자동으로 동기화됩니다
            PhotonNetwork.AutomaticallySyncScene = true;
            UpdateCntNetworkClientState();

        }

        /// <summary>
        /// 마스터 서버에 진입한 후에 바로 실행
        /// </summary>
        public override void OnConnectedToMaster()
        {
            UpdateCntNetworkClientState();
            PhotonNetwork.JoinLobby();
            PhotonNetwork.NickName = PlayerPrefs.GetString("NickName");
        }

        /// <summary>
        /// 접속이 종료되었을 경우 실행된다.
        /// </summary>
        /// <param name="cause"></param>
        public override void OnDisconnected(DisconnectCause cause)
        {

            if (cause == DisconnectCause.DisconnectByServerLogic)
            {
                // 로비 입장 실패
                Debug.LogFormat($"<color=red> Failed to enter lobby : {cause} </color>");
            }
            else
            {
                // 기타 연결 끊김 원인(예: 인터넷 연결 끊김)
                Debug.Log($"<color=red> Disconnected from server : {cause} </color>");
            }
            UpdateCntNetworkClientState();
            OnDisconnectedAction?.Invoke();
        }

        public override void OnJoinedLobby()
        {
            UpdateCntNetworkClientState();
            OnJoinedLobbyAction?.Invoke();
        }

        public override void OnJoinedRoom()
        {

            string userId = PhotonNetwork.LocalPlayer.UserId;
            Debug.Log("Joined Room - User ID: " + userId);

            OnJoinedRoomAction?.Invoke();

        }

        public override void OnJoinRoomFailed(short returnCode, string message)
        {
            
            OnJoinRoomFailedAction?.Invoke(returnCode, message);
        }


        public override void OnLeftRoom()
        {
            OnLeftRoomAction?.Invoke();
        }

        public void CreateRoomWithNickName(bool _CntReset)
        {
            if (!_CntReset)
            {
                string _RoomStringBase = PlayerPrefs.GetString("NickName");
                string _UserGuid = PlayerPrefs.GetString("UserGuid");
                if (_UserGuid.Length >= _CreateRoomCnt)
                    PhotonNetwork.CreateRoom(_RoomStringBase + "_#" + _UserGuid[.._CreateRoomCnt++], new RoomOptions { MaxPlayers = maxPlayersPerRoom, CleanupCacheOnLeave = true, PlayerTtl = 1000 });
                else Debug.Log("방생성 실패(너무 많은 생성 실패)");
                
            }
            else _CreateRoomCnt = 1;
            

        }

        #endregion



        #region Public Methods

        /// <summary>
        /// 연결 프로세스를 시작합니다.
        /// </summary>
        public void Connect()
        {
            // 연결되었다면 로비에 참여
            if (PhotonNetwork.IsConnected) PhotonNetwork.JoinLobby(new TypedLobby("MainLobby", LobbyType.Default));
            else
            {
                PhotonNetwork.GameVersion = gameVersion;
                PhotonNetwork.ConnectUsingSettings();
            }
        }

        public void JoinRoom(string _roomName)
        {
            PhotonNetwork.JoinRoom(_roomName);
        }

        public void DisconnectMainServer()
        {
            PhotonNetwork.Disconnect();
        }

        public void UpdateCntNetworkClientState()
        {
            CntNetworkClientState = PhotonNetwork.NetworkClientState;
        }

        #endregion

    }
}

RoomItem.CS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using UnityEngine;
using UnityEngine.UI;
using TMPro;
namespace Com.Lycos7560
{
public class RoomItem : MonoBehaviour
{
public TMP_Text RoomName;
public TMP_Text PeopleNumber;
public Button JoinRoomBtn;
public void ChangeRoomInfo(string _name, int _cnt, int _max)
{
RoomName.text = _name;
PeopleNumber.text = string.Format($"{_cnt} / {_max}");
}
}
}
using UnityEngine; using UnityEngine.UI; using TMPro; namespace Com.Lycos7560 { public class RoomItem : MonoBehaviour { public TMP_Text RoomName; public TMP_Text PeopleNumber; public Button JoinRoomBtn; public void ChangeRoomInfo(string _name, int _cnt, int _max) { RoomName.text = _name; PeopleNumber.text = string.Format($"{_cnt} / {_max}"); } } }
using UnityEngine;
using UnityEngine.UI;
using TMPro;

namespace Com.Lycos7560
{
    public class RoomItem : MonoBehaviour
    {
        public TMP_Text RoomName;
        public TMP_Text PeopleNumber;
        public Button JoinRoomBtn;

        public void ChangeRoomInfo(string _name, int _cnt, int _max)
        {
            RoomName.text = _name;
            PeopleNumber.text = string.Format($"{_cnt} / {_max}");
        }



    }
}

Photon PUN2 + Chat + Voice

Chatting.CS (수정)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Chat;
using Photon.Voice.Unity;
using ExitGames.Client.Photon;
namespace Com.Lycos7560
{
public class Chatting : MonoBehaviourPunCallbacks, IChatClientListener
{
public ChatClient _ChatClient;
public GameObject ChattingMain;
public Button _CloseChattingMainBtn;
public TMP_Text _ServerStateText;
public TMP_InputField _ChatInputField;
public Button _ChatSendBtn;
public TMP_Text _ChattingContentText;
public TMP_Text SubscribeUsersText;
public ChatChannel _CntChatChannel;
public GameObject _PlayerSpeaker;
#region IChatClientListener CallBacks
public void OnGetMessages(string channelName, string[] senders, object[] messages)
{
for (int i = 0; i < senders.Length; i++)
{
string sender = senders[i];
string message = messages[i].ToString();
string chatMessage = $"[{sender}]: {message}";
// 채팅 메시지 추가
_ChattingContentText.text += chatMessage + "\n";
}
}
// 개인 메시지(귓속말) 미구현
public void OnPrivateMessage(string sender, object message, string channelName)
{
Debug.Log("Private message from [" + sender + "]: " + message);
}
// 접속한 Room의 이름과 관련된 채널 구독이 성공 CallBack
public void OnSubscribed(string[] channels, bool[] results)
{
_ChattingContentText.text = string.Empty;
// 채널을 캐싱해준다. (구독 완료된 시점)
if (_ChatClient.TryGetChannel("Room_" + PhotonNetwork.CurrentRoom.Name, out _CntChatChannel))
//// 나가기 버튼 활성화
//_CloseChattingMainBtn.gameObject.SetActive(true);
// 첫 화면 출력
_ChattingContentText.text += " Welcome to Photon Chat. \n";
UpdateSubscribeUsersText();
/* 디버깅
for (int i = 0; i < channels.Length; i++)
Debug.Log("Subscribed to Channel: " + channels[i]);
*/
}
// 접속한 Room의 이름과 관련된 채널 구독을 해제 CallBack
public void OnUnsubscribed(string[] channels)
{
// 구독 해제와 동시에 Clear
_ChattingContentText.text = string.Empty;
/* 디버깅
for (int i = 0; i < channels.Length; i++)
Debug.Log("Unsubscribed from Channel: " + channels[i]);
*/
}
// 디버그 CallBack 미구현
public void DebugReturn(DebugLevel level, string message)
{
Debug.Log("Debug: " + level + " - " + message);
}
// 디버그 CallBack 미구현
public void OnDisconnected()
{
Debug.Log("Disconnected from Chat Server");
}
// 디버그 CallBack 미구현
public void OnChatStateChange(ChatState state)
{
_ServerStateText.text = string.Format($"Server State : {state}");
}
// 디버그 CallBack 미구현
public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
{
Debug.Log("Status Update - User: " + user + ", Status: " + status);
}
// 어떤 유저가 해당 채널을 구독 CallBack
public void OnUserSubscribed(string channel, string user)
{
// 메시지 창에 어떤 유저가 구독했는지 출력
string message = $"<color=#06FF00>'{user}' has joined '{channel}'</color>";
_ChattingContentText.text += message + "\n";
UpdateSubscribeUsersText();
}
// 어떤 유저가 해당 채널을 구독 해제 CallBack
public void OnUserUnsubscribed(string channel, string user)
{
// 메시지 창에 어떤 유저가 구독을 해제했는지 출력
string message = $"<color=#FF0000> '{user}' has left '{channel}'</color>";
_ChattingContentText.text += message + "\n";
UpdateSubscribeUsersText();
}
#endregion
#region MonoBehaviour
private void Awake()
{
ChattingMain.SetActive(false);
_CloseChattingMainBtn.onClick.AddListener(() => {
// 나가기 버튼 비활성화
_CloseChattingMainBtn.gameObject.SetActive(false);
PhotonNetwork.LeaveRoom();
});
_ChatSendBtn.onClick.AddListener(() => {
if (_ChatInputField.text == string.Empty) return;
else {
SendRoomMessage(_ChatInputField.text);
_ChatInputField.text = string.Empty;
}
});
}
private void Start()
{
// 액션 등록
NetworkManager.Instance.OnJoinedRoomAction += ChattingOnJoinedRoom;
NetworkManager.Instance.OnLeftRoomAction += ChattingOnLeftRoom;
NetworkManager.Instance.OnJoinedLobbyAction += ChattingOnJoinedLobby;
}
private void Update()
{
// !!필수!!
// ChatClient의 콜백 처리를 위해 주기적으로 호출
if (_ChatClient != null)
_ChatClient.Service();
}
#endregion
#region ActionFuctions
/// <summary>
/// 로비에 접속하면 Chatting Server를 활성화 시킨다.
/// </summary>
private void ChattingOnJoinedLobby()
{
// 구독 전에 나가는 것을 방지
_CloseChattingMainBtn.gameObject.SetActive(false);
if (_ChatClient == null) {
// 로비에 접속한 후 ChatClient 초기화 및 연결
_ChatClient = new ChatClient(this);
_ChatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new Photon.Chat.AuthenticationValues(PhotonNetwork.NickName));
Debug.LogFormat($"Chatting Server 초기화 및 연결 시작");
}
}
/// <summary>
/// Room에 접속하면 실행되는 함수
/// Room의 이름과 관련된 채팅 서버에 접속한다.
/// </summary>
private void ChattingOnJoinedRoom()
{
_ChattingContentText.text = string.Empty;
ChattingMain.SetActive(true);
string _Channel = "Room_" + PhotonNetwork.CurrentRoom.Name; // 가입할 채널 이름 배열
_ChatClient.Subscribe(_Channel, 0, -1, new ChannelCreationOptions { PublishSubscribers = true } ); // 채널에 구독
Debug.LogFormat($"{"Room_" + PhotonNetwork.CurrentRoom.Name} :: 구독");
_PlayerSpeaker = PhotonNetwork.Instantiate("PlayerVoiceChatPrefab", Vector3.zero, Quaternion.identity);
_PlayerSpeaker.GetComponent<Speaker>().enabled = false;
_PlayerSpeaker.GetComponent<AudioSource>().enabled = false;
// 나가기 버튼 활성화
_CloseChattingMainBtn.gameObject.SetActive(true);
}
/// <summary>
/// Room에서 나갈 경우 실행되는 함수
/// </summary>
private void ChattingOnLeftRoom()
{
PhotonNetwork.Destroy(_PlayerSpeaker.GetPhotonView());
string[] _Channels = new string[] { _CntChatChannel.Name };
_ChatClient.Unsubscribe(_Channels);
_CntChatChannel = null;
ChattingMain.SetActive(false);
}
#endregion
/// <summary>
/// 구독한 Channel에 메시지를 보냅니다.
/// </summary>
/// <param name="message"></param>
private void SendRoomMessage(string message)
{
if (_ChatClient != null && _ChatClient.CanChat) {
// _ChatClient가 구독한 방에 메시지를 보냅니다.
_ChatClient.PublishMessage("Room_" + PhotonNetwork.CurrentRoom.Name, message);
}
}
/// <summary>
/// 체널의 있는 유저들의 정보를 갱신합니다.
/// </summary>
private void UpdateSubscribeUsersText()
{
if (_ChatClient != null && _CntChatChannel != null) {
var _Users = _CntChatChannel.Subscribers;
SubscribeUsersText.text = string.Empty;
foreach (var _user in _Users)
SubscribeUsersText.text += _user + " ";
}
else SubscribeUsersText.text = "There is a problem with the network.";
}
}
}
using UnityEngine; using UnityEngine.UI; using TMPro; using Photon.Pun; using Photon.Chat; using Photon.Voice.Unity; using ExitGames.Client.Photon; namespace Com.Lycos7560 { public class Chatting : MonoBehaviourPunCallbacks, IChatClientListener { public ChatClient _ChatClient; public GameObject ChattingMain; public Button _CloseChattingMainBtn; public TMP_Text _ServerStateText; public TMP_InputField _ChatInputField; public Button _ChatSendBtn; public TMP_Text _ChattingContentText; public TMP_Text SubscribeUsersText; public ChatChannel _CntChatChannel; public GameObject _PlayerSpeaker; #region IChatClientListener CallBacks public void OnGetMessages(string channelName, string[] senders, object[] messages) { for (int i = 0; i < senders.Length; i++) { string sender = senders[i]; string message = messages[i].ToString(); string chatMessage = $"[{sender}]: {message}"; // 채팅 메시지 추가 _ChattingContentText.text += chatMessage + "\n"; } } // 개인 메시지(귓속말) 미구현 public void OnPrivateMessage(string sender, object message, string channelName) { Debug.Log("Private message from [" + sender + "]: " + message); } // 접속한 Room의 이름과 관련된 채널 구독이 성공 CallBack public void OnSubscribed(string[] channels, bool[] results) { _ChattingContentText.text = string.Empty; // 채널을 캐싱해준다. (구독 완료된 시점) if (_ChatClient.TryGetChannel("Room_" + PhotonNetwork.CurrentRoom.Name, out _CntChatChannel)) //// 나가기 버튼 활성화 //_CloseChattingMainBtn.gameObject.SetActive(true); // 첫 화면 출력 _ChattingContentText.text += " Welcome to Photon Chat. \n"; UpdateSubscribeUsersText(); /* 디버깅 for (int i = 0; i < channels.Length; i++) Debug.Log("Subscribed to Channel: " + channels[i]); */ } // 접속한 Room의 이름과 관련된 채널 구독을 해제 CallBack public void OnUnsubscribed(string[] channels) { // 구독 해제와 동시에 Clear _ChattingContentText.text = string.Empty; /* 디버깅 for (int i = 0; i < channels.Length; i++) Debug.Log("Unsubscribed from Channel: " + channels[i]); */ } // 디버그 CallBack 미구현 public void DebugReturn(DebugLevel level, string message) { Debug.Log("Debug: " + level + " - " + message); } // 디버그 CallBack 미구현 public void OnDisconnected() { Debug.Log("Disconnected from Chat Server"); } // 디버그 CallBack 미구현 public void OnChatStateChange(ChatState state) { _ServerStateText.text = string.Format($"Server State : {state}"); } // 디버그 CallBack 미구현 public void OnStatusUpdate(string user, int status, bool gotMessage, object message) { Debug.Log("Status Update - User: " + user + ", Status: " + status); } // 어떤 유저가 해당 채널을 구독 CallBack public void OnUserSubscribed(string channel, string user) { // 메시지 창에 어떤 유저가 구독했는지 출력 string message = $"<color=#06FF00>'{user}' has joined '{channel}'</color>"; _ChattingContentText.text += message + "\n"; UpdateSubscribeUsersText(); } // 어떤 유저가 해당 채널을 구독 해제 CallBack public void OnUserUnsubscribed(string channel, string user) { // 메시지 창에 어떤 유저가 구독을 해제했는지 출력 string message = $"<color=#FF0000> '{user}' has left '{channel}'</color>"; _ChattingContentText.text += message + "\n"; UpdateSubscribeUsersText(); } #endregion #region MonoBehaviour private void Awake() { ChattingMain.SetActive(false); _CloseChattingMainBtn.onClick.AddListener(() => { // 나가기 버튼 비활성화 _CloseChattingMainBtn.gameObject.SetActive(false); PhotonNetwork.LeaveRoom(); }); _ChatSendBtn.onClick.AddListener(() => { if (_ChatInputField.text == string.Empty) return; else { SendRoomMessage(_ChatInputField.text); _ChatInputField.text = string.Empty; } }); } private void Start() { // 액션 등록 NetworkManager.Instance.OnJoinedRoomAction += ChattingOnJoinedRoom; NetworkManager.Instance.OnLeftRoomAction += ChattingOnLeftRoom; NetworkManager.Instance.OnJoinedLobbyAction += ChattingOnJoinedLobby; } private void Update() { // !!필수!! // ChatClient의 콜백 처리를 위해 주기적으로 호출 if (_ChatClient != null) _ChatClient.Service(); } #endregion #region ActionFuctions /// <summary> /// 로비에 접속하면 Chatting Server를 활성화 시킨다. /// </summary> private void ChattingOnJoinedLobby() { // 구독 전에 나가는 것을 방지 _CloseChattingMainBtn.gameObject.SetActive(false); if (_ChatClient == null) { // 로비에 접속한 후 ChatClient 초기화 및 연결 _ChatClient = new ChatClient(this); _ChatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new Photon.Chat.AuthenticationValues(PhotonNetwork.NickName)); Debug.LogFormat($"Chatting Server 초기화 및 연결 시작"); } } /// <summary> /// Room에 접속하면 실행되는 함수 /// Room의 이름과 관련된 채팅 서버에 접속한다. /// </summary> private void ChattingOnJoinedRoom() { _ChattingContentText.text = string.Empty; ChattingMain.SetActive(true); string _Channel = "Room_" + PhotonNetwork.CurrentRoom.Name; // 가입할 채널 이름 배열 _ChatClient.Subscribe(_Channel, 0, -1, new ChannelCreationOptions { PublishSubscribers = true } ); // 채널에 구독 Debug.LogFormat($"{"Room_" + PhotonNetwork.CurrentRoom.Name} :: 구독"); _PlayerSpeaker = PhotonNetwork.Instantiate("PlayerVoiceChatPrefab", Vector3.zero, Quaternion.identity); _PlayerSpeaker.GetComponent<Speaker>().enabled = false; _PlayerSpeaker.GetComponent<AudioSource>().enabled = false; // 나가기 버튼 활성화 _CloseChattingMainBtn.gameObject.SetActive(true); } /// <summary> /// Room에서 나갈 경우 실행되는 함수 /// </summary> private void ChattingOnLeftRoom() { PhotonNetwork.Destroy(_PlayerSpeaker.GetPhotonView()); string[] _Channels = new string[] { _CntChatChannel.Name }; _ChatClient.Unsubscribe(_Channels); _CntChatChannel = null; ChattingMain.SetActive(false); } #endregion /// <summary> /// 구독한 Channel에 메시지를 보냅니다. /// </summary> /// <param name="message"></param> private void SendRoomMessage(string message) { if (_ChatClient != null && _ChatClient.CanChat) { // _ChatClient가 구독한 방에 메시지를 보냅니다. _ChatClient.PublishMessage("Room_" + PhotonNetwork.CurrentRoom.Name, message); } } /// <summary> /// 체널의 있는 유저들의 정보를 갱신합니다. /// </summary> private void UpdateSubscribeUsersText() { if (_ChatClient != null && _CntChatChannel != null) { var _Users = _CntChatChannel.Subscribers; SubscribeUsersText.text = string.Empty; foreach (var _user in _Users) SubscribeUsersText.text += _user + " "; } else SubscribeUsersText.text = "There is a problem with the network."; } } }
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Photon.Pun;
using Photon.Chat;
using Photon.Voice.Unity;
using ExitGames.Client.Photon;

namespace Com.Lycos7560
{
    public class Chatting : MonoBehaviourPunCallbacks, IChatClientListener
    {
        public ChatClient _ChatClient;

        public GameObject ChattingMain;

        public Button _CloseChattingMainBtn;

        public TMP_Text _ServerStateText;

        public TMP_InputField _ChatInputField;

        public Button _ChatSendBtn;

        public TMP_Text _ChattingContentText;
        public TMP_Text SubscribeUsersText;

        public ChatChannel _CntChatChannel;

        public GameObject _PlayerSpeaker;

        #region IChatClientListener CallBacks

        public void OnGetMessages(string channelName, string[] senders, object[] messages)
        {
            for (int i = 0; i < senders.Length; i++)
            {
                string sender = senders[i];
                string message = messages[i].ToString();

                string chatMessage = $"[{sender}]: {message}";

                // 채팅 메시지 추가
                _ChattingContentText.text += chatMessage + "\n";
            }
        }

        // 개인 메시지(귓속말) 미구현
        public void OnPrivateMessage(string sender, object message, string channelName)
        {
            Debug.Log("Private message from [" + sender + "]: " + message);
        }

        // 접속한 Room의 이름과 관련된 채널 구독이 성공 CallBack
        public void OnSubscribed(string[] channels, bool[] results)
        {
            _ChattingContentText.text = string.Empty;
            // 채널을 캐싱해준다. (구독 완료된 시점)
            if (_ChatClient.TryGetChannel("Room_" + PhotonNetwork.CurrentRoom.Name, out _CntChatChannel))  

            //// 나가기 버튼 활성화
            //_CloseChattingMainBtn.gameObject.SetActive(true); 

            // 첫 화면 출력
            _ChattingContentText.text += " Welcome to Photon Chat. \n";
            UpdateSubscribeUsersText();
            /* 디버깅
            for (int i = 0; i < channels.Length; i++)
                Debug.Log("Subscribed to Channel: " + channels[i]); 
            */
        }

        // 접속한 Room의 이름과 관련된 채널 구독을 해제 CallBack
        public void OnUnsubscribed(string[] channels)
        {
            // 구독 해제와 동시에 Clear
            _ChattingContentText.text = string.Empty;
            /* 디버깅
            for (int i = 0; i < channels.Length; i++)
                Debug.Log("Unsubscribed from Channel: " + channels[i]);
            */
        }

        // 디버그 CallBack 미구현
        public void DebugReturn(DebugLevel level, string message)
        {
            Debug.Log("Debug: " + level + " - " + message);
        }

        // 디버그 CallBack 미구현
        public void OnDisconnected()
        {
            Debug.Log("Disconnected from Chat Server");
        }

        // 디버그 CallBack 미구현
        public void OnChatStateChange(ChatState state)
        {
            _ServerStateText.text = string.Format($"Server State : {state}");
        }

        // 디버그 CallBack 미구현
        public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
        {
            Debug.Log("Status Update - User: " + user + ", Status: " + status);
        }

        //  어떤 유저가 해당 채널을 구독 CallBack
        public void OnUserSubscribed(string channel, string user)
        {
            // 메시지 창에 어떤 유저가 구독했는지 출력
            string message = $"<color=#06FF00>'{user}' has joined '{channel}'</color>";
            _ChattingContentText.text += message + "\n";
            UpdateSubscribeUsersText();
        }

        //  어떤 유저가 해당 채널을 구독 해제 CallBack
        public void OnUserUnsubscribed(string channel, string user)
        {
            // 메시지 창에 어떤 유저가 구독을 해제했는지 출력
            string message = $"<color=#FF0000> '{user}' has left '{channel}'</color>";
            _ChattingContentText.text += message + "\n";
            UpdateSubscribeUsersText();
        }


        #endregion


        #region MonoBehaviour

        private void Awake()
        {         
            ChattingMain.SetActive(false);
            _CloseChattingMainBtn.onClick.AddListener(() => {
                // 나가기 버튼 비활성화
                _CloseChattingMainBtn.gameObject.SetActive(false);
                PhotonNetwork.LeaveRoom();
            });
            _ChatSendBtn.onClick.AddListener(() => {
                if (_ChatInputField.text == string.Empty) return;
                else {
                    SendRoomMessage(_ChatInputField.text);
                    _ChatInputField.text = string.Empty;
                }
            });
        }

        private void Start()
        {
            // 액션 등록
            NetworkManager.Instance.OnJoinedRoomAction += ChattingOnJoinedRoom;
            NetworkManager.Instance.OnLeftRoomAction += ChattingOnLeftRoom;
            NetworkManager.Instance.OnJoinedLobbyAction += ChattingOnJoinedLobby;
        }

        private void Update()
        {
            // !!필수!!
            // ChatClient의 콜백 처리를 위해 주기적으로 호출
            if (_ChatClient != null)
                _ChatClient.Service();
        }

        #endregion



        #region ActionFuctions

        /// <summary>
        /// 로비에 접속하면 Chatting Server를 활성화 시킨다.
        /// </summary>
        private void ChattingOnJoinedLobby()
        {
            // 구독 전에 나가는 것을 방지
            _CloseChattingMainBtn.gameObject.SetActive(false); 

            if (_ChatClient == null) {
                // 로비에 접속한 후 ChatClient 초기화 및 연결
                _ChatClient = new ChatClient(this);
                _ChatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new Photon.Chat.AuthenticationValues(PhotonNetwork.NickName));
                Debug.LogFormat($"Chatting Server 초기화 및 연결 시작");
            }
        }

        /// <summary>
        ///  Room에 접속하면 실행되는 함수
        ///  Room의 이름과 관련된 채팅 서버에 접속한다.
        /// </summary>
        private void ChattingOnJoinedRoom()
        {
            _ChattingContentText.text = string.Empty;
            ChattingMain.SetActive(true);
            string _Channel = "Room_" + PhotonNetwork.CurrentRoom.Name; // 가입할 채널 이름 배열
            _ChatClient.Subscribe(_Channel, 0, -1, new ChannelCreationOptions { PublishSubscribers = true } ); // 채널에 구독
            Debug.LogFormat($"{"Room_" + PhotonNetwork.CurrentRoom.Name} :: 구독");

            _PlayerSpeaker = PhotonNetwork.Instantiate("PlayerVoiceChatPrefab", Vector3.zero, Quaternion.identity);
            _PlayerSpeaker.GetComponent<Speaker>().enabled = false;
            _PlayerSpeaker.GetComponent<AudioSource>().enabled = false;
            // 나가기 버튼 활성화
            _CloseChattingMainBtn.gameObject.SetActive(true);
        }

        /// <summary>
        /// Room에서 나갈 경우 실행되는 함수
        /// </summary>
        private void ChattingOnLeftRoom()
        {
            PhotonNetwork.Destroy(_PlayerSpeaker.GetPhotonView());
            string[] _Channels = new string[] { _CntChatChannel.Name };
            _ChatClient.Unsubscribe(_Channels);
            _CntChatChannel = null;
            ChattingMain.SetActive(false);
        }

        #endregion

        /// <summary>
        /// 구독한 Channel에 메시지를 보냅니다.
        /// </summary>
        /// <param name="message"></param>
        private void SendRoomMessage(string message)
        {
            if (_ChatClient != null && _ChatClient.CanChat) {
                //  _ChatClient가 구독한 방에 메시지를 보냅니다.
                _ChatClient.PublishMessage("Room_" + PhotonNetwork.CurrentRoom.Name, message);
            }
        }

        /// <summary>
        /// 체널의 있는 유저들의 정보를 갱신합니다.
        /// </summary>
        private void UpdateSubscribeUsersText()
        {
            if (_ChatClient != null && _CntChatChannel != null) {
                var _Users = _CntChatChannel.Subscribers;
                SubscribeUsersText.text = string.Empty;
                foreach (var _user in _Users)
                    SubscribeUsersText.text += _user + "  ";               
            }
            else SubscribeUsersText.text = "There is a problem with the network.";
           
        }
    }






}

APK File

  • 마이크 온오프 기능 추가
  • 스피커 관련 오류 수정

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다