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
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
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
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
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
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
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 (수정)
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
- 마이크 온오프 기능 추가
- 스피커 관련 오류 수정