ChatManager
채팅 시스템의 싱글톤 매니저 클래스입니다. 채팅 서버 연결 및 메시지 송수신을 관리합니다.
URL 확인
이 API는 service-api.playnanoo.com 도메인을 사용합니다.
API 정보
- 서버 목록 URL:
https://service-api.playnanoo.com/chat/v20211101/server - 필터 URL:
https://service-api.playnanoo.com/chat/v20211101/filter - Method:
PUT - 인증 필요: 아니오
주요 기능
| 메서드 | 설명 |
|---|---|
| Connect | 채팅 서버에 연결 |
| IsConnected | 연결 상태 확인 |
| Subscribe | 채널 구독 (이전 메시지 개수 설정 가능) |
| Unsubscribe | 채널 구독 해제 |
| GetChannels | 채널 목록 조회 |
| GetPlayersOnline | 플레이어 온라인 상태 조회 |
| SendPublicMessage | 공개 메시지 전송 |
| SendPrivateMessage | 비공개 메시지 전송 |
| FetchFilterWords | 금칙어 목록 가져오기 |
| Filter | 메시지에 금칙어 필터 적용 |
Unity C# 구현
using System.Collections;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Networking;
public class ChatManager : MonoBehaviour
{
public static ChatManager Instance
{
get
{
if (_instance == null)
{
var go = new GameObject("ChatManager");
_instance = go.AddComponent<ChatManager>();
}
return _instance;
}
}
private static ChatManager _instance;
private const string CHAT_SERVER_URL = "https://service-api.playnanoo.com/chat/v20211101/server";
private const string CHAT_FILTER_URL = "https://service-api.playnanoo.com/chat/v20211101/filter";
private ChatClient _chatClient;
private IChatListener _listener;
private string[] _filterWords;
void Awake()
{
if (_instance != null && _instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
DontDestroyOnLoad(gameObject);
}
public void Connect(IChatListener listener)
{
_listener = listener;
_chatClient = new ChatClient(listener, DataManager.Instance.Nickname);
StartCoroutine(FetchServerListAndConnect());
}
void Update()
{
// 실시간 메시지를 수신하기 위해선 지속적으로 이벤트를 발생 시켜야 합니다.
// 메시지 수신 이벤트가 실행 되지 않는 경우 사용자의 메시지가 수신 되지 않습니다.
_chatClient?.Service();
}
void OnDestroy()
{
if (_instance == this)
_instance = null;
_chatClient?.Disconnect();
}
#region Server Connection
private IEnumerator FetchServerListAndConnect()
{
bool done = false;
ChatServerResponse response = null;
string error = null;
yield return HttpClient.Send<object, ChatServerResponse>(
UnityWebRequest.kHttpVerbPUT, CHAT_SERVER_URL, false, null,
res => { response = res; done = true; },
err => { error = err?.Message; done = true; });
while (!done) yield return null;
if (error != null || response?.Servers == null || response.Servers.Length == 0)
{
_listener?.OnError("SERVER_LIST_FAILED", "Failed to fetch server list");
yield break;
}
var server = response.Servers[Random.Range(0, response.Servers.Length)];
_chatClient.Connect(server);
}
#endregion
#region Filter
public void FetchFilterWords()
{
StartCoroutine(FetchFilterWordsCoroutine());
}
private IEnumerator FetchFilterWordsCoroutine()
{
bool done = false;
ChatFilterResponse response = null;
yield return HttpClient.Send<object, ChatFilterResponse>(
UnityWebRequest.kHttpVerbPUT, CHAT_FILTER_URL, false, null,
res => { response = res; done = true; },
err => { done = true; });
while (!done) yield return null;
if (response?.FilterWords != null)
_filterWords = response.FilterWords;
}
public string Filter(string message, char separator = '*')
{
if (_filterWords == null || _filterWords.Length == 0)
return message;
foreach (var word in _filterWords)
{
if (!string.IsNullOrEmpty(word))
message = Regex.Replace(message, word, new string(separator, word.Length), RegexOptions.IgnoreCase);
}
return message;
}
#endregion
#region Public API
public bool IsConnected() => _chatClient?.IsConnected ?? false;
public void Subscribe(string channel, int prevMessageCount = 0) => _chatClient?.Subscribe(channel, prevMessageCount);
public void Unsubscribe(string channel) => _chatClient?.Unsubscribe(channel);
public void GetChannels() => _chatClient?.GetChannels();
public void GetPlayersOnline(string[] userIds) => _chatClient?.GetPlayersOnline(userIds);
public void SendPublicMessage(string channel, string text) => _chatClient?.SendPublicMessage(channel, text);
public void SendPrivateMessage(string targetUserId, string text) => _chatClient?.SendPrivateMessage(targetUserId, text);
#endregion
}
사용 예제
public class ChatExample : MonoBehaviour, IChatListener
{
void Start()
{
ChatManager.Instance.Connect(this);
}
public void OnConnected()
{
Debug.Log("채팅 서버 연결 성공");
// 금칙어 목록 가져오기
ChatManager.Instance.FetchFilterWords();
// 이전 채팅 내역 10개 가져오기
ChatManager.Instance.Subscribe("global", 10);
}
public void OnDisconnected()
{
Debug.Log("채팅 서버 연결 해제");
}
public void OnError(string code, string message)
{
Debug.LogError($"채팅 오류: [{code}] {message}");
}
public void OnChannels(ChatChannelInfo[] channels)
{
foreach (var ch in channels)
{
Debug.Log($"채널: {ch.channel}, 인원: {ch.count}");
}
}
public void OnSubscribed(ChatUserInfo user)
{
Debug.Log($"{user.visitorName}님이 입장했습니다.");
}
public void OnUnSubscribed(ChatUserInfo user)
{
Debug.Log($"{user.visitorName}님이 퇴장했습니다.");
}
public void OnPublicMessage(ChatUserInfo sender, string message)
{
// 금칙어 필터 적용
Debug.Log($"[{sender.visitorName}]: {ChatManager.Instance.Filter(message)}");
}
public void OnPrivateMessage(ChatUserInfo sender, string message)
{
// 금칙어 필터 적용
Debug.Log($"[귓속말][{sender.visitorName}]: {ChatManager.Instance.Filter(message)}");
}
public void OnNotifyMessage(ChatUserInfo sender, string message)
{
Debug.Log($"[알림]: {ChatManager.Instance.Filter(message)}");
}
public void OnPlayerOnline(ChatPlayerInfo[] players)
{
foreach (var p in players)
{
Debug.Log($"플레이어: {p.userUniqueId}, 온라인: {p.online}");
}
}
void SendMessage()
{
// 메시지 전송 (서버에 원본 그대로 전송)
ChatManager.Instance.SendPublicMessage("global", "안녕하세요!");
}
}