From 46e6d7c3b2cf657851fe783abde85204775a6158 Mon Sep 17 00:00:00 2001
From: CuongNV <>
Date: Wed, 8 Apr 2026 15:43:36 +0700
Subject: [PATCH 1/7] add ui emoji
---
.../ChatSystems/EmotionLibrarySpriteMap.asset | 2 +-
.../EmotionData/EmotionLibrarySpriteMap.cs | 10 +-
.../Scripts/Chat/EmotionTMPTagBuilder.cs | 151 +
.../Scripts/Chat/EmotionTMPTagBuilder.cs.meta | 2 +
.../Scripts/Chat/UI/EmojiButtonCell.cs | 70 +
.../Scripts/Chat/UI/EmojiButtonCell.cs.meta | 2 +
.../Scripts/Chat/UI/EmojiPickerUI.cs | 198 +
.../Scripts/Chat/UI/EmojiPickerUI.cs.meta | 2 +
.../Editor/EmotionAtlasConverterCore.cs | 171 +
.../Editor/EmotionAtlasConverterWindow.cs | 116 +-
.../Scripts/Network/CSNetwork/GameSession.cs | 4 +-
.../GeneratedEmotions}/EmotionLibrary.asset | 0
.../EmotionLibrary.asset.meta | 2 +-
.../Emotions7/Emotions7_atlas.png.meta | 2 +-
.../ChatSystem/prefab_ChatSystemUI.prefab | 330 +-
.../ChatSystem/prefab_EmojiCell.prefab | 136 +
.../ChatSystem/prefab_EmojiCell.prefab.meta | 7 +
.../Resources/Sprite Assets/EmojiOne.asset | 4 +-
.../Resources/Sprite Assets/Emotions 0.asset | 5970 ++++++++
.../Sprite Assets/Emotions 0.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 1.asset | 5970 ++++++++
.../Sprite Assets/Emotions 1.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 2.asset | 11346 ++++++++++++++++
.../Sprite Assets/Emotions 2.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 3.asset | 11346 ++++++++++++++++
.../Sprite Assets/Emotions 3.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 4.asset | 5970 ++++++++
.../Sprite Assets/Emotions 4.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 5.asset | 5970 ++++++++
.../Sprite Assets/Emotions 5.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 6.asset | 5970 ++++++++
.../Sprite Assets/Emotions 6.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 7.asset | 5970 ++++++++
.../Sprite Assets/Emotions 7.asset.meta | 8 +
.../Resources/Sprite Assets/Emotions 8.asset | 5970 ++++++++
.../Sprite Assets/Emotions 8.asset.meta | 8 +
36 files changed, 65671 insertions(+), 92 deletions(-)
create mode 100644 Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs
create mode 100644 Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs.meta
create mode 100644 Assets/PerfectWorld/Scripts/Chat/UI/EmojiButtonCell.cs
create mode 100644 Assets/PerfectWorld/Scripts/Chat/UI/EmojiButtonCell.cs.meta
create mode 100644 Assets/PerfectWorld/Scripts/Chat/UI/EmojiPickerUI.cs
create mode 100644 Assets/PerfectWorld/Scripts/Chat/UI/EmojiPickerUI.cs.meta
rename Assets/PerfectWorld/{ScriptableObjects/ChatSystems => UI/Chat/GeneratedEmotions}/EmotionLibrary.asset (100%)
rename Assets/PerfectWorld/{ScriptableObjects/ChatSystems => UI/Chat/GeneratedEmotions}/EmotionLibrary.asset.meta (79%)
create mode 100644 Assets/Prefabs/ChatSystem/prefab_EmojiCell.prefab
create mode 100644 Assets/Prefabs/ChatSystem/prefab_EmojiCell.prefab.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 0.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 0.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 1.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 1.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 2.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 2.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 3.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 3.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 4.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 4.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 5.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 5.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 6.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 6.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 7.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 7.asset.meta
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 8.asset
create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/Emotions 8.asset.meta
diff --git a/Assets/PerfectWorld/ScriptableObjects/ChatSystems/EmotionLibrarySpriteMap.asset b/Assets/PerfectWorld/ScriptableObjects/ChatSystems/EmotionLibrarySpriteMap.asset
index c873bc9b2b..bf346510ce 100644
--- a/Assets/PerfectWorld/ScriptableObjects/ChatSystems/EmotionLibrarySpriteMap.asset
+++ b/Assets/PerfectWorld/ScriptableObjects/ChatSystems/EmotionLibrarySpriteMap.asset
@@ -12,7 +12,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: af2fa24fb63c4aa45bb99a711c857114, type: 3}
m_Name: EmotionLibrarySpriteMap
m_EditorClassIdentifier:
- Library: {fileID: 11400000, guid: 3011939e4e9c0ce4e83bc03a748fcf96, type: 2}
+ Library: {fileID: 11400000, guid: e4fbe1473e80a9c4794327d8bb11a4ab, type: 2}
TmpSpriteAsset: {fileID: 11400000, guid: c41005c129ba4d66911b75229fd70b45, type: 2}
PreferSpriteNameTag: 1
DefaultAnimFps: 10
diff --git a/Assets/PerfectWorld/Scripts/Chat/EmotionData/EmotionLibrarySpriteMap.cs b/Assets/PerfectWorld/Scripts/Chat/EmotionData/EmotionLibrarySpriteMap.cs
index 90b6f7477a..8664df87a3 100644
--- a/Assets/PerfectWorld/Scripts/Chat/EmotionData/EmotionLibrarySpriteMap.cs
+++ b/Assets/PerfectWorld/Scripts/Chat/EmotionData/EmotionLibrarySpriteMap.cs
@@ -95,12 +95,14 @@ namespace BrewMonster.Scripts.Chat.EmotionData
if (TmpSpriteAsset == null || string.IsNullOrEmpty(spriteName))
return -1;
- if (TmpSpriteAsset.spriteInfoList != null)
+ // TMP 3.x: dùng spriteCharacterTable (spriteInfoList đã deprecated)
+ // TMP 3.x: use spriteCharacterTable (spriteInfoList is deprecated)
+ var charTable = TmpSpriteAsset.spriteCharacterTable;
+ if (charTable != null)
{
- for (int i = 0; i < TmpSpriteAsset.spriteInfoList.Count; i++)
+ for (int i = 0; i < charTable.Count; i++)
{
- var s = TmpSpriteAsset.spriteInfoList[i];
- if (s != null && s.name == spriteName)
+ if (charTable[i] != null && charTable[i].name == spriteName)
return i;
}
}
diff --git a/Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs b/Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs
new file mode 100644
index 0000000000..9130f8660d
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs
@@ -0,0 +1,151 @@
+using TMPro;
+using UnityEngine;
+
+namespace BrewMonster.Scripts.Chat
+{
+ ///
+ /// Helper tĩnh: chuyển EmotionSpriteInfo → TMP rich-text tag và insert vào TMP_InputField.
+ /// Static helper: converts EmotionSpriteInfo → TMP rich-text tag and inserts it into a TMP_InputField.
+ ///
+ /// Cách dùng điển hình / Typical usage:
+ ///
+ /// // Khi người dùng bấm chọn emoji từ picker:
+ /// // When user taps an emoji in the picker:
+ /// EmotionTMPTagBuilder.InsertEmotionTag(_chatInputField, _spriteMap, emotionSet, emotionIndex);
+ ///
+ /// // Hoặc chỉ lấy tag string rồi tự xử lý:
+ /// // Or just get the tag string and handle it yourself:
+ /// if (EmotionTMPTagBuilder.TryBuildEmotionTag(_spriteMap, set, idx, out string tag))
+ /// Debug.Log(tag); // → "" hoặc ""
+ ///
+ ///
+ public static class EmotionTMPTagBuilder
+ {
+ // ─────────────────────────────────────────────────────────────────────
+ // Tag builders
+ // ─────────────────────────────────────────────────────────────────────
+
+ ///
+ /// Tạo TMP rich-text tag từ EmotionSpriteInfo đã resolve.
+ /// Build TMP rich-text tag from an already-resolved EmotionSpriteInfo.
+ ///
+ /// Thứ tự ưu tiên / Priority:
+ /// 1. UseSpriteName → <sprite name="…">
+ /// 2. IsAnimated → <sprite anim="start,end,fps">
+ /// 3. (fallback) → <sprite index=N>
+ ///
+ public static string BuildSpriteTag(EmotionSpriteInfo info)
+ {
+ if (info.UseSpriteName && !string.IsNullOrEmpty(info.SpriteName))
+ return $"";
+
+ if (info.IsAnimated)
+ return $"";
+
+ return $"";
+ }
+
+ ///
+ /// Tra bảng spriteMap rồi tạo TMP tag.
+ /// Lookup spriteMap then build the TMP tag.
+ ///
+ /// Bảng ánh xạ emotion → sprite. Emotion-to-sprite mapping.
+ /// Chỉ số bộ (N trong Emotions{N}). Emotion set index.
+ /// Chỉ số emotion trong bộ (dòng trong .txt). Emotion index within set.
+ /// TMP tag được tạo ra nếu thành công. Built TMP tag on success.
+ /// true nếu tạo được tag, false nếu không tìm thấy emotion. true if tag was built.
+ public static bool TryBuildEmotionTag(IEmotionSpriteMap spriteMap, int emotionSet, int emotionIndex, out string tag)
+ {
+ tag = string.Empty;
+ if (spriteMap == null)
+ {
+ Debug.LogWarning("[EmotionTMPTagBuilder] spriteMap is null.");
+ return false;
+ }
+
+ if (!spriteMap.TryGetSprite(emotionSet, emotionIndex, out EmotionSpriteInfo info))
+ return false;
+
+ tag = BuildSpriteTag(info);
+ return true;
+ }
+
+ // ─────────────────────────────────────────────────────────────────────
+ // TMP_InputField helpers
+ // ─────────────────────────────────────────────────────────────────────
+
+ ///
+ /// Insert TMP emotion tag vào TMP_InputField tại vị trí caret hiện tại.
+ /// Insert the TMP emotion tag into a TMP_InputField at the current caret position.
+ ///
+ /// InputField đang nhập chat. The active chat input field.
+ /// Bảng ánh xạ. Sprite map.
+ /// Chỉ số bộ. Emotion set index.
+ /// Chỉ số emotion. Emotion index within set.
+ /// true nếu tag đã được insert. true if the tag was inserted.
+ public static bool InsertEmotionTag(TMP_InputField inputField, IEmotionSpriteMap spriteMap, int emotionSet, int emotionIndex)
+ {
+ if (inputField == null)
+ {
+ Debug.LogWarning("[EmotionTMPTagBuilder] inputField is null.");
+ return false;
+ }
+
+ if (!TryBuildEmotionTag(spriteMap, emotionSet, emotionIndex, out string tag))
+ return false;
+
+ InsertTagAtCaret(inputField, tag);
+ return true;
+ }
+
+ ///
+ /// Insert tag tại vị trí caret, cập nhật caret sau khi insert.
+ /// Insert tag at caret position, advance caret after insertion.
+ ///
+ public static void InsertTagAtCaret(TMP_InputField inputField, string tag)
+ {
+ if (inputField == null || string.IsNullOrEmpty(tag))
+ return;
+
+ string text = inputField.text ?? string.Empty;
+ int caret = Mathf.Clamp(inputField.caretPosition, 0, text.Length);
+
+ inputField.text = text.Insert(caret, tag);
+
+ // Đặt caret sau tag vừa insert — Move caret to end of inserted tag
+ inputField.caretPosition = caret + tag.Length;
+ inputField.ForceLabelUpdate();
+ }
+
+ // ─────────────────────────────────────────────────────────────────────
+ // Diagnostics
+ // ─────────────────────────────────────────────────────────────────────
+
+ ///
+ /// Log toàn bộ emotion set/index có trong spriteMap ra Console — dùng debug.
+ /// Log all emotion set/index entries in spriteMap to Console — for debugging.
+ ///
+ public static void DebugLogAllEntries(IEmotionSpriteMap spriteMap, int maxSets = 10, int maxEmotionsPerSet = 50)
+ {
+ if (spriteMap == null)
+ {
+ Debug.LogWarning("[EmotionTMPTagBuilder] spriteMap is null.");
+ return;
+ }
+
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ sb.AppendLine("[EmotionTMPTagBuilder] All entries:");
+
+ for (int s = 0; s < maxSets; s++)
+ {
+ for (int e = 0; e < maxEmotionsPerSet; e++)
+ {
+ if (spriteMap.TryGetSprite(s, e, out EmotionSpriteInfo info))
+ sb.AppendLine($" set={s} idx={e} → {BuildSpriteTag(info)}");
+ }
+ }
+
+ Debug.Log(sb.ToString());
+ }
+ }
+}
diff --git a/Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs.meta b/Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs.meta
new file mode 100644
index 0000000000..093e5d1af1
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Chat/EmotionTMPTagBuilder.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 200b07ddd8d07064b9e6896fda84dafe
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/EmojiButtonCell.cs b/Assets/PerfectWorld/Scripts/Chat/UI/EmojiButtonCell.cs
new file mode 100644
index 0000000000..be3fcf7f35
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Chat/UI/EmojiButtonCell.cs
@@ -0,0 +1,70 @@
+using System;
+using TMPro;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace BrewMonster.Scripts.ChatUI
+{
+ ///
+ /// Một ô emoji trong bảng chọn emoji — One emoji cell in the emoji picker grid.
+ /// Gán lên prefab Button có Image + (tuỳ chọn) TMP_Text cho tooltip.
+ ///
+ [RequireComponent(typeof(Button))]
+ public class EmojiButtonCell : MonoBehaviour
+ {
+ [SerializeField] Image _icon;
+ [Tooltip("Tuỳ chọn: hiện hint text (tên emoji). Optional: show hint/tooltip text.")]
+
+ public event Action OnClicked; // (emotionSet, emotionIndex)
+
+ private int _emotionSet;
+ private int _emotionIndex;
+ private Button _button;
+
+ private void Awake()
+ {
+ _button = GetComponent