add limit char for chat

This commit is contained in:
CuongNV
2026-04-09 16:33:52 +07:00
parent 87e14a1d8a
commit b1fc46b50c
11 changed files with 84 additions and 7 deletions
@@ -47,3 +47,4 @@ MonoBehaviour:
iconName:
icon: {fileID: 0}
prefix: '!#'
maxRawCharactersPerMessage: 80
@@ -11,6 +11,7 @@ namespace BrewMonster.Scripts.Chat
public static class ChatWireTmpCodec
{
private static readonly Regex SpriteTagRegex = new Regex(@"<sprite\s[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex OrphanSpriteFragmentRegex = new Regex(@"^\s*sprite\s[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
/// <summary>
/// Tạo một đoạn wire marshal cho một emotion (set:index) — gửi server đúng protocol.
@@ -45,19 +46,40 @@ namespace BrewMonster.Scripts.Chat
int last = 0;
foreach (Match m in SpriteTagRegex.Matches(tmpBody))
{
sb.Append(tmpBody, last, m.Index - last);
AppendSanitizedPlainText(sb, tmpBody, last, m.Index - last);
string tag = m.Value;
if (TryMatchSpriteTagToEmotion(map, tag, out int es, out int ei))
sb.Append(BuildMarshaledEmotionWire(es, ei));
else
sb.Append(tag);
last = m.Index + m.Length;
// Defensive: TMP_InputField can transiently expose an orphan fragment like
// `sprite anim="..."` right after a valid <sprite ...> tag when input updates race.
// Skip it so we do not leak malformed rich-text into wire text.
var orphan = OrphanSpriteFragmentRegex.Match(tmpBody, last);
if (orphan.Success)
last += orphan.Length;
}
sb.Append(tmpBody, last, tmpBody.Length - last);
AppendSanitizedPlainText(sb, tmpBody, last, tmpBody.Length - last);
return sb.ToString();
}
private static void AppendSanitizedPlainText(StringBuilder sb, string source, int start, int length)
{
if (length <= 0)
return;
int end = start + length;
for (int i = start; i < end; i++)
{
char ch = source[i];
if (!AUICommon.IsEditboxItemCode(ch))
sb.Append(ch);
}
}
/// <summary>
/// Khớp tag với EmotionTMPTagBuilder — duyệt (set,index) đủ nhỏ.
/// Match tag to EmotionTMPTagBuilder output — brute-force over (set,index) within reasonable bounds.
@@ -23,5 +23,34 @@ namespace BrewMonster.Scripts.ChatUI
[Header("Channel Icons")]
public List<ChannelIconMapping> channelIcons = new List<ChannelIconMapping>();
[Header("Message Limits")]
[Tooltip("Giới hạn số ký tự thô cho một tin nhắn. <= 0 nghĩa là không giới hạn. " +
"TMP tag như <sprite ...> cũng được tính theo đúng số ký tự của tag.")]
public int maxRawCharactersPerMessage = 60;
/// <summary>
/// Đếm số ký tự thô (raw) của nội dung đang nhập.
/// Count raw characters from current input text.
/// </summary>
public int CountRawCharacters(string rawText)
{
if (string.IsNullOrEmpty(rawText))
return 0;
return rawText.Length;
}
/// <summary>
/// Kiểm tra có thể dùng thêm reserveChars mà vẫn không vượt giới hạn ký tự thô.
/// Check whether reserveChars can be added without exceeding raw character limit.
/// </summary>
public bool CanUseRawCharacters(string rawText, int reserveChars, out int usedChars, out int limitChars)
{
limitChars = maxRawCharactersPerMessage;
usedChars = CountRawCharacters(rawText) + Mathf.Max(0, reserveChars);
if (limitChars <= 0)
return true;
return usedChars <= limitChars;
}
}
}
@@ -164,8 +164,9 @@ namespace BrewMonster.Scripts.ChatUI
TryAutoWireIfNeeded();
if (_chatInput != null)
{
EmotionTMPTagBuilder.InsertEmotionTag(_chatInput.inputField, _emotionSpriteMap, emotionSet,
emotionIndex);
// Keep wire body as source of truth to avoid TMP tag race/corruption
// when player taps emoji repeatedly.
_chatInput.InsertEmoji(emotionSet, emotionIndex);
Debug.Log("[Cuong] HandleEmojiClicked.");
}
else
@@ -277,7 +277,7 @@ MonoBehaviour:
_gridContent: {fileID: 7741139062211830239}
_cellPrefab: {fileID: 4685469653980001717, guid: 616f563fe32927844be2a17dbb408331, type: 3}
_cellSize: {x: 64, y: 64}
_cellSpacing: {x: 4, y: 4}
_cellSpacing: {x: 0, y: 4}
_columnCount: 8
_chatInput: {fileID: 5889020827802476297}
_chatSystemUI: {fileID: 2621697629504226575}
@@ -746,7 +746,7 @@ MonoBehaviour:
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 0
m_Interactable: 1
m_TargetGraphic: {fileID: 2689844286198437230}
m_OnClick:
m_PersistentCalls:
@@ -1061,7 +1061,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.392}
m_Color: {r: 1, g: 1, b: 1, a: 0}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
+24
View File
@@ -259,6 +259,9 @@ namespace BrewMonster.Scripts.ChatUI
FilterBadWords(ref strText);
_chatWireBody = strText;
if (!CanUseRawCharacters(0))
return;
if (HandleDebugCommand(routingLine))
return;
@@ -752,6 +755,14 @@ namespace BrewMonster.Scripts.ChatUI
string segment = ChatWireTmpCodec.BuildMarshaledEmotionWire(emotionSet, emotionIndex);
if (string.IsNullOrEmpty(segment))
return;
int reserveChars = 0;
if (_spriteMap != null && EmotionTMPTagBuilder.TryBuildEmotionTag(_spriteMap, emotionSet, emotionIndex, out string tag))
reserveChars = tag.Length;
if (!CanUseRawCharacters(reserveChars))
return;
_chatWireBody += segment;
RefreshInputDisplayFromWire();
}
@@ -766,5 +777,18 @@ namespace BrewMonster.Scripts.ChatUI
{
AppendEmotionWire(emotionSet, emotionIndex);
}
private bool CanUseRawCharacters(int reserveChars)
{
if (chatSystem == null)
return true;
string rawBody = ExtractMessageBodyFromVisual(inputField != null ? inputField.text ?? "" : "");
if (chatSystem.CanUseRawCharacters(rawBody, reserveChars, out int usedChars, out int limitChars))
return true;
//AddChatMessage($"Tin nhan vuot gioi han: {usedChars}/{limitChars} ky tu.", ChatChannel.GP_CHAT_MISC);
return false;
}
}
}