ChatManager
Singleton manager class for the chat system. Manages chat server connection and message transmission/reception.
URL Verification
This API uses the service-api.playnanoo.com domain.
API Information
- Server List URL:
https://service-api.playnanoo.com/chat/v20211101/server - Filter URL:
https://service-api.playnanoo.com/chat/v20211101/filter - Method:
PUT - Authentication Required: No
Key Features
| Method | Description |
|---|---|
| Connect | Connect to chat server |
| IsConnected | Check connection status |
| Subscribe | Subscribe to channel (with previous message count option) |
| Unsubscribe | Unsubscribe from channel |
| GetChannels | Query channel list |
| GetPlayersOnline | Query player online status |
| SendPublicMessage | Send public message |
| SendPrivateMessage | Send private message |
| FetchFilterWords | Fetch prohibited words list |
| Filter | Apply prohibited word filter to message |
Unity C# Implementation
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()
{
// Continuously trigger events to receive real-time messages.
// If message reception event is not executed, user messages will not be received.
_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
}
Usage Example
public class ChatExample : MonoBehaviour, IChatListener
{
void Start()
{
ChatManager.Instance.Connect(this);
}
public void OnConnected()
{
Debug.Log("Chat server connection successful");
// Fetch prohibited words list
ChatManager.Instance.FetchFilterWords();
// Fetch 10 previous chat messages
ChatManager.Instance.Subscribe("global", 10);
}
public void OnDisconnected()
{
Debug.Log("Chat server disconnected");
}
public void OnError(string code, string message)
{
Debug.LogError($"Chat error: [{code}] {message}");
}
public void OnChannels(ChatChannelInfo[] channels)
{
foreach (var ch in channels)
{
Debug.Log($"Channel: {ch.channel}, Users: {ch.count}");
}
}
public void OnSubscribed(ChatUserInfo user)
{
Debug.Log($"{user.visitorName} has entered.");
}
public void OnUnSubscribed(ChatUserInfo user)
{
Debug.Log($"{user.visitorName} has left.");
}
public void OnPublicMessage(ChatUserInfo sender, string message)
{
// Apply prohibited word filter
Debug.Log($"[{sender.visitorName}]: {ChatManager.Instance.Filter(message)}");
}
public void OnPrivateMessage(ChatUserInfo sender, string message)
{
// Apply prohibited word filter
Debug.Log($"[Whisper][{sender.visitorName}]: {ChatManager.Instance.Filter(message)}");
}
public void OnNotifyMessage(ChatUserInfo sender, string message)
{
Debug.Log($"[Notification]: {ChatManager.Instance.Filter(message)}");
}
public void OnPlayerOnline(ChatPlayerInfo[] players)
{
foreach (var p in players)
{
Debug.Log($"Player: {p.userUniqueId}, Online: {p.online}");
}
}
void SendMessage()
{
// Send message (send original to server)
ChatManager.Instance.SendPublicMessage("global", "Hello!");
}
}