243 lines
9.1 KiB
C#
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à & 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;
|
|
}
|
|
}
|
|
}
|
|
}
|