Files
test/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs
T
2026-03-19 13:41:38 +07:00

243 lines
9.1 KiB
C#

using System;
using System.Collections.Generic;
using BrewMonster.Network;
using BrewMonster.Scripts.UI;
using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.Protocols;
namespace BrewMonster.Scripts.Chat
{
public static class Chat_GameSession
{
private static List<Protocol> m_aPendingProtocols = new();
private static List<int> m_aPendingPlayers = new();
public static void AddElemForPendingProtocols(Protocol p)
{
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)
{
if (EC_Game.GetGameRun().GetPlayerName(id, false) != null)
{
m_aPendingPlayers.Add(id);
}
}
public static bool ShouldBlockByLevel(chatmessage p)
{
int levelBlock = EC_Game.GetConfigs().GetBlackListSettings().levelBlock;
if (p.Srclevel > 0 && p.Srclevel < levelBlock)
{
if ((ChatChannel)p.Channel is ChatChannel.GP_CHAT_LOCAL
or ChatChannel.GP_CHAT_WHISPER
or ChatChannel.GP_CHAT_TRADE)
{
if (!EC_Game.GetGameRun().GetHostPlayer().IsOmitBlocking(p.Srcroleid))
{
// should be filted by level
return true;
}
}
}
return false;
}
/// <summary>
/// [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à &amp; cho hiển thị an toàn.
/// </summary>
/// <param name="pProtocol">Protocol gốc (để add vào pending nếu name chưa ready)</param>
/// <param name="p">Chat message data</param>
/// <param name="strTemp">ref: nội dung chat (đã qua FilterInvalidTags), sẽ bị thay đổi nếu là policy chat</param>
/// <param name="szMsg">out: chuỗi đã convert sẵn cho hiển thị (tương đương ACHAR szMsg[1024] trong C++)</param>
/// <returns>true = xử lý xong, false = cần chờ (pending name từ server)</returns>
public static bool PolicyResolver(Protocol pProtocol, chatmessage p, ref string strTemp, out string szMsg)
{
szMsg = strTemp;
if (IsPolicyChat(p))
{
// C++: CHAT_S2C::CreatPolicyChatParameter(p->data)
CHAT_S2C.PolicyChatParameter pPolicyChatPara = CHAT_S2C.CreatPolicyChatParameter(p.Data);
// C++: if (!pPolicyChatPara && p->data.size() > 0) → parse failed nhưng có data → hiển thị "???"
if (pPolicyChatPara == null && p.Data.Size > 0)
{
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))
{
// TODO: strTemp = CECUIHelper.FormatCoordText(strTemp);
}
}
// C++: wcsncpy(szMsg, strTemp, strLen) — Policy chat không cần convert ^ &
szMsg = strTemp;
}
else
{
// 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 static bool IsPolicyChat(chatmessage p)
{
bool bOK = false;
switch (p.Channel)
{
case (byte)ChatChannel.GP_CHAT_LOCAL: // ÃæÏò¸Ã NPC ¿É¼ûÓòÖÐËùÓÐÍæ¼Ò
if (p.Srcroleid == 0 || // £¨²ßÂÔº°»°Öбê¼Ç $A £©
ISNPCID(p.Srcroleid))
{
// £¨²ßÂÔº°»°ÖÐÎÞ±ê¼Ç £©
bOK = true;
}
break;
case (byte)ChatChannel.GP_CHAT_BATTLE: // ÃæÏò³ÇÕ½¸±±¾Ö¸¶¨ÕóÓª»òÈ«²¿Íæ¼Òº°»°£¨²ßÂÔº°»°Öбê¼Ç $F¡¢$T £©
if (p.Srcroleid == 0)
{
// Ϊ·ÀÒÔºóÓб仯£¬Ôö¼Ó´ËÅжÏ
bOK = true;
}
break;
case (byte)ChatChannel.GP_CHAT_BROADCAST: // ÃæÏòÈ«ÌåÔÚÏßÍæ¼Ò£¨²ßÂÔº°»°Öбê¼Ç $S £©
if (p.Srcroleid == 0)
{
bOK = true;
}
break;
case (byte)ChatChannel.GP_CHAT_INSTANCE
: // ÃæÏò¸±±¾ÖÐÍæ¼Ò£¨²ßÂÔº°»°Öбê¼Ç $I £©£¨ $X ±ê¼Çʱ p->srcroleid == 1£¬´Ëʱֻ³öÏÖÔÚÆÁÄ»ÖÐÑ룩
if (p.Srcroleid == 0 || p.Srcroleid == 1)
{
bOK = true;
}
break;
}
return bOK;
}
static bool ISNPCID(int id)
{
uint uid = (uint)id;
return (uid & 0x80000000) != 0 &&
(uid & 0x40000000) == 0;
}
static bool CanFormatCoordText(chatmessage p)
{
bool bOK = false;
switch (p.Channel)
{
case (byte)ChatChannel.GP_CHAT_LOCAL: // ÃæÏò¸Ã NPC ¿É¼ûÓòÖÐËùÓÐÍæ¼Ò
if (p.Srcroleid == 0 || // £¨²ßÂÔº°»°Öбê¼Ç $A £©
ISNPCID(p.Srcroleid))
{
// £¨²ßÂÔº°»°ÖÐÎÞ±ê¼Ç £©
bOK = true;
}
break;
case (byte)ChatChannel.GP_CHAT_BATTLE: // ÃæÏò³ÇÕ½¸±±¾Ö¸¶¨ÕóÓª»òÈ«²¿Íæ¼Òº°»°£¨²ßÂÔº°»°Öбê¼Ç $F¡¢$T £©
if (p.Srcroleid == 0)
{
// Ϊ·ÀÒÔºóÓб仯£¬Ôö¼Ó´ËÅжÏ
bOK = true;
}
break;
case (byte)ChatChannel.GP_CHAT_BROADCAST: // ÃæÏòÈ«ÌåÔÚÏßÍæ¼Ò£¨²ßÂÔº°»°Öбê¼Ç $S £©
if (p.Srcroleid == 0)
{
bOK = true;
}
break;
case (byte)ChatChannel.GP_CHAT_INSTANCE: //p->srcroleid == 1 ʱ²»½øÐÐ×ø±êµÄÌæ»»
if (p.Srcroleid == 0)
{
bOK = true;
}
break;
}
return bOK;
}
public class AUICTranslate
{
protected string m_AString = string.Empty;
protected string m_AWString = string.Empty;
public AUICTranslate()
{
}
public string Translate(string str)
{
// In original C++ this likely performs UI charset translation.
// Here we simply return the same string or store it.
m_AString = str;
return m_AString;
}
public string Translate(ReadOnlySpan<char> str)
{
m_AWString = new string(str);
return m_AWString;
}
public string ReverseTranslate(string str)
{
// Reverse translation placeholder
m_AString = str;
return m_AString;
}
public string ReverseTranslate(ReadOnlySpan<char> str)
{
m_AWString = new string(str);
return m_AWString;
}
}
}
}