103 lines
4.7 KiB
C#
103 lines
4.7 KiB
C#
using System.Text.RegularExpressions;
|
|
using CSNetwork;
|
|
using UnityEngine;
|
|
|
|
namespace BrewMonster.Scripts.Chat
|
|
{
|
|
/// <summary>
|
|
/// Chat 表情与内联富文本 — Emotion set + TMP conversion for chat (ported from CECGameUIMan::AddChatMessage).
|
|
/// Keeps channel emotion filtering and Unmarshal/Convert-to-TMP in one place.
|
|
/// </summary>
|
|
public sealed class ChatEmotionDisplayPipeline
|
|
{
|
|
/// <summary>
|
|
/// Khi thiếu ký tự PUA trước payload, Unmarshal không chạy nhưng vẫn còn <0><set:index> (Serialize).
|
|
/// When PUA prefix is missing, Unmarshal skips but <0><set:index> (Serialize) may remain.
|
|
/// </summary>
|
|
private static readonly Regex LooseMarshaledEmotionRegex = new Regex(
|
|
@"<0><(\d+):(\d+)>",
|
|
RegexOptions.Compiled);
|
|
|
|
private IEmotionSpriteMap _spriteMap = new StubEmotionSpriteMap();
|
|
|
|
/// <summary>
|
|
/// Wire 正文(服务器 / 输入缓冲)→ TMP 显示用富文本 — 与 CECGameUIMan.AddChatMessage 内转换一致(不含 FilterBadWords)。
|
|
/// Wire body (server / input buffer) → TMP rich text for display — same as CECGameUIMan.AddChatMessage (without FilterBadWords).
|
|
/// </summary>
|
|
public static string ConvertWireBodyToTmpDisplay(string wireBody, IEmotionSpriteMap map, int cEmotion)
|
|
{
|
|
if (string.IsNullOrEmpty(wireBody))
|
|
return "";
|
|
if (map == null)
|
|
return wireBody;
|
|
|
|
var p = new ChatEmotionDisplayPipeline(map);
|
|
string filtered = p.ApplyChannelEmotionFilter(wireBody, cEmotion);
|
|
return p.ConvertInlineItemsToTmp(filtered);
|
|
}
|
|
|
|
public ChatEmotionDisplayPipeline(IEmotionSpriteMap spriteMap = null)
|
|
{
|
|
if (spriteMap != null)
|
|
_spriteMap = spriteMap;
|
|
else
|
|
BMLogger.LogWarning("[ChatEmotionDisplayPipeline] spriteMap is null — using StubEmotionSpriteMap. Call SetSpriteMap() or assign EmotionLibrarySpriteMap SO on CECUIManager.");
|
|
}
|
|
|
|
public void SetSpriteMap(IEmotionSpriteMap spriteMap)
|
|
{
|
|
if (spriteMap == null)
|
|
BMLogger.LogWarning("[ChatEmotionDisplayPipeline] SetSpriteMap() called with null — EmotionLibrarySpriteMap SO chưa được gán trên CECUIManager Inspector.");
|
|
_spriteMap = spriteMap ?? new StubEmotionSpriteMap();
|
|
}
|
|
|
|
/// <summary>C++: FilterEmotionSet — map inline emotion codes to the correct set for this channel.</summary>
|
|
public string ApplyChannelEmotionFilter(string pszMsg, int cEmotion)
|
|
{
|
|
return AUICommon.FilterEmotionSet(pszMsg, cEmotion);
|
|
}
|
|
|
|
/// <summary>
|
|
/// TMP: Unmarshal edit-box item codes and convert emotion / coord / inventory links to TMP rich text.
|
|
/// Call after <see cref="CECUIManager.FilterBadWords"/> when the message is from a player channel.
|
|
/// </summary>
|
|
public string ConvertInlineItemsToTmp(string pszMsgAfterBadWordFilter)
|
|
{
|
|
EditBoxItemsSet itemsSet = new EditBoxItemsSet();
|
|
string displayText = AUICommon.UnmarshalEditBoxText(pszMsgAfterBadWordFilter, itemsSet);
|
|
string tmpText;
|
|
if (itemsSet.GetItemCount() <= 0)
|
|
tmpText = pszMsgAfterBadWordFilter;
|
|
else
|
|
{
|
|
tmpText = displayText;
|
|
tmpText = AUICommon.ConvertEmotionsToTMP(tmpText, itemsSet, _spriteMap);
|
|
tmpText = AUICommon.ConvertCoordsToTMP(tmpText, itemsSet);
|
|
tmpText = AUICommon.ConvertIvtrItemsToTMP(tmpText, itemsSet);
|
|
tmpText = AUICommon.StripRemainingItemCodes(tmpText);
|
|
}
|
|
|
|
return ReplaceLooseMarshaledEmotionTags(tmpText);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fallback: wire emotion chỉ còn dạng Serialize <0><set:index> (không qua PUA) → TMP <sprite>.
|
|
/// Fallback: emotion wire as Serialize-only <0><set:index> (no PUA) → TMP <sprite>.
|
|
/// </summary>
|
|
private string ReplaceLooseMarshaledEmotionTags(string text)
|
|
{
|
|
if (string.IsNullOrEmpty(text) || _spriteMap == null)
|
|
return text;
|
|
|
|
return LooseMarshaledEmotionRegex.Replace(text, match =>
|
|
{
|
|
int set = int.Parse(match.Groups[1].Value);
|
|
int index = int.Parse(match.Groups[2].Value);
|
|
if (_spriteMap.TryGetSprite(set, index, out EmotionSpriteInfo info))
|
|
return EmotionTMPTagBuilder.BuildSpriteTag(info);
|
|
return match.Value;
|
|
});
|
|
}
|
|
}
|
|
}
|