add new chat mini

This commit is contained in:
CuongNV
2026-04-09 14:52:37 +07:00
parent 1a9a350b8b
commit c3bc869457
5 changed files with 122 additions and 57 deletions
@@ -2083,11 +2083,16 @@ namespace CSNetwork
pGameUI.AddChatMessage(formatted, (ChatChannel)p.Channel, p.Roleid, strSrcName,
0, p.Emotion, null, strMsg);
// Bubble chat on head
CECPlayer pSrcPlayer = EC_Game.GetGameRun().GetWorld().GetPlayerMan().GetPlayer(p.Roleid);
if (pSrcPlayer != null)
// Kênh không thuộc showsAboveHead trong AddChatMessage 时 vẫn cần bong bóng — English: extra bubble for channels AddChatMessage does not publish.
if (!CECGameUIMan.ChannelShowsChatBubbleAboveHead((ChatChannel)p.Channel))
{
EventBus.PublishChannel(p.Roleid, new EventChatMessageOnTopPlayer(p.Roleid, strMsg));
CECPlayer pSrcPlayer = EC_Game.GetGameRun().GetWorld().GetPlayerMan().GetPlayer(p.Roleid);
if (pSrcPlayer != null)
{
string bubbleTmp = pGameUI.ConvertWireBodyForHeadBubble(
strMsg, (ChatChannel)p.Channel, p.Roleid, p.Emotion);
EventBus.PublishChannel(p.Roleid, new EventChatMessageOnTopPlayer(p.Roleid, bubbleTmp));
}
}
return true;
@@ -2303,11 +2308,14 @@ namespace CSNetwork
p.Channel, p.Emotion, null, strMsg);
}
// Set player's last said words for head bubble
// 私聊头顶气泡:AddChatMessage 对 GP_CHAT_WHISPER 不发布 EventChatMessageOnTopPlayer,在此单独发 TMP 正文。
// Whisper head bubble: AddChatMessage does not publish EventChatMessageOnTopPlayer for whisper — publish TMP body here.
CECPlayer pSrcPlayer = EC_Game.GetGameRun().GetWorld().GetPlayerMan().GetPlayer(p.Srcroleid);
if (pSrcPlayer != null)
{
EventBus.PublishChannel(p.Srcroleid, new EventChatMessageOnTopPlayer(p.Srcroleid, strMsg));
string bubbleTmp = pGameUI.ConvertWireBodyForHeadBubble(
strMsg, ChatChannel.GP_CHAT_WHISPER, p.Srcroleid, p.Emotion);
EventBus.PublishChannel(p.Srcroleid, new EventChatMessageOnTopPlayer(p.Srcroleid, bubbleTmp));
}
}
@@ -58,6 +58,45 @@ namespace BrewMonster.UI
return _chatEmotionPipeline.ConvertInlineItemsToTmp(f);
}
/// <summary>
/// 仅正文 wire(无 printf 包装)→ 头顶气泡 TMP — 与 AddChatMessage 内 FilterBadWords + 内联转 TMP 一致。
/// Wire body only (no printf wrapper) → head-bubble TMP — same as AddChatMessage FilterBadWords + inline to TMP.
/// </summary>
public string ConvertWireBodyForHeadBubble(string wireBody, ChatChannel cChannel, int idPlayer, int cEmotion)
{
if (string.IsNullOrEmpty(wireBody))
return wireBody;
string s = _chatEmotionPipeline.ApplyChannelEmotionFilter(wireBody, cEmotion);
if (string.IsNullOrEmpty(s))
return s;
bool isPlayerChannel = cChannel == ChatChannel.GP_CHAT_LOCAL
|| cChannel == ChatChannel.GP_CHAT_FARCRY
|| cChannel == ChatChannel.GP_CHAT_TEAM
|| cChannel == ChatChannel.GP_CHAT_FACTION
|| cChannel == ChatChannel.GP_CHAT_WHISPER
|| cChannel == ChatChannel.GP_CHAT_TRADE
|| cChannel == ChatChannel.GP_CHAT_SUPERFARCRY
|| cChannel == ChatChannel.GP_CHAT_BATTLE
|| cChannel == ChatChannel.GP_CHAT_COUNTRY;
if (isPlayerChannel && idPlayer > 0)
CECUIManager.Instance.FilterBadWords(ref s);
return _chatEmotionPipeline.ConvertInlineItemsToTmp(s);
}
/// <summary>
/// Kênh có bong bóng trên đầu trong AddChatMessage — dùng để tránh double-publish với PROTOCOL_WORLDCHAT.
/// Channels that get head bubble from AddChatMessage — avoids double-publish with PROTOCOL_WORLDCHAT.
/// </summary>
public static bool ChannelShowsChatBubbleAboveHead(ChatChannel cChannel)
{
return cChannel == ChatChannel.GP_CHAT_LOCAL
|| cChannel == ChatChannel.GP_CHAT_FARCRY
|| cChannel == ChatChannel.GP_CHAT_TEAM
|| cChannel == ChatChannel.GP_CHAT_SUPERFARCRY
|| cChannel == ChatChannel.GP_CHAT_BATTLE
|| cChannel == ChatChannel.GP_CHAT_COUNTRY;
}
// Layout/settings flags for GetUserLayout (saved to server)
// 布局/设置标志,用于 GetUserLayout(保存到服务器)
private bool m_bAutoReply;
@@ -613,18 +652,15 @@ namespace BrewMonster.UI
// C++: AddChatMessage also handles head bubble via pPlayer->SetLastSaidWords
// Unity equivalent: Publish EventChatMessageOnTopPlayer
bool showsAboveHead = cChannel == ChatChannel.GP_CHAT_LOCAL
|| cChannel == ChatChannel.GP_CHAT_FARCRY
|| cChannel == ChatChannel.GP_CHAT_TEAM
|| cChannel == ChatChannel.GP_CHAT_SUPERFARCRY
|| cChannel == ChatChannel.GP_CHAT_BATTLE
|| cChannel == ChatChannel.GP_CHAT_COUNTRY;
bool showsAboveHead = ChannelShowsChatBubbleAboveHead(cChannel);
if (showsAboveHead && idPlayer > 0)
{
// C++: pPlayer->SetLastSaidWords(strTemp, ...) — strTemp là nội dung chat thuần,
// KHÔNG bao gồm tên người chơi. Dùng pszMsgOrigion thay vì pszMsg.
string bubbleText = !string.IsNullOrEmpty(pszMsgOrigion) ? pszMsgOrigion : pszMsg;
// C++: pPlayer->SetLastSaidWords(strTemp, ...) — chỉ thân tin (không tên); bản wire pszMsgOrigion phải → TMP giống khung chat.
// C++: SetLastSaidWords — body only (no name); wire pszMsgOrigion must become TMP like chat panel.
string bubbleText = !string.IsNullOrEmpty(pszMsgOrigion)
? ConvertWireBodyForHeadBubble(pszMsgOrigion, cChannel, idPlayer, cEmotion)
: pszMsg;
EventBus.PublishChannel(idPlayer, new EventChatMessageOnTopPlayer(idPlayer, bubbleText));
}
@@ -87,6 +87,7 @@ GameObject:
- component: {fileID: 7228077960814023056}
- component: {fileID: 5305392080666511277}
- component: {fileID: 7604324431011831295}
- component: {fileID: 8883197050699466089}
m_Layer: 5
m_Name: Text (TMP)
m_TagString: Untagged
@@ -236,6 +237,26 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_HorizontalFit: 0
m_VerticalFit: 2
--- !u!114 &8883197050699466089
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6240941777052618231}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: 291.7
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &6627717456258223658
GameObject:
m_ObjectHideFlags: 0
@@ -368,10 +368,10 @@ RectTransform:
- {fileID: 4845475585563704660}
m_Father: {fileID: 3676046446549609595}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: -219, y: 141}
m_SizeDelta: {x: 638, y: 227}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 0}
m_AnchoredPosition: {x: -175.64499, y: 151.8}
m_SizeDelta: {x: -1148.71, y: 227}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5093099212117339368
CanvasRenderer:
@@ -664,9 +664,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 5189750139888259924}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 538.9, y: -37.5}
m_SizeDelta: {x: 65, y: 65}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3313632616987073809
@@ -1208,10 +1208,10 @@ RectTransform:
- {fileID: 739609527060018247}
m_Father: {fileID: 5751167674555460373}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 67, y: -213.5}
m_SizeDelta: {x: 134, y: 51}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &38225373003582705
CanvasRenderer:
@@ -1404,10 +1404,10 @@ RectTransform:
- {fileID: 610143082050100740}
m_Father: {fileID: 5751167674555460373}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 67, y: -45.5}
m_SizeDelta: {x: 134, y: 51}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7779409169763482013
CanvasRenderer:
@@ -1525,9 +1525,9 @@ RectTransform:
- {fileID: 4952957933435979972}
m_Father: {fileID: 5189750139888259924}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 293.2, y: -37.5}
m_SizeDelta: {x: 400, y: 60}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &20947868772470573
@@ -1686,7 +1686,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &1473246120053017968
RectTransform:
m_ObjectHideFlags: 0
@@ -1780,9 +1780,9 @@ RectTransform:
- {fileID: 5804952772034601221}
m_Father: {fileID: 5189750139888259924}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 637.6, y: -37.5}
m_SizeDelta: {x: 106, y: 62}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7641285342810036890
@@ -2248,10 +2248,10 @@ RectTransform:
- {fileID: 6015197618098464652}
m_Father: {fileID: 5751167674555460373}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 67, y: -157.5}
m_SizeDelta: {x: 134, y: 51}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3744810705978608696
CanvasRenderer:
@@ -2620,7 +2620,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &2739455247741079987
RectTransform:
m_ObjectHideFlags: 0
@@ -3086,9 +3086,9 @@ RectTransform:
- {fileID: 1242095235490096923}
m_Father: {fileID: 5189750139888259924}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 40, y: -37.5}
m_SizeDelta: {x: 80, y: 60}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2491747450976635330
@@ -3227,10 +3227,10 @@ RectTransform:
- {fileID: 5053277402852973834}
m_Father: {fileID: 5751167674555460373}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 67, y: -101.5}
m_SizeDelta: {x: 134, y: 51}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &78804016905584931
CanvasRenderer:
@@ -3801,10 +3801,10 @@ RectTransform:
- {fileID: 1012966277253133821}
m_Father: {fileID: 5751167674555460373}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 67, y: -269.5}
m_SizeDelta: {x: 134, y: 51}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7711523176654121571
CanvasRenderer:
@@ -4834,10 +4834,10 @@ RectTransform:
- {fileID: 7795282280205679886}
m_Father: {fileID: 5751167674555460373}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 67, y: -325.5}
m_SizeDelta: {x: 134, y: 51}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &519132139347130033
CanvasRenderer: