98 lines
3.6 KiB
C#
98 lines
3.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
// Панель чата: вкладки "Общий мир" / "Круг", лента сообщений, поле ввода и кнопка отправки.
|
|
public class ChatPanel : MonoBehaviour
|
|
{
|
|
[Header("Вкладки")]
|
|
public Button worldTabButton;
|
|
public Button circleTabButton;
|
|
|
|
[Header("Сообщения")]
|
|
public TMP_Text messagesText;
|
|
|
|
[Header("Ввод")]
|
|
public TMP_InputField inputField;
|
|
public Button sendButton;
|
|
|
|
const int MaxShownMessages = 30; // старые всё равно уходят за верхний край ленты
|
|
|
|
static readonly Color ActiveTabColor = new Color(0.16f, 0.35f, 0.7f);
|
|
static readonly Color InactiveTabColor = new Color(0.12f, 0.13f, 0.17f);
|
|
static readonly string[] NameColors = { "#6EC6FF", "#FF8A65", "#C792EA", "#81C784", "#FFD54F", "#4DD0E1" };
|
|
const string OwnNameColor = "#FFC857";
|
|
|
|
private ChatChannel currentChannel = ChatChannel.World;
|
|
private readonly StringBuilder sb = new StringBuilder();
|
|
|
|
void Start()
|
|
{
|
|
worldTabButton.onClick.AddListener(() => SwitchChannel(ChatChannel.World));
|
|
circleTabButton.onClick.AddListener(() => SwitchChannel(ChatChannel.Circle));
|
|
sendButton.onClick.AddListener(Send);
|
|
inputField.onSubmit.AddListener(_ => Send()); // Enter на клавиатуре
|
|
inputField.characterLimit = ChatService.MaxMessageLength;
|
|
|
|
ChatService.Instance.MessageReceived += OnMessageReceived;
|
|
SwitchChannel(ChatChannel.World);
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
ChatService.Instance.MessageReceived -= OnMessageReceived;
|
|
}
|
|
|
|
void SwitchChannel(ChatChannel channel)
|
|
{
|
|
currentChannel = channel;
|
|
worldTabButton.image.color = channel == ChatChannel.World ? ActiveTabColor : InactiveTabColor;
|
|
circleTabButton.image.color = channel == ChatChannel.Circle ? ActiveTabColor : InactiveTabColor;
|
|
Redraw();
|
|
}
|
|
|
|
void Send()
|
|
{
|
|
if (ChatService.Instance.Send(currentChannel, inputField.text))
|
|
{
|
|
inputField.text = "";
|
|
}
|
|
inputField.ActivateInputField(); // курсор остаётся в поле -- можно писать дальше
|
|
}
|
|
|
|
void OnMessageReceived(ChatMessage message)
|
|
{
|
|
if (message.channel == currentChannel) Redraw();
|
|
}
|
|
|
|
void Redraw()
|
|
{
|
|
IReadOnlyList<ChatMessage> messages = ChatService.Instance.GetMessages(currentChannel);
|
|
int start = Mathf.Max(0, messages.Count - MaxShownMessages);
|
|
|
|
sb.Clear();
|
|
for (int i = start; i < messages.Count; i++)
|
|
{
|
|
ChatMessage m = messages[i];
|
|
string time = DateTimeOffset.FromUnixTimeMilliseconds(m.timeMs).ToLocalTime().ToString("HH:mm");
|
|
string color = m.senderId == MarchManager.LocalPlayerId ? OwnNameColor : GetNameColor(m.senderId);
|
|
|
|
if (sb.Length > 0) sb.Append('\n');
|
|
// <noparse> -- чтобы игрок не мог вставить в сообщение теги оформления
|
|
sb.Append($"<color=#9AA3B5>[{time}]</color> <color={color}>{m.senderName}:</color> <noparse>{m.text}</noparse>");
|
|
}
|
|
messagesText.text = sb.ToString();
|
|
}
|
|
|
|
// Один и тот же игрок -- всегда один цвет
|
|
static string GetNameColor(string senderId)
|
|
{
|
|
int hash = 0;
|
|
foreach (char c in senderId) hash = hash * 31 + c;
|
|
return NameColors[(hash & int.MaxValue) % NameColors.Length];
|
|
}
|
|
}
|