diff --git a/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs b/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs
index 84fce2a20f..70b629d0c8 100644
--- a/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs
+++ b/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using BrewMonster.Network;
using BrewMonster.Scripts.UI;
+using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.Protocols;
@@ -16,7 +17,7 @@ namespace BrewMonster.Scripts.Chat
{
m_aPendingProtocols.Add(p);
}
-
+
// Add one player's id to a buffer in order to get his name later
public static void AddChatPlayerID(int id)
{
@@ -25,7 +26,7 @@ namespace BrewMonster.Scripts.Chat
m_aPendingPlayers.Add(id);
}
}
-
+
public static bool ShouldBlockByLevel(chatmessage p)
{
int levelBlock = EC_Game.GetConfigs().GetBlackListSettings().levelBlock;
@@ -46,73 +47,71 @@ namespace BrewMonster.Scripts.Chat
return false;
}
- public static bool PolicyResolver(Protocol pProtocol, chatmessage p, ref string strTemp)
+ ///
+ /// [Port] OnPrtcChatMessage policy chat handling (EC_GameSession.cpp:4597-4621)
+ /// Xử lý Policy Chat (chat từ NPC/hệ thống với tham số đặc biệt $A, $S, $I...).
+ /// Nếu là Policy Chat: thay thế các ký tự đặc biệt, format tọa độ.
+ /// Nếu không: chỉ convert ký tự ^ và & cho hiển thị an toàn.
+ ///
+ /// Protocol gốc (để add vào pending nếu name chưa ready)
+ /// Chat message data
+ /// ref: nội dung chat (đã qua FilterInvalidTags), sẽ bị thay đổi nếu là policy chat
+ /// out: chuỗi đã convert sẵn cho hiển thị (tương đương ACHAR szMsg[1024] trong C++)
+ /// true = xử lý xong, false = cần chờ (pending name từ server)
+ public static bool PolicyResolver(Protocol pProtocol, chatmessage p, ref string strTemp, out string szMsg)
{
+ szMsg = strTemp;
+
if (IsPolicyChat(p))
{
- // Todo: check logic
+ // C++: CHAT_S2C::CreatPolicyChatParameter(p->data)
CHAT_S2C.PolicyChatParameter pPolicyChatPara = CHAT_S2C.CreatPolicyChatParameter(p.Data);
- if (pPolicyChatPara != null && p.Data.Size > 0)
+
+ // C++: if (!pPolicyChatPara && p->data.size() > 0) → parse failed nhưng có data → hiển thị "???"
+ if (pPolicyChatPara == null && p.Data.Size > 0)
{
- strTemp = ("???");
+ strTemp = "???";
}
else
{
+ // C++: if (pPolicyChatPara && !pPolicyChatPara->IsNameReady())
if (pPolicyChatPara != null && !pPolicyChatPara.IsNameReady())
{
pPolicyChatPara.GetNameFromServer();
m_aPendingProtocols.Add(pProtocol);
+ szMsg = strTemp;
return false;
}
+ // Thay thế ký tự đặc biệt trong policy chat ($A → tên NPC, v.v.)
strTemp = CECUIHelper.PolicySpecialCharReplace(strTemp, pPolicyChatPara);
+
+ // Format tọa độ nếu channel hỗ trợ
if (CanFormatCoordText(p))
{
- //strTemp = CECUIHelper.FormatCoordText(strTemp);
+ // TODO: strTemp = CECUIHelper.FormatCoordText(strTemp);
}
}
- //int strLen = strTemp.GetLength();
- //wcsncpy(szMsg, strTemp, strLen);
- //szMsg[strLen] = 0;
+
+ // C++: wcsncpy(szMsg, strTemp, strLen) — Policy chat không cần convert ^ &
+ szMsg = strTemp;
}
else
{
- //AUI_ConvertChatString(strTemp, szMsg, false);
+ // C++: AUI_ConvertChatString(strTemp, szMsg, false)
+ // Convert ký tự ^ và & cho hiển thị an toàn
+ char[] convBuf = new char[1024];
+ string input = strTemp;
+ AUICommon.AUI_ConvertChatString(ref input, ref convBuf, false);
+
+ // Tìm null terminator và tạo string
+ int len = Array.IndexOf(convBuf, '\0');
+ szMsg = len >= 0 ? new string(convBuf, 0, len) : new string(convBuf);
}
return true;
}
- /*private void AUI_ConvertChatString(string pszChat, string pszConv, bool bName)
- {
- int i, nLen = 0;
- if (pszChat != null || pszConv != null)
- return;
-
- pszConv[0] = 0;
- for( i = 0; i < (int)a_strlen(pszChat); i++ )
- {
- if( pszChat[i] == '^' )
- {
- pszConv[nLen] = '^';
- pszConv[nLen + 1] = '^';
- nLen += 2;
- }
- else if( pszChat[i] == '&' )
- {
- pszConv[nLen] = '^';
- pszConv[nLen + 1] = '&';
- nLen += 2;
- }
- else
- {
- pszConv[nLen] = pszChat[i];
- nLen++;
- }
- }
- pszConv[nLen] = 0;
- }*/
-
private static bool IsPolicyChat(chatmessage p)
{
bool bOK = false;
@@ -240,4 +239,4 @@ namespace BrewMonster.Scripts.Chat
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs
index cb9e652961..83c7157e53 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs
@@ -343,7 +343,7 @@ namespace CSNetwork
else
{
sb.Append('{').Append(argIndex++).Append('}');
-
+
i++;
// Nhảy qua các ký tự định dạng (ví dụ: %02d, %ls, %f)
while (i < format.Length && (char.IsDigit(format[i]) || format[i] == '.' || format[i] == 'l' || format[i] == 'u' || format[i] == 'd' || format[i] == 's' || format[i] == 'f' || format[i] == 'x'))
@@ -366,6 +366,88 @@ namespace CSNetwork
}
return sb.ToString();
}
+
+ ///
+ /// [Port] CECGameUIMan::FilterInvalidTags (EC_GameUIMan.cpp:6424)
+ /// Lọc bỏ các tag đặc biệt không hợp lệ trong nội dung chat nhận từ server.
+ /// - Emotion (biểu cảm): luôn giữ lại.
+ /// - IvtrItem (link vật phẩm): giữ hoặc loại tùy bFilterItem.
+ /// - Tất cả loại khác (image, coord...): luôn bị loại bỏ (thay bằng text thuần).
+ ///
+ public static string FilterInvalidTags(string szText, bool bFilterItem)
+ {
+ return AUI_FilterEditboxItem(szText, (EditBoxItemBase pItem) =>
+ {
+ var type = pItem.GetType();
+
+ if (type == EditboxItemType.enumEIEmotion)
+ return false;
+
+ if (type == EditboxItemType.enumEIIvtrlItem)
+ {
+ pItem.SetInfo("");
+ return bFilterItem;
+ }
+
+ return true;
+ });
+ }
+
+ ///
+ /// [Port] CECGameUIMan::AUI_FilterEditboxItem (EC_GameUIMan.cpp:6477)
+ /// Duyệt qua các EditboxItem trong text, filter trả về true thì item bị loại
+ /// (thay bằng tên hiển thị dạng text thuần), false thì giữ nguyên.
+ ///
+ public static string AUI_FilterEditboxItem(string szText, Func filter)
+ {
+ EditBoxItemsSet itemsSet = new EditBoxItemsSet();
+ string strText = UnmarshalEditBoxText(szText, itemsSet);
+
+ int nCount = itemsSet.GetItemCount();
+ if (nCount == 0)
+ return szText;
+
+ var it = itemsSet.GetItemIterator();
+ int i = 0;
+ var itemsToFilter = new List>();
+
+ while (it.MoveNext() && i < nCount)
+ {
+ EditBoxItemBase pItem = it.Current.Value;
+ if (pItem != null && filter(pItem))
+ {
+ itemsToFilter.Add(new KeyValuePair(it.Current.Key, pItem.GetName()));
+ }
+ i++;
+ }
+
+ foreach (var kv in itemsToFilter)
+ {
+ strText = AUI_ReplaceEditboxItem(strText, kv.Key, kv.Value);
+ }
+
+ return MarshalEditBoxText(strText, itemsSet);
+ }
+
+ ///
+ /// [Port] CECGameUIMan::AUI_ReplaceEditboxItem (EC_GameUIMan.cpp:6431)
+ /// Thay thế ký tự EditboxItem code trong chuỗi bằng một đoạn text thay thế.
+ ///
+ public static string AUI_ReplaceEditboxItem(string szText, char cItem, string szSubText)
+ {
+ if (string.IsNullOrEmpty(szText) || !IsEditboxItemCode(cItem))
+ return szText ?? "";
+
+ var sb = new StringBuilder(szText.Length);
+ for (int i = 0; i < szText.Length; i++)
+ {
+ if (szText[i] == cItem)
+ sb.Append(szSubText ?? "");
+ else
+ sb.Append(szText[i]);
+ }
+ return sb.ToString();
+ }
}
}
diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
index ee7525407a..913df0fd1c 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
@@ -2073,15 +2073,15 @@ namespace CSNetwork
string szMsg = null;
string strTemp = Encoding.Unicode.GetString(p.Msg.ToArray(), 0, p.Msg.Length);
string strMsgOrigion = strTemp;
- // Todo: Show Text on Ui Game
- //strTemp = pGameUI.FilterInvalidTags(strTemp, pItem==NULL);
- /*if (!Chat_GameSession.PolicyResolver(pProtocol, p, ref strTemp))
+ // [Port] CECGameUIMan::FilterInvalidTags — Lọc các tag đặc biệt không hợp lệ
+ strTemp = AUICommon.FilterInvalidTags(strTemp, pItem == null);
+ if (!Chat_GameSession.PolicyResolver(pProtocol, p, ref strTemp, out szMsg))
{
Debug.Log("[Cuong] 2");
return false;
}
- if (Chat_GameSession.HanldeGPChatSystem(p, bCalledagain))
+ /*if (Chat_GameSession.HanldeGPChatSystem(p, bCalledagain))
{
Debug.Log("[Cuong] 3");
}*/
@@ -2168,7 +2168,7 @@ namespace CSNetwork
string str = string.Format(
fmt,
szName,
- strTemp
+ szMsg
);
// [Port] Gọi AddChatMessage để hiển thị lên UI Chat Box.
// AddChatMessage bên trong đã tự publish ChatMessageEvent (cho ChatPanelUI)
@@ -2192,7 +2192,7 @@ namespace CSNetwork
string message = string.Format(
template,
pNPC.GetName(),
- strTemp
+ szMsg
);
EC_Game.GetGameRun().AddChatMessage(
diff --git a/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs b/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs
index 3952f93eec..93dcc86fe8 100644
--- a/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs
+++ b/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs
@@ -546,7 +546,10 @@ namespace BrewMonster.UI
if (showsAboveHead && idPlayer > 0)
{
- EventBus.PublishChannel(idPlayer, new EventChatMessageOnTopPlayer(idPlayer, pszMsg));
+ // 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;
+ EventBus.PublishChannel(idPlayer, new EventChatMessageOnTopPlayer(idPlayer, bubbleText));
}
// C++: if( cChannel == GP_CHAT_BROADCAST && byFlag == 0 ) SetMarqueeMsg(strConverted);
diff --git a/Assets/Prefabs/ChatSystem/prefab_ChatCanvas.prefab b/Assets/Prefabs/ChatSystem/prefab_ChatCanvas.prefab
index e7d9c03282..513d2bdf52 100644
--- a/Assets/Prefabs/ChatSystem/prefab_ChatCanvas.prefab
+++ b/Assets/Prefabs/ChatSystem/prefab_ChatCanvas.prefab
@@ -700,7 +700,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 1
+ m_IsActive: 0
--- !u!224 &4963429530816417249
RectTransform:
m_ObjectHideFlags: 0
@@ -718,7 +718,7 @@ RectTransform:
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: -396, y: 79}
+ m_AnchoredPosition: {x: -495, y: 55}
m_SizeDelta: {x: 75, y: 75}
m_Pivot: {x: 0.5, y: 0}
--- !u!1 &4030418742857763219
@@ -892,7 +892,7 @@ RectTransform:
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: -346.5, y: 50}
+ m_AnchoredPosition: {x: -483, y: 26}
m_SizeDelta: {x: 706.4468, y: 450}
m_Pivot: {x: 0, y: 0}
--- !u!222 &5213722908587404148
@@ -961,7 +961,7 @@ RectTransform:
m_GameObject: {fileID: 4425286880128952433}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
- m_LocalScale: {x: 1, y: 1, z: 1}
+ m_LocalScale: {x: 1, y: 1.5, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5425127200754731771}
@@ -2623,7 +2623,7 @@ GameObject:
- component: {fileID: 6422370174043654984}
- component: {fileID: 5572451279827723964}
- component: {fileID: 7570271903590474125}
- - component: {fileID: 1824650527810444928}
+ - component: {fileID: 1219475443647629663}
m_Layer: 5
m_Name: Content
m_TagString: Untagged
@@ -2690,7 +2690,7 @@ MonoBehaviour:
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
---- !u!114 &1824650527810444928
+--- !u!114 &1219475443647629663
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -2739,8 +2739,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
- m_AnchoredPosition: {x: 0, y: 0}
- m_SizeDelta: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 8.5}
+ m_SizeDelta: {x: 0, y: -17}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4906838759260176767
CanvasRenderer:
@@ -2830,8 +2830,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
- m_AnchoredPosition: {x: 0, y: -13.292114}
- m_SizeDelta: {x: 0, y: -86.5841}
+ m_AnchoredPosition: {x: 0, y: -13.292}
+ m_SizeDelta: {x: 0, y: -86.584}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7307691078876554531
CanvasRenderer:
diff --git a/Assets/Prefabs/ChatSystem/prefab_TextContents.prefab b/Assets/Prefabs/ChatSystem/prefab_TextContents.prefab
index 767f05e756..4a502fb8cb 100644
--- a/Assets/Prefabs/ChatSystem/prefab_TextContents.prefab
+++ b/Assets/Prefabs/ChatSystem/prefab_TextContents.prefab
@@ -110,9 +110,9 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
- m_AnchoredPosition: {x: 399.5, y: -5}
+ m_AnchoredPosition: {x: 99, y: -5}
m_SizeDelta: {x: 601, y: 0}
- m_Pivot: {x: 0.5, y: 1}
+ m_Pivot: {x: 0, y: 1}
--- !u!222 &7228077960814023056
CanvasRenderer:
m_ObjectHideFlags: 0
@@ -250,7 +250,7 @@ GameObject:
- component: {fileID: 1976417251556044024}
- component: {fileID: -887576589064363463}
- component: {fileID: 8910872808253115585}
- - component: {fileID: 2909592183608440979}
+ - component: {fileID: 6178869782871973483}
m_Layer: 5
m_Name: prefab_TextContents
m_TagString: Untagged
@@ -276,9 +276,9 @@ RectTransform:
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_AnchoredPosition: {x: -350, y: 88.255005}
m_SizeDelta: {x: 700, y: 0}
- m_Pivot: {x: 0.5, y: 0.5}
+ m_Pivot: {x: 0, y: 1}
--- !u!222 &616079771158270572
CanvasRenderer:
m_ObjectHideFlags: 0
@@ -371,7 +371,7 @@ MonoBehaviour:
m_ChildScaleWidth: 0
m_ChildScaleHeight: 1
m_ReverseArrangement: 0
---- !u!114 &2909592183608440979
+--- !u!114 &6178869782871973483
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
diff --git a/Assets/Scripts/ChatInputHandler.cs b/Assets/Scripts/ChatInputHandler.cs
index 623583c253..ba6943c85a 100644
--- a/Assets/Scripts/ChatInputHandler.cs
+++ b/Assets/Scripts/ChatInputHandler.cs
@@ -52,7 +52,7 @@ namespace BrewMonster.Scripts.ChatUI
if (strText.Length <= 0)
{
- ChangeFocus();
+ //ChangeFocus();
return;
}
@@ -79,7 +79,7 @@ namespace BrewMonster.Scripts.ChatUI
SaveHistory(resolvedChannel, strText, nPack, nSlot, now);
- ChangeFocus();
+ //ChangeFocus();
}
// =====================================================
@@ -294,14 +294,14 @@ namespace BrewMonster.Scripts.ChatUI
{
CECUIManager.Instance.FilterBadWords(ref text);
}
-
+
private void AddChatMessage(string msg, ChatChannel channel, int idPlayer = -1, string pszPlayer = "", byte byFlag = 0)
{
string strModified = msg;
-
+
// 1. Filter bad words
CECUIManager.Instance.FilterBadWords(ref strModified);
-
+
if (string.IsNullOrEmpty(strModified))
return;
@@ -320,13 +320,13 @@ namespace BrewMonster.Scripts.ChatUI
string colorHex = GetChannelColorHex(channel);
string prefix = GetChannelPrefix(channel);
string sender = string.IsNullOrEmpty(pszPlayer) ? "" : $"{pszPlayer}: ";
-
+
string finalMsg = $"{prefix}{sender}{strModified}";
// 5. Publish event
EventBus.Publish(new GameSession.ChatMessageEvent(finalMsg, (byte)channel));
-
- Debug.Log(finalMsg);
+
+ Debug.Log("[Cuong] AddChatMessage" + finalMsg);
}
private string GetChannelColorHex(ChatChannel channel)
@@ -365,4 +365,4 @@ namespace BrewMonster.Scripts.ChatUI
private int GetPlayerItemCount(int id) => 0;
private int GetPlayerLevel() => 10;
}
-}
\ No newline at end of file
+}