Chat System Overview
The PlayNANOO chat system provides real-time WebSocket-based chat functionality. This document explains the overall structure and usage of the chat system.
System Architecture
The chat system consists of 3 core classes.
| Class | Role |
|---|---|
| ChatManager | Singleton manager that handles chat server connection and API calls |
| ChatClient | Core class that processes WebSocket connection and message transmission/reception |
| ChatModels | Defines data models and event listener interfaces |
The above 3 classes are required implementation classes and can be freely modified to fit your project structure.
Required Implementation Elements:
- Implement all callback methods of the
IChatListenerinterface - Periodically call the
ChatClient.Service()method in Update() (required for message reception) - Call server list API for WebSocket connection (
PUT /chat/v20211101/server) - Implement HMAC-SHA256 hash authentication logic
Workflow
1. Call ChatManager.Connect()
↓
2. Request server list API (PUT /chat/v20211101/server)
↓
3. Select random server after receiving server list
↓
4. ChatClient performs WebSocket connection
↓
5. Call IChatListener.OnConnected() on successful connection
↓
6. Subscribe to channels and send/receive messages
Step 1: Implement Listener
To receive chat events, you must implement the IChatListener interface.
public class MyChatHandler : MonoBehaviour, IChatListener
{
public void OnConnected()
{
// Server connection successful
Debug.Log("Connected to chat server.");
}
public void OnDisconnected()
{
// Server disconnected
Debug.Log("Disconnected from chat server.");
}
public void OnError(string code, string message)
{
// Error occurred
Debug.LogError($"Error: [{code}] {message}");
}
public void OnChannels(ChatChannelInfo[] channels)
{
// Channel list received
foreach (var ch in channels)
{
Debug.Log($"Channel: {ch.channel}, Users: {ch.count}");
}
}
public void OnSubscribed(ChatUserInfo user)
{
// User entered channel
Debug.Log($"{user.visitorName} has entered.");
}
public void OnUnSubscribed(ChatUserInfo user)
{
// User left channel
Debug.Log($"{user.visitorName} has left.");
}
public void OnPublicMessage(ChatUserInfo sender, string message)
{
// Public message received
Debug.Log($"[{sender.visitorName}]: {message}");
}
public void OnPrivateMessage(ChatUserInfo sender, string message)
{
// Whisper received
Debug.Log($"[Whisper][{sender.visitorName}]: {message}");
}
public void OnNotifyMessage(ChatUserInfo sender, string message)
{
// System notification received
Debug.Log($"[System]: {message}");
}
public void OnPlayerOnline(ChatPlayerInfo[] players)
{
// Player online status received
foreach (var p in players)
{
string status = p.online == "Y" ? "online" : "offline";
Debug.Log($"{p.userUniqueId}: {status}");
}
}
}
Step 2: Connect to Chat Server
Connect to the chat server by calling ChatManager.Instance.Connect().
void Start()
{
// Pass object that implements IChatListener
ChatManager.Instance.Connect(this);
}
When connection is successful, the OnConnected() callback is called.
Step 3: Subscribe to Channel
After connecting, subscribe to the desired channel.
public void OnConnected()
{
// Subscribe to global channel
ChatManager.Instance.Subscribe("global");
// Or subscribe to specific channel
ChatManager.Instance.Subscribe("room_123");
}
Step 4: Send Messages
Send Public Message
Send a message to all users in the channel.
public void SendChatMessage(string text)
{
ChatManager.Instance.SendPublicMessage("global", text);
}
Send Whisper
Send a message only to a specific user.
public void SendWhisper(string targetUserId, string text)
{
ChatManager.Instance.SendPrivateMessage(targetUserId, text);
}
Step 5: Other Features
Query Channel List
ChatManager.Instance.GetChannels();
// Result received in OnChannels() callback
Unsubscribe from Channel
ChatManager.Instance.Unsubscribe("global");
Query Player Online Status
string[] userIds = new string[] { "user_001", "user_002", "user_003" };
ChatManager.Instance.GetPlayersOnline(userIds);
// Result received in OnPlayerOnline() callback
Check Connection Status
if (ChatManager.Instance.IsConnected())
{
Debug.Log("Connected to chat server.");
}
Complete Usage Example
using UnityEngine;
public class ChatExample : MonoBehaviour, IChatListener
{
void Start()
{
// 1. Connect to chat server
ChatManager.Instance.Connect(this);
}
// 2. Subscribe to channel on successful connection
public void OnConnected()
{
Debug.Log("Connection successful!");
ChatManager.Instance.Subscribe("global");
}
// 3. Channel entry notification
public void OnSubscribed(ChatUserInfo user)
{
Debug.Log($"{user.visitorName} has entered.");
}
// 4. Receive messages
public void OnPublicMessage(ChatUserInfo sender, string message)
{
Debug.Log($"[{sender.visitorName}]: {message}");
}
// 5. Send message (called from UI button)
public void OnSendButtonClick()
{
ChatManager.Instance.SendPublicMessage("global", "Hello!");
}
// Other callback implementations
public void OnDisconnected() => Debug.Log("Disconnected");
public void OnError(string code, string message) => Debug.LogError($"[{code}] {message}");
public void OnChannels(ChatChannelInfo[] channels) { }
public void OnUnSubscribed(ChatUserInfo user) => Debug.Log($"{user.visitorName} has left.");
public void OnPrivateMessage(ChatUserInfo sender, string message) => Debug.Log($"[Whisper] {message}");
public void OnNotifyMessage(ChatUserInfo sender, string message) => Debug.Log($"[Notification] {message}");
public void OnPlayerOnline(ChatPlayerInfo[] players) { }
}
Important Notes
Call Service in Update: ChatClient.Service() is called in ChatManager's Update() to process WebSocket callbacks on the main thread. If you modify ChatManager directly, you must maintain this part.
Singleton Pattern: ChatManager is implemented as a singleton and accessed via
ChatManager.Instance. It persists across scene transitions.Disconnect: The connection is automatically disconnected in ChatManager.OnDestroy() when the app exits.