add handlr input

This commit is contained in:
CuongNV
2026-03-16 11:25:31 +07:00
parent 67b6d6f388
commit 37bc21271b
6 changed files with 543 additions and 563 deletions
@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using BrewMonster.Network;
using BrewMonster.Scripts.UI;
using BrewMonster.UI;
using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.Protocols;
@@ -207,356 +203,6 @@ namespace BrewMonster.Scripts.Chat
return bOK;
}
public static bool HanldeGPChatSystem(chatmessage p, bool bCalledagain)
{
/*string strMsg = "";
switch (p.Srcroleid)
{
case 1: //CMSG_BIDSTART
case 2: //CMSG_BIDEND
case 3: //CMSG_BATTLESTART
case 4: //CMSG_BATTLEEND
case 6: //CMSG_BONUSSEND
case 7: //CMSG_SPECIAL
{
if (!bCalledagain)
{
List<int, int> pending;
if (!OnBattleChatMessage(p, pending))
{
if (pending.GetSize() > 0)
{
GetFactionInfo(pending.GetSize(), pending.GetData());
m_aPendingProtocols.Add(pProtocol);
return false;
}
}
}
else
{
if (!OnBattleChatMessage(p, NULL))
{
return false;
}
}
return true;
}
}
return true;
}
public static bool OnBattleChatMessage(chatmessage p, AArray<int, int> pPendingFactions)
{
var pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
var pDlgGuildMap = (CDlgGuildMap)pGameUI.GetDialog("Win_GuildMap");
var info = GlobalData.GetDomainInfos();
var pMan = g_pGame.GetFactionMan();
string strMsg = string.Empty;
if (pPendingFactions != null)
{
pPendingFactions.RemoveAll();
}
switch (p.srcroleid)
{
case 1: // CMSG_BIDSTART
{
strMsg = pGameUI.GetStringFromTable(4001);
break;
}
case 2: // CMSG_BIDEND
{
int group = p.msg.Size / (sizeof(short) + 2 * sizeof(uint));
strMsg = pGameUI.GetStringFromTable(4002);
if (group == 0)
break;
int idFaction = g_pGame.GetGameRun().GetHostPlayer().GetFactionID();
string strAttacker = "";
string strDefender = "";
string strAnnounce = "";
pDlgGuildMap.ClearMessage();
var o = new OctetsStream(p.msg);
for (; group > 0; group--)
{
short id = o.ReadShort();
uint owner = o.ReadUInt();
uint challenger = o.ReadUInt();
var finfo = pMan.GetFaction(challenger);
if ((int)challenger == idFaction)
strAttacker = pGameUI.GetStringFromTable(4500);
else if (finfo != null)
strAttacker = string.Format(pGameUI.GetStringFromTable(4499), finfo.GetName());
else if (pPendingFactions != null)
pPendingFactions.UniquelyAdd((int)challenger);
if (string.IsNullOrEmpty(strAttacker))
{
strMsg = "";
continue;
}
for (int i = 0; i < info.Count; i++)
{
if (info[i].id == id)
{
if (info[i].id_owner != 0)
{
if (info[i].id_owner == idFaction)
strDefender = pGameUI.GetStringFromTable(4500);
else
{
var finfo2 = pMan.GetFaction(info[i].id_owner);
if (finfo2 != null)
strDefender = string.Format(
pGameUI.GetStringFromTable(4499),
finfo2.GetName());
else if (pPendingFactions != null)
pPendingFactions.UniquelyAdd(info[i].id_owner);
}
}
if (string.IsNullOrEmpty(strDefender))
{
strAnnounce = string.Format(
pGameUI.GetStringFromTable(4511),
strAttacker,
info[i].name);
}
else
{
strAnnounce = string.Format(
pGameUI.GetStringFromTable(4512),
strAttacker,
strDefender,
info[i].name);
}
if (pPendingFactions == null || pPendingFactions.GetSize() == 0)
{
pDlgGuildMap.AddMessage(strAnnounce);
}
break;
}
}
strAttacker = "";
strDefender = "";
}
if ((pPendingFactions != null && pPendingFactions.GetSize() > 0) || string.IsNullOrEmpty(strMsg))
{
pDlgGuildMap.ClearMessage();
strMsg = "";
}
break;
}
case 3: // CMSG_BATTLESTART
{
if (p.msg.Size < 2)
return false;
var os = new OctetsStream(p.msg);
byte id = os.ReadByte();
byte result = os.ReadByte();
for (int i = 0; i < info.Count; i++)
{
if (info[i].id == id)
{
strMsg = string.Format(
pGameUI.GetStringFromTable(4003),
info[i].name);
strMsg += pGameUI.GetStringFromTable(3900 + result);
break;
}
}
break;
}
case 4: // CMSG_BATTLEEND
{
if (p.msg.Size < 1)
return false;
var os = new OctetsStream(p.msg);
byte id = os.ReadByte();
for (int i = 0; i < info.Count; i++)
{
if (info[i].id == id)
{
strMsg = string.Format(
pGameUI.GetStringFromTable(4004),
info[i].name);
break;
}
}
break;
}
case 6: // CMSG_BONUSSEND
{
if (p.msg.Size < sizeof(uint) * 3)
return false;
var os = new OctetsStream(p.msg);
uint money = os.ReadUInt();
uint id = os.ReadUInt();
uint count = os.ReadUInt();
var item = CECIvtrItem.CreateItem(id, 0, count);
strMsg = string.Format(
pGameUI.GetStringFromTable(4006),
item.GetName(),
item.GetCount());
break;
}
case 7: // CMSG_SPECIAL
{
if (p.msg.Size < sizeof(short))
return false;
var os = new OctetsStream(p.msg);
short id = os.ReadShort();
for (int i = 0; i < info.Count; i++)
{
if (info[i].id == id)
{
uint fid = info[i].id_owner;
if (fid > 0)
{
var finfo = pMan.GetFaction(fid);
if (finfo != null)
{
strMsg = string.Format(
pGameUI.GetStringFromTable(4007),
info[i].name,
info[i].name,
finfo.GetName());
}
else if (pPendingFactions != null)
{
pPendingFactions.UniquelyAdd((int)fid);
}
}
else
{
strMsg = string.Format(
pGameUI.GetStringFromTable(4005),
info[i].name);
}
break;
}
}
break;
}
default:
return false;
}
if ((pPendingFactions != null && pPendingFactions.GetSize() > 0) || string.IsNullOrEmpty(strMsg))
{
return false;
}
g_pGame.GetGameRun().AddChatMessage(
strMsg,
ChatChannel.GP_CHAT_BROADCAST,
p.srcroleid,
null,
1,
p.emotion);*/
return true;
}
/*public static void OnTaskChatMessage(byte[] buffer, int size)
{
const int iNameLen = 20;
int expectedSize = 4 * 5 + iNameLen * 2;
if (size < expectedSize)
return;
int offset = 0;
int self_id = BitConverter.ToInt32(buffer, offset); offset += 4;
uint task_id = BitConverter.ToUInt32(buffer, offset); offset += 4;
int channel = BitConverter.ToInt32(buffer, offset); offset += 4;
int param = BitConverter.ToInt32(buffer, offset); offset += 4;
int map_id = BitConverter.ToInt32(buffer, offset); offset += 4;
// name (UTF16 20 chars)
string name = Encoding.Unicode.GetString(buffer, offset, iNameLen * 2);
name = name.TrimEnd('\0');
var pTempl = EC_Game.GetTaskTemplateMan()
.GetTaskTemplByID(task_id);
if (pTempl == null)
return;
var tribute = pTempl.GetTribute();
if (string.IsNullOrEmpty(tribute))
return;
// register player name
EC_Game.GetGameRun().AddPlayerName(self_id, name);
string strMsg = tribute;
// replace $name
strMsg = strMsg.Replace("$name", $"&{name}&");
// replace $map
string strMap = "";
var instance = EC_Game.GetGameRun().GetInstance(map_id);
if (instance != null)
strMap = instance.GetName();
strMsg = strMsg.Replace("$map", strMap);
EC_Game.GetGameRun().AddChatMessage(strMsg, channel);
}*/
public class AUICTranslate
{
protected string m_AString = string.Empty;
@@ -1694,7 +1694,6 @@ namespace CSNetwork
BitConverter.GetBytes(cmd).CopyTo(bytes, 0);
BitConverter.GetBytes(cardId).CopyTo(bytes, 2);
Debug.Log($"[Cuong] SendChatData {bytes}");
p.Data.Replace(bytes);
}
}
@@ -1743,6 +1742,7 @@ namespace CSNetwork
}
}
EventBus.PublishChannel(pHost.GetCharacterID(), new EventChatMessageOnTopPlayer(pHost.GetCharacterID(), szMsg));
EventBus.Publish(new ChatMessageEvent(szMsg, p.Channel));
}
}
+1
View File
@@ -24,6 +24,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
[SerializeField] private int currentTargetNPCID;
CECGameUIMan gameUI;
public CECGameUIMan GameUI => gameUI;
AUIManager aUIManager;
AUIDialog _dlgPlayerOptions;
[SerializeField] private DialogScriptTableObject dialogResouce;
+231
View File
@@ -0,0 +1,231 @@
/*
using UnityEngine;
using System.Collections.Generic;
using BrewMonster.Network;
using CSNetwork.GPDataType;
namespace BrewMonster.Scripts.ChatUI
{
public class ChatCommandProcessor
{
private struct ChatHistoryEntry
{
public ChatChannel channel;
public float time;
public string message;
}
private static List<ChatHistoryEntry> _history = new List<ChatHistoryEntry>();
private const int MAX_HISTORY = 10;
private static float _lastFarCryTime = 0;
private static float _lastSuperFarCryTime = 0;
public struct ProcessResult
{
public bool success;
public ChatChannel channel;
public string message;
public string targetPlayer; // For whisper
public int itemPack;
public int itemSlot;
public string errorString;
public bool showConfirmation;
public int confirmationStringId;
}
public static ProcessResult Process(string text, int itemPack = -1, int itemSlot = -1)
{
ProcessResult result = new ProcessResult
{
success = false,
channel = ChatChannel.GP_CHAT_LOCAL,
message = text,
itemPack = itemPack,
itemSlot = itemSlot,
showConfirmation = false
};
if (string.IsNullOrWhiteSpace(text))
{
return result;
}
// Flood protection
float now = Time.time;
if (_history.Count > 0)
{
var last = _history[_history.Count - 1];
if (now - last.time <= 1.0f)
{
result.errorString = GetStringFromTable(272);
return result;
}
foreach (var entry in _history)
{
if (entry.channel != ChatChannel.GP_CHAT_WHISPER &&
entry.message == text &&
now - entry.time <= 6.0f)
{
result.errorString = GetStringFromTable(273);
return result;
}
}
}
// Debug commands
if (text == "##debug")
{
// Toggle console logic here if needed
result.success = true;
return result;
}
string pszMsg = text;
ChatChannel channel = ChatChannel.GP_CHAT_LOCAL;
if (text.Length >= 2 && text.StartsWith("!!"))
{
channel = ChatChannel.GP_CHAT_TEAM;
pszMsg = text.Substring(2);
}
else if (text.Length >= 2 && text.StartsWith("!~"))
{
channel = ChatChannel.GP_CHAT_FACTION;
pszMsg = text.Substring(2);
}
else if (text.Length >= 2 && text.StartsWith("!@"))
{
channel = ChatChannel.GP_CHAT_FARCRY;
pszMsg = text.Substring(2);
// Requirement check
int itemNum = GetPlayerItemCount(12979) + GetPlayerItemCount(36092);
if (itemNum < 1 || GetPlayerLevel() < 5)
{
result.errorString = GetStringFromTable(731);
return result;
}
if (now - _lastFarCryTime <= 1.0f)
{
result.errorString = GetStringFromTable(730);
return result;
}
result.showConfirmation = true;
result.confirmationStringId = 732;
}
else if (text.Length >= 2 && text.StartsWith("!#"))
{
channel = ChatChannel.GP_CHAT_SUPERFARCRY;
pszMsg = text.Substring(2);
int itemNum = GetPlayerItemCount(27728) + GetPlayerItemCount(27729);
if (itemNum < 1)
{
result.errorString = GetStringFromTable(8531);
return result;
}
if (now - _lastSuperFarCryTime <= 1.0f)
{
result.errorString = GetStringFromTable(8530);
return result;
}
result.showConfirmation = true;
result.confirmationStringId = 8532;
}
else if (text.Length >= 1 && text.StartsWith("$"))
{
if (HasCountryChannel())
{
channel = ChatChannel.GP_CHAT_COUNTRY;
pszMsg = text.Substring(1);
// Add king/money checks if needed
}
else
{
channel = ChatChannel.GP_CHAT_TRADE;
pszMsg = text.Substring(1);
if (GetPlayerLevel() <= 30)
{
result.errorString = GetStringFromTable(530);
return result;
}
}
}
else if (text.Length >= 1 && text.StartsWith("/"))
{
string cmdPart = text.Substring(1);
int spaceIdx = cmdPart.IndexOf(' ');
if (spaceIdx > 0)
{
result.targetPlayer = cmdPart.Substring(0, spaceIdx);
pszMsg = cmdPart.Substring(spaceIdx + 1);
channel = ChatChannel.GP_CHAT_WHISPER;
}
else
{
// Maybe just showing help or something
result.errorString = GetStringFromTable(234);
return result;
}
}
else
{
channel = HasCountryWarChannel() ? ChatChannel.GP_CHAT_BATTLE : ChatChannel.GP_CHAT_LOCAL;
pszMsg = text;
}
if (string.IsNullOrWhiteSpace(pszMsg))
{
return result;
}
result.success = true;
result.channel = channel;
result.message = pszMsg;
// Update history
if (_history.Count >= MAX_HISTORY)
_history.RemoveAt(0);
_history.Add(new ChatHistoryEntry { channel = channel, time = now, message = text });
if (channel == ChatChannel.GP_CHAT_FARCRY) _lastFarCryTime = now;
if (channel == ChatChannel.GP_CHAT_SUPERFARCRY) _lastSuperFarCryTime = now;
return result;
}
private static string GetStringFromTable(int id)
{
return CECUIManager.Instance?.GetInGameUIMan()?.GetStringFromTable(id) ?? $"[STR_{id}]";
}
private static int GetPlayerItemCount(int tid)
{
return 0;
//return EC_GameRun.Instance?.GetHostPlayer()?.GetPack()?.GetItemTotalNum(tid) ?? 0;
}
private static int GetPlayerLevel()
{
return 0;
//return EC_GameRun.Instance?.GetHostPlayer()?.GetBasicProps()?.iLevel ?? 0;
}
private static bool HasCountryChannel()
{
return false;
//return EC_GameRun.Instance?.GetHostPlayer()?.HasCountryChannel() ?? false;
}
private static bool HasCountryWarChannel()
{
return false;
//return EC_GameRun.Instance?.GetHostPlayer()?.HasCountryWarChannel() ?? false;
}
}
}
*/
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3a090b5a4bce36b44b6def3542c520d4
+308 -208
View File
@@ -1,267 +1,367 @@
using UnityEngine;
using TMPro;
using BrewMonster;
using BrewMonster.Network;
using CSNetwork.GPDataType;
using System;
using System.Collections.Generic;
using System.Text;
using BrewMonster.Scripts.Task;
using BrewMonster.Network;
using BrewMonster.UI;
using CSNetwork;
namespace BrewMonster.Scripts.ChatUI
{
/// <summary>
/// Handles chat input from TMP_InputField and provides task-sharing functionality.
/// Converted from CDlgTaskTrace::OnCommand_Chat (DlgTaskTrace.cpp line 888).
/// </summary>
public class ChatInputHandler : MonoBehaviour
{
[Header("UI References")]
public TMP_InputField inputField; // Ô gõ text
public TMP_InputField inputField;
[Header("Chat Settings")]
[Tooltip("Giới hạn số ký tự tối đa cho mỗi tin nhắn chat")]
public int maxChatLength = 256;
private const int MAX_HISTORY = 10;
// ===== Constants from C++ source =====
private const string INDENTATION = " ";
private const int MAX_ITEM_WANTED = 10;
private const int MAX_MONSTER_WANTED = 3;
private const int MAX_PLAYER_WANTED = MAX_MONSTER_WANTED;
private struct ChatMsg
{
public ChatChannel channel;
public float time;
public string msg;
public int pack;
public int slot;
}
private List<ChatMsg> m_vecHistory = new();
private int m_nCurHistory = 0;
private float m_dwTickFarCry = 0;
private float m_dwTickFarCry2 = 0;
private void Start()
{
inputField.onSubmit.AddListener(OnSubmit);
// Giới hạn ký tự trực tiếp trên InputField
if (inputField.characterLimit <= 0 || inputField.characterLimit > maxChatLength)
inputField.characterLimit = maxChatLength;
}
private void OnDestroy()
{
inputField.onSubmit.RemoveListener(OnSubmit);
}
// ===== Khi nhấn Enter =====
private void OnSubmit(string text)
{
if (string.IsNullOrWhiteSpace(text))
return;
HandleUserInput(text);
OnCommand_speak(text);
}
// ===== Hàm xử lý input (gửi server) =====
private void HandleUserInput(string text)
// =====================================================
// PORT C++: CDlgChat::OnCommand_speak
// =====================================================
private void OnCommand_speak(string text)
{
// Áp dụng giới hạn ký tự
text = TruncateText(text, maxChatLength);
string strText = text.Trim();
// Lọc từ cấm (bad words filter)
CECUIManager.Instance?.FilterBadWords(ref text);
if (strText.Length <= 0)
{
ChangeFocus();
return;
}
UnityGameSession.SendChatData(
(byte)ChatChannel.GP_CHAT_LOCAL,
text,
0,
0
);
int nPack = -1;
int nSlot = -1;
// reset input
inputField.text = "";
inputField.ActivateInputField(); // focus lại để tiếp tục gõ
}
FilterBadWords(ref strText);
public void Send(string text)
{
if (string.IsNullOrWhiteSpace(text))
if (HandleDebugCommand(strText))
return;
HandleUserInput(text);
float now = Time.time;
if (!CheckFarCryRequirement(strText, now))
return;
if (!CheckSuperFarCryRequirement(strText, now))
return;
if (!CheckSpamProtection(strText, now))
return;
ParseAndSendMessage(strText, nPack, nSlot);
SaveHistory(strText, nPack, nSlot, now);
ChangeFocus();
}
// =================================================================
// SECTION: OnCommand_Chat - Chia sẻ trạng thái nhiệm vụ lên chat
// Converted from CDlgTaskTrace::OnCommand_Chat (DlgTaskTrace.cpp)
// =================================================================
// =====================================================
// DEBUG COMMAND
// =====================================================
/// <summary>
/// Builds a chat message describing task progress and sends it to the appropriate channel.
/// Gọi hàm này khi người chơi bấm nút "Chia sẻ nhiệm vụ" trên giao diện Task Trace.
/// </summary>
/// <param name="idTask">ID của nhiệm vụ cần chia sẻ.</param>
public void OnCommand_Chat(uint idTask)
private bool HandleDebugCommand(string text)
{
// TODO: Replace with actual EC_Game Unity Wrapper when available
// CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
// CECTaskInterface pTask = pHost.GetTaskInterface();
// ATaskTempl pTemp = pTask.GetTaskTemplMan().GetTaskTemplByID(idTask);
// --- MOCK DATA FOR COMPILATION ---
bool bActiveTask = true;
StringBuilder sb = new StringBuilder();
// string strName = pTemp.GetName();
string strName = $"[Task_{idTask}]";
strName = DeleteColorStr(strName);
sb.Append(strName);
/*
// --- Lấy thông tin trạng thái task ---
Task_State_info tsi = new Task_State_info();
pTask.GetTaskStateInfo(idTask, ref tsi, bActiveTask);
// --- NPC trao thưởng (nếu có thể hoàn thành task) ---
int nANPC = (int)pTemp.GetAwardNPC();
if (nANPC > 0 && pTask.CanFinishTask(idTask))
...
*/
// --- MOCK LOGIC TO APPEND PROGRESS ---
sb.Append(INDENTATION);
sb.AppendFormat(GetStringFromTable(248), GetItemName(123), 2, 10); // Mock item progress
// --- Cắt bớt trailing '\r' ---
string strText = sb.ToString().TrimEnd('\r');
// --- Áp dụng giới hạn ký tự ---
strText = TruncateText(strText, maxChatLength);
// --- Xác định kênh chat: Team nếu có đội, Local nếu không ---
byte channel = (byte)ChatChannel.GP_CHAT_LOCAL;
// --- Gửi lên server ---
UnityGameSession.SendChatData(channel, strText, 0, 0);
Debug.Log($"[ChatInputHandler] OnCommand_Chat: Sent mock task {idTask} to channel {channel}, length={strText.Length}");
}
// =================================================================
// SECTION: Helper methods
// =================================================================
/// <summary>
/// Cắt chuỗi nếu vượt quá giới hạn ký tự, thêm dấu "..." ở cuối.
/// </summary>
private static string TruncateText(string text, int maxLength)
{
if (string.IsNullOrEmpty(text) || maxLength <= 0)
return text;
if (text.Length <= maxLength)
return text;
// Trừ 3 ký tự để chèn "..."
if (maxLength > 3)
return text.Substring(0, maxLength - 3) + "...";
else
return text.Substring(0, maxLength);
}
/// <summary>
/// Xóa các mã màu "^xxxxxx" ra khỏi chuỗi.
/// Tương đương CDlgTaskTrace::DeleteColorStr trong C++.
/// </summary>
private static string DeleteColorStr(string str)
{
if (string.IsNullOrEmpty(str))
return str;
StringBuilder result = new StringBuilder(str.Length);
for (int i = 0; i < str.Length; i++)
if (text == "##debug")
{
if (str[i] == '^' && i + 6 < str.Length)
Debug.Log("Toggle debug console");
return true;
}
return false;
}
// =====================================================
// FARCRY CHECK (!@)
// =====================================================
private bool CheckFarCryRequirement(string text, float now)
{
if (text.StartsWith("!@"))
{
int itemNum = GetPlayerItemCount(12979) + GetPlayerItemCount(36092);
if (itemNum < 1 || GetPlayerLevel() < 5)
{
// Kiểm tra 6 ký tự tiếp theo có phải hex không
bool isColorCode = true;
for (int j = 1; j <= 6; j++)
{
char c = str[i + j];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
{
isColorCode = false;
break;
}
}
if (isColorCode)
{
i += 6; // bỏ qua 6 ký tự hex
continue;
}
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(731), ChatChannel.GP_CHAT_MISC);
return false;
}
if (now - m_dwTickFarCry <= 1f)
{
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(730), ChatChannel.GP_CHAT_MISC);
return false;
}
result.Append(str[i]);
}
return result.ToString();
return true;
}
/// <summary>
/// Format thời gian cho task (tương đương CDlgTask::FormatTime trong C++).
/// </summary>
private static string FormatTime(int nSec, string format, int totalTime)
// =====================================================
// SUPER FARCRY (!#)
// =====================================================
private bool CheckSuperFarCryRequirement(string text, float now)
{
int hours = nSec / 3600;
int minutes = (nSec % 3600) / 60;
int seconds = nSec % 60;
string timeStr;
if (hours > 0)
timeStr = $"{hours:D2}:{minutes:D2}:{seconds:D2}";
else
timeStr = $"{minutes:D2}:{seconds:D2}";
if (!string.IsNullOrEmpty(format))
if (text.StartsWith("!#"))
{
try { return string.Format(format, timeStr); }
catch { return timeStr; }
int itemNum = GetPlayerItemCount(27728) + GetPlayerItemCount(27729);
if (itemNum < 1)
{
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(8531), ChatChannel.GP_CHAT_MISC);
return false;
}
if (now - m_dwTickFarCry2 <= 1f)
{
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(8530), ChatChannel.GP_CHAT_MISC);
return false;
}
}
return timeStr;
return true;
}
/// <summary>
/// Lấy string từ bảng String Table (StringFromTable).
/// Tương đương pUIMan->GetStringFromTable(id) trong C++.
/// </summary>
private static string GetStringFromTable(int id)
// =====================================================
// SPAM PROTECTION
// =====================================================
private bool CheckSpamProtection(string text, float now)
{
// Sử dụng hệ thống StringTable có sẵn trong project
var gameUI = CECUIManager.Instance?.GetInGameUIMan();
string result = gameUI?.GetStringFromTable(id);
return result ?? $"[STR_{id}]";
if (m_vecHistory.Count == 0)
return true;
var last = m_vecHistory[m_vecHistory.Count - 1];
if (now - last.time <= 1f)
{
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(272), ChatChannel.GP_CHAT_MISC);
return false;
}
foreach (var cm in m_vecHistory)
{
if (cm.channel != ChatChannel.GP_CHAT_WHISPER &&
cm.msg == text &&
now - cm.time <= 6f)
{
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(273), ChatChannel.GP_CHAT_MISC);
return false;
}
}
return true;
}
/// <summary>
/// Lấy tên NPC theo ID từ ElementDataMan.
/// </summary>
private static string GetNPCName(int npcId)
// =====================================================
// PARSE MESSAGE PREFIX
// =====================================================
private void ParseAndSendMessage(string text, int nPack, int nSlot)
{
// TODO: Kết nối với ElementDataMan của bạn khi đã port xong
// var pDataMan = EC_Game.GetElementDataMan();
// return pDataMan?.GetNPCName(npcId);
return $"NPC_{npcId}";
ChatChannel channel;
string pszMsg;
if (text.StartsWith("!!"))
{
channel = ChatChannel.GP_CHAT_TEAM;
pszMsg = text.Substring(2);
}
else if (text.StartsWith("!~"))
{
channel = ChatChannel.GP_CHAT_FACTION;
pszMsg = text.Substring(2);
}
else if (text.StartsWith("!@"))
{
channel = ChatChannel.GP_CHAT_FARCRY;
pszMsg = text.Substring(2);
}
else if (text.StartsWith("!#"))
{
channel = ChatChannel.GP_CHAT_SUPERFARCRY;
pszMsg = text.Substring(2);
}
else if (text.StartsWith("$"))
{
channel = ChatChannel.GP_CHAT_TRADE;
pszMsg = text.Substring(1);
}
else if (text.StartsWith("/"))
{
HandleWhisper(text, nPack, nSlot);
return;
}
else
{
channel = ChatChannel.GP_CHAT_LOCAL;
pszMsg = text;
}
SendChat(channel, pszMsg, nPack, nSlot);
}
/// <summary>
/// Lấy tên Monster theo ID từ ElementDataMan.
/// </summary>
private static string GetMonsterName(int monsterId)
// =====================================================
// WHISPER
// =====================================================
private void HandleWhisper(string text, int nPack, int nSlot)
{
// TODO: Kết nối với ElementDataMan của bạn khi đã port xong
// var pDataMan = EC_Game.GetElementDataMan();
// return pDataMan?.GetMonsterName(monsterId);
return $"Monster_{monsterId}";
string cmd = text.Substring(1);
int spaceIndex = cmd.IndexOf(' ');
if (spaceIndex <= 0)
{
AddChatMessage(CECUIManager.Instance.GameUI.GetStringFromTable(234), ChatChannel.GP_CHAT_MISC);
return;
}
string player = cmd.Substring(0, spaceIndex);
string msg = cmd.Substring(spaceIndex + 1);
SendPrivateChat(player, msg, nPack, nSlot);
}
/// <summary>
/// Lấy tên Item theo ID từ ElementDataMan.
/// </summary>
private static string GetItemName(int itemId)
// =====================================================
// SEND CHAT
// =====================================================
private void SendChat(ChatChannel channel, string msg, int pack, int slot)
{
// TODO: Kết nối với ElementDataMan của bạn khi đã port xong
// var pDataMan = EC_Game.GetElementDataMan();
// return pDataMan?.GetItemName(itemId);
return $"Item_{itemId}";
UnityGameSession.SendChatData((byte)channel, msg, pack, slot);
}
private void SendPrivateChat(string target, string msg, int pack, int slot)
{
Debug.Log($"Whisper to {target}: {msg}");
}
// =====================================================
// HISTORY
// =====================================================
private void SaveHistory(string msg, int pack, int slot, float now)
{
if (m_vecHistory.Count >= MAX_HISTORY)
m_vecHistory.RemoveAt(0);
m_vecHistory.Add(new ChatMsg
{
channel = ChatChannel.GP_CHAT_LOCAL,
msg = msg,
pack = pack,
slot = slot,
time = now
});
m_nCurHistory = m_vecHistory.Count;
}
// =====================================================
// UTILITIES
// =====================================================
private void FilterBadWords(ref string text)
{
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;
// 2. Blacklist check (Placeholder for porting)
if (IsPlayerBlacklisted(idPlayer))
return;
// 3. Flag handling (Friend chat routing)
if (byFlag == 1) // CHANNEL_FRIEND equivalent
{
// AddFriendMessage(strModified, idPlayer, pszPlayer, ...);
// return;
}
// 4. Formatting with Rich Text
string colorHex = GetChannelColorHex(channel);
string prefix = GetChannelPrefix(channel);
string sender = string.IsNullOrEmpty(pszPlayer) ? "" : $"{pszPlayer}: ";
string finalMsg = $"<color=#{colorHex}>{prefix}{sender}{strModified}</color>";
// 5. Publish event
EventBus.Publish(new GameSession.ChatMessageEvent(finalMsg, (byte)channel));
Debug.Log(finalMsg);
}
private string GetChannelColorHex(ChatChannel channel)
{
// Simplified mapping based on common PW colors
return channel switch
{
ChatChannel.GP_CHAT_TEAM => "00FFFF", // Cyan
ChatChannel.GP_CHAT_FACTION => "00FF00", // Green
ChatChannel.GP_CHAT_FARCRY => "FFFF00", // Yellow
ChatChannel.GP_CHAT_WHISPER => "FF00FF", // Magenta
_ => "FFFFFF" // White
};
}
private string GetChannelPrefix(ChatChannel channel)
{
return channel switch
{
ChatChannel.GP_CHAT_TEAM => "[Team] ",
ChatChannel.GP_CHAT_FACTION => "[Faction] ",
ChatChannel.GP_CHAT_FARCRY => "[World] ",
ChatChannel.GP_CHAT_WHISPER => "[Whisper] ",
_ => ""
};
}
private bool IsPlayerBlacklisted(int idPlayer) => false; // Placeholder
private void ChangeFocus()
{
inputField.text = "";
inputField.ActivateInputField();
}
private int GetPlayerItemCount(int id) => 0;
private int GetPlayerLevel() => 10;
}
}