From c0e6cb2a0ce840bd594d05c7e2cf0a185c312fa0 Mon Sep 17 00:00:00 2001
From: lcy <1459594991@qq.com>
Date: 星期四, 20 十一月 2025 21:27:48 +0800
Subject: [PATCH] 262 幻境阁系统-客户端

---
 Main/Core/GameEngine/Player/PlayerBaseData.cs                                         |   13 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs                              |   33 
 Main/System/PhantasmPavilion/PhantasmPavilionWin.cs.meta                              |    2 
 Main/Config/Configs/ModelConfig.cs                                                    |  116 +
 Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs                          |   68 
 Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs.meta                   |    0 
 Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs.meta                      |    2 
 Main/System/Redpoint/MainRedDot.cs                                                    |    5 
 Main/System/Attribute/AttributeManager.cs                                             |   14 
 Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs.meta                     |    0 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs        |   12 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs                               |  448 +++++
 Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs.meta                         |    2 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs.meta |    2 
 Main/System/PhantasmPavilion/IPhantasmPavilionTabHandler.cs                           |   41 
 Main/System/Chat/ChatCenter.cs                                                        |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs.meta                 |    2 
 Main/System/PlayerProfile/PlayerProfileWin.cs                                         |    7 
 Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs                              |  299 +++
 Main/Utility/EnumHelper.cs                                                            |    6 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs.meta   |    2 
 Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs                |   20 
 Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs.meta                      |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs                           |   67 
 Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs.meta                     |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs                          |   67 
 Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs.meta                         |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs                              |   47 
 Main/Config/Configs/PlayerFacePicConfig.cs                                            |   78 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs                      |   32 
 Main/Config/PartialConfigs/ModelConfig.cs.meta                                        |    2 
 Main/Config/Configs/ModelConfig.cs.meta                                               |    2 
 Main/System/Attribute/TotalAttributeWin.cs                                            |   16 
 Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs                  |   33 
 Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs.meta                        |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs                           |   33 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs.meta                         |    2 
 Main/Config/Configs/TitleConfig.cs                                                    |  116 +
 Main/System/Attribute/AttributeManager.cs.meta                                        |    2 
 Main/System/HeroUI/HeroTrainWin.cs                                                    |   15 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs.meta                          |    2 
 Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs.meta             |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs                          |   67 
 Main/Component/UI/Effect/EllipseMask.cs                                               |    4 
 Main/System/OfficialRank/OfficialTitleCell.cs                                         |   67 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB118_tagMCFacePicInfo.cs      |    5 
 Main/System/PhantasmPavilion/PhantasmPavilionWin.cs                                   |   47 
 Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs.meta                        |    2 
 Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs                                  |    6 
 Main/System/Main/MainWin.cs                                                           |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs                     |  122 +
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs.meta   |    2 
 Main/System/HeroUI/HeroUIManager.cs                                                   |    2 
 Main/System/Attribute/TotalAttributeWin.cs.meta                                       |    0 
 Main/Core/GameEngine/Player/PlayerDatas.cs                                            |   11 
 Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs                           |   45 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs        |   12 
 Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs                              |   17 
 Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs.meta                      |    0 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs.meta                |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.cs                               |  799 +++++++++
 Main/System/PhantasmPavilion/ChatBubbleHelper.cs                                      |    8 
 Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs.meta                        |    2 
 Main/Config/Configs/ChatBubbleBoxConfig.cs                                            |  124 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs                          |  111 +
 Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs                  |   33 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs.meta                 |    2 
 Main/System/Chat/ChatBubbleManager.cs                                                 |   95 
 Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs.meta                      |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs.meta               |    2 
 Main/Config/PartialConfigs/TitleConfig.cs.meta                                        |    2 
 Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs.meta             |    2 
 Main/Config/Configs/PlayerFaceConfig.cs                                               |  107 
 Main/System/Main/FightPowerManager.cs                                                 |    4 
 Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs                             |   33 
 Main/Config/PartialConfigs/TitleConfig.cs                                             |   25 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB117_tagMCFaceInfo.cs         |    5 
 Main/System/PhantasmPavilion/AvatarHelper.cs                                          |   83 
 Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs                              |  309 +++
 Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs.meta                    |    2 
 Main/System/Attribute.meta                                                            |    8 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs                    |  131 +
 Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs.meta                     |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs                             |   63 
 Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs                           |   33 
 Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs.meta                         |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.cs.meta                          |    2 
 Main/Config/ConfigManager.cs                                                          |    9 
 Main/System/InternalAffairs/AffairFuncCell.cs                                         |    5 
 Main/Config/Configs/TitleConfig.cs.meta                                               |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs                           |   51 
 Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs                           |   39 
 Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs                        |   67 
 Main/Config/PartialConfigs/ModelConfig.cs                                             |   25 
 Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs.meta                      |    2 
 Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs               |   22 
 Main/Main.cs                                                                          |    4 
 Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs                        |   67 
 Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs.meta                      |    2 
 Main/System/PhantasmPavilion/AvatarCell.cs                                            |  302 +-
 Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs.meta                         |    2 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs      |   12 
 Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs.meta           |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs.meta                     |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs                         |   62 
 /dev/null                                                                             |   11 
 Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs                             |   52 
 Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs                              |   54 
 Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs                      |  280 +++
 Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs.meta          |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs                             |   33 
 Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs.meta                   |    0 
 Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs.meta                         |    2 
 Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs.meta                        |    2 
 114 files changed, 4,545 insertions(+), 592 deletions(-)

diff --git a/Main/Component/UI/Effect/EllipseMask.cs b/Main/Component/UI/Effect/EllipseMask.cs
index b896aa7..17c5e09 100644
--- a/Main/Component/UI/Effect/EllipseMask.cs
+++ b/Main/Component/UI/Effect/EllipseMask.cs
@@ -88,9 +88,11 @@
             }
         }
     }
-
+    static int order=1;
     protected virtual void Awake()
     {
+        order++;
+        StencilID = order;
         m_RectTransform = GetComponent<RectTransform>();
         
         // 鍒涘缓閬僵鍥惧儚
diff --git a/Main/Config/ConfigManager.cs b/Main/Config/ConfigManager.cs
index 7866caa..47c6024 100644
--- a/Main/Config/ConfigManager.cs
+++ b/Main/Config/ConfigManager.cs
@@ -63,19 +63,20 @@
             typeof(LLMJConfig),
             typeof(MainChapterConfig),
             typeof(MainLevelConfig),
+            typeof(ModelConfig),
             typeof(NPCConfig),
             typeof(NPCExConfig),
             typeof(NPCLineupConfig),
             typeof(OrderInfoConfig),
             typeof(PlayerAttrConfig),
             typeof(PlayerFaceConfig),
-            typeof(PriorBundleConfig),
             typeof(RandomNameConfig),
             typeof(SignInConfig),
             typeof(StoreConfig),
             typeof(SuccessConfig),
             typeof(SysInfoConfig),
             typeof(TianziConfig),
+            typeof(TitleConfig),
             typeof(TitleStarUpConfig),
             typeof(TreasureSetConfig),
             typeof(TreeLVConfig),
@@ -281,6 +282,8 @@
         ClearConfigDictionary<MainChapterConfig>();
         // 娓呯┖ MainLevelConfig 瀛楀吀
         ClearConfigDictionary<MainLevelConfig>();
+        // 娓呯┖ ModelConfig 瀛楀吀
+        ClearConfigDictionary<ModelConfig>();
         // 娓呯┖ NPCConfig 瀛楀吀
         ClearConfigDictionary<NPCConfig>();
         // 娓呯┖ NPCExConfig 瀛楀吀
@@ -293,8 +296,6 @@
         ClearConfigDictionary<PlayerAttrConfig>();
         // 娓呯┖ PlayerFaceConfig 瀛楀吀
         ClearConfigDictionary<PlayerFaceConfig>();
-        // 娓呯┖ PriorBundleConfig 瀛楀吀
-        ClearConfigDictionary<PriorBundleConfig>();
         // 娓呯┖ RandomNameConfig 瀛楀吀
         ClearConfigDictionary<RandomNameConfig>();
         // 娓呯┖ SignInConfig 瀛楀吀
@@ -307,6 +308,8 @@
         ClearConfigDictionary<SysInfoConfig>();
         // 娓呯┖ TianziConfig 瀛楀吀
         ClearConfigDictionary<TianziConfig>();
+        // 娓呯┖ TitleConfig 瀛楀吀
+        ClearConfigDictionary<TitleConfig>();
         // 娓呯┖ TitleStarUpConfig 瀛楀吀
         ClearConfigDictionary<TitleStarUpConfig>();
         // 娓呯┖ TreasureSetConfig 瀛楀吀
diff --git a/Main/Config/Configs/ChatBubbleBoxConfig.cs b/Main/Config/Configs/ChatBubbleBoxConfig.cs
index 3ac83a9..b8216b6 100644
--- a/Main/Config/Configs/ChatBubbleBoxConfig.cs
+++ b/Main/Config/Configs/ChatBubbleBoxConfig.cs
@@ -1,6 +1,6 @@
 锘�//--------------------------------------------------------
 //    [Author]:           YYL
-//    [  Date ]:           2025骞�8鏈�5鏃�
+//    [  Date ]:           2025骞�11鏈�16鏃�
 //--------------------------------------------------------
 
 using System.Collections.Generic;
@@ -18,24 +18,18 @@
 
     public int ID;
 	public string Name;
-	public int NeedLV;
-	public int SortNum;
-	public int UnlockDefault;
+	public int ResourceType;
+	public string ResourceValue;
 	public int ExpireMinutes;
-	public int[][] UnlockNeedItemList;
-	public int[] LightAttrType;
-	public int[] LightAttrValue;
-	public int LightFightPower;
-	public string leftBubbleIcon;
-	public string rightBubbleIcon;
-	public int[] leftOffset;
-	public int[] rightOffset;
-	public string Icon;
-	public int Jump;
-	public string GainTip;
-	public int[] color;
-	public int top;
-	public string Descriptive;
+	public int UnlockWay;
+	public int UnlockValue;
+	public int UnlockNeedCnt;
+	public int UpNeedCnt;
+	public int StarMax;
+	public int[] AttrIDList;
+	public int[] InitAttrValueList;
+	public int[] AttrPerStarAddList;
+	public string GetWayString;
 
     public override int LoadKey(string _key)
     {
@@ -51,101 +45,65 @@
 
 			Name = tables[1];
 
-			int.TryParse(tables[2],out NeedLV); 
+			int.TryParse(tables[2],out ResourceType); 
 
-			int.TryParse(tables[3],out SortNum); 
+			ResourceValue = tables[3];
 
-			int.TryParse(tables[4],out UnlockDefault); 
+			int.TryParse(tables[4],out ExpireMinutes); 
 
-			int.TryParse(tables[5],out ExpireMinutes); 
+			int.TryParse(tables[5],out UnlockWay); 
 
-			UnlockNeedItemList = JsonMapper.ToObject<int[][]>(tables[6].Replace("(", "[").Replace(")", "]")); 
+			int.TryParse(tables[6],out UnlockValue); 
 
-			if (tables[7].Contains("["))
+			int.TryParse(tables[7],out UnlockNeedCnt); 
+
+			int.TryParse(tables[8],out UpNeedCnt); 
+
+			int.TryParse(tables[9],out StarMax); 
+
+			if (tables[10].Contains("["))
 			{
-				LightAttrType = JsonMapper.ToObject<int[]>(tables[7]);
+				AttrIDList = JsonMapper.ToObject<int[]>(tables[10]);
 			}
 			else
 			{
-				string[] LightAttrTypeStringArray = tables[7].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				LightAttrType = new int[LightAttrTypeStringArray.Length];
-				for (int i=0;i<LightAttrTypeStringArray.Length;i++)
+				string[] AttrIDListStringArray = tables[10].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrIDList = new int[AttrIDListStringArray.Length];
+				for (int i=0;i<AttrIDListStringArray.Length;i++)
 				{
-					 int.TryParse(LightAttrTypeStringArray[i],out LightAttrType[i]);
+					 int.TryParse(AttrIDListStringArray[i],out AttrIDList[i]);
 				}
 			}
 
-			if (tables[8].Contains("["))
+			if (tables[11].Contains("["))
 			{
-				LightAttrValue = JsonMapper.ToObject<int[]>(tables[8]);
+				InitAttrValueList = JsonMapper.ToObject<int[]>(tables[11]);
 			}
 			else
 			{
-				string[] LightAttrValueStringArray = tables[8].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				LightAttrValue = new int[LightAttrValueStringArray.Length];
-				for (int i=0;i<LightAttrValueStringArray.Length;i++)
+				string[] InitAttrValueListStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				InitAttrValueList = new int[InitAttrValueListStringArray.Length];
+				for (int i=0;i<InitAttrValueListStringArray.Length;i++)
 				{
-					 int.TryParse(LightAttrValueStringArray[i],out LightAttrValue[i]);
+					 int.TryParse(InitAttrValueListStringArray[i],out InitAttrValueList[i]);
 				}
 			}
-
-			int.TryParse(tables[9],out LightFightPower); 
-
-			leftBubbleIcon = tables[10];
-
-			rightBubbleIcon = tables[11];
 
 			if (tables[12].Contains("["))
 			{
-				leftOffset = JsonMapper.ToObject<int[]>(tables[12]);
+				AttrPerStarAddList = JsonMapper.ToObject<int[]>(tables[12]);
 			}
 			else
 			{
-				string[] leftOffsetStringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				leftOffset = new int[leftOffsetStringArray.Length];
-				for (int i=0;i<leftOffsetStringArray.Length;i++)
+				string[] AttrPerStarAddListStringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrPerStarAddList = new int[AttrPerStarAddListStringArray.Length];
+				for (int i=0;i<AttrPerStarAddListStringArray.Length;i++)
 				{
-					 int.TryParse(leftOffsetStringArray[i],out leftOffset[i]);
+					 int.TryParse(AttrPerStarAddListStringArray[i],out AttrPerStarAddList[i]);
 				}
 			}
 
-			if (tables[13].Contains("["))
-			{
-				rightOffset = JsonMapper.ToObject<int[]>(tables[13]);
-			}
-			else
-			{
-				string[] rightOffsetStringArray = tables[13].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				rightOffset = new int[rightOffsetStringArray.Length];
-				for (int i=0;i<rightOffsetStringArray.Length;i++)
-				{
-					 int.TryParse(rightOffsetStringArray[i],out rightOffset[i]);
-				}
-			}
-
-			Icon = tables[14];
-
-			int.TryParse(tables[15],out Jump); 
-
-			GainTip = tables[16];
-
-			if (tables[17].Contains("["))
-			{
-				color = JsonMapper.ToObject<int[]>(tables[17]);
-			}
-			else
-			{
-				string[] colorStringArray = tables[17].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				color = new int[colorStringArray.Length];
-				for (int i=0;i<colorStringArray.Length;i++)
-				{
-					 int.TryParse(colorStringArray[i],out color[i]);
-				}
-			}
-
-			int.TryParse(tables[18],out top); 
-
-			Descriptive = tables[19];
+			GetWayString = tables[13];
         }
         catch (Exception exception)
         {
diff --git a/Main/Config/Configs/ModelConfig.cs b/Main/Config/Configs/ModelConfig.cs
new file mode 100644
index 0000000..860ecf8
--- /dev/null
+++ b/Main/Config/Configs/ModelConfig.cs
@@ -0,0 +1,116 @@
+锘�//--------------------------------------------------------
+//    [Author]:           YYL
+//    [  Date ]:           2025骞�11鏈�18鏃�
+//--------------------------------------------------------
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using LitJson;
+
+public partial class ModelConfig : ConfigBase<int, ModelConfig>
+{
+    static ModelConfig()
+    {
+        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
+        visit = true; 
+    }
+
+    public int ID;
+	public int TabType;
+	public string Name;
+	public string FaceBg;
+	public int SkinID;
+	public int ExpireMinutes;
+	public int UnlockWay;
+	public int UnlockValue;
+	public int UnlockNeedCnt;
+	public int UpNeedCnt;
+	public int StarMax;
+	public int[] AttrIDList;
+	public int[] InitAttrValueList;
+	public int[] AttrPerStarAddList;
+	public string GetWayString;
+
+    public override int LoadKey(string _key)
+    {
+        int key = GetKey(_key);
+        return key;
+    }
+
+    public override void LoadConfig(string input)
+    {
+        try {
+        string[] tables = input.Split('\t');
+        int.TryParse(tables[0],out ID); 
+
+			int.TryParse(tables[1],out TabType); 
+
+			Name = tables[2];
+
+			FaceBg = tables[3];
+
+			int.TryParse(tables[4],out SkinID); 
+
+			int.TryParse(tables[5],out ExpireMinutes); 
+
+			int.TryParse(tables[6],out UnlockWay); 
+
+			int.TryParse(tables[7],out UnlockValue); 
+
+			int.TryParse(tables[8],out UnlockNeedCnt); 
+
+			int.TryParse(tables[9],out UpNeedCnt); 
+
+			int.TryParse(tables[10],out StarMax); 
+
+			if (tables[11].Contains("["))
+			{
+				AttrIDList = JsonMapper.ToObject<int[]>(tables[11]);
+			}
+			else
+			{
+				string[] AttrIDListStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrIDList = new int[AttrIDListStringArray.Length];
+				for (int i=0;i<AttrIDListStringArray.Length;i++)
+				{
+					 int.TryParse(AttrIDListStringArray[i],out AttrIDList[i]);
+				}
+			}
+
+			if (tables[12].Contains("["))
+			{
+				InitAttrValueList = JsonMapper.ToObject<int[]>(tables[12]);
+			}
+			else
+			{
+				string[] InitAttrValueListStringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				InitAttrValueList = new int[InitAttrValueListStringArray.Length];
+				for (int i=0;i<InitAttrValueListStringArray.Length;i++)
+				{
+					 int.TryParse(InitAttrValueListStringArray[i],out InitAttrValueList[i]);
+				}
+			}
+
+			if (tables[13].Contains("["))
+			{
+				AttrPerStarAddList = JsonMapper.ToObject<int[]>(tables[13]);
+			}
+			else
+			{
+				string[] AttrPerStarAddListStringArray = tables[13].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrPerStarAddList = new int[AttrPerStarAddListStringArray.Length];
+				for (int i=0;i<AttrPerStarAddListStringArray.Length;i++)
+				{
+					 int.TryParse(AttrPerStarAddListStringArray[i],out AttrPerStarAddList[i]);
+				}
+			}
+
+			GetWayString = tables[14];
+        }
+        catch (Exception exception)
+        {
+            Debug.LogError(exception);
+        }
+    }
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Config/Configs/ModelConfig.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Config/Configs/ModelConfig.cs.meta
index c7311ca..2a16434 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Config/Configs/ModelConfig.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 5d32887e6728d224a8c67d4a3b9227bb
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Config/Configs/PlayerFaceConfig.cs b/Main/Config/Configs/PlayerFaceConfig.cs
index 79511cf..f8f9abb 100644
--- a/Main/Config/Configs/PlayerFaceConfig.cs
+++ b/Main/Config/Configs/PlayerFaceConfig.cs
@@ -1,6 +1,6 @@
 锘�//--------------------------------------------------------
 //    [Author]:           YYL
-//    [  Date ]:           2025骞�8鏈�5鏃�
+//    [  Date ]:           Wednesday, November 19, 2025
 //--------------------------------------------------------
 
 using System.Collections.Generic;
@@ -18,18 +18,19 @@
 
     public int FaceID;
 	public string Name;
-	public int[] JobShowList;
-	public int UnlockDefault;
-	public int ExpireMinutes;
-	public int CustomPlayerID;
-	public string Image;
+	public int ResourceType;
+	public string ResourceValue;
 	public int BgColor;
-	public int EffectID;
-	public int[][] UnlockNeedItemList;
-	public int[] LightAttrType;
-	public int[] LightAttrValue;
-	public int LightFightPower;
-	public string Descriptive;
+	public int ExpireMinutes;
+	public int UnlockWay;
+	public int UnlockValue;
+	public int UnlockNeedCnt;
+	public int UpNeedCnt;
+	public int StarMax;
+	public int[] AttrIDList;
+	public int[] InitAttrValueList;
+	public int[] AttrPerStarAddList;
+	public string GetWayString;
 
     public override int LoadKey(string _key)
     {
@@ -45,65 +46,67 @@
 
 			Name = tables[1];
 
-			if (tables[2].Contains("["))
-			{
-				JobShowList = JsonMapper.ToObject<int[]>(tables[2]);
-			}
-			else
-			{
-				string[] JobShowListStringArray = tables[2].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				JobShowList = new int[JobShowListStringArray.Length];
-				for (int i=0;i<JobShowListStringArray.Length;i++)
-				{
-					 int.TryParse(JobShowListStringArray[i],out JobShowList[i]);
-				}
-			}
+			int.TryParse(tables[2],out ResourceType); 
 
-			int.TryParse(tables[3],out UnlockDefault); 
+			ResourceValue = tables[3];
 
-			int.TryParse(tables[4],out ExpireMinutes); 
+			int.TryParse(tables[4],out BgColor); 
 
-			int.TryParse(tables[5],out CustomPlayerID); 
+			int.TryParse(tables[5],out ExpireMinutes); 
 
-			Image = tables[6];
+			int.TryParse(tables[6],out UnlockWay); 
 
-			int.TryParse(tables[7],out BgColor); 
+			int.TryParse(tables[7],out UnlockValue); 
 
-			int.TryParse(tables[8],out EffectID); 
+			int.TryParse(tables[8],out UnlockNeedCnt); 
 
-			UnlockNeedItemList = JsonMapper.ToObject<int[][]>(tables[9].Replace("(", "[").Replace(")", "]")); 
+			int.TryParse(tables[9],out UpNeedCnt); 
 
-			if (tables[10].Contains("["))
-			{
-				LightAttrType = JsonMapper.ToObject<int[]>(tables[10]);
-			}
-			else
-			{
-				string[] LightAttrTypeStringArray = tables[10].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				LightAttrType = new int[LightAttrTypeStringArray.Length];
-				for (int i=0;i<LightAttrTypeStringArray.Length;i++)
-				{
-					 int.TryParse(LightAttrTypeStringArray[i],out LightAttrType[i]);
-				}
-			}
+			int.TryParse(tables[10],out StarMax); 
 
 			if (tables[11].Contains("["))
 			{
-				LightAttrValue = JsonMapper.ToObject<int[]>(tables[11]);
+				AttrIDList = JsonMapper.ToObject<int[]>(tables[11]);
 			}
 			else
 			{
-				string[] LightAttrValueStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				LightAttrValue = new int[LightAttrValueStringArray.Length];
-				for (int i=0;i<LightAttrValueStringArray.Length;i++)
+				string[] AttrIDListStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrIDList = new int[AttrIDListStringArray.Length];
+				for (int i=0;i<AttrIDListStringArray.Length;i++)
 				{
-					 int.TryParse(LightAttrValueStringArray[i],out LightAttrValue[i]);
+					 int.TryParse(AttrIDListStringArray[i],out AttrIDList[i]);
 				}
 			}
 
-			int.TryParse(tables[12],out LightFightPower); 
+			if (tables[12].Contains("["))
+			{
+				InitAttrValueList = JsonMapper.ToObject<int[]>(tables[12]);
+			}
+			else
+			{
+				string[] InitAttrValueListStringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				InitAttrValueList = new int[InitAttrValueListStringArray.Length];
+				for (int i=0;i<InitAttrValueListStringArray.Length;i++)
+				{
+					 int.TryParse(InitAttrValueListStringArray[i],out InitAttrValueList[i]);
+				}
+			}
 
-			Descriptive = tables[13];
+			if (tables[13].Contains("["))
+			{
+				AttrPerStarAddList = JsonMapper.ToObject<int[]>(tables[13]);
+			}
+			else
+			{
+				string[] AttrPerStarAddListStringArray = tables[13].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrPerStarAddList = new int[AttrPerStarAddListStringArray.Length];
+				for (int i=0;i<AttrPerStarAddListStringArray.Length;i++)
+				{
+					 int.TryParse(AttrPerStarAddListStringArray[i],out AttrPerStarAddList[i]);
+				}
+			}
+
+			GetWayString = tables[14];
         }
         catch (Exception exception)
         {
diff --git a/Main/Config/Configs/PlayerFacePicConfig.cs b/Main/Config/Configs/PlayerFacePicConfig.cs
index 942a416..920e903 100644
--- a/Main/Config/Configs/PlayerFacePicConfig.cs
+++ b/Main/Config/Configs/PlayerFacePicConfig.cs
@@ -1,6 +1,6 @@
 锘�//--------------------------------------------------------
 //    [Author]:           YYL
-//    [  Date ]:           2025骞�8鏈�5鏃�
+//    [  Date ]:           2025骞�11鏈�16鏃�
 //--------------------------------------------------------
 
 using System.Collections.Generic;
@@ -18,16 +18,18 @@
 
     public int FacePicID;
 	public string Name;
-	public string Image;
-	public int SortNum;
-	public int EffectID;
-	public int UnlockDefault;
+	public int ResourceType;
+	public string ResourceValue;
 	public int ExpireMinutes;
-	public int[][] UnlockNeedItemList;
-	public int[] LightAttrType;
-	public int[] LightAttrValue;
-	public int LightFightPower;
-	public string Descriptive;
+	public int UnlockWay;
+	public int UnlockValue;
+	public int UnlockNeedCnt;
+	public int UpNeedCnt;
+	public int StarMax;
+	public int[] AttrIDList;
+	public int[] InitAttrValueList;
+	public int[] AttrPerStarAddList;
+	public string GetWayString;
 
     public override int LoadKey(string _key)
     {
@@ -43,49 +45,65 @@
 
 			Name = tables[1];
 
-			Image = tables[2];
+			int.TryParse(tables[2],out ResourceType); 
 
-			int.TryParse(tables[3],out SortNum); 
+			ResourceValue = tables[3];
 
-			int.TryParse(tables[4],out EffectID); 
+			int.TryParse(tables[4],out ExpireMinutes); 
 
-			int.TryParse(tables[5],out UnlockDefault); 
+			int.TryParse(tables[5],out UnlockWay); 
 
-			int.TryParse(tables[6],out ExpireMinutes); 
+			int.TryParse(tables[6],out UnlockValue); 
 
-			UnlockNeedItemList = JsonMapper.ToObject<int[][]>(tables[7].Replace("(", "[").Replace(")", "]")); 
+			int.TryParse(tables[7],out UnlockNeedCnt); 
 
-			if (tables[8].Contains("["))
+			int.TryParse(tables[8],out UpNeedCnt); 
+
+			int.TryParse(tables[9],out StarMax); 
+
+			if (tables[10].Contains("["))
 			{
-				LightAttrType = JsonMapper.ToObject<int[]>(tables[8]);
+				AttrIDList = JsonMapper.ToObject<int[]>(tables[10]);
 			}
 			else
 			{
-				string[] LightAttrTypeStringArray = tables[8].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				LightAttrType = new int[LightAttrTypeStringArray.Length];
-				for (int i=0;i<LightAttrTypeStringArray.Length;i++)
+				string[] AttrIDListStringArray = tables[10].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrIDList = new int[AttrIDListStringArray.Length];
+				for (int i=0;i<AttrIDListStringArray.Length;i++)
 				{
-					 int.TryParse(LightAttrTypeStringArray[i],out LightAttrType[i]);
+					 int.TryParse(AttrIDListStringArray[i],out AttrIDList[i]);
 				}
 			}
 
-			if (tables[9].Contains("["))
+			if (tables[11].Contains("["))
 			{
-				LightAttrValue = JsonMapper.ToObject<int[]>(tables[9]);
+				InitAttrValueList = JsonMapper.ToObject<int[]>(tables[11]);
 			}
 			else
 			{
-				string[] LightAttrValueStringArray = tables[9].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				LightAttrValue = new int[LightAttrValueStringArray.Length];
-				for (int i=0;i<LightAttrValueStringArray.Length;i++)
+				string[] InitAttrValueListStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				InitAttrValueList = new int[InitAttrValueListStringArray.Length];
+				for (int i=0;i<InitAttrValueListStringArray.Length;i++)
 				{
-					 int.TryParse(LightAttrValueStringArray[i],out LightAttrValue[i]);
+					 int.TryParse(InitAttrValueListStringArray[i],out InitAttrValueList[i]);
 				}
 			}
 
-			int.TryParse(tables[10],out LightFightPower); 
+			if (tables[12].Contains("["))
+			{
+				AttrPerStarAddList = JsonMapper.ToObject<int[]>(tables[12]);
+			}
+			else
+			{
+				string[] AttrPerStarAddListStringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrPerStarAddList = new int[AttrPerStarAddListStringArray.Length];
+				for (int i=0;i<AttrPerStarAddListStringArray.Length;i++)
+				{
+					 int.TryParse(AttrPerStarAddListStringArray[i],out AttrPerStarAddList[i]);
+				}
+			}
 
-			Descriptive = tables[11];
+			GetWayString = tables[13];
         }
         catch (Exception exception)
         {
diff --git a/Main/Config/Configs/PlayerFacePicStarConfig.cs b/Main/Config/Configs/PlayerFacePicStarConfig.cs
deleted file mode 100644
index 02a8def..0000000
--- a/Main/Config/Configs/PlayerFacePicStarConfig.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-锘�//--------------------------------------------------------
-//    [Author]:           YYL
-//    [  Date ]:           2025骞�8鏈�5鏃�
-//--------------------------------------------------------
-
-using System.Collections.Generic;
-using System;
-using UnityEngine;
-using LitJson;
-
-public partial class PlayerFacePicStarConfig : ConfigBase<int, PlayerFacePicStarConfig>
-{
-    static PlayerFacePicStarConfig()
-    {
-        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
-        visit = true; 
-    }
-
-    public int index;
-	public int FacePicID;
-	public int FacePicStar;
-	public int[][] StarUpNeedItemList;
-	public int[] StarAttrType;
-	public int[] StarAttrValue;
-
-    public override int LoadKey(string _key)
-    {
-        int key = GetKey(_key);
-        return key;
-    }
-
-    public override void LoadConfig(string input)
-    {
-        try {
-        string[] tables = input.Split('\t');
-        int.TryParse(tables[0],out index); 
-
-			int.TryParse(tables[1],out FacePicID); 
-
-			int.TryParse(tables[2],out FacePicStar); 
-
-			StarUpNeedItemList = JsonMapper.ToObject<int[][]>(tables[3].Replace("(", "[").Replace(")", "]")); 
-
-			if (tables[4].Contains("["))
-			{
-				StarAttrType = JsonMapper.ToObject<int[]>(tables[4]);
-			}
-			else
-			{
-				string[] StarAttrTypeStringArray = tables[4].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				StarAttrType = new int[StarAttrTypeStringArray.Length];
-				for (int i=0;i<StarAttrTypeStringArray.Length;i++)
-				{
-					 int.TryParse(StarAttrTypeStringArray[i],out StarAttrType[i]);
-				}
-			}
-
-			if (tables[5].Contains("["))
-			{
-				StarAttrValue = JsonMapper.ToObject<int[]>(tables[5]);
-			}
-			else
-			{
-				string[] StarAttrValueStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				StarAttrValue = new int[StarAttrValueStringArray.Length];
-				for (int i=0;i<StarAttrValueStringArray.Length;i++)
-				{
-					 int.TryParse(StarAttrValueStringArray[i],out StarAttrValue[i]);
-				}
-			}
-        }
-        catch (Exception exception)
-        {
-            Debug.LogError(exception);
-        }
-    }
-}
diff --git a/Main/Config/Configs/PlayerFacePicStarConfig.cs.meta b/Main/Config/Configs/PlayerFacePicStarConfig.cs.meta
deleted file mode 100644
index ece512d..0000000
--- a/Main/Config/Configs/PlayerFacePicStarConfig.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 71543467d1c8a4544b1e0441440327cb
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs b/Main/Config/Configs/PlayerFaceStarConfig.cs
deleted file mode 100644
index 71419d4..0000000
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-锘�//--------------------------------------------------------
-//    [Author]:           YYL
-//    [  Date ]:           2025骞�8鏈�5鏃�
-//--------------------------------------------------------
-
-using System.Collections.Generic;
-using System;
-using UnityEngine;
-using LitJson;
-
-public partial class PlayerFaceStarConfig : ConfigBase<int, PlayerFaceStarConfig>
-{
-    static PlayerFaceStarConfig()
-    {
-        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
-        visit = true; 
-    }
-
-    public int index;
-	public int FaceID;
-	public int FaceStar;
-	public int[][] StarUpNeedItemList;
-	public int[] StarAttrType;
-	public int[] StarAttrValue;
-
-    public override int LoadKey(string _key)
-    {
-        int key = GetKey(_key);
-        return key;
-    }
-
-    public override void LoadConfig(string input)
-    {
-        try {
-        string[] tables = input.Split('\t');
-        int.TryParse(tables[0],out index); 
-
-			int.TryParse(tables[1],out FaceID); 
-
-			int.TryParse(tables[2],out FaceStar); 
-
-			StarUpNeedItemList = JsonMapper.ToObject<int[][]>(tables[3].Replace("(", "[").Replace(")", "]")); 
-
-			if (tables[4].Contains("["))
-			{
-				StarAttrType = JsonMapper.ToObject<int[]>(tables[4]);
-			}
-			else
-			{
-				string[] StarAttrTypeStringArray = tables[4].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				StarAttrType = new int[StarAttrTypeStringArray.Length];
-				for (int i=0;i<StarAttrTypeStringArray.Length;i++)
-				{
-					 int.TryParse(StarAttrTypeStringArray[i],out StarAttrType[i]);
-				}
-			}
-
-			if (tables[5].Contains("["))
-			{
-				StarAttrValue = JsonMapper.ToObject<int[]>(tables[5]);
-			}
-			else
-			{
-				string[] StarAttrValueStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
-				StarAttrValue = new int[StarAttrValueStringArray.Length];
-				for (int i=0;i<StarAttrValueStringArray.Length;i++)
-				{
-					 int.TryParse(StarAttrValueStringArray[i],out StarAttrValue[i]);
-				}
-			}
-        }
-        catch (Exception exception)
-        {
-            Debug.LogError(exception);
-        }
-    }
-}
diff --git a/Main/Config/Configs/TitleConfig.cs b/Main/Config/Configs/TitleConfig.cs
new file mode 100644
index 0000000..b73297e
--- /dev/null
+++ b/Main/Config/Configs/TitleConfig.cs
@@ -0,0 +1,116 @@
+锘�//--------------------------------------------------------
+//    [Author]:           YYL
+//    [  Date ]:           2025骞�11鏈�18鏃�
+//--------------------------------------------------------
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using LitJson;
+
+public partial class TitleConfig : ConfigBase<int, TitleConfig>
+{
+    static TitleConfig()
+    {
+        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
+        visit = true; 
+    }
+
+    public int TitleID;
+	public int TabType;
+	public string Name;
+	public int ResourceType;
+	public string ResourceValue;
+	public int ExpireMinutes;
+	public int UnlockWay;
+	public int UnlockValue;
+	public int UnlockNeedCnt;
+	public int UpNeedCnt;
+	public int StarMax;
+	public int[] AttrIDList;
+	public int[] InitAttrValueList;
+	public int[] AttrPerStarAddList;
+	public string GetWayString;
+
+    public override int LoadKey(string _key)
+    {
+        int key = GetKey(_key);
+        return key;
+    }
+
+    public override void LoadConfig(string input)
+    {
+        try {
+        string[] tables = input.Split('\t');
+        int.TryParse(tables[0],out TitleID); 
+
+			int.TryParse(tables[1],out TabType); 
+
+			Name = tables[2];
+
+			int.TryParse(tables[3],out ResourceType); 
+
+			ResourceValue = tables[4];
+
+			int.TryParse(tables[5],out ExpireMinutes); 
+
+			int.TryParse(tables[6],out UnlockWay); 
+
+			int.TryParse(tables[7],out UnlockValue); 
+
+			int.TryParse(tables[8],out UnlockNeedCnt); 
+
+			int.TryParse(tables[9],out UpNeedCnt); 
+
+			int.TryParse(tables[10],out StarMax); 
+
+			if (tables[11].Contains("["))
+			{
+				AttrIDList = JsonMapper.ToObject<int[]>(tables[11]);
+			}
+			else
+			{
+				string[] AttrIDListStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrIDList = new int[AttrIDListStringArray.Length];
+				for (int i=0;i<AttrIDListStringArray.Length;i++)
+				{
+					 int.TryParse(AttrIDListStringArray[i],out AttrIDList[i]);
+				}
+			}
+
+			if (tables[12].Contains("["))
+			{
+				InitAttrValueList = JsonMapper.ToObject<int[]>(tables[12]);
+			}
+			else
+			{
+				string[] InitAttrValueListStringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				InitAttrValueList = new int[InitAttrValueListStringArray.Length];
+				for (int i=0;i<InitAttrValueListStringArray.Length;i++)
+				{
+					 int.TryParse(InitAttrValueListStringArray[i],out InitAttrValueList[i]);
+				}
+			}
+
+			if (tables[13].Contains("["))
+			{
+				AttrPerStarAddList = JsonMapper.ToObject<int[]>(tables[13]);
+			}
+			else
+			{
+				string[] AttrPerStarAddListStringArray = tables[13].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				AttrPerStarAddList = new int[AttrPerStarAddListStringArray.Length];
+				for (int i=0;i<AttrPerStarAddListStringArray.Length;i++)
+				{
+					 int.TryParse(AttrPerStarAddListStringArray[i],out AttrPerStarAddList[i]);
+				}
+			}
+
+			GetWayString = tables[14];
+        }
+        catch (Exception exception)
+        {
+            Debug.LogError(exception);
+        }
+    }
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Config/Configs/TitleConfig.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Config/Configs/TitleConfig.cs.meta
index c7311ca..56782a3 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Config/Configs/TitleConfig.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: e9a2f986928879e4e82dc649281f0ff3
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Config/PartialConfigs/ModelConfig.cs b/Main/Config/PartialConfigs/ModelConfig.cs
new file mode 100644
index 0000000..84b2b20
--- /dev/null
+++ b/Main/Config/PartialConfigs/ModelConfig.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+public partial class ModelConfig : ConfigBase<int, ModelConfig>
+{
+    //<TabType,List<TitleID>>
+    static Dictionary<int, List<int>> tabTypeDict = new Dictionary<int, List<int>>();
+
+    protected override void OnConfigParseCompleted()
+    {
+        if (!tabTypeDict.ContainsKey(TabType))
+        {
+            tabTypeDict[TabType] = new List<int>();
+        }
+        tabTypeDict[TabType].Add(ID);
+    }
+
+    public static List<int> GetTabTypeTitles(int tabType)
+    {
+        if (!tabTypeDict.ContainsKey(tabType))
+        {
+            return new List<int>();
+        }
+        return tabTypeDict[tabType];
+    }
+
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Config/PartialConfigs/ModelConfig.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Config/PartialConfigs/ModelConfig.cs.meta
index c7311ca..8729b64 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Config/PartialConfigs/ModelConfig.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: ff454609a146675479c45454e1e7e414
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Config/PartialConfigs/TitleConfig.cs b/Main/Config/PartialConfigs/TitleConfig.cs
new file mode 100644
index 0000000..97d618c
--- /dev/null
+++ b/Main/Config/PartialConfigs/TitleConfig.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+public partial class TitleConfig : ConfigBase<int, TitleConfig>
+{
+    //<TabType,List<TitleID>>
+    static Dictionary<int, List<int>> tabTypeDict = new Dictionary<int, List<int>>();
+
+    protected override void OnConfigParseCompleted()
+    {
+        if (!tabTypeDict.ContainsKey(TabType))
+        {
+            tabTypeDict[TabType] = new List<int>();
+        }
+        tabTypeDict[TabType].Add(TitleID);
+    }
+
+    public static List<int> GetTabTypeTitles(int tabType)
+    {
+        if (!tabTypeDict.ContainsKey(tabType))
+        {
+            return new List<int>();
+        }
+        return tabTypeDict[tabType];
+    }
+
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Config/PartialConfigs/TitleConfig.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Config/PartialConfigs/TitleConfig.cs.meta
index c7311ca..6afa872 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Config/PartialConfigs/TitleConfig.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 166064f5d63bfd14a99728820f9057a7
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/GameEngine/Player/PlayerBaseData.cs b/Main/Core/GameEngine/Player/PlayerBaseData.cs
index 56f00f0..abc24d9 100644
--- a/Main/Core/GameEngine/Player/PlayerBaseData.cs
+++ b/Main/Core/GameEngine/Player/PlayerBaseData.cs
@@ -65,7 +65,7 @@
     public uint copperExtend;    //鎵╁睍灞炴��6锛屽悇椤圭洰涓撶敤
     public uint sp;    //鎵╁睍灞炴��7锛屽悇椤圭洰涓撶敤
     public uint spExtend;    //鎵╁睍灞炴��8锛屽悇椤圭洰涓撶敤
-    public uint bubbleId;    //鎵╁睍灞炴��10锛屽悇椤圭洰涓撶敤
+    public uint chatBox;    //鎵╁睍灞炴��10锛屽悇椤圭洰涓撶敤
     public uint ExAttr11;    //棰勭暀鐨勬墿灞曞睘鎬у瓧娈碉紝鐢ㄦ潵瀛樻斁椤圭洰鐗瑰畾鐨勫睘鎬�121 鐜伴噾浠e竵锛堜唬閲戝埜锛�
     public uint ExAttr16;    //棰勭暀鐨勬墿灞曞睘鎬у瓧娈碉紝鐢ㄦ潵瀛樻斁椤圭洰鐗瑰畾鐨勫睘鎬�    鍏ㄨ韩鐗规晥
     public uint ServerGroupId;    //鏈嶅姟鍣ㄧ粍ID
@@ -75,7 +75,7 @@
     public int face;//澶村儚
     public int facePic;//澶村儚澶栨
     public long FightPower;    //鎴樻枟鍔�
-
+    public int modelMark;       //褰㈣薄 
     public uint coinPointTotal
     {
         private get { return m_coinPointTotal; }
@@ -201,7 +201,6 @@
         copperExtend = _serverInfo.ExAttr6;
         sp = _serverInfo.ExAttr7;
         spExtend = _serverInfo.ExAttr8;
-        bubbleId = _serverInfo.ExAttr10;
         ExAttr11 = _serverInfo.ExAttr11;
         leaveGuildInfo = (int)_serverInfo.ExAttr12;
         ExAttr16 = _serverInfo.ExAttr16;
@@ -211,12 +210,14 @@
         equipShowSwitch = _serverInfo.EquipShowSwitch;
         mapRealmSelect = (int)_serverInfo.ExAttr18;
         leaveFamilyTime = (int)_serverInfo.ExAttr19;
-        face = (int)_serverInfo.Face;
-        facePic = (int)_serverInfo.FacePic;
-
         HP = _serverInfo.HP + _serverInfo.HPEx * Constants.ExpPointValue;
         AttackMode = _serverInfo.AttackMode;
         UseHarmerCount = (int)_serverInfo.FightPoint;   //閿ゅ瓙鍊嶆暟锛岄潪鎴樻枟鍔�
+        face = (int)_serverInfo.Face;
+        facePic = (int)_serverInfo.FacePic;
+        modelMark = (int)_serverInfo.ModelMark;
+        chatBox = (uint)_serverInfo.ExAttr10;
+        TitleID = (int)_serverInfo.ExAttr3;
 
     }
 
diff --git a/Main/Core/GameEngine/Player/PlayerDatas.cs b/Main/Core/GameEngine/Player/PlayerDatas.cs
index beb8f19..ea98e19 100644
--- a/Main/Core/GameEngine/Player/PlayerDatas.cs
+++ b/Main/Core/GameEngine/Player/PlayerDatas.cs
@@ -240,9 +240,8 @@
             case PlayerDataType.ExAttr2:
                 baseData.ExAttr2 = Math.Max((int)value, 10101); //鏂板彿鍒濆澶勭悊
                 break;
-            case PlayerDataType.ExAttr3:
-                baseData.dungeonLineId = (int)value % 1000;
-                baseData.dungeonMapId = (int)value / 1000;
+            case PlayerDataType.ExAttr3://绉板彿
+                baseData.TitleID = (int)value;
                 break;
             case PlayerDataType.ExAttr4:
                 baseData.shield = value;
@@ -264,7 +263,7 @@
                 baseData.copperExtend = value;
                 break;
             case PlayerDataType.ExAttr10:
-                baseData.bubbleId = value;
+                baseData.chatBox = value;
                 break;
             case PlayerDataType.ExAttr11:
                 baseData.ExAttr11 = value;
@@ -530,7 +529,9 @@
             case PlayerDataType.FacePic:
                 baseData.facePic = (int)value;
                 break;
-
+            case PlayerDataType.ModelMark:
+                baseData.modelMark = (int)value;
+                break;
         }
     }
 
diff --git a/Main/Core/NetworkPackage/ClientPack/CA2_Interaction/CA230_tagCMSetChatBubbleBox.cs b/Main/Core/NetworkPackage/ClientPack/CA2_Interaction/CA230_tagCMSetChatBubbleBox.cs
deleted file mode 100644
index 099b347..0000000
--- a/Main/Core/NetworkPackage/ClientPack/CA2_Interaction/CA230_tagCMSetChatBubbleBox.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-// A2 30 璁剧疆鑱婂ぉ姘旀场妗� #tagCMSetChatBubbleBox
-
-public class CA230_tagCMSetChatBubbleBox : GameNetPackBasic {
-    public byte BubbleBoxType;    //姘旀场妗嗙被鍨�
-
-    public CA230_tagCMSetChatBubbleBox () {
-        combineCmd = (ushort)0x03FE;
-        _cmd = (ushort)0xA230;
-    }
-
-    public override void WriteToBytes () {
-        WriteBytes (BubbleBoxType, NetDataType.BYTE);
-    }
-
-}
diff --git a/Main/Core/NetworkPackage/ClientPack/CA2_Interaction/CA230_tagCMSetChatBubbleBox.cs.meta b/Main/Core/NetworkPackage/ClientPack/CA2_Interaction/CA230_tagCMSetChatBubbleBox.cs.meta
deleted file mode 100644
index 975baf7..0000000
--- a/Main/Core/NetworkPackage/ClientPack/CA2_Interaction/CA230_tagCMSetChatBubbleBox.cs.meta
+++ /dev/null
@@ -1,12 +0,0 @@
-fileFormatVersion: 2
-guid: 2bd82e50dd886f640bb5c2c2a95029ae
-timeCreated: 1541388926
-licenseType: Pro
-MonoImporter:
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs
new file mode 100644
index 0000000..587258d
--- /dev/null
+++ b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs
@@ -0,0 +1,22 @@
+using UnityEngine;
+using System.Collections;
+
+// B2 25 骞诲闃佹搷浣� #tagCSHJGOP
+
+public class CB225_tagCSHJGOP : GameNetPackBasic {
+    public byte Type;    // 绫诲瀷 1-褰㈣薄锛�2-澶村儚锛�3-澶村儚妗嗭紱4-姘旀场锛�5-绉板彿	
+    public byte OPType;    // 鎿嶄綔 1-婵�娲伙紱2-浣╂埓锛�3-鍗镐笅锛�4-鍗囨槦
+    public uint OPID;    // 鎿嶄綔瀵瑰簲鐨処D锛屽褰㈣薄ID绛�
+
+    public CB225_tagCSHJGOP () {
+        combineCmd = (ushort)0x03FE;
+        _cmd = (ushort)0xB225;
+    }
+
+    public override void WriteToBytes () {
+        WriteBytes (Type, NetDataType.BYTE);
+        WriteBytes (OPType, NetDataType.BYTE);
+        WriteBytes (OPID, NetDataType.DWORD);
+    }
+
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs.meta
index c7311ca..05138a2 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB225_tagCSHJGOP.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 5f0f67735acb316478945f53ab8c8abd
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB226_tagCMFaceChange.cs b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB226_tagCMFaceChange.cs
deleted file mode 100644
index 6c75905..0000000
--- a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB226_tagCMFaceChange.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-// B2 26 澶村儚骞诲寲 #tagCMFaceChange
-
-public class CB226_tagCMFaceChange : GameNetPackBasic {
-    public uint FaceID;    // 骞诲寲鐨処D
-
-    public CB226_tagCMFaceChange () {
-        combineCmd = (ushort)0x03FE;
-        _cmd = (ushort)0xB226;
-    }
-
-    public override void WriteToBytes () {
-        WriteBytes (FaceID, NetDataType.DWORD);
-    }
-
-}
diff --git a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB226_tagCMFaceChange.cs.meta b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB226_tagCMFaceChange.cs.meta
deleted file mode 100644
index c9602e9..0000000
--- a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB226_tagCMFaceChange.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 042dc115cedb16645883ab6af37fea1c
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB228_tagCMFacePicChange.cs b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB228_tagCMFacePicChange.cs
deleted file mode 100644
index ad7e9c7..0000000
--- a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB228_tagCMFacePicChange.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-// B2 28 澶村儚妗嗗够鍖� #tagCMFacePicChange
-
-public class CB228_tagCMFacePicChange : GameNetPackBasic {
-    public uint FacePicID;    // 骞诲寲鐨処D
-
-    public CB228_tagCMFacePicChange () {
-        combineCmd = (ushort)0x03FE;
-        _cmd = (ushort)0xB228;
-    }
-
-    public override void WriteToBytes () {
-        WriteBytes (FacePicID, NetDataType.DWORD);
-    }
-
-}
diff --git a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB228_tagCMFacePicChange.cs.meta b/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB228_tagCMFacePicChange.cs.meta
deleted file mode 100644
index 61e1780..0000000
--- a/Main/Core/NetworkPackage/ClientPack/CB2_NewFunction/CB228_tagCMFacePicChange.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 13ff6fad4eb84dd4ea3e3a09e8d8f474
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA721_tagMCEmojiPackInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA721_tagMCEmojiPackInfo.cs
deleted file mode 100644
index 3091ffb..0000000
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA721_tagMCEmojiPackInfo.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-// A7 21 琛ㄦ儏鍖呬俊鎭� #tagMCEmojiPackInfo
-
-public class DTCA721_tagMCEmojiPackInfo : DtcBasic {
-    public override void Done(GameNetPackBasic vNetPack)
-    {
-        base.Done(vNetPack);
-        HA721_tagMCEmojiPackInfo vNetData = vNetPack as HA721_tagMCEmojiPackInfo;
-        PhantasmPavilionModel.Instance.UpdateEmojiPackInfo(vNetData);
-    }
-}
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA721_tagMCEmojiPackInfo.cs.meta b/Main/Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA721_tagMCEmojiPackInfo.cs.meta
deleted file mode 100644
index c2693b5..0000000
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA721_tagMCEmojiPackInfo.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 01710fb61664f4c4c8f7bfb47fe1c6b0
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB117_tagMCFaceInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB117_tagMCFaceInfo.cs
index 8ddbe6f..426ce48 100644
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB117_tagMCFaceInfo.cs
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB117_tagMCFaceInfo.cs
@@ -4,10 +4,9 @@
 // B1 17 澶村儚淇℃伅 #tagMCFaceInfo
 
 public class DTCB117_tagMCFaceInfo : DtcBasic {
-    public override void Done(GameNetPackBasic vNetPack)
-    {
+    public override void Done(GameNetPackBasic vNetPack) {
         base.Done(vNetPack);
         HB117_tagMCFaceInfo vNetData = vNetPack as HB117_tagMCFaceInfo;
-        PhantasmPavilionModel.Instance.UpdateFaceInfo(vNetData);
+        PhantasmPavilionManager.Instance.UpdateFaceInfo(vNetData);
     }
 }
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB118_tagMCFacePicInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB118_tagMCFacePicInfo.cs
index 235694d..fc1397c 100644
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB118_tagMCFacePicInfo.cs
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB118_tagMCFacePicInfo.cs
@@ -4,10 +4,9 @@
 // B1 18 澶村儚妗嗕俊鎭� #tagMCFacePicInfo
 
 public class DTCB118_tagMCFacePicInfo : DtcBasic {
-    public override void Done(GameNetPackBasic vNetPack)
-    {
+    public override void Done(GameNetPackBasic vNetPack) {
         base.Done(vNetPack);
         HB118_tagMCFacePicInfo vNetData = vNetPack as HB118_tagMCFacePicInfo;
-        PhantasmPavilionModel.Instance.UpdateFacePicInfo(vNetData);
+        PhantasmPavilionManager.Instance.UpdateFacePicInfo(vNetData);
     }
 }
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs
new file mode 100644
index 0000000..4e1083f
--- /dev/null
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+using System.Collections;
+
+// B1 19 褰㈣薄淇℃伅 #tagSCModelInfo
+
+public class DTCB119_tagSCModelInfo : DtcBasic {
+    public override void Done(GameNetPackBasic vNetPack) {
+        base.Done(vNetPack);
+        HB119_tagSCModelInfo vNetData = vNetPack as HB119_tagSCModelInfo;
+        PhantasmPavilionManager.Instance.UpdateModelInfo(vNetData);
+    }
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs.meta
index c7311ca..23df57c 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB119_tagSCModelInfo.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: b60388212c0c03c41981fd8c354de402
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs
new file mode 100644
index 0000000..164a63d
--- /dev/null
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+using System.Collections;
+
+// B1 26 绉板彿淇℃伅 #tagSCTitleInfo
+
+public class DTCB126_tagSCTitleInfo : DtcBasic {
+    public override void Done(GameNetPackBasic vNetPack) {
+        base.Done(vNetPack);
+        HB126_tagSCTitleInfo vNetData = vNetPack as HB126_tagSCTitleInfo;
+        PhantasmPavilionManager.Instance.UpdateTitleInfo(vNetData);
+    }
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs.meta
index c7311ca..51a466f 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB126_tagSCTitleInfo.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: f55129cdc6478ab4b967606874a28a35
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs
new file mode 100644
index 0000000..1115ab3
--- /dev/null
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+using System.Collections;
+
+// B1 27 鑱婂ぉ姘旀场妗嗕俊鎭� #tagSCChatBoxInfo
+
+public class DTCB127_tagSCChatBoxInfo : DtcBasic {
+    public override void Done(GameNetPackBasic vNetPack) {
+        base.Done(vNetPack);
+        HB127_tagSCChatBoxInfo vNetData = vNetPack as HB127_tagSCChatBoxInfo;
+        PhantasmPavilionManager.Instance.UpdateChatBoxInfo(vNetData);
+    }
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs.meta
index c7311ca..c0806fb 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB1_Role/DTCB127_tagSCChatBoxInfo.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 7ffa77d347ddbb845b4361e9bc6dd07b
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs b/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
index 9fd86d4..d703417 100644
--- a/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
+++ b/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
@@ -70,7 +70,6 @@
         Register(typeof(HA802_tagSCShopItemBuyCntInfo), typeof(DTCA802_tagSCShopItemBuyCntInfo));
         Register(typeof(HA803_tagSCShopRefreshItemInfo), typeof(DTCA803_tagSCShopRefreshItemInfo));
         Register(typeof(HA809_tagMCItemDayUseCntInfo), typeof(DTCA809_tagMCItemDayUseCntInfo));
-        Register(typeof(HA721_tagMCEmojiPackInfo), typeof(DTCA721_tagMCEmojiPackInfo));
         Register(typeof(HB117_tagMCFaceInfo), typeof(DTCB117_tagMCFaceInfo));
         Register(typeof(HB118_tagMCFacePicInfo), typeof(DTCB118_tagMCFacePicInfo));
         Register(typeof(HB120_tagMCZhanlingInfo), typeof(DTCB120_tagMCZhanlingInfo));
@@ -127,6 +126,11 @@
         Register(typeof(HA921_tagSCRenameResult), typeof(DTCA921_tagSCRenameResult));
         Register(typeof(HA303_tagSCHorseClassInfo), typeof(DTCA303_tagSCHorseClassInfo));
         Register(typeof(HA304_tagSCHorseSkinInfo), typeof(DTCA304_tagSCHorseSkinInfo));
+
+        Register(typeof(HB119_tagSCModelInfo), typeof(DTCB119_tagSCModelInfo));
+        Register(typeof(HB126_tagSCTitleInfo), typeof(DTCB126_tagSCTitleInfo));
+        Register(typeof(HB127_tagSCChatBoxInfo), typeof(DTCB127_tagSCChatBoxInfo));
+
     }
 
     //涓诲伐绋嬫敞鍐屽皝鍖�
diff --git a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA717_tagMCChatBubbleBoxState.cs.meta b/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA717_tagMCChatBubbleBoxState.cs.meta
deleted file mode 100644
index 5802a10..0000000
--- a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA717_tagMCChatBubbleBoxState.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: aaebeb73934873643b8350191cbc297e
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA721_tagMCEmojiPackInfo.cs b/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA721_tagMCEmojiPackInfo.cs
deleted file mode 100644
index dddca56..0000000
--- a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA721_tagMCEmojiPackInfo.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using UnityEngine;
-using System.Collections;
-
-// A7 21 琛ㄦ儏鍖呬俊鎭� #tagMCEmojiPackInfo
-
-public class HA721_tagMCEmojiPackInfo : GameNetPackBasic {
-    public byte Count;
-    public  tagMCEmojiPack[] EmojiPackList;
-
-    public HA721_tagMCEmojiPackInfo () {
-        _cmd = (ushort)0xA721;
-    }
-
-    public override void ReadFromBytes (byte[] vBytes) {
-        TransBytes (out Count, vBytes, NetDataType.BYTE);
-        EmojiPackList = new tagMCEmojiPack[Count];
-        for (int i = 0; i < Count; i ++) {
-            EmojiPackList[i] = new tagMCEmojiPack();
-            TransBytes (out EmojiPackList[i].PackID, vBytes, NetDataType.BYTE);
-            TransBytes (out EmojiPackList[i].State, vBytes, NetDataType.BYTE);
-            TransBytes (out EmojiPackList[i].EndTime, vBytes, NetDataType.DWORD);
-        }
-    }
-
-    public class tagMCEmojiPack {
-        public byte PackID;        //琛ㄦ儏鍖匢D
-        public byte State;        //鏄惁宸叉縺娲�
-        public uint EndTime;        //鍒版湡鏃堕棿鎴筹紝0涓烘案涔�
-    }
-
-}
diff --git a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA721_tagMCEmojiPackInfo.cs.meta b/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA721_tagMCEmojiPackInfo.cs.meta
deleted file mode 100644
index 1e6bcbf..0000000
--- a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA721_tagMCEmojiPackInfo.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: c33dee2148092354f9d6f8404713ea4a
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs
new file mode 100644
index 0000000..798b669
--- /dev/null
+++ b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+using System.Collections;
+
+// B1 19 褰㈣薄淇℃伅 #tagSCModelInfo
+
+public class HB119_tagSCModelInfo : GameNetPackBasic {
+    public byte Count;
+    public  tagSCModel[] ModelList;
+
+    public HB119_tagSCModelInfo () {
+        _cmd = (ushort)0xB119;
+    }
+
+    public override void ReadFromBytes (byte[] vBytes) {
+        TransBytes (out Count, vBytes, NetDataType.BYTE);
+        ModelList = new tagSCModel[Count];
+        for (int i = 0; i < Count; i ++) {
+            ModelList[i] = new tagSCModel();
+            TransBytes (out ModelList[i].ModelID, vBytes, NetDataType.DWORD);
+            TransBytes (out ModelList[i].State, vBytes, NetDataType.BYTE);
+            TransBytes (out ModelList[i].EndTime, vBytes, NetDataType.DWORD);
+            TransBytes (out ModelList[i].Star, vBytes, NetDataType.BYTE);
+        }
+    }
+
+    public class tagSCModel {
+        public uint ModelID;        //褰㈣薄ID
+        public byte State;        //鏄惁宸叉縺娲�
+        public uint EndTime;        //鍒版湡鏃堕棿鎴筹紝0涓烘案涔�
+        public byte Star;        //鏄熺骇
+    }
+
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs.meta
index c7311ca..ed7af30 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB119_tagSCModelInfo.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: ccf5a2f55a06f274c8c195bcc9599040
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs
new file mode 100644
index 0000000..750ce3e
--- /dev/null
+++ b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+using System.Collections;
+
+// B1 26 绉板彿淇℃伅 #tagSCTitleInfo
+
+public class HB126_tagSCTitleInfo : GameNetPackBasic {
+    public byte Count;
+    public  tagSCTitle[] TitleList;
+
+    public HB126_tagSCTitleInfo () {
+        _cmd = (ushort)0xB126;
+    }
+
+    public override void ReadFromBytes (byte[] vBytes) {
+        TransBytes (out Count, vBytes, NetDataType.BYTE);
+        TitleList = new tagSCTitle[Count];
+        for (int i = 0; i < Count; i ++) {
+            TitleList[i] = new tagSCTitle();
+            TransBytes (out TitleList[i].TitleID, vBytes, NetDataType.DWORD);
+            TransBytes (out TitleList[i].State, vBytes, NetDataType.BYTE);
+            TransBytes (out TitleList[i].EndTime, vBytes, NetDataType.DWORD);
+            TransBytes (out TitleList[i].Star, vBytes, NetDataType.BYTE);
+        }
+    }
+
+    public class tagSCTitle {
+        public uint TitleID;        //绉板彿ID
+        public byte State;        //鏄惁宸叉縺娲�
+        public uint EndTime;        //鍒版湡鏃堕棿鎴筹紝0涓烘案涔�
+        public byte Star;        //鏄熺骇
+    }
+
+}
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs.meta
index c7311ca..5e7552a 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB126_tagSCTitleInfo.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 425c648daf9d77f48b10b6a8a09665c6
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA717_tagMCChatBubbleBoxState.cs b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs
similarity index 61%
rename from Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA717_tagMCChatBubbleBoxState.cs
rename to Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs
index 41c9f4d..b5c7786 100644
--- a/Main/Core/NetworkPackage/ServerPack/HA7_Interaction/HA717_tagMCChatBubbleBoxState.cs
+++ b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs
@@ -1,30 +1,30 @@
 using UnityEngine;
 using System.Collections;
 
-// A7 17 鑱婂ぉ姘旀场妗嗙姸鎬� #tagMCChatBubbleBoxState
+// B1 27 鑱婂ぉ姘旀场妗嗕俊鎭� #tagSCChatBoxInfo
 
-public class HA717_tagMCChatBubbleBoxState : GameNetPackBasic {
+public class HB127_tagSCChatBoxInfo : GameNetPackBasic {
     public byte Count;
-    public  tagMCChatBubbleBox[] BoxList;
+    public  tagSCChatBox[] BoxList;
 
-    public HA717_tagMCChatBubbleBoxState () {
-        _cmd = (ushort)0xA717;
+    public HB127_tagSCChatBoxInfo () {
+        _cmd = (ushort)0xB127;
     }
 
     public override void ReadFromBytes (byte[] vBytes) {
         TransBytes (out Count, vBytes, NetDataType.BYTE);
-        BoxList = new tagMCChatBubbleBox[Count];
+        BoxList = new tagSCChatBox[Count];
         for (int i = 0; i < Count; i ++) {
-            BoxList[i] = new tagMCChatBubbleBox();
-            TransBytes (out BoxList[i].BoxID, vBytes, NetDataType.BYTE);
+            BoxList[i] = new tagSCChatBox();
+            TransBytes (out BoxList[i].BoxID, vBytes, NetDataType.DWORD);
             TransBytes (out BoxList[i].State, vBytes, NetDataType.BYTE);
             TransBytes (out BoxList[i].EndTime, vBytes, NetDataType.DWORD);
             TransBytes (out BoxList[i].Star, vBytes, NetDataType.BYTE);
         }
     }
 
-    public class tagMCChatBubbleBox {
-        public byte BoxID;        //姘旀场ID
+    public class tagSCChatBox {
+        public uint BoxID;        //姘旀场妗咺D
         public byte State;        //鏄惁宸叉縺娲�
         public uint EndTime;        //鍒版湡鏃堕棿鎴筹紝0涓烘案涔�
         public byte Star;        //鏄熺骇
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs.meta
index c7311ca..3ceb317 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/Core/NetworkPackage/ServerPack/HB1_Role/HB127_tagSCChatBoxInfo.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 62844095792db2c40bd630462e650322
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/Main.cs b/Main/Main.cs
index 41ff955..1d52dd8 100644
--- a/Main/Main.cs
+++ b/Main/Main.cs
@@ -50,7 +50,6 @@
         managers.Add(OtherPlayerDetailManager.Instance);
         managers.Add(RechargeManager.Instance);
         managers.Add(StoreModel.Instance);
-        managers.Add(PhantasmPavilionModel.Instance);
         managers.Add(GuildManager.Instance);
         managers.Add(TeamManager.Instance);
         managers.Add(TaskManager.Instance);
@@ -89,7 +88,8 @@
         managers.Add(RenameManager.Instance);
         managers.Add(AchievementManager.Instance);
         managers.Add(HorseManager.Instance);
-
+        managers.Add(PhantasmPavilionManager.Instance);
+        managers.Add(AttributeManager.Instance);
 
         foreach (var manager in managers)
         {
diff --git a/Main/System/Attribute.meta b/Main/System/Attribute.meta
new file mode 100644
index 0000000..7f09049
--- /dev/null
+++ b/Main/System/Attribute.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ecabae745862c6d4b9e865c3e9d775cf
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Attribute/AttributeManager.cs b/Main/System/Attribute/AttributeManager.cs
new file mode 100644
index 0000000..2bd08f3
--- /dev/null
+++ b/Main/System/Attribute/AttributeManager.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+public class AttributeManager : GameSystemManager<AttributeManager>
+{
+    public Dictionary<int, long> totalAttrDict = new Dictionary<int, long>();
+    public void OpenTotalAttributeWin(Dictionary<int, long> totalAttrDict, int functionOrder = 0)
+    {
+        this.totalAttrDict = totalAttrDict;
+        if (!UIManager.Instance.IsOpened<TotalAttributeWin>())
+        {
+            UIManager.Instance.OpenWindow<TotalAttributeWin>(functionOrder);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/Attribute/AttributeManager.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/Attribute/AttributeManager.cs.meta
index c7311ca..7994e75 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/Attribute/AttributeManager.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 1ff6398b3797afb4eb0fd9633ac75cfe
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/HeroUI/HeroAllAttrWin.cs b/Main/System/Attribute/TotalAttributeWin.cs
similarity index 91%
rename from Main/System/HeroUI/HeroAllAttrWin.cs
rename to Main/System/Attribute/TotalAttributeWin.cs
index 455bd7e..e9e8052 100644
--- a/Main/System/HeroUI/HeroAllAttrWin.cs
+++ b/Main/System/Attribute/TotalAttributeWin.cs
@@ -4,19 +4,13 @@
 using UnityEngine;
 using UnityEngine.UI;
 
-
-/// <summary>
-/// 姝﹀皢灞炴�х晫闈細 functionOrder 鐢ㄦ潵浼犻�掓灏嗚儗鍖呯储寮�
-/// </summary>
-public class HeroAllAttrWin : UIBase
+public class TotalAttributeWin : UIBase
 {
     [SerializeField] Transform allContent;
     [SerializeField] GameObject baseAttrGroup;
     [SerializeField] GameObject fightAttrGroup;
     [SerializeField] GameObject fightAntiAttrGroup;
     [SerializeField] GameObject specialAttrGroup;
-
-
 
     Dictionary<int, Button> attrBtns = new Dictionary<int, Button>();
 
@@ -105,13 +99,9 @@
 
     protected override void OnPreOpen()
     {
-        var item = PackManager.Instance.GetItemByIndex(PackType.Hero, functionOrder);
-        if (item == null)
+        if (AttributeManager.Instance.totalAttrDict.IsNullOrEmpty())
             return;
-        var hero = HeroManager.Instance.GetHero(item.guid);
-        if (hero == null)
-            return;
-        var dict = FightPowerManager.Instance.GetHeroTotalAttr(hero);
+        var dict = AttributeManager.Instance.totalAttrDict;
         foreach (var kv in attrBtns)
         {
             //姣忎釜鎸夐挳涓嬫湁涓や釜Text锛歯ame 鍜� value
diff --git a/Main/System/HeroUI/HeroAllAttrWin.cs.meta b/Main/System/Attribute/TotalAttributeWin.cs.meta
similarity index 100%
rename from Main/System/HeroUI/HeroAllAttrWin.cs.meta
rename to Main/System/Attribute/TotalAttributeWin.cs.meta
diff --git a/Main/System/Chat/ChatBubbleManager.cs b/Main/System/Chat/ChatBubbleManager.cs
index fbfd584..df138fb 100644
--- a/Main/System/Chat/ChatBubbleManager.cs
+++ b/Main/System/Chat/ChatBubbleManager.cs
@@ -1,5 +1,4 @@
 锘縰sing System;
-using System.Collections;
 using System.Collections.Generic;
 
 using UnityEngine;
@@ -78,51 +77,51 @@
 
         public Dictionary<int, BubbleBox> bubblesIfo = new Dictionary<int, BubbleBox>();
 
-        public void UpdateBubbleState(HA717_tagMCChatBubbleBoxState package)
-        {
-            List<int> list = null;
-            if (serverInited)
-            {
-                list = new List<int>();
-                foreach (var id in chatBubbles.Keys)
-                {
-                    if (!IsBubbleGot(id))
-                    {
-                        list.Add(id);
-                    }
-                }
-            }
+        // public void UpdateBubbleState(HA717_tagMCChatBubbleBoxState package)
+        // {
+        //     List<int> list = null;
+        //     if (serverInited)
+        //     {
+        //         list = new List<int>();
+        //         foreach (var id in chatBubbles.Keys)
+        //         {
+        //             if (!IsBubbleGot(id))
+        //             {
+        //                 list.Add(id);
+        //             }
+        //         }
+        //     }
 
-            for (int i = 0; i < package.Count; i++)
-            {
-                var info = package.BoxList[i];
-                bubblesIfo[info.BoxID] = new BubbleBox()
-                {
-                    State = info.State,
-                    EndTime = (int)info.EndTime,
-                    Star = info.Star,
-                };
-            }
+        //     for (int i = 0; i < package.Count; i++)
+        //     {
+        //         var info = package.BoxList[i];
+        //         bubblesIfo[info.BoxID] = new BubbleBox()
+        //         {
+        //             State = info.State,
+        //             EndTime = (int)info.EndTime,
+        //             Star = info.Star,
+        //         };
+        //     }
 
-            if (serverInited)
-            {
-                if (list != null)
-                {
-                    for (int i = 0; i < list.Count; i++)
-                    {
-                        if (IsBubbleGot(list[i]))
-                        {
-                            SendUseBubble(list[i]);
-                            break;
-                        }
-                    }
-                }
-            }
-            if (chatBubbleStateRefresh != null)
-            {
-                chatBubbleStateRefresh();
-            }
-        }
+        //     if (serverInited)
+        //     {
+        //         if (list != null)
+        //         {
+        //             for (int i = 0; i < list.Count; i++)
+        //             {
+        //                 if (IsBubbleGot(list[i]))
+        //                 {
+        //                     SendUseBubble(list[i]);
+        //                     break;
+        //                 }
+        //             }
+        //         }
+        //     }
+        //     if (chatBubbleStateRefresh != null)
+        //     {
+        //         chatBubbleStateRefresh();
+        //     }
+        // }
 
         public void SendUseBubble(int id)
         {
@@ -130,13 +129,13 @@
             {
                 return;
             }
-            if (id == PlayerDatas.Instance.baseData.bubbleId)
+            if (id == PlayerDatas.Instance.baseData.chatBox)
             {
                 return;
             }
-            CA230_tagCMSetChatBubbleBox pak = new CA230_tagCMSetChatBubbleBox();
-            pak.BubbleBoxType = (byte)id;
-            GameNetSystem.Instance.SendInfo(pak);
+            // CA230_tagCMSetChatBubbleBox pak = new CA230_tagCMSetChatBubbleBox();
+            // pak.BubbleBoxType = (byte)id;
+            // GameNetSystem.Instance.SendInfo(pak);
         }
         #endregion
 
diff --git a/Main/System/Chat/ChatCenter.cs b/Main/System/Chat/ChatCenter.cs
index 2552fe7..db034a0 100644
--- a/Main/System/Chat/ChatCenter.cs
+++ b/Main/System/Chat/ChatCenter.cs
@@ -354,7 +354,7 @@
         {
             var vipLevel = PlayerDatas.Instance.baseData.VIPLv;
             var job = PlayerDatas.Instance.baseData.Job;
-            var bubbleId = PlayerDatas.Instance.baseData.bubbleId;
+            var bubbleId = PlayerDatas.Instance.baseData.chatBox;
             var serverGroupId = PlayerDatas.Instance.baseData.ServerGroupId;
             return StringUtility.Contact(vipLevel.ToString().PadLeft(2, '0'), 0, job,
                 bubbleId.ToString().PadLeft(2, '0'), serverGroupId.ToString().PadLeft(7, '0'));
diff --git a/Main/System/HeroUI/HeroTrainWin.cs b/Main/System/HeroUI/HeroTrainWin.cs
index 967a788..d8f840d 100644
--- a/Main/System/HeroUI/HeroTrainWin.cs
+++ b/Main/System/HeroUI/HeroTrainWin.cs
@@ -157,7 +157,14 @@
 
         allAttrBtn.AddListener(() =>
         {
-            UIManager.Instance.OpenWindow<HeroAllAttrWin>(hero.itemHero.gridIndex);
+            var item = PackManager.Instance.GetItemByIndex(PackType.Hero, functionOrder);
+            if (item == null)
+                return;
+            var hero = HeroManager.Instance.GetHero(item.guid);
+            if (hero == null)
+                return;
+            var dict = FightPowerManager.Instance.GetHeroTotalAttr(hero);
+            AttributeManager.Instance.OpenTotalAttributeWin(dict, hero.itemHero.gridIndex);
         });
         lvupBtn.AddListener(LVUp);
         lvupBtn.onPress.AddListener(LVUp);
@@ -491,8 +498,8 @@
                 lvupEffect.Play();
                 var cell = RequestCell();
                 cell.transform.localPosition = new Vector3(0, 0, 0);
-                cell.Display(hero.qualityConfig.LVAddPer, ()=>
-                { 
+                cell.Display(hero.qualityConfig.LVAddPer, () =>
+                {
                     cell.SetActive(false);
                     ReturnCell(cell);
                 });
@@ -507,7 +514,7 @@
 
     HeroTrainAddAttrCell RequestCell()
     {
-        
+
         if (lvupAttrQueue.Count == 0)
         {
             return Instantiate(addPerObject, addPerParent);
diff --git a/Main/System/HeroUI/HeroUIManager.cs b/Main/System/HeroUI/HeroUIManager.cs
index 2e556e0..19f4bb9 100644
--- a/Main/System/HeroUI/HeroUIManager.cs
+++ b/Main/System/HeroUI/HeroUIManager.cs
@@ -323,6 +323,8 @@
             return;
         }
         newHeroIDList.Add(heroID);
+
+        PhantasmPavilionManager.Instance.AddNewHero(heroID);
     }
 
     public void RemoveNewHero(int heroID)
diff --git a/Main/System/InternalAffairs/AffairFuncCell.cs b/Main/System/InternalAffairs/AffairFuncCell.cs
index d7842d9..d23f007 100644
--- a/Main/System/InternalAffairs/AffairFuncCell.cs
+++ b/Main/System/InternalAffairs/AffairFuncCell.cs
@@ -43,6 +43,11 @@
         {
             UIManager.Instance.OpenWindow<GoldRushWorkerWin>();
         }
+
+        if (funcID == 42)
+        {
+            UIManager.Instance.OpenWindow<PhantasmPavilionWin>();
+        }
         // else if (funcID == 214)
         // { 
         //     GoldRushManager.Instance.NotifyGoldRushEvent(0, 0, 2);
diff --git a/Main/System/Main/FightPowerManager.cs b/Main/System/Main/FightPowerManager.cs
index 65d802d..20fc8eb 100644
--- a/Main/System/Main/FightPowerManager.cs
+++ b/Main/System/Main/FightPowerManager.cs
@@ -281,8 +281,8 @@
         propertyVariables["realmPer"] = GetOfficialPer(attrType) / 10000.0f;
         propertyVariables["gubaoValue"] = 0;
         propertyVariables["gubaoPer"] = 0;
-        propertyVariables["hjgValue"] = 0;
-        propertyVariables["hjgPer"] = 0;
+        propertyVariables["hjgValue"] = PhantasmPavilionManager.Instance.GetAttrValue(attrType);
+        propertyVariables["hjgPer"] = PhantasmPavilionManager.Instance.GetAttrPer(attrType) / 10000.0f;
         propertyVariables["horseValue"] = HorseManager.Instance.GetAttrValue(attrType);
         propertyVariables["horsePer"] = HorseManager.Instance.GetAttrPer(attrType) / 10000.0f;
 
diff --git a/Main/System/Main/MainWin.cs b/Main/System/Main/MainWin.cs
index cef589f..8139624 100644
--- a/Main/System/Main/MainWin.cs
+++ b/Main/System/Main/MainWin.cs
@@ -36,7 +36,7 @@
     protected override void InitComponent()
     {
         base.InitComponent();
-
+        avatarCell.redpoint.redpointId = MainRedDot.PhantasmPavilionRepoint;
         avatarCell.button.SetListener(() =>
         {
             UIManager.Instance.OpenWindow<PlayerProfileWin>();
diff --git a/Main/System/OfficialRank/OfficialTitleCell.cs b/Main/System/OfficialRank/OfficialTitleCell.cs
index 7b8c832..e71d83f 100644
--- a/Main/System/OfficialRank/OfficialTitleCell.cs
+++ b/Main/System/OfficialRank/OfficialTitleCell.cs
@@ -18,7 +18,7 @@
     private Image officialRankObj
     {
         get
-        {   
+        {
             if (m_OfficialRankObj == null)
             {
                 m_OfficialRankObj = this.GetComponent<Image>("OfficialTitleCell/offcialRank");
@@ -31,8 +31,8 @@
     Text m_OfficialRankText;
     private Text officialRankText
     {
-                get
-        {   
+        get
+        {
             if (m_OfficialRankText == null)
             {
                 m_OfficialRankText = this.GetComponent<Text>("OfficialTitleCell/offcialRank/text");
@@ -41,14 +41,14 @@
         }
     }
 
-    Image m_TitleImage;
-    private Image titleImage
+    ImageEx m_TitleImage;
+    private ImageEx titleImage
     {
         get
         {
             if (m_TitleImage == null)
             {
-                m_TitleImage = this.GetComponent<Image>("OfficialTitleCell/Img_Title");
+                m_TitleImage = this.GetComponent<ImageEx>("OfficialTitleCell/Img_Title");
             }
             return m_TitleImage;
         }
@@ -69,6 +69,36 @@
         }
     }
 
+    UIEffectPlayer m_UIEffectPlayer;
+    private UIEffectPlayer effectPlayer
+    {
+        get
+        {
+            if (m_UIEffectPlayer == null)
+            {
+                m_UIEffectPlayer = this.GetComponent<UIEffectPlayer>("OfficialTitleCell/Img_Title/UIEffectPlayer");
+            }
+            return m_UIEffectPlayer;
+        }
+    }
+
+    void OnEnable()
+    {
+        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
+    }
+
+    void OnDisable()
+    {
+        PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh;
+    }
+
+    private void PlayerDataRefresh(PlayerDataType type)
+    {
+        if (type == PlayerDataType.ExAttr3)
+        {
+          InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID);
+        }
+    }
     
     GameObject prefab;
 
@@ -109,28 +139,11 @@
             officialRankObj.SetActive(false);
             titleUIFrame.SetActive(true);
             titleUIFrame.enabled = false;
-            var titleConfig = DienstgradConfig.Get(titleID);
-            string imgStr = titleConfig.Image;
-            if (!FrameAnimationConfig.HasKey(imgStr))
-            {
-                titleImage.SetSprite(imgStr);
-                titleImage.SetNativeSize();
-                return;
-            }
 
-            if (UIFrameMgr.Inst.ContainsDynamicImage(imgStr))
-            {
-                titleUIFrame.ResetFrame(imgStr);
-
-                List<Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(imgStr);
-                if (!spriteList.IsNullOrEmpty())
-                {
-                    titleImage.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height);
-                }
-
-                titleUIFrame.enabled = true;
-            }
+            int resourceType = PhantasmPavilionManager.Instance.GetResourceType(PhantasmPavilionType.Title, titleID);
+            string resourceValue = PhantasmPavilionManager.Instance.GetResourceValue(PhantasmPavilionType.Title, titleID);
+            PhantasmPavilionManager.Instance.Show(titleImage, effectPlayer, titleUIFrame, resourceType, resourceValue);
         }
     }
-    
+
 }
diff --git a/Main/System/PhantasmPavilion/AvatarCell.cs b/Main/System/PhantasmPavilion/AvatarCell.cs
index 354704e..dead145 100644
--- a/Main/System/PhantasmPavilion/AvatarCell.cs
+++ b/Main/System/PhantasmPavilion/AvatarCell.cs
@@ -1,54 +1,9 @@
-using System.Collections.Generic;
+using System;
 using UnityEngine;
 
-//澶村儚妯″潡锛堟敮鎸佸抚鍔ㄧ敾鍜岀壒鏁堬級
+//澶村儚妯″潡
 public class AvatarCell : MonoBehaviour
 {
-
-    private void Awake()
-    {
-        LoadPrefab();
-
-    }
-    ImageEx m_BgImage;
-    private ImageEx bgImage
-    {
-        get
-        {
-            if (m_BgImage == null)
-            {
-                m_BgImage = this.GetComponent<ImageEx>("AvatarCell/Img_BG");
-            }
-            return m_BgImage;
-        }
-    }
-
-    ImageEx m_AvatarImage;
-    private ImageEx avatarImage
-    {
-        get
-        {
-            if (m_AvatarImage == null)
-            {
-                m_AvatarImage = this.GetComponent<ImageEx>("AvatarCell/Img_BG/Img_AvatarFrame/GameObject/Img_Avatar");
-            }
-            return m_AvatarImage;
-        }
-    }
-
-    ImageEx m_AvatarFrameImage;
-    private ImageEx avatarFrameImage
-    {
-        get
-        {
-            if (m_AvatarFrameImage == null)
-            {
-                m_AvatarFrameImage = this.GetComponent<ImageEx>("AvatarCell/Img_BG/Img_AvatarFrame");
-            }
-            return m_AvatarFrameImage;
-        }
-    }
-
     ButtonEx m_button;
     public ButtonEx button
     {
@@ -57,66 +12,168 @@
             if (m_button == null)
             {
                 LoadPrefab();
-                m_button = this.GetComponent<ButtonEx>("AvatarCell/Img_BG");
+                m_button = this.GetComponent<ButtonEx>("AvatarCell/Img_FaceBG");
             }
             return m_button;
         }
     }
 
-    UIFrame m_AvatarUIFrame;
-    private UIFrame avatarUIFrame
+    ImageEx m_FaceBGImage;
+    public ImageEx faceBGImage
     {
         get
         {
-            if (m_AvatarUIFrame == null)
+            if (m_FaceBGImage == null)
             {
-                m_AvatarUIFrame = this.GetComponent<UIFrame>("AvatarCell/Img_BG/Img_AvatarFrame/GameObject/Img_Avatar");
+                LoadPrefab();
+                m_FaceBGImage = this.GetComponent<ImageEx>("AvatarCell/Img_FaceBG");
             }
-            return m_AvatarUIFrame;
+            return m_FaceBGImage;
         }
     }
 
-    UIFrame m_AvatarFrameUIFrame;
-    private UIFrame avatarFrameUIFrame
+    EllipseMask m_FaceMask;
+    public EllipseMask faceMask
     {
         get
         {
-            if (m_AvatarFrameUIFrame == null)
+            if (m_FaceMask == null)
             {
-                m_AvatarFrameUIFrame = this.GetComponent<UIFrame>("AvatarCell/Img_BG/Img_AvatarFrame");
+                LoadPrefab();
+                m_FaceMask = this.GetComponent<EllipseMask>("AvatarCell/Img_FaceBG/Mask_Face");
             }
-            return m_AvatarFrameUIFrame;
+            return m_FaceMask;
         }
     }
 
-    UIEffectPlayer m_AvatarUIEffect;
-    private UIEffectPlayer avatarUIEffect
+    UIFrame m_FaceUIFrame;
+    public UIFrame faceUIFrame
     {
         get
         {
-            if (m_AvatarUIEffect == null)
+            if (m_FaceUIFrame == null)
             {
-                m_AvatarUIEffect = this.GetComponent<UIEffectPlayer>("AvatarCell/Img_BG/Img_AvatarFrame/GameObject/Img_Avatar");
+                LoadPrefab();
+                m_FaceUIFrame = this.GetComponent<UIFrame>("AvatarCell/Img_FaceBG/Mask_Face/Img_Face");
             }
-            return m_AvatarUIEffect;
+            return m_FaceUIFrame;
         }
     }
 
-    UIEffectPlayer m_AvatarFrameUIEffect;
-    private UIEffectPlayer avatarFrameUIEffect
+    ImageEx m_FaceImage;
+    public ImageEx faceImage
     {
         get
         {
-            if (m_AvatarFrameUIEffect == null)
+            if (m_FaceImage == null)
             {
-                m_AvatarFrameUIEffect = this.GetComponent<UIEffectPlayer>("AvatarCell/Img_BG/Img_AvatarFrame");
+                LoadPrefab();
+                m_FaceImage = this.GetComponent<ImageEx>("AvatarCell/Img_FaceBG/Mask_Face/Img_Face");
             }
-            return m_AvatarFrameUIEffect;
+            return m_FaceImage;
+        }
+    }
+
+    UIEffectPlayer m_faceSpine;
+    public UIEffectPlayer faceSpine
+    {
+        get
+        {
+            if (m_faceSpine == null)
+            {
+                LoadPrefab();
+                m_faceSpine = this.GetComponent<UIEffectPlayer>("AvatarCell/Img_FaceBG/Mask_Face/Img_Face/Spine_Face");
+            }
+            return m_faceSpine;
+        }
+    }
+
+
+    ImageEx m_FacePicImage;
+    public ImageEx facePicImage
+    {
+        get
+        {
+            if (m_FacePicImage == null)
+            {
+                LoadPrefab();
+                m_FacePicImage = this.GetComponent<ImageEx>("AvatarCell/Img_FaceBG/Img_FacePic");
+            }
+            return m_FacePicImage;
+        }
+    }
+
+    UIFrame m_FacePicUIFrame;
+    public UIFrame facePicUIFrame
+    {
+        get
+        {
+            if (m_FacePicUIFrame == null)
+            {
+                LoadPrefab();
+                m_FacePicUIFrame = this.GetComponent<UIFrame>("AvatarCell/Img_FaceBG/Img_FacePic");
+            }
+            return m_FacePicUIFrame;
+        }
+    }
+
+    UIEffectPlayer m_facePicSpine;
+    public UIEffectPlayer facePicSpine
+    {
+        get
+        {
+            if (m_facePicSpine == null)
+            {
+                LoadPrefab();
+                m_facePicSpine = this.GetComponent<UIEffectPlayer>("AvatarCell/Img_FaceBG/Img_FacePic/Spine_FacePic");
+            }
+            return m_facePicSpine;
+        }
+    }
+
+    RedpointBehaviour m_redpoint;
+    public RedpointBehaviour redpoint
+    {
+        get
+        {
+            if (m_redpoint == null)
+            {
+                LoadPrefab();
+                m_redpoint = this.GetComponent<RedpointBehaviour>("AvatarCell/Img_FaceBG/RedPoint");
+            }
+            return m_redpoint;
         }
     }
 
     GameObject prefab;
+    AvatarModel avatarModel;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    private void Awake()
+    {
+        LoadPrefab();
+    }
 
+    void OnEnable()
+    {
+        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
+    }
+
+    void OnDisable()
+    {
+        PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh;
+    }
+
+    private void PlayerDataRefresh(PlayerDataType type)
+    {
+        if (type == PlayerDataType.Face || type == PlayerDataType.FacePic)
+        {
+            if (avatarModel == null || avatarModel.playerID != PlayerDatas.Instance.baseData.PlayerID)
+                return;
+            InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
+                                                                PlayerDatas.Instance.baseData.face,
+                                                                PlayerDatas.Instance.baseData.facePic));
+        }
+    }
 
     protected void LoadPrefab()
     {
@@ -143,107 +200,44 @@
             prefabRect.sizeDelta = new Vector2(parentRect.rect.width, parentRect.rect.height);
         }
     }
-
     public void InitUI(AvatarModel model)
     {
         if (model == null)
             return;
+        avatarModel = model;
         LoadPrefab();   //瀛樺湪琚嵏杞界殑鍙兘锛岄噸鏂板姞杞�
-        string img = AvatarHelper.GetAvatarBgColorStr(model.avatarID);
-        bgImage.SetSprite(img);
-        InitUI(model.avatarID, model.avatarUIEffectID, model.avatarFrameID, model.avatarFrameUIEffectID);
-    }
 
-    private void InitUI(int avatarID, int avatarUIEffectID, int avatarFrameID, int avatarFrameUIEffectID)
-    {
-        InitAvatarUI(avatarID, avatarUIEffectID);
-        InitAvatarFrameUI(avatarFrameID, avatarFrameUIEffectID);
-    }
+        int faceID = model.faceID;
+        int facePicID = model.facePicID;
+        manager.ShowFace(faceImage, faceSpine, faceUIFrame, faceMask, faceID);
 
-    private void InitAvatarUI(int avatarID, int avatarUIEffectID)
-    {
-        avatarUIEffect?.Stop();
-        avatarUIFrame.enabled = false;
-        if (!PlayerFaceConfig.HasKey(avatarID))
-            return;
+        string str = AvatarHelper.GetAvatarBgColorStr(faceID);
+        faceBGImage.SetSprite(str);
 
-        PlayerFaceConfig config = PlayerFaceConfig.Get(avatarID);
-        string imgStr = config.Image;
-        if (UIFrameMgr.Inst.ContainsDynamicImage(imgStr))
-        {
-            avatarUIFrame.ResetFrame(imgStr);
+        int resourceType = manager.GetResourceType(PhantasmPavilionType.FacePic, facePicID);
+        string resourceValue = manager.GetResourceValue(PhantasmPavilionType.FacePic, facePicID);
+        manager.Show(facePicImage, facePicSpine, facePicUIFrame, resourceType, resourceValue);
 
-            List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(imgStr);
-            if (!spriteList.IsNullOrEmpty())
-            {
-                avatarImage.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height);
-            }
-
-            avatarUIFrame.enabled = true;
-        }
-        else
-        {
-            avatarImage.SetSprite(imgStr);
-            avatarImage.SetNativeSize();
-            avatarUIFrame.enabled = false;
-        }
-
-        if (!EffectConfig.HasKey(avatarUIEffectID))
-            return;
-        avatarUIEffect.effectId = avatarUIEffectID;
-        // avatarUIEffect.loop = true;
-        avatarUIEffect.Play();
-    }
-
-    private void InitAvatarFrameUI(int avatarFrameID, int avatarFrameUIEffectID)
-    {
-        avatarFrameUIEffect?.Stop();
-        avatarFrameUIFrame.enabled = false;
-        if (!PlayerFacePicConfig.HasKey(avatarFrameID))
-            return;
-
-        PlayerFacePicConfig config = PlayerFacePicConfig.Get(avatarFrameID);
-        string imgStr = config.Image;
-        if (UIFrameMgr.Inst.ContainsDynamicImage(imgStr))
-        {
-            avatarFrameUIFrame.ResetFrame(imgStr);
-
-            List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(imgStr);
-            if (!spriteList.IsNullOrEmpty())
-            {
-                avatarFrameImage.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height);
-            }
-
-            avatarFrameUIFrame.enabled = true;
-        }
-        else
-        {
-            avatarFrameImage.SetSprite(imgStr);
-            avatarFrameImage.SetNativeSize();
-            avatarFrameUIFrame.enabled = false;
-        }
-
-        if (!EffectConfig.HasKey(avatarFrameUIEffectID))
-            return;
-        avatarUIEffect.effectId = avatarFrameUIEffectID;
-        // avatarUIEffect.loop = true;
-        avatarUIEffect.Play();
+        faceBGImage.SetNativeSize();
+        faceImage.SetNativeSize();
+        facePicImage.SetNativeSize();
     }
 }
 
 public class AvatarModel
 {
-    public int avatarID { get; private set; }
-    public int avatarFrameID { get; private set; }
-    public int avatarUIEffectID { get; private set; }
-    public int avatarFrameUIEffectID { get; private set; }
-    public float scale { get; private set; }
+    public int playerID { get; private set; }
+    public int faceID { get; private set; }
+    public int facePicID { get; private set; }
+    public int redpointID { get; private set; }
+    public Action clickAction { get; private set; }
 
-    public AvatarModel(int avatarID, int avatarFrameID, int avatarUIEffectID = 0, int avatarFrameUIEffectID = 0)
+    public AvatarModel(int playerID, int faceID, int facePicID, int redpointID = 0, Action clickAction = null)
     {
-        this.avatarID = avatarID;
-        this.avatarFrameID = avatarFrameID;
-        this.avatarUIEffectID = avatarUIEffectID;
-        this.avatarFrameUIEffectID = avatarFrameUIEffectID;
+        this.playerID = playerID;
+        this.faceID = faceID;
+        this.facePicID = facePicID;
+        this.redpointID = redpointID;
+        this.clickAction = clickAction;
     }
 }
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/AvatarHelper.cs b/Main/System/PhantasmPavilion/AvatarHelper.cs
index bafbb2a..68fb411 100644
--- a/Main/System/PhantasmPavilion/AvatarHelper.cs
+++ b/Main/System/PhantasmPavilion/AvatarHelper.cs
@@ -1,39 +1,21 @@
 public static class AvatarHelper
 {
-
     public static AvatarModel GetAvatarModel(int playerId, int face, int facePic, int job = 0)
     {
         bool isMyself = playerId == PlayerDatas.Instance.PlayerId;
-        return isMyself ? GetMyAvatarModel() : GetOtherAvatarModel(face, facePic, job);
-    }
-
-    //鑾峰彇澶村儚淇℃伅锛堝鏋滆〃涓笉瀛樺湪锛岃繑鍥為粯璁ょ殑锛�
-    public static AvatarModel GetOtherAvatarModel(int face, int facePic, int job = 0)
-    {
-        int nowFace = GetOtherAvatarID(face, job);
-        int nowfacePic = GetOtherAvatarFrameID(facePic, job);
-        int faceEffectID = GetAvatarEffectID(nowFace);
-        int facePicEffectID = GetAvatarFrameDefaultID(nowfacePic);
-        return new AvatarModel(nowFace, nowfacePic, faceEffectID, facePicEffectID);
-    }
-
-    //鑾峰彇鎴戠殑澶村儚淇℃伅锛堝鏋滆〃涓笉瀛樺湪 鎴� 宸茶繃鏈燂紝杩斿洖榛樿鐨勶級
-    public static AvatarModel GetMyAvatarModel()
-    {
-        int nowFace = GetMyAvatarID();
-        int nowfacePic = GetMyAvatarFrameID();
-        int faceEffectID = GetAvatarEffectID(nowFace);
-        int facePicEffectID = GetAvatarFrameDefaultID(nowfacePic);
-        return new AvatarModel(nowFace, nowfacePic, faceEffectID, facePicEffectID);
-    }
-
-    public static AvatarModel GetDefaultAvatarModel(int job = 0)
-    {
-        int nowFace = GetAvatarDefaultID(job);
-        int nowfacePic = GetAvatarFrameDefaultID(job);
-        int faceEffectID = GetAvatarEffectID(nowFace);
-        int facePicEffectID = GetAvatarFrameDefaultID(nowfacePic);
-        return new AvatarModel(nowFace, nowfacePic, faceEffectID, facePicEffectID);
+        int nowFace;
+        int nowfacePic;
+        if (isMyself)
+        {
+            nowFace = GetMyAvatarID();
+            nowfacePic = GetMyAvatarFrameID();
+        }
+        else
+        {
+            nowFace = GetOtherAvatarID(face, job);
+            nowfacePic = GetOtherAvatarFrameID(facePic, job);
+        }
+        return new AvatarModel(playerId, nowFace, nowfacePic);
     }
 
     public static int GetAvatarID(int playerId, int nowID, int job)
@@ -51,60 +33,43 @@
     // 鑾峰彇鍏朵粬鐜╁澶村儚id(灏佸寘涓殑id鍦ㄨ〃涓笉瀛樺湪鏄剧ず榛樿鐨�)
     public static int GetOtherAvatarID(int nowID, int job)
     {
-        if (PlayerFaceConfig.HasKey(nowID))
-            return nowID;
-        return PhantasmPavilionModel.Instance.TryGetDefaultID(PhantasmPavilionTab.Avatar, job, out int defaultID) ? defaultID : 0;
+        int defaultID = GetAvatarDefaultID(job);
+        return PlayerFaceConfig.HasKey(nowID) ? nowID : defaultID;
     }
 
     public static int GetOtherAvatarFrameID(int nowID, int job)
     {
-        if (PlayerFaceConfig.HasKey(nowID))
-            return nowID;
-        return PhantasmPavilionModel.Instance.TryGetDefaultID(PhantasmPavilionTab.AvatarFrame, job, out int defaultID) ? defaultID : 0;
+        int defaultID = GetAvatarFrameDefaultID(job);
+        return PlayerFacePicConfig.HasKey(nowID) ? nowID : defaultID;
     }
 
     //杩斿洖鐜╁澶村儚id(褰撳墠瑁呭鐨勮繃鏈熶簡鏄剧ず榛樿鐨�)
     public static int GetMyAvatarID()
     {
-        PhantasmPavilionModel.Instance.TryGetNowShowID(PhantasmPavilionTab.Avatar, out int defaultID);
-        return defaultID;
+        return PhantasmPavilionManager.Instance.TryGetNowShowID(PhantasmPavilionType.Face, out int defaultID) ? defaultID : 0;
     }
 
     public static int GetMyAvatarFrameID()
     {
-        PhantasmPavilionModel.Instance.TryGetNowShowID(PhantasmPavilionTab.AvatarFrame, out int defaultID);
-        return defaultID;
+        int job = PlayerDatas.Instance.baseData.Job;
+        return PhantasmPavilionManager.Instance.TryGetNowShowID(PhantasmPavilionType.FacePic, out int defaultID) ? defaultID : 0;
     }
 
     //鏍规嵁job 鐩存帴杩斿洖瀵瑰簲鐨勯粯璁ゅご鍍廼d
     public static int GetAvatarDefaultID(int job)
     {
-        PhantasmPavilionModel.Instance.TryGetDefaultID(PhantasmPavilionTab.Avatar, job, out int defaultID);
-        return defaultID;
+        return PhantasmPavilionManager.Instance.TryGetDefaultID(PhantasmPavilionType.Face, job, out int defaultID) ? defaultID : 0;
     }
 
+    //鏍规嵁job 鐩存帴杩斿洖瀵瑰簲鐨勯粯璁ゅご鍍忔id
     public static int GetAvatarFrameDefaultID(int job)
     {
-        PhantasmPavilionModel.Instance.TryGetDefaultID(PhantasmPavilionTab.AvatarFrame, job, out int defaultID);
-        return defaultID;
+        return PhantasmPavilionManager.Instance.TryGetDefaultID(PhantasmPavilionType.FacePic, job, out int defaultID) ? defaultID : 0;
     }
 
-    public static int GetAvatarEffectID(int id)
-    {
-        PhantasmPavilionModel.Instance.TryGetEffectID(PhantasmPavilionTab.Avatar, id, out int effectID);
-        return effectID;
-    }
-
-    public static int GetAvatarFrameEffectID(int id)
-    {
-        PhantasmPavilionModel.Instance.TryGetEffectID(PhantasmPavilionTab.AvatarFrame, id, out int effectID);
-        return effectID;
-    }
-
-    //鑾峰彇鎸囧畾澶村儚搴曞浘鍝佽川
     public static int GetAvatarBgColor(int faceID)
     {
-        int defaultColor = 1;//榛樿鍝佽川鏄櫧鑹�
+        int defaultColor = 1;
         if (!PlayerFaceConfig.HasKey(faceID))
             return defaultColor;
         return PlayerFaceConfig.Get(faceID).BgColor;
diff --git a/Main/System/PhantasmPavilion/ChatBubbleHelper.cs b/Main/System/PhantasmPavilion/ChatBubbleHelper.cs
index 7beaa1e..eccfc81 100644
--- a/Main/System/PhantasmPavilion/ChatBubbleHelper.cs
+++ b/Main/System/PhantasmPavilion/ChatBubbleHelper.cs
@@ -4,17 +4,17 @@
 
     public static int GetOtherChatBubbleID(int nowID)
     {
-        return PhantasmPavilionModel.Instance.GetNowOtherChatBubbleID(nowID);
+        return 0;//PhantasmPavilionModel.Instance.GetNowOtherChatBubbleID(nowID);
     }
 
     public static int GetMyChatBubbleID()
     {
-        return PhantasmPavilionModel.Instance.GetNowChatBubbleID();
+        return 0;//PhantasmPavilionModel.Instance.GetNowChatBubbleID();
     }
 
     public static int GetChatBubbleDefaultID()
     {
-        PhantasmPavilionModel.Instance.TryGetDefaultID(PhantasmPavilionTab.ChatBubble, 0, out int defaultID);
-        return defaultID;
+        // PhantasmPavilionModel.Instance.TryGetDefaultID(PhantasmPavilionTab.ChatBubble, 0, out int defaultID);
+        return 0;//defaultID;
     }
 }
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs b/Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs
new file mode 100644
index 0000000..b8485b2
--- /dev/null
+++ b/Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs
@@ -0,0 +1,17 @@
+// 杩欎釜鎺ュ彛瀹氫箟浜嗘墍鏈夌浉鍏矯onfig绫婚渶瑕佹彁渚涚殑鍏叡灞炴��
+public interface IPhantasmPavilionConfigProperties
+{
+    string Name { get; }
+    int ExpireMinutes { get; }
+    int UnlockWay { get; }
+    int UnlockValue { get; }
+    int UnlockNeedCnt { get; }
+    int UpNeedCnt { get; }
+    int StarMax { get; }
+    int[] AttrIDList { get; }
+    int[] InitAttrValueList { get; }
+    int[] AttrPerStarAddList { get; }
+    int ResourceType { get; }
+    string ResourceValue { get; }
+    string GetWayString { get; }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs.meta
index c7311ca..5c2200e 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/IPhantasmPavilionHandler.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 2a6fae5b536e8eb41b6573731bddb7ed
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/IPhantasmPavilionTabHandler.cs b/Main/System/PhantasmPavilion/IPhantasmPavilionTabHandler.cs
index 9acbc7e..777dab0 100644
--- a/Main/System/PhantasmPavilion/IPhantasmPavilionTabHandler.cs
+++ b/Main/System/PhantasmPavilion/IPhantasmPavilionTabHandler.cs
@@ -1,31 +1,20 @@
 using System.Collections.Generic;
 
-public interface IPhantasmPavilionTabHandler
+public interface IPhantasmPavilionHandler
 {
-    string GetDescriptive(int id);
-
-    int GetSortNum(int id);
-
-    int GetExpireMinutes(int id);
-
-    string GetImage(int id);
-
+    bool HasTableKey(int id);
+    List<int> GetKeyList();
+    int GetResourceType(int id);
+    string GetResourceValue(int id);
     string GetName(int id);
-
-    List<int> GetTableKeys();
-
-    int GetUnlockDefault(int id);
-
-    bool Has(int id);
-
-
-    void SendUsePack(int id);
-
-
-    bool TryGetEffectID(int id, out int effectID);
-
-
-    bool TryGetUnLockAttr(int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr);
-
-    bool TryGetUnLockNeedItem(int id, out int itemId, out int count);
+    int GetExpireMinutes(int id);
+    int GetUnlockWay(int id);
+    int GetUnlockValue(int id);
+    int GetUnlockNeedCnt(int id);
+    int GetUpNeedCnt(int id);
+    int GetStarMax(int id);
+    int[] GetAttrIDList(int id);
+    int[] GetInitAttrValueList(int id);
+    int[] GetAttrPerStarAddList(int id);
+    string GetGetWayString(int id);
 }
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs b/Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs
new file mode 100644
index 0000000..f48fcc8
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs
@@ -0,0 +1,62 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionAddStarButton : MonoBehaviour
+{
+    [SerializeField] ButtonEx btnAddStar;
+    [SerializeField] ImageEx imgAddStar;
+    [SerializeField] TextEx txtAddStar;
+    [SerializeField] ImageEx imgItem;
+    [SerializeField] TextEx txtCount;
+    [SerializeField] Image imgRed;
+    PhantasmPavilionType type;
+    int id;
+    int unlockWay;
+    int unlockValue;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        type = manager.nowType;
+        this.id = id;
+        btnAddStar.SetListener(() =>
+        {
+            if (unlockWay == 2)
+            {
+                var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, unlockValue);
+                int useCnt = manager.GetUpNeedCnt(type, id);
+                if (useCnt > hasCnt)
+                {
+                    if (!ItemConfig.HasKey(unlockValue))
+                        return;
+                    string name = ItemConfig.Get(unlockValue).ItemName;
+                    SysNotifyMgr.Instance.ShowTip("UnLockFail2", name);
+                    return;
+                }
+            }
+            manager.SendOPPack(type, PhantasmPavilionOperation.UpgradeStar, (uint)id);
+        });
+
+        unlockWay = manager.GetUnlockWay(type, id);
+        unlockValue = manager.GetUnlockValue(type, id);
+
+        bool isStarMax = manager.IsStarMax(type, id);
+        txtAddStar.text = Language.Get(isStarMax ? "L1110" : "L1109");
+        imgAddStar.gray = isStarMax;
+        btnAddStar.interactable = !isStarMax;
+        imgRed.SetActive(false);
+        txtCount.SetActive(unlockWay == 2 && !isStarMax);
+        if (unlockWay == 2)
+        {
+            if (!ItemConfig.HasKey(unlockValue))
+                return;
+            ItemConfig itemConfig = ItemConfig.Get(unlockValue);
+            imgItem.SetSprite(itemConfig.IconKey);
+
+            var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, unlockValue);
+            int useCnt = manager.GetUpNeedCnt(type, id);
+            txtCount.text = UIHelper.AppendColor(useCnt <= hasCnt ? TextColType.Green : TextColType.Red, Language.Get("BoneField09", hasCnt, useCnt));
+            imgRed.SetActive(useCnt <= hasCnt && !isStarMax);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs.meta
index c7311ca..892aaa1 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionAddStarButton.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 7f7449ee889babf4187ff71d8be6c1f0
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionAvatarFrameHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionAvatarFrameHandler.cs
deleted file mode 100644
index 4950bab..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionAvatarFrameHandler.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using System.Collections.Generic;
-
-public class PhantasmPavilionAvatarFrameHandler : IPhantasmPavilionTabHandler
-{
-
-    public string GetDescriptive(int id)
-    {
-        return PlayerFacePicConfig.Get(id).Descriptive;
-    }
-
-    public int GetExpireMinutes(int id)
-    {
-        return PlayerFacePicConfig.Get(id).ExpireMinutes;
-    }
-
-    public string GetImage(int id)
-    {
-        return PlayerFacePicConfig.Get(id).Image;
-    }
-
-    public string GetName(int id)
-    {
-        return PlayerFacePicConfig.Get(id).Name;
-    }
-
-    public int GetSortNum(int id)
-    {
-        return PlayerFacePicConfig.Get(id).SortNum;
-    }
-
-    public List<int> GetTableKeys()
-    {
-        return PlayerFacePicConfig.GetKeys();
-    }
-
-    public int GetUnlockDefault(int id)
-    {
-        return PlayerFacePicConfig.Get(id).UnlockDefault;
-    }
-
-    public bool Has(int id)
-    {
-        return PlayerFacePicConfig.HasKey(id);
-    }
-
-
-
-    public void SendUsePack(int id)
-    {
-        PhantasmPavilionModel.Instance.SendCB228FacePicChange(id);
-    }
-
-
-    public bool TryGetEffectID(int id, out int effectID)
-    {
-        effectID = 0;
-        if (!PlayerFacePicConfig.HasKey(id))
-            return false;
-        PlayerFacePicConfig config = PlayerFacePicConfig.Get(id);
-        if (!EffectConfig.HasKey(config.EffectID))
-            return false;
-        effectID = config.EffectID;
-        return true;
-    }
-
-
-    public bool TryGetUnLockAttr(int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr)
-    {
-        lightAttrTypeArr = new int[0];
-        lightAttrValueArr = new int[0];
-        if (!PlayerFacePicConfig.HasKey(id))
-            return false;
-        PlayerFacePicConfig config = PlayerFacePicConfig.Get(id);
-        if (config.LightAttrType.IsNullOrEmpty() || config.LightAttrValue.IsNullOrEmpty() || config.LightAttrType.Length != config.LightAttrValue.Length)
-            return false;
-        lightAttrTypeArr = config.LightAttrType;
-        lightAttrValueArr = config.LightAttrValue;
-        return true;
-    }
-
-    public bool TryGetUnLockNeedItem(int id, out int itemId, out int count)
-    {
-        itemId = 0;
-        count = 0;
-        if (!PlayerFacePicConfig.HasKey(id))
-            return false;
-        PlayerFacePicConfig config = PlayerFacePicConfig.Get(id);
-
-        if (config.UnlockNeedItemList.IsNullOrEmpty())
-            return false;
-        itemId = config.UnlockNeedItemList[0][0];
-        count = config.UnlockNeedItemList[0][1];
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionAvatarHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionAvatarHandler.cs
deleted file mode 100644
index d62dfbe..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionAvatarHandler.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using System.Collections.Generic;
-
-public class PhantasmPavilionAvatarHandler : IPhantasmPavilionTabHandler
-{
-
-    public string GetDescriptive(int id)
-    {
-        return PlayerFaceConfig.Get(id).Descriptive;
-    }
-
-    public int GetExpireMinutes(int id)
-    {
-        return PlayerFaceConfig.Get(id).ExpireMinutes;
-    }
-
-    public string GetImage(int id)
-    {
-        return PlayerFaceConfig.Get(id).Image;
-    }
-
-    public string GetName(int id)
-    {
-        return PlayerFaceConfig.Get(id).Name;
-    }
-
-    public int GetSortNum(int id)
-    {
-        return PlayerFaceConfig.Get(id).BgColor;
-    }
-
-    public List<int> GetTableKeys()
-    {
-        return PlayerFaceConfig.GetKeys();
-    }
-
-    public int GetUnlockDefault(int id)
-    {
-        return PlayerFaceConfig.Get(id).UnlockDefault;
-    }
-
-    public bool Has(int id)
-    {
-        return PlayerFaceConfig.HasKey(id);
-    }
-
-
-    public void SendUsePack(int id)
-    {
-        PhantasmPavilionModel.Instance.SendCB226FaceChange(id);
-    }
-
-
-    public bool TryGetEffectID(int id, out int effectID)
-    {
-        effectID = 0;
-        if (!PlayerFaceConfig.HasKey(id))
-            return false;
-        PlayerFaceConfig config = PlayerFaceConfig.Get(id);
-        if (!EffectConfig.HasKey(config.EffectID))
-            return false;
-        effectID = config.EffectID;
-        return true;
-    }
-
-
-
-    public bool TryGetUnLockAttr(int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr)
-    {
-        lightAttrTypeArr = new int[0];
-        lightAttrValueArr = new int[0];
-        if (!PlayerFaceConfig.HasKey(id))
-            return false;
-        PlayerFaceConfig config = PlayerFaceConfig.Get(id);
-        if (config.LightAttrType.IsNullOrEmpty() || config.LightAttrValue.IsNullOrEmpty() || config.LightAttrType.Length != config.LightAttrValue.Length)
-            return false;
-        lightAttrTypeArr = config.LightAttrType;
-        lightAttrValueArr = config.LightAttrValue;
-        return true;
-    }
-
-    public bool TryGetUnLockNeedItem(int id, out int itemId, out int count)
-    {
-        itemId = 0;
-        count = 0;
-        if (!PlayerFaceConfig.HasKey(id))
-            return false;
-        PlayerFaceConfig config = PlayerFaceConfig.Get(id);
-
-        if (config.UnlockNeedItemList.IsNullOrEmpty())
-            return false;
-        itemId = config.UnlockNeedItemList[0][0];
-        count = config.UnlockNeedItemList[0][1];
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs
new file mode 100644
index 0000000..1efa1b1
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs
@@ -0,0 +1,33 @@
+锘縰sing System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionChatBoxCell : MonoBehaviour
+{
+    readonly PhantasmPavilionType type = PhantasmPavilionType.ChatBox;
+    [SerializeField] List<PhantasmPavilionChatBoxItem> items = new List<PhantasmPavilionChatBoxItem>();
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int rowIndex)
+    {
+
+        List<int> showItemList = manager.ShowItemList(type);
+        if (showItemList.IsNullOrEmpty() || !manager.TryGetRowCountMax(type, out int rowCountMax))
+            return;
+        for (int i = 0; i < items.Count; i++)
+        {
+            int index = rowIndex * rowCountMax + i;
+            if (!showItemList.IsNullOrEmpty())
+            {
+                if (index < showItemList.Count)
+                {
+                    items[i].SetActive(true);
+                    items[i].Display(showItemList[index]);
+                }
+                else
+                {
+                    items[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs.meta
index c7311ca..7dc1f6e 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxCell.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: ca07fe405726ac140970eba578283e6e
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs
new file mode 100644
index 0000000..0902368
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+public class PhantasmPavilionChatBoxHandler : IPhantasmPavilionHandler
+{
+    public bool HasTableKey(int id)
+    {
+        return ChatBubbleBoxConfig.HasKey(id);
+    }
+    public List<int> GetKeyList()
+    {
+        return ChatBubbleBoxConfig.GetKeys();
+    }
+    public int GetResourceType(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).ResourceType;
+    }
+    public string GetResourceValue(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).ResourceValue;
+    }
+
+    public string GetName(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).Name;
+    }
+    public int GetExpireMinutes(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).ExpireMinutes;
+    }
+    public int GetUnlockWay(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).UnlockWay;
+    }
+    public int GetUnlockValue(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).UnlockValue;
+    }
+    public int GetUnlockNeedCnt(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).UnlockNeedCnt;
+    }
+    public int GetUpNeedCnt(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).UpNeedCnt;
+    }
+    public int GetStarMax(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).StarMax;
+    }
+    public int[] GetAttrIDList(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).AttrIDList;
+    }
+    public int[] GetInitAttrValueList(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).InitAttrValueList;
+    }
+    public int[] GetAttrPerStarAddList(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).AttrPerStarAddList;
+    }
+    public string GetGetWayString(int id)
+    {
+        return ChatBubbleBoxConfig.Get(id).GetWayString;
+    }
+
+}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatBubbleHandler.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs.meta
similarity index 100%
rename from Main/System/PhantasmPavilion/PhantasmPavilionChatBubbleHandler.cs.meta
rename to Main/System/PhantasmPavilion/PhantasmPavilionChatBoxHandler.cs.meta
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs
new file mode 100644
index 0000000..8d4a361
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs
@@ -0,0 +1,51 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionChatBoxItem : MonoBehaviour
+{
+    [SerializeField] ImageEx imgBg;
+    [SerializeField] ImageEx imgFace;
+    [SerializeField] UIFrame uiFrame;
+    [SerializeField] UIEffectPlayer spine;
+    [SerializeField] Button btnChoose;
+
+    [SerializeField] ImageEx imgLimit;
+    [SerializeField] ImageEx imgLock;
+    [SerializeField] ImageEx imgChoose;
+    [SerializeField] ImageEx imgCanUnlock;
+    [SerializeField] Image imgUsing;
+    [SerializeField] Image imgRed;
+
+    readonly PhantasmPavilionType type = PhantasmPavilionType.ChatBox;
+    int id;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        this.id = id;
+        btnChoose.SetListener(() =>
+        {
+            manager.selectId = id;
+        });
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isLimitedTime = manager.IsLimitTime(type, id);
+        bool isUsing = manager.IsUsing(type, id);
+        imgChoose.SetActive(manager.selectId == id);
+        imgBg.SetSprite(manager.selectId == id ? "ChatBoxSelect" : "ChatBoxUnSelect");
+        imgLimit.SetActive(state == PhantasmPavilionState.Activated && isLimitedTime);
+        imgLock.SetActive(state != PhantasmPavilionState.Activated);
+        imgCanUnlock.SetActive(state == PhantasmPavilionState.CanActivate);
+        imgUsing.SetActive(state == PhantasmPavilionState.Activated && isUsing);
+
+        int resourceType = manager.GetResourceType(type, id);
+        string resourceValue = manager.GetResourceValue(type, id);
+        manager.Show(imgFace, spine, uiFrame, resourceType, resourceValue);
+        if (resourceType == 1)
+        {
+            imgFace.SetNativeSize();
+        }
+
+        manager.UpdateItemRedPoint(imgRed, type, id);
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs.meta
index c7311ca..d1a197a 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionChatBoxItem.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 6d8dd643a8963624f989e3d1f4022264
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatBubbleHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionChatBubbleHandler.cs
deleted file mode 100644
index 8d305ff..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionChatBubbleHandler.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using System.Collections.Generic;
-
-public class PhantasmPavilionChatBubbleHandler : IPhantasmPavilionTabHandler
-{
-
-
-    public string GetDescriptive(int id)
-    {
-        return ChatBubbleBoxConfig.Get(id).Descriptive;
-    }
-
-    public int GetExpireMinutes(int id)
-    {
-        return ChatBubbleBoxConfig.Get(id).ExpireMinutes;
-    }
-
-    public string GetImage(int id)
-    {
-        return ChatBubbleBoxConfig.Get(id).Icon;
-    }
-
-    public string GetName(int id)
-    {
-        return ChatBubbleBoxConfig.Get(id).Name;
-    }
-
-    public int GetSortNum(int id)
-    {
-        return ChatBubbleBoxConfig.Get(id).SortNum;
-    }
-
-    public List<int> GetTableKeys()
-    {
-        return ChatBubbleBoxConfig.GetKeys();
-    }
-
-    public int GetUnlockDefault(int id)
-    {
-        return ChatBubbleBoxConfig.Get(id).UnlockDefault;
-    }
-
-    public bool Has(int id)
-    {
-        return ChatBubbleBoxConfig.HasKey(id);
-    }
-
-
-
-    public void SendUsePack(int id)
-    {
-        PhantasmPavilionModel.Instance.SendCA230SetChatBubbleBox(id);
-    }
-
-    public bool TryGetEffectID(int id, out int effectID)
-    {
-        effectID = 0;
-        return false;
-    }
-
- 
-
-    public bool TryGetUnLockAttr(int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr)
-    {
-        lightAttrTypeArr = new int[0];
-        lightAttrValueArr = new int[0];
-        if (!ChatBubbleBoxConfig.HasKey(id))
-            return false;
-        ChatBubbleBoxConfig config = ChatBubbleBoxConfig.Get(id);
-        if (config.LightAttrType.IsNullOrEmpty() || config.LightAttrValue.IsNullOrEmpty() || config.LightAttrType.Length != config.LightAttrValue.Length)
-            return false;
-        lightAttrTypeArr = config.LightAttrType;
-        lightAttrValueArr = config.LightAttrValue;
-        return true;
-    }
-
-    public bool TryGetUnLockNeedItem(int id, out int itemId, out int count)
-    {
-        itemId = 0;
-        count = 0;
-        if (!ChatBubbleBoxConfig.HasKey(id))
-            return false;
-        ChatBubbleBoxConfig config = ChatBubbleBoxConfig.Get(id);
-
-        if (config.UnlockNeedItemList.IsNullOrEmpty())
-            return false;
-        itemId = config.UnlockNeedItemList[0][0];
-        count = config.UnlockNeedItemList[0][1];
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatExpressionHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionChatExpressionHandler.cs
deleted file mode 100644
index fb9a723..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionChatExpressionHandler.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System.Collections.Generic;
-
-public class PhantasmPavilionChatExpressionHandler : IPhantasmPavilionTabHandler
-{
-
-    public string GetDescriptive(int id)
-    {
-        return EmojiPackConfig.Get(id).Descriptive;
-    }
-
-    public int GetExpireMinutes(int id)
-    {
-        return EmojiPackConfig.Get(id).ExpireMinutes;
-    }
-
-    public string GetImage(int id)
-    {
-        return EmojiPackConfig.Get(id).Image;
-    }
-
-    public string GetName(int id)
-    {
-        return EmojiPackConfig.Get(id).Name;
-    }
-
-    public int GetSortNum(int id)
-    {
-        return EmojiPackConfig.Get(id).SortNum;
-    }
-
-    public List<int> GetTableKeys()
-    {
-        return EmojiPackConfig.GetKeys();
-    }
-
-    public int GetUnlockDefault(int id)
-    {
-        return EmojiPackConfig.Get(id).UnlockDefault;
-    }
-
-    public bool Has(int id)
-    {
-        return EmojiPackConfig.HasKey(id);
-    }
-
-
-
-    public void SendUsePack(int id)
-    {
-        PhantasmPavilionModel.Instance.SendCA230SetChatBubbleBox(id);
-    }
-
-
-
-    public bool TryGetEffectID(int id, out int effectID)
-    {
-        effectID = 0;
-        if (!EmojiPackConfig.HasKey(id))
-            return false;
-        EmojiPackConfig config = EmojiPackConfig.Get(id);
-        if (!EffectConfig.HasKey(config.EffectID))
-            return false;
-        effectID = config.EffectID;
-        return true;
-    }
-
-
-
-
-    public bool TryGetUnLockAttr(int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr)
-    {
-        lightAttrTypeArr = new int[0];
-        lightAttrValueArr = new int[0];
-        return false;
-    }
-
-    public bool TryGetUnLockNeedItem(int id, out int itemId, out int count)
-    {
-        itemId = 0;
-        count = 0;
-        if (!EmojiPackConfig.HasKey(id))
-            return false;
-        EmojiPackConfig config = EmojiPackConfig.Get(id);
-
-        if (config.UnlockNeedItemList.IsNullOrEmpty())
-            return false;
-        itemId = config.UnlockNeedItemList[0][0];
-        count = config.UnlockNeedItemList[0][1];
-        return true;
-    }
-}
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs
new file mode 100644
index 0000000..544267a
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs
@@ -0,0 +1,33 @@
+锘縰sing System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionFaceCell : MonoBehaviour
+{
+    readonly PhantasmPavilionType type = PhantasmPavilionType.Face;
+    [SerializeField] List<PhantasmPavilionFaceItem> items = new List<PhantasmPavilionFaceItem>();
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int rowIndex)
+    {
+
+        List<int> showItemList = manager.ShowItemList(type);
+        if (showItemList.IsNullOrEmpty() || !manager.TryGetRowCountMax(type, out int rowCountMax))
+            return;
+        for (int i = 0; i < items.Count; i++)
+        {
+            int index = rowIndex * rowCountMax + i;
+            if (!showItemList.IsNullOrEmpty())
+            {
+                if (index < showItemList.Count)
+                {
+                    items[i].SetActive(true);
+                    items[i].Display(showItemList[index]);
+                }
+                else
+                {
+                    items[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs.meta
index c7311ca..9935b90 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceCell.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: e6cbc0f5d8da9394d81c82c48b4dd58c
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs
new file mode 100644
index 0000000..1860f26
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+public class PhantasmPavilionFaceHandler : IPhantasmPavilionHandler
+{
+    public bool HasTableKey(int id)
+    {
+        return PlayerFaceConfig.HasKey(id);
+    }
+    public List<int> GetKeyList()
+    {
+        return PlayerFaceConfig.GetKeys();
+    }
+    public int GetResourceType(int id)
+    {
+        return PlayerFaceConfig.Get(id).ResourceType;
+    }
+    public string GetResourceValue(int id)
+    {
+        return PlayerFaceConfig.Get(id).ResourceValue;
+    }
+
+    public string GetName(int id)
+    {
+        return PlayerFaceConfig.Get(id).Name;
+    }
+    public int GetExpireMinutes(int id)
+    {
+        return PlayerFaceConfig.Get(id).ExpireMinutes;
+    }
+    public int GetUnlockWay(int id)
+    {
+        return PlayerFaceConfig.Get(id).UnlockWay;
+    }
+    public int GetUnlockValue(int id)
+    {
+        return PlayerFaceConfig.Get(id).UnlockValue;
+    }
+    public int GetUnlockNeedCnt(int id)
+    {
+        return PlayerFaceConfig.Get(id).UnlockNeedCnt;
+    }
+    public int GetUpNeedCnt(int id)
+    {
+        return PlayerFaceConfig.Get(id).UpNeedCnt;
+    }
+    public int GetStarMax(int id)
+    {
+        return PlayerFaceConfig.Get(id).StarMax;
+    }
+    public int[] GetAttrIDList(int id)
+    {
+        return PlayerFaceConfig.Get(id).AttrIDList;
+    }
+    public int[] GetInitAttrValueList(int id)
+    {
+        return PlayerFaceConfig.Get(id).InitAttrValueList;
+    }
+    public int[] GetAttrPerStarAddList(int id)
+    {
+        return PlayerFaceConfig.Get(id).AttrPerStarAddList;
+    }
+    public string GetGetWayString(int id)
+    {
+        return PlayerFaceConfig.Get(id).GetWayString;
+    }
+
+}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionAvatarHandler.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs.meta
similarity index 100%
rename from Main/System/PhantasmPavilion/PhantasmPavilionAvatarHandler.cs.meta
rename to Main/System/PhantasmPavilion/PhantasmPavilionFaceHandler.cs.meta
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs
new file mode 100644
index 0000000..81e2b52
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs
@@ -0,0 +1,47 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionFaceItem : MonoBehaviour
+{
+    [SerializeField] EllipseMask mask;
+    [SerializeField] ImageEx imgBg;
+    [SerializeField] ImageEx imgFace;
+    [SerializeField] UIFrame uiFrame;
+    [SerializeField] UIEffectPlayer spine;
+    [SerializeField] Button btnChoose;
+
+    [SerializeField] ImageEx imgLimit;
+    [SerializeField] ImageEx imgLock;
+    [SerializeField] ImageEx imgChoose;
+    [SerializeField] ImageEx imgCanUnlock;
+    [SerializeField] TextEx txtUsing;
+    [SerializeField] Image imgRed;
+
+    readonly PhantasmPavilionType type = PhantasmPavilionType.Face;
+    int id;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        this.id = id;
+        btnChoose.SetListener(() =>
+        {
+            manager.selectId = id;
+        });
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isLimitedTime = manager.IsLimitTime(type, id);
+        bool isUsing = manager.IsUsing(type, id);
+        imgChoose.SetActive(manager.selectId == id);
+        imgLimit.SetActive(state == PhantasmPavilionState.Activated && isLimitedTime);
+        imgLock.SetActive(state != PhantasmPavilionState.Activated);
+        imgCanUnlock.SetActive(state == PhantasmPavilionState.CanActivate);
+        txtUsing.SetActive(state == PhantasmPavilionState.Activated && isUsing);
+
+        string str = AvatarHelper.GetAvatarBgColorStr(id);
+        imgBg.SetSprite(str);
+        manager.ShowFace(imgFace, spine, uiFrame, mask, id);
+
+        manager.UpdateItemRedPoint(imgRed, type, id);
+
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs.meta
index c7311ca..8316c47 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceItem.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: dda542d2b8148544fb2a89824c2c943b
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs
new file mode 100644
index 0000000..bb842f7
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs
@@ -0,0 +1,33 @@
+锘縰sing System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionFacePicCell : MonoBehaviour
+{
+    readonly PhantasmPavilionType type = PhantasmPavilionType.FacePic;
+    [SerializeField] List<PhantasmPavilionFacePicItem> items = new List<PhantasmPavilionFacePicItem>();
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int rowIndex)
+    {
+
+        List<int> showItemList = manager.ShowItemList(type);
+        if (showItemList.IsNullOrEmpty() || !manager.TryGetRowCountMax(type, out int rowCountMax))
+            return;
+        for (int i = 0; i < items.Count; i++)
+        {
+            int index = rowIndex * rowCountMax + i;
+            if (!showItemList.IsNullOrEmpty())
+            {
+                if (index < showItemList.Count)
+                {
+                    items[i].SetActive(true);
+                    items[i].Display(showItemList[index]);
+                }
+                else
+                {
+                    items[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs.meta
index c7311ca..4243ba9 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicCell.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 47af8fe5da030e14181647ac6423f4a2
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs
new file mode 100644
index 0000000..ce96f65
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+public class PhantasmPavilionFacePicHandler : IPhantasmPavilionHandler
+{
+
+    public bool HasTableKey(int id)
+    {
+        return PlayerFacePicConfig.HasKey(id);
+    }
+    public List<int> GetKeyList()
+    {
+        return PlayerFacePicConfig.GetKeys();
+    }
+    public int GetResourceType(int id)
+    {
+        return PlayerFacePicConfig.Get(id).ResourceType;
+    }
+    public string GetResourceValue(int id)
+    {
+        return PlayerFacePicConfig.Get(id).ResourceValue;
+    }
+
+    public string GetName(int id)
+    {
+        return PlayerFacePicConfig.Get(id).Name;
+    }
+    public int GetExpireMinutes(int id)
+    {
+        return PlayerFacePicConfig.Get(id).ExpireMinutes;
+    }
+    public int GetUnlockWay(int id)
+    {
+        return PlayerFacePicConfig.Get(id).UnlockWay;
+    }
+    public int GetUnlockValue(int id)
+    {
+        return PlayerFacePicConfig.Get(id).UnlockValue;
+    }
+    public int GetUnlockNeedCnt(int id)
+    {
+        return PlayerFacePicConfig.Get(id).UnlockNeedCnt;
+    }
+    public int GetUpNeedCnt(int id)
+    {
+        return PlayerFacePicConfig.Get(id).UpNeedCnt;
+    }
+    public int GetStarMax(int id)
+    {
+        return PlayerFacePicConfig.Get(id).StarMax;
+    }
+    public int[] GetAttrIDList(int id)
+    {
+        return PlayerFacePicConfig.Get(id).AttrIDList;
+    }
+    public int[] GetInitAttrValueList(int id)
+    {
+        return PlayerFacePicConfig.Get(id).InitAttrValueList;
+    }
+    public int[] GetAttrPerStarAddList(int id)
+    {
+        return PlayerFacePicConfig.Get(id).AttrPerStarAddList;
+    }
+    public string GetGetWayString(int id)
+    {
+        return PlayerFacePicConfig.Get(id).GetWayString;
+    }
+}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionAvatarFrameHandler.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs.meta
similarity index 100%
rename from Main/System/PhantasmPavilion/PhantasmPavilionAvatarFrameHandler.cs.meta
rename to Main/System/PhantasmPavilion/PhantasmPavilionFacePicHandler.cs.meta
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs
new file mode 100644
index 0000000..35d8119
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs
@@ -0,0 +1,45 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionFacePicItem : MonoBehaviour
+{
+    [SerializeField] ImageEx imgFace;
+    [SerializeField] UIFrame uiFrame;
+    [SerializeField] UIEffectPlayer spine;
+    [SerializeField] Button btnChoose;
+
+    [SerializeField] ImageEx imgLimit;
+    [SerializeField] ImageEx imgLock;
+    [SerializeField] ImageEx imgChoose;
+    [SerializeField] ImageEx imgCanUnlock;
+    [SerializeField] TextEx txtUsing;
+    [SerializeField] Image imgRed;
+
+    readonly PhantasmPavilionType type = PhantasmPavilionType.FacePic;
+    int id;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        this.id = id;
+        btnChoose.SetListener(() =>
+        {
+            manager.selectId = id;
+        });
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isLimitedTime = manager.IsLimitTime(type, id);
+        bool isUsing = manager.IsUsing(type, id);
+        imgChoose.SetActive(manager.selectId == id);
+        imgLimit.SetActive(state == PhantasmPavilionState.Activated && isLimitedTime);
+        imgLock.SetActive(state != PhantasmPavilionState.Activated);
+        imgCanUnlock.SetActive(state == PhantasmPavilionState.CanActivate);
+        txtUsing.SetActive(state == PhantasmPavilionState.Activated && isUsing);
+
+        int resourceType = manager.GetResourceType(type, id);
+        string resourceValue = manager.GetResourceValue(type, id);
+        manager.Show(imgFace, spine, uiFrame, resourceType, resourceValue);
+
+        manager.UpdateItemRedPoint(imgRed, type, id);
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs.meta
index c7311ca..badcfb8 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFacePicItem.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 4a3d2c189d477724b8b31431f12ffae3
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs b/Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs
new file mode 100644
index 0000000..eed4233
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs
@@ -0,0 +1,448 @@
+锘縰sing System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionFaceWin : UIBase
+{
+    [SerializeField] ButtonEx btnAllAdd;
+    [Header("浜岀骇鏍囩椤�")]
+    [SerializeField] GroupButtonEx btnFace;
+    [SerializeField] GroupButtonEx btnFacePic;
+    [SerializeField] GroupButtonEx btnChatBox;
+
+    [Header("閫変腑椤瑰睍绀�")]
+    [SerializeField] Transform transNowFace;
+    [SerializeField] Transform transNowFacePic;
+    [SerializeField] Transform transNowChatBox;
+    // 褰撳墠澶村儚
+    [SerializeField] EllipseMask maskNowFace;
+    [SerializeField] ImageEx imgNowFaceBg;
+    [SerializeField] ImageEx imgNowFace;
+    [SerializeField] UIFrame uiFrameNowFace;
+    [SerializeField] UIEffectPlayer effectPlayerNowFace;
+    // 褰撳墠澶村儚妗�
+
+    [SerializeField] ImageEx imgNowFacePicFaceBg;
+    [SerializeField] EllipseMask maskNowFacePicFace;
+    [SerializeField] ImageEx imgNowFacePicFace;
+    [SerializeField] UIFrame uiFrameNowFacePicFace;
+    [SerializeField] UIEffectPlayer UIEffectPlayerNowFacePicFace;
+
+    [SerializeField] ImageEx imgNowFacePic;
+    [SerializeField] UIFrame uiFrameNowFacePic;
+    [SerializeField] UIEffectPlayer UIEffectPlayerNowFacePic;
+
+    //褰撳墠姘旀场
+    [SerializeField] ImageEx imgNowChatBox;
+    [SerializeField] UIFrame uiFrameNowChatBox;
+    [SerializeField] UIEffectPlayer UIEffectPlayerNowChatBox;
+
+
+    [Header("灞炴�у睍绀�")]
+    [SerializeField] TextEx txtName;
+    [SerializeField] TextEx txtGetWayString;
+    [SerializeField] TextEx txtAddInfo;
+    [SerializeField] TextEx txtUnLockInfo;
+    [SerializeField] TextEx txtNoInfo;
+    [SerializeField] ScrollerController scrInfo;
+
+    [Header("婊氬姩鍒楄〃")]
+    [SerializeField] ScrollerController scrFace;
+    [SerializeField] ScrollerController scrFacePic;
+    [SerializeField] ScrollerController scrChatBox;
+
+    [Header("鎸夐挳")]
+    [SerializeField] PhantasmPavilionUnlockButton btnUnlock;
+    [SerializeField] PhantasmPavilionPutOnButton btnPutOn1;
+    [SerializeField] PhantasmPavilionPutOnButton btnPutOn2;
+    [SerializeField] PhantasmPavilionAddStarButton btnAddStar;
+
+    [SerializeField] TextEx txtRemainingTime1;
+    [SerializeField] TextEx txtRemainingTime2;
+
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnFace.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.Face); });
+        btnFacePic.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.FacePic); });
+        btnChatBox.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.ChatBox); });
+        btnAllAdd.AddListener(() => { AttributeManager.Instance.OpenTotalAttributeWin(manager.GetTotalAttr()); });
+    }
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        scrInfo.OnRefreshCell += OnRefreshInfoCell;
+        scrFace.OnRefreshCell += OnRefreshFaceCell;
+        scrFacePic.OnRefreshCell += OnRefreshFacePicCell;
+        scrChatBox.OnRefreshCell += OnRefreshChatBoxCell;
+        manager.OnSelectItemIdChange += OnSelectItemIdChange;
+        PackManager.Instance.RefreshItemEvent += OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;
+        manager.OnUpdateChatBoxInfoEvent += OnUpdateChatBoxInfoEvent;
+        manager.OnUpdateFaceInfoEvent += OnUpdateFaceInfoEvent;
+        manager.OnUpdateFacePicInfo += OnUpdateFacePicInfo;
+        manager.OnTimeOut += OnTimeOut;
+        InitRedPoint();
+        SelectTiltleBtn();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        scrInfo.OnRefreshCell -= OnRefreshInfoCell;
+        scrFace.OnRefreshCell -= OnRefreshFaceCell;
+        scrFacePic.OnRefreshCell -= OnRefreshFacePicCell;
+        scrChatBox.OnRefreshCell -= OnRefreshChatBoxCell;
+        manager.OnSelectItemIdChange -= OnSelectItemIdChange;
+        PackManager.Instance.RefreshItemEvent -= OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;
+        manager.OnUpdateChatBoxInfoEvent -= OnUpdateChatBoxInfoEvent;
+        manager.OnUpdateFaceInfoEvent -= OnUpdateFaceInfoEvent;
+        manager.OnUpdateFacePicInfo -= OnUpdateFacePicInfo;
+        manager.OnTimeOut -= OnTimeOut;
+    }
+
+    private void OnTimeOut()
+    {
+        RefreshAll(manager.nowType);
+    }
+
+    private void OnUpdateFacePicInfo()
+    {
+        RefreshAll(manager.nowType);
+    }
+    private void OnUpdateFaceInfoEvent()
+    {
+        RefreshAll(manager.nowType);
+    }
+
+    private void OnUpdateChatBoxInfoEvent()
+    {
+        RefreshAll(manager.nowType);
+    }
+
+    void InitRedPoint()
+    {
+        btnFace.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.FaceAvatar);
+        btnFacePic.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.FaceFrame);
+        btnChatBox.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.FaceBubble);
+    }
+
+    void SelectTiltleBtn()
+    {
+        if (functionOrder == 0)
+        {
+            btnFace.SelectBtn();
+            SelectTeamFunc(PhantasmPavilionType.Face);
+        }
+        else if (functionOrder == 1)
+        {
+            btnFacePic.SelectBtn();
+            SelectTeamFunc(PhantasmPavilionType.FacePic);
+        }
+        else if (functionOrder == 2)
+        {
+            btnChatBox.SelectBtn();
+            SelectTeamFunc(PhantasmPavilionType.ChatBox);
+        }
+    }
+
+    void SelectTeamFunc(PhantasmPavilionType type)
+    {
+        manager.SetSelectItemId(type);
+        manager.nowType = type;
+        CreateAll(type);
+    }
+
+    private void OnPlayerDataRefreshEvent(PlayerDataType type)
+    {
+        switch (type)
+        {
+            case PlayerDataType.Face:
+            case PlayerDataType.FacePic:
+            case PlayerDataType.ExAttr10:
+                RefreshAll(manager.nowType, false);
+                break;
+        }
+    }
+
+    private void OnSecondEvent()
+    {
+        bool isLimitedTime = manager.IsLimitTime(manager.nowType, manager.selectId);
+        if (isLimitedTime)
+        {
+            UpdateTimer(manager.nowType, manager.selectId);
+        }
+    }
+
+    private void OnRefreshItemEvent(PackType type, int arg2, int arg3)
+    {
+        if (type != PackType.Item)
+            return;
+        DisplayButton(manager.nowType, manager.selectId);
+    }
+
+    private void OnSelectItemIdChange(int id)
+    {
+        RefreshAll(manager.nowType, false);
+    }
+
+    private void RefreshAll(PhantasmPavilionType type, bool isJump = true)
+    {
+        switch (type)
+        {
+            case PhantasmPavilionType.Face:
+                scrFace.m_Scorller.RefreshActiveCellViews();
+                if (isJump)
+                {
+                    scrFace.JumpIndex(manager.GetJumpIndex(type));
+                }
+                break;
+            case PhantasmPavilionType.FacePic:
+                scrFacePic.m_Scorller.RefreshActiveCellViews();
+                if (isJump)
+                {
+                    scrFacePic.JumpIndex(manager.GetJumpIndex(type));
+                }
+                break;
+            case PhantasmPavilionType.ChatBox:
+                scrChatBox.m_Scorller.RefreshActiveCellViews();
+                if (isJump)
+                {
+                    scrChatBox.JumpIndex(manager.GetJumpIndex(type));
+                }
+                break;
+        }
+        CreateInfoScroller();
+        DisplayButton(type, manager.selectId);
+        DisplayInfo(type, manager.selectId);
+    }
+
+    void CreateAll(PhantasmPavilionType type)
+    {
+        transNowFace.SetActive(type == PhantasmPavilionType.Face);
+        transNowFacePic.SetActive(type == PhantasmPavilionType.FacePic);
+        transNowChatBox.SetActive(type == PhantasmPavilionType.ChatBox);
+
+        scrFace.SetActive(type == PhantasmPavilionType.Face);
+        scrFacePic.SetActive(type == PhantasmPavilionType.FacePic);
+        scrChatBox.SetActive(type == PhantasmPavilionType.ChatBox);
+        switch (type)
+        {
+            case PhantasmPavilionType.Face:
+                CreateFaceScroller();
+                break;
+            case PhantasmPavilionType.FacePic:
+                CreateFacePicScroller();
+                break;
+            case PhantasmPavilionType.ChatBox:
+                CreateChatBoxScroller();
+                break;
+        }
+        CreateInfoScroller();
+        DisplayButton(manager.nowType, manager.selectId);
+        DisplayInfo(manager.nowType, manager.selectId);
+    }
+    private void OnRefreshInfoCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionInfoCell>();
+        _cell?.Display(cell.index, cell);
+    }
+
+    private void OnRefreshFaceCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionFaceCell>();
+        _cell?.Display(cell.index);
+    }
+
+    private void OnRefreshFacePicCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionFacePicCell>();
+        _cell?.Display(cell.index);
+    }
+
+    private void OnRefreshChatBoxCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionChatBoxCell>();
+        _cell?.Display(cell.index);
+    }
+
+    public void DisplayInfo(PhantasmPavilionType type, int id)
+    {
+        int resourceType = manager.GetResourceType(type, id);
+        string resourceValue = manager.GetResourceValue(type, id);
+        string str = AvatarHelper.GetAvatarBgColorStr(id);
+        switch (type)
+        {
+            case PhantasmPavilionType.Face:
+                manager.ShowFace(imgNowFace, effectPlayerNowFace, uiFrameNowFace, maskNowFace, id);
+                imgNowFaceBg.SetSprite(str);
+                if (resourceType == 1)
+                {
+                    imgNowFace.SetNativeSize();
+                }
+                break;
+            case PhantasmPavilionType.FacePic:
+                if (!manager.TryGetNowShowID(PhantasmPavilionType.Face, out int faceID))
+                    return;
+                manager.ShowFace(imgNowFacePicFace, UIEffectPlayerNowFacePicFace, uiFrameNowFacePicFace, maskNowFacePicFace, faceID);
+                str = AvatarHelper.GetAvatarBgColorStr(faceID);
+                imgNowFacePicFaceBg.SetSprite(str);
+                manager.Show(imgNowFacePic, UIEffectPlayerNowFacePic, uiFrameNowFacePic, resourceType, resourceValue);
+                if (resourceType == 1)
+                {
+                    imgNowFacePicFace.SetNativeSize();
+                    imgNowFacePic.SetNativeSize();
+                }
+
+                break;
+            case PhantasmPavilionType.ChatBox:
+                manager.Show(imgNowChatBox, UIEffectPlayerNowChatBox, uiFrameNowChatBox, resourceType, resourceValue);
+                if (resourceType == 1)
+                {
+                    imgNowChatBox.SetNativeSize();
+                }
+                break;
+        }
+
+        txtName.text = manager.GetName(type, id);
+        txtGetWayString.text = Language.Get("PhantasmPavilion06", manager.GetGetWayString(type, id));
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isHasAttr = manager.HasInitAttr(type, id);        // 鏄惁鏈夎В閿佸睘鎬�
+        txtAddInfo.SetActive(state == PhantasmPavilionState.Activated);
+        txtUnLockInfo.SetActive(state != PhantasmPavilionState.Activated);
+        txtNoInfo.SetActive(!isHasAttr);
+        CreateInfoScroller();
+    }
+
+    public void DisplayButton(PhantasmPavilionType type, int id)
+    {
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+
+        btnUnlock.SetActive(state != PhantasmPavilionState.Activated);
+        btnAddStar.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd);
+        btnPutOn1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd);
+        btnPutOn2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd);
+
+        btnUnlock.Display(id);
+        btnAddStar.Display(id);
+        btnPutOn1.Display(id);
+        btnPutOn2.Display(id);
+
+
+        UpdateTimer(type, id);
+    }
+
+    private void CreateInfoScroller()
+    {
+        PhantasmPavilionType type = manager.nowType;
+        int id = manager.selectId;
+        if (!manager.Has(type, id))
+            return;
+        scrInfo.Refresh();
+        int[] attrIDList = manager.GetAttrIDList(type, id);
+        int[] initAttrValueList = manager.GetInitAttrValueList(type, id);
+        if (!attrIDList.IsNullOrEmpty() && !initAttrValueList.IsNullOrEmpty() && attrIDList.Length == initAttrValueList.Length)
+        {
+            for (int i = 0; i < attrIDList.Length; i++)
+            {
+                CellInfo cellInfo = new CellInfo();
+                cellInfo.infoInt1 = id;
+                scrInfo.AddCell(ScrollerDataType.Header, i, cellInfo);
+            }
+        }
+        scrInfo.Restart();
+    }
+
+    private void CreateFaceScroller()
+    {
+        PhantasmPavilionType type = PhantasmPavilionType.Face;
+        scrFace.Refresh();
+        List<int> showItemList = manager.ShowItemList(type);
+        if (!showItemList.IsNullOrEmpty() && manager.TryGetRowCountMax(type, out int rowCountMax))
+        {
+            int rowCount = (int)Math.Ceiling((double)showItemList.Count / rowCountMax);
+            for (int i = 0; i < rowCount; i++)
+            {
+                scrFace.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+        scrFace.Restart();
+
+        int jumpIndex = manager.GetJumpIndex(type);
+        scrFace.JumpIndex(jumpIndex);
+    }
+
+    private void CreateFacePicScroller()
+    {
+        PhantasmPavilionType type = PhantasmPavilionType.FacePic;
+        scrFacePic.Refresh();
+        List<int> showItemList = manager.ShowItemList(type);
+        if (!showItemList.IsNullOrEmpty() && manager.TryGetRowCountMax(type, out int rowCountMax))
+        {
+            int rowCount = (int)Math.Ceiling((double)showItemList.Count / rowCountMax);
+            for (int i = 0; i < rowCount; i++)
+            {
+                scrFacePic.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+        scrFacePic.Restart();
+
+        int jumpIndex = manager.GetJumpIndex(type);
+        scrFacePic.JumpIndex(jumpIndex);
+    }
+
+    private void CreateChatBoxScroller()
+    {
+        PhantasmPavilionType type = PhantasmPavilionType.ChatBox;
+        scrChatBox.Refresh();
+        List<int> showItemList = manager.ShowItemList(type);
+        if (!showItemList.IsNullOrEmpty() && manager.TryGetRowCountMax(type, out int rowCountMax))
+        {
+            int rowCount = (int)Math.Ceiling((double)showItemList.Count / rowCountMax);
+            for (int i = 0; i < rowCount; i++)
+            {
+                scrChatBox.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+        scrChatBox.Restart();
+
+        int jumpIndex = manager.GetJumpIndex(type);
+        scrChatBox.JumpIndex(jumpIndex);
+    }
+
+    public void UpdateTimer(PhantasmPavilionType type, int id)
+    {
+        bool isUnlock = manager.IsUnlock(type, id);
+        bool isLimitTime = manager.IsLimitTime(type, id);
+        if (!isUnlock || !isLimitTime || !manager.TryGetInfo(type, id, out var info) || info.EndTime <= 0)
+        {
+            txtRemainingTime1.SetActive(false);
+            txtRemainingTime2.SetActive(false);
+            return;
+        }
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+
+        DateTime endDateTime = TimeUtility.OriginalTime.AddSeconds(info.EndTime);
+        TimeSpan remainingTime = endDateTime - TimeUtility.ServerNow;
+        int remainingSeconds = (int)remainingTime.TotalSeconds;
+        txtRemainingTime1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd && remainingSeconds > 0);
+        txtRemainingTime2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd && remainingSeconds > 0);
+        if (remainingSeconds > 0)
+        {
+            string countdownText = TimeUtility.SecondsToShortDHMS(remainingSeconds);
+            txtRemainingTime1.text = Language.Get("PhantasmPavilion10", UIHelper.AppendColor(TextColType.LightGreen, countdownText));
+            txtRemainingTime2.text = Language.Get("PhantasmPavilion10", UIHelper.AppendColor(TextColType.LightGreen, countdownText));
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs.meta
index c7311ca..d708043 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionFaceWin.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 822ea055abfe5aa4c801bf8dd200cb8e
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs
new file mode 100644
index 0000000..a4dcb59
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs
@@ -0,0 +1,54 @@
+锘縰sing UnityEngine;
+
+public class PhantasmPavilionInfoCell : MonoBehaviour
+{
+    [SerializeField] TextEx txtUnLockInfo;
+    [SerializeField] TextEx txtAddInfo;
+    [SerializeField] TextEx txtAddNext;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int index, CellView cellView)
+    {
+        int id = cellView.info.Value.infoInt1;
+        PhantasmPavilionType type = manager.nowType;
+        int[] attrIDList = manager.GetAttrIDList(type, id);
+        int[] initAttrValueList = manager.GetInitAttrValueList(type, id);
+        if (attrIDList.IsNullOrEmpty() || initAttrValueList.IsNullOrEmpty()
+        || attrIDList.Length != initAttrValueList.Length || attrIDList.Length <= index)
+        {
+            txtUnLockInfo.SetActive(false);
+            txtAddInfo.SetActive(false);
+            txtAddNext.SetActive(false);
+            return;
+        }
+
+        int attrID = attrIDList[index];
+        int attrValue = initAttrValueList[index];
+        bool isHasAttr = manager.HasInitAttr(type, id);        // 鏄惁鏈夎В閿佸睘鎬�
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id); // 鏄惁鍙崌鏄�
+        bool isStarMax = manager.IsStarMax(type, id);       // 鏄惁宸插崌婊�
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        txtUnLockInfo.SetActive(state != PhantasmPavilionState.Activated || (state == PhantasmPavilionState.Activated && isHasAttr && !isCanStarAdd));
+        txtAddInfo.SetActive(state == PhantasmPavilionState.Activated && isHasAttr && isCanStarAdd);
+        txtAddNext.SetActive(state == PhantasmPavilionState.Activated && isHasAttr && isCanStarAdd && !isStarMax);
+        if (isHasAttr)
+        {
+            txtUnLockInfo.text = PlayerPropertyConfig.GetFullDescription(attrID, attrValue);
+        }
+
+        if (isCanStarAdd)
+        {
+            int addValue = manager.GetEndAttrValue(type, id, index);
+            txtAddInfo.text = PlayerPropertyConfig.GetFullDescription(attrID, addValue);
+        }
+
+        if (isCanStarAdd && !isStarMax)
+        {
+            int[] attrPerStarAddList = manager.GetAttrPerStarAddList(type, id);
+            if (attrPerStarAddList.IsNullOrEmpty() || attrIDList.Length != initAttrValueList.Length || attrPerStarAddList.Length <= index)
+                return;
+            int attrPerStarAdd = attrPerStarAddList[index];
+            txtAddNext.text = Language.Get("PhantasmPavilion12", UIHelper.AppendColor(TextColType.LightGreen, StringUtility.Contact("+", PlayerPropertyConfig.GetValueDescription(attrID, attrPerStarAdd))));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs.meta
index c7311ca..42e7962 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionInfoCell.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 9c67fd8c3ac120b4f9d5b9532aee635c
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs
new file mode 100644
index 0000000..30e7d8b
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+// 灞炴�ц绠楃浉鍏�
+public partial class PhantasmPavilionManager : GameSystemManager<PhantasmPavilionManager>
+{
+    public Dictionary<int, long> attrDic = new Dictionary<int, long>();
+
+    public Dictionary<int, long> GetTotalAttr()
+    {
+        return attrDic;
+    }
+
+    public long GetAttrValue(int attrID)
+    {
+        attrDic.TryGetValue(attrID, out long value);
+        return value;
+    }
+
+    public int GetAttrPer(int attrID)
+    {
+        if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrID))
+        {
+            var pertype = PlayerPropertyConfig.baseAttr2perDict[attrID];
+            attrDic.TryGetValue(pertype, out long value);
+            return (int)(value);
+        }
+
+        return 0;
+    }
+
+    public void RefreshAttr()
+    {
+        attrDic.Clear();
+
+        foreach (string name in Enum.GetNames(typeof(PhantasmPavilionType)))
+        {
+            PhantasmPavilionType type = (PhantasmPavilionType)Enum.Parse(typeof(PhantasmPavilionType), name);
+            if (!TryGetHandlerValue(type, out var handler))
+                continue;
+            var list = handler.GetKeyList();
+            if (list.IsNullOrEmpty())
+                continue;
+            foreach (var id in list)
+            {
+                bool hasInitAttr = HasInitAttr(type, id);
+                bool hasStarAddAttr = HasStarAddAttr(type, id);
+                // 鏈夊垵濮嬪睘鎬�
+                if (hasInitAttr && !hasStarAddAttr)
+                {
+                    int[] attrIDList = GetAttrIDList(type, id);
+                    // 涓嶆敮鎸佸崌鏄�
+                    if (!hasStarAddAttr)
+                    {
+                        int[] initAttrValueList = GetInitAttrValueList(type, id);
+                        for (int i = 0; i < attrIDList.Length; i++)
+                        {
+                            if (!attrDic.ContainsKey(attrIDList[i]))
+                            {
+                                attrDic[attrIDList[i]] = 0;
+                            }
+                            // 瑙i攣鐨勬墠绱姞璁$畻灞炴��
+                            bool isUnlock = IsUnlock(type, id);
+                            if (!isUnlock)
+                                continue;
+                            attrDic[attrIDList[i]] += initAttrValueList[i];
+                        }
+                    }
+                    // 鏀寔鍗囨槦
+                    else
+                    {
+
+                        for (int i = 0; i < attrIDList.Length; i++)
+                        {
+                            if (!attrDic.ContainsKey(attrIDList[i]))
+                            {
+                                attrDic[attrIDList[i]] = 0;
+                            }
+
+                            // 瑙i攣鐨勬墠绱姞璁$畻灞炴��
+                            bool isUnlock = IsUnlock(type, id);
+                            if (!isUnlock)
+                                continue;
+                                
+                            int addValue = GetEndAttrValue(type, id, i);
+                            attrDic[attrIDList[i]] += addValue;
+                        }
+                    }
+
+                }
+            }
+        }
+    }
+
+    //鏈�缁堝睘鎬� =  鍒濆灞炴�� + 鏄熺骇*鍗囨槦鍔犳垚鍊�
+    public int GetEndAttrValue(PhantasmPavilionType type, int id, int AttrIndex)
+    {
+        bool isCanStarAdd = HasStarAddAttr(type, id); // 鏄惁鍙崌鏄�
+        if (!isCanStarAdd || !TryGetInfo(type, id, out PhantasmPavilionData info))
+            return 0;
+        int[] attrIDList = GetAttrIDList(type, id);
+        int[] initAttrValueList = GetInitAttrValueList(type, id);
+        int[] attrPerStarAddList = GetAttrPerStarAddList(type, id);
+        if (attrIDList.IsNullOrEmpty() || initAttrValueList.IsNullOrEmpty() || attrPerStarAddList.IsNullOrEmpty() ||
+        attrIDList.Length != initAttrValueList.Length || attrIDList.Length != attrPerStarAddList.Length ||
+        attrIDList.Length <= AttrIndex)
+            return 0;
+        int initAttrValue = initAttrValueList[AttrIndex];
+        int attrPerStarAdd = attrPerStarAddList[AttrIndex];
+        return initAttrValue + info.Star * attrPerStarAdd;
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs.meta
index c7311ca..0044272 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Attr.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: e244948b4dd758f44803a70bf221746c
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs b/Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs
new file mode 100644
index 0000000..a307ff0
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+// 榛樿ID鐩稿叧
+public partial class PhantasmPavilionManager : GameSystemManager<PhantasmPavilionManager>
+{
+    //<绫诲瀷,<job,id>>
+    public Dictionary<PhantasmPavilionType, Dictionary<int, int>> defaultIDDict = new Dictionary<PhantasmPavilionType, Dictionary<int, int>>();
+    //<绫诲瀷,id>
+    public Dictionary<PhantasmPavilionType, int> nowIDDict = new Dictionary<PhantasmPavilionType, int>();
+    void InitTable()
+    {
+        var tabValues = Enum.GetValues(typeof(PhantasmPavilionType));
+        for (int i = 0; i < tabValues.Length; i++)
+        {
+            PhantasmPavilionType tab = (PhantasmPavilionType)tabValues.GetValue(i);
+            if (!defaultIDDict.ContainsKey(tab))
+            {
+                defaultIDDict[tab] = new Dictionary<int, int>();
+            }
+        }
+        var config = FuncConfigConfig.Get("PhantasmPavilion");
+        defaultIDDict[PhantasmPavilionType.Face] = ConfigParse.ParseIntDict(config.Numerical1);
+        defaultIDDict[PhantasmPavilionType.FacePic] = ConfigParse.ParseIntDict(config.Numerical2);
+        defaultIDDict[PhantasmPavilionType.ChatBox] = ConfigParse.ParseIntDict(config.Numerical3);
+        defaultIDDict[PhantasmPavilionType.Model] = ConfigParse.ParseIntDict(config.Numerical4);
+        //PhantasmPavilionType.Title 鏀寔鍗镐笅,涓嶉渶瑕佷繚搴曠殑榛樿鍊�
+    }
+
+    void InitNowIDDict()
+    {
+        nowIDDict[PhantasmPavilionType.Face] = PlayerDatas.Instance.baseData.face;
+        nowIDDict[PhantasmPavilionType.FacePic] = PlayerDatas.Instance.baseData.facePic;
+        nowIDDict[PhantasmPavilionType.ChatBox] = (int)PlayerDatas.Instance.baseData.chatBox;
+        nowIDDict[PhantasmPavilionType.Model] = PlayerDatas.Instance.baseData.modelMark;
+        nowIDDict[PhantasmPavilionType.Title] = PlayerDatas.Instance.baseData.TitleID;
+    }
+
+    void UpdateNowIDDict(PlayerDataType type)
+    {
+        bool isUpdate = true;
+        PhantasmPavilionType phantasmPavilionType = PhantasmPavilionType.Face;
+        switch (type)
+        {
+            case PlayerDataType.Face:
+                phantasmPavilionType = PhantasmPavilionType.Face;
+                nowIDDict[phantasmPavilionType] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.Face);
+                break;
+            case PlayerDataType.FacePic:
+                phantasmPavilionType = PhantasmPavilionType.FacePic;
+                nowIDDict[phantasmPavilionType] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.FacePic);
+                break;
+            case PlayerDataType.ExAttr10:
+                phantasmPavilionType = PhantasmPavilionType.ChatBox;
+                nowIDDict[phantasmPavilionType] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr10);
+                break;
+            case PlayerDataType.ModelMark:
+                phantasmPavilionType = PhantasmPavilionType.Model;
+                nowIDDict[phantasmPavilionType] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ModelMark);
+                break;
+            case PlayerDataType.ExAttr3:
+                phantasmPavilionType = PhantasmPavilionType.Title;
+                nowIDDict[phantasmPavilionType] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr3);
+                break;
+            default:
+                isUpdate = false;
+                break;
+        }
+
+        if (isUpdate)
+        {
+            if (nowType == phantasmPavilionType)
+            {
+                if (TryGetNowShowID(phantasmPavilionType, out int showID))
+                {
+                    selectId = showID;
+                }
+
+            }
+            UpdateRedPoint();
+        }
+    }
+
+    //鑾峰彇涓嶅悓鑱屼笟瀵瑰簲鐨処D榛樿鍊�
+    public bool TryGetDefaultID(PhantasmPavilionType type, int job, out int defaultID)
+    {
+        defaultID = 0;
+        if (defaultIDDict == null || !defaultIDDict.TryGetValue(type, out var dict) || dict == null)
+            return false;
+        return dict.TryGetValue(job, out defaultID) || dict.TryGetValue(0, out defaultID);
+    }
+
+    // 鑾峰彇褰撳墠搴旇鏄剧ず鐨処D
+    public bool TryGetNowShowID(PhantasmPavilionType type, out int showID)
+    {
+        showID = 0;
+        int job = PlayerDatas.Instance.baseData.Job;
+
+        if (type != PhantasmPavilionType.Title)
+        {
+            if (!TryGetDefaultID(type, job, out int defaultID))
+                return false;
+
+            // 灏濊瘯鑾峰彇鐜╁褰撳墠浣╂埓鐨処D
+            bool hasEquippedID = nowIDDict.TryGetValue(type, out int equippedID);
+            // 妫�鏌ュ綋鍓嶄僵鎴寸殑ID鏄惁鏈夋晥
+            bool isEquippedIDValid = hasEquippedID && IsUnlock(type, equippedID);
+            // 濡傛灉浣╂埓鐨処D鏈夋晥锛屽垯浣跨敤瀹冿紱鍚﹀垯锛屽洖閫�鍒颁箣鍓嶈幏鍙栫殑榛樿ID
+            showID = isEquippedIDValid ? equippedID : defaultID;
+            return true;
+        }
+        else
+        {
+            // 灏濊瘯鑾峰彇鐜╁褰撳墠浣╂埓鐨処D
+            bool hasEquippedID = nowIDDict.TryGetValue(type, out int equippedID);
+            // 妫�鏌ュ綋鍓嶄僵鎴寸殑ID鏄惁鏈夋晥
+            bool isEquippedIDValid = hasEquippedID && IsUnlock(type, equippedID);
+            // 濡傛灉浣╂埓鐨処D鏈夋晥锛屽垯浣跨敤瀹冿紱鍚﹀垯锛岃繑鍥�0
+            showID = isEquippedIDValid ? equippedID : 0;
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs.meta
similarity index 83%
rename from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
rename to Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs.meta
index c7311ca..52d8413 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 21fc13d90db03874e9b475fa46e4aefc
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs b/Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs
new file mode 100644
index 0000000..2a2d361
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs
@@ -0,0 +1,131 @@
+using System.Collections.Generic;
+
+// 閫氱敤鐨勮config鏂规硶
+public partial class PhantasmPavilionManager : GameSystemManager<PhantasmPavilionManager>
+{
+    public bool Has(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return false;
+        return handler.HasTableKey(id);
+    }
+    public List<int> GetTableKeys(PhantasmPavilionType type)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return new List<int>();
+        return handler.GetKeyList();
+    }
+    public string GetName(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return string.Empty;
+        if (!Has(type, id))
+            return string.Empty;
+        return handler.GetName(id);
+    }
+    public int GetExpireMinutes(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetExpireMinutes(id);
+    }
+
+    public int GetUnlockWay(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetUnlockWay(id);
+    }
+
+    public int GetUnlockValue(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetUnlockValue(id);
+    }
+
+    public int GetUnlockNeedCnt(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetUnlockNeedCnt(id);
+    }
+
+    public int GetUpNeedCnt(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetUpNeedCnt(id);
+    }
+    public int GetStarMax(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetStarMax(id);
+    }
+
+    public int[] GetAttrIDList(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return null;
+        if (!Has(type, id))
+            return null;
+        return handler.GetAttrIDList(id);
+    }
+    public int[] GetInitAttrValueList(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return null;
+        if (!Has(type, id))
+            return null;
+        return handler.GetInitAttrValueList(id);
+    }
+
+    public int[] GetAttrPerStarAddList(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return null;
+        if (!Has(type, id))
+            return null;
+        return handler.GetAttrPerStarAddList(id);
+    }
+
+    public int GetResourceType(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return 0;
+        if (!Has(type, id))
+            return 0;
+        return handler.GetResourceType(id);
+    }
+
+    public string GetResourceValue(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return string.Empty;
+        if (!Has(type, id))
+            return string.Empty;
+        return handler.GetResourceValue(id);
+    }
+
+    public string GetGetWayString(PhantasmPavilionType type, int id)
+    {
+        if (!TryGetHandlerValue(type, out var handler))
+            return string.Empty;
+        if (!Has(type, id))
+            return string.Empty;
+        return handler.GetGetWayString(id);
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs.meta
index c7311ca..4d986f7 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.LoadConfig.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 37106de00e81c334c85b15934744d20b
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs b/Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs
new file mode 100644
index 0000000..9a25373
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+public partial class PhantasmPavilionManager : GameSystemManager<PhantasmPavilionManager>
+{
+    readonly public Dictionary<PhantasmPavilionType, IPhantasmPavilionHandler> handlers = new Dictionary<PhantasmPavilionType, IPhantasmPavilionHandler>()
+    {
+        { PhantasmPavilionType.Face, new PhantasmPavilionFaceHandler() },
+        { PhantasmPavilionType.FacePic, new PhantasmPavilionFacePicHandler() },
+        { PhantasmPavilionType.ChatBox, new PhantasmPavilionChatBoxHandler() },
+        { PhantasmPavilionType.Title, new PhantasmPavilionTitleHandler() },
+        { PhantasmPavilionType.Model, new PhantasmPavilionModelHandler() },
+    };
+    public bool TryGetHandlerValue(PhantasmPavilionType type, out IPhantasmPavilionHandler handler)
+    {
+        return handlers.TryGetValue(type, out handler);
+    }
+
+    // 涓�琛屽睍绀簒涓墿鍝�
+    public readonly Dictionary<PhantasmPavilionType, int> rowCountMaxDict = new Dictionary<PhantasmPavilionType, int>()
+    {
+     {PhantasmPavilionType.Face, 4},
+     {PhantasmPavilionType.FacePic, 4},
+     {PhantasmPavilionType.ChatBox, 3},
+     {PhantasmPavilionType.Title, 3},
+     {PhantasmPavilionType.Model, 5},
+    };
+
+    public bool TryGetRowCountMax(PhantasmPavilionType type, out int rowCountMax)
+    {
+        return rowCountMaxDict.TryGetValue(type, out rowCountMax);
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs.meta
index c7311ca..1c87567 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.ReadOnly.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 58fd21664f7fe9e439b4d81e1ca57218
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs
new file mode 100644
index 0000000..b0c9a8b
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs
@@ -0,0 +1,280 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine.UI;
+
+public partial class PhantasmPavilionManager : GameSystemManager<PhantasmPavilionManager>
+{
+    public Redpoint parentRedpoint = new Redpoint(MainRedDot.MainAffairsRedpoint, MainRedDot.PhantasmPavilionRepoint);
+    public Dictionary<PhantasmPavilionRepointType, Redpoint> tabRedPointDict = new Dictionary<PhantasmPavilionRepointType, Redpoint>();
+
+    private void InitTabRedPoint()
+    {
+
+
+        tabRedPointDict[PhantasmPavilionRepointType.Model] = new Redpoint(MainRedDot.PhantasmPavilionRepoint, GetRedpointId(PhantasmPavilionRepointType.Model));
+        tabRedPointDict[PhantasmPavilionRepointType.Face] = new Redpoint(MainRedDot.PhantasmPavilionRepoint, GetRedpointId(PhantasmPavilionRepointType.Face));
+        tabRedPointDict[PhantasmPavilionRepointType.Title] = new Redpoint(MainRedDot.PhantasmPavilionRepoint, GetRedpointId(PhantasmPavilionRepointType.Title));
+        tabRedPointDict[PhantasmPavilionRepointType.ModelNormal] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Model), GetRedpointId(PhantasmPavilionRepointType.ModelNormal));
+        tabRedPointDict[PhantasmPavilionRepointType.ModelEvent] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Model), GetRedpointId(PhantasmPavilionRepointType.ModelEvent));
+        tabRedPointDict[PhantasmPavilionRepointType.FaceAvatar] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Face), GetRedpointId(PhantasmPavilionRepointType.FaceAvatar));
+        tabRedPointDict[PhantasmPavilionRepointType.FaceFrame] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Face), GetRedpointId(PhantasmPavilionRepointType.FaceFrame));
+        tabRedPointDict[PhantasmPavilionRepointType.FaceBubble] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Face), GetRedpointId(PhantasmPavilionRepointType.FaceBubble));
+        tabRedPointDict[PhantasmPavilionRepointType.TitlePalace] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Title), GetRedpointId(PhantasmPavilionRepointType.TitlePalace));
+        tabRedPointDict[PhantasmPavilionRepointType.TitleEvent] = new Redpoint(GetRedpointId(PhantasmPavilionRepointType.Title), GetRedpointId(PhantasmPavilionRepointType.TitleEvent));
+    }
+    public int GetRedpointId(PhantasmPavilionRepointType type)
+    {
+        return MainRedDot.PhantasmPavilionRepoint * 100 + (int)type;
+    }
+
+    void UpdateRedPointByCanActivate(PhantasmPavilionType type, PhantasmPavilionRepointType redType, int tabType = 0)
+    {
+        List<int> list = ShowItemList(type, tabType);
+        if (list.IsNullOrEmpty() || !tabRedPointDict.ContainsKey(redType))
+            return;
+        foreach (var id in list)
+        {
+            if (!Has(type, id))
+                continue;
+            PhantasmPavilionState state = GetUnLockState(type, id);
+            if (state == PhantasmPavilionState.CanActivate)
+            {
+                tabRedPointDict[redType].state = RedPointState.Simple;
+            }
+        }
+    }
+
+    void UpdateRedPointByCanUpStar(PhantasmPavilionType type, PhantasmPavilionRepointType redType, int tabType = 0)
+    {
+        List<int> list = ShowItemList(type, tabType);
+        if (list.IsNullOrEmpty() || !tabRedPointDict.ContainsKey(redType))
+            return;
+        foreach (var id in list)
+        {
+            if (!Has(type, id))
+                continue;
+            bool isCanUpStar = CheckCanUpByItem(type, id);
+            if (isCanUpStar)
+            {
+                tabRedPointDict[redType].state = RedPointState.Simple;
+            }
+        }
+    }
+
+    void UpdateRedPointByNoSee(PhantasmPavilionType type, PhantasmPavilionRepointType redType, int tabType = 0)
+    {
+        List<int> list = ShowItemList(type, tabType);
+        if (list.IsNullOrEmpty() || !tabRedPointDict.ContainsKey(redType))
+            return;
+        foreach (var id in list)
+        {
+            if (!Has(type, id))
+                continue;
+            int unlockWay = GetUnlockWay(type, id);
+            int unlockValue = GetUnlockValue(type, id);
+            if (unlockWay != 3)
+                continue;
+            bool hasNewHero = HasNewHero(type, unlockValue);
+            if (hasNewHero)
+            {
+                tabRedPointDict[redType].state = RedPointState.Simple;
+            }
+        }
+    }
+
+    public void UpdateItemRedPoint(Image imgRed, PhantasmPavilionType type, int id)
+    {
+        imgRed.SetActive(false);
+
+        if (!Has(type, id))
+            return;
+        PhantasmPavilionState state = GetUnLockState(type, id);
+        if (state == PhantasmPavilionState.CanActivate)
+        {
+            imgRed.SetActive(true);
+        }
+
+        bool isCanUpStar = CheckCanUpByItem(type, id);
+        if (isCanUpStar)
+        {
+            imgRed.SetActive(true);
+        }
+
+        int unlockWay = GetUnlockWay(type, id);
+        if (unlockWay != 3)
+            return;
+
+        int unlockValue = GetUnlockValue(type, id);
+        bool hasNewHero = HasNewHero(type, unlockValue);
+        if (hasNewHero)
+        {
+            imgRed.SetActive(true);
+        }
+    }
+    public void UpdateRedPoint()
+    {
+        parentRedpoint.state = RedPointState.None;
+
+        if (!tabRedPointDict.IsNullOrEmpty())
+        {
+            foreach (var item in tabRedPointDict)
+            {
+                item.Value.state = RedPointState.None;
+            }
+        }
+
+        // 鏈夊彲鎵嬪姩瑙i攣鐨�
+        UpdateRedPointByCanActivate(PhantasmPavilionType.Model, PhantasmPavilionRepointType.ModelNormal, 1);
+        UpdateRedPointByCanActivate(PhantasmPavilionType.Model, PhantasmPavilionRepointType.ModelEvent, 2);
+        UpdateRedPointByCanActivate(PhantasmPavilionType.Face, PhantasmPavilionRepointType.FaceAvatar);
+        UpdateRedPointByCanActivate(PhantasmPavilionType.FacePic, PhantasmPavilionRepointType.FaceFrame);
+        UpdateRedPointByCanActivate(PhantasmPavilionType.ChatBox, PhantasmPavilionRepointType.FaceBubble);
+        UpdateRedPointByCanActivate(PhantasmPavilionType.Title, PhantasmPavilionRepointType.TitlePalace, 1);
+        UpdateRedPointByCanActivate(PhantasmPavilionType.Title, PhantasmPavilionRepointType.TitleEvent, 2);
+
+        // 鏈夊彲鍗囩骇鐨�
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.Model, PhantasmPavilionRepointType.ModelNormal, 1);
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.Model, PhantasmPavilionRepointType.ModelEvent, 2);
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.Face, PhantasmPavilionRepointType.FaceAvatar);
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.FacePic, PhantasmPavilionRepointType.FaceFrame);
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.ChatBox, PhantasmPavilionRepointType.FaceBubble);
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.Title, PhantasmPavilionRepointType.TitlePalace, 1);
+        UpdateRedPointByCanUpStar(PhantasmPavilionType.Title, PhantasmPavilionRepointType.TitleEvent, 2);
+
+        // 鑷姩瑙i攣鏈煡鐪嬬殑
+        UpdateRedPointByNoSee(PhantasmPavilionType.Model, PhantasmPavilionRepointType.ModelNormal, 1);
+        UpdateRedPointByNoSee(PhantasmPavilionType.Model, PhantasmPavilionRepointType.ModelEvent, 2);
+        UpdateRedPointByNoSee(PhantasmPavilionType.Face, PhantasmPavilionRepointType.FaceAvatar);
+        UpdateRedPointByNoSee(PhantasmPavilionType.FacePic, PhantasmPavilionRepointType.FaceFrame);
+        UpdateRedPointByNoSee(PhantasmPavilionType.ChatBox, PhantasmPavilionRepointType.FaceBubble);
+        UpdateRedPointByNoSee(PhantasmPavilionType.Title, PhantasmPavilionRepointType.TitlePalace, 1);
+        UpdateRedPointByNoSee(PhantasmPavilionType.Title, PhantasmPavilionRepointType.TitleEvent, 2);
+
+    }
+
+    public List<int> newHeroIDModelList = new List<int>();
+    public List<int> newHeroIDFaceList = new List<int>();
+    public void AddNewHero(int heroID)
+    {
+        AddNewHero(newHeroIDModelList, heroID);
+        AddNewHero(newHeroIDFaceList, heroID);
+    }
+
+    void AddNewHero(List<int> list, int heroID)
+    {
+        if (list.Contains(heroID))
+            return;
+        list.Add(heroID);
+        SaveLocal();
+        UpdateRedPoint();
+    }
+
+    public void RemoveNewHero(PhantasmPavilionType type, int id)
+    {
+        if (!Has(type, id))
+            return;
+        int unlockWay = GetUnlockWay(type, id);
+        int unlockValue = GetUnlockValue(type, id);
+        if (unlockWay != 3)
+            return;
+
+        switch (type)
+        {
+            case PhantasmPavilionType.Model:
+                RemoveNewHero(newHeroIDModelList, unlockValue);
+                break;
+            case PhantasmPavilionType.Face:
+                RemoveNewHero(newHeroIDFaceList, unlockValue);
+                break;
+        }
+    }
+
+    void RemoveNewHero(List<int> list, int heroID)
+    {
+        if (!list.Contains(heroID))
+            return;
+        list.Remove(heroID);
+        SaveLocal();
+        UpdateRedPoint();
+    }
+
+    public bool HasNewHero(PhantasmPavilionType type, int heroID)
+    {
+        switch (type)
+        {
+            case PhantasmPavilionType.Model:
+                return newHeroIDModelList.Contains(heroID);
+            case PhantasmPavilionType.Face:
+                return newHeroIDFaceList.Contains(heroID);
+            default:
+                return false;
+        }
+
+    }
+
+    string modelkey { get { return StringUtility.Contact("PhantasmPavilion_Redponit_Model_", PlayerDatas.Instance.PlayerId); } }
+    string facekey { get { return StringUtility.Contact("PhantasmPavilion_Redponit_Face_", PlayerDatas.Instance.PlayerId); } }
+    public void SaveLocal()
+    {
+        LocalSave.SetIntArray(modelkey, newHeroIDModelList.ToArray());
+        LocalSave.SetIntArray(facekey, newHeroIDFaceList.ToArray());
+    }
+    public void LoadLocal()
+    {
+        LoadLocalModel();
+        LoadLocalFace();
+    }
+
+    void LoadLocalModel()
+    {
+        if (!LocalSave.HasKey(modelkey))
+        {
+            newHeroIDModelList = new List<int>();
+            return;
+        }
+
+        int[] arr = LocalSave.GetIntArray(modelkey);
+        if (arr.IsNullOrEmpty())
+        {
+            newHeroIDModelList = new List<int>();
+            return;
+        }
+
+        newHeroIDModelList = arr.ToList();
+    }
+
+    void LoadLocalFace()
+    {
+        if (!LocalSave.HasKey(facekey))
+        {
+            newHeroIDFaceList = new List<int>();
+            return;
+        }
+
+        int[] arr = LocalSave.GetIntArray(facekey);
+        if (arr.IsNullOrEmpty())
+        {
+            newHeroIDFaceList = new List<int>();
+            return;
+        }
+
+        newHeroIDFaceList = arr.ToList();
+    }
+}
+
+public enum PhantasmPavilionRepointType
+{
+    Model = 10,
+    Face = 20,
+    Title = 30,
+
+    ModelNormal = 11,
+    ModelEvent = 12,
+
+    FaceAvatar = 21,
+    FaceFrame = 22,
+    FaceBubble = 23,
+
+    TitlePalace = 31,
+    TitleEvent = 32,
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs.meta
index c7311ca..7f100f0 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.Redpoint.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 06d4eaa4dfa565046be8aed58dfe467c
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionManager.cs b/Main/System/PhantasmPavilion/PhantasmPavilionManager.cs
new file mode 100644
index 0000000..8425e25
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.cs
@@ -0,0 +1,799 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public partial class PhantasmPavilionManager : GameSystemManager<PhantasmPavilionManager>
+{
+    public event Action<PhantasmPavilionType> OnShowItemListChange;
+    private PhantasmPavilionType m_nowType;
+    public PhantasmPavilionType nowType
+    {
+        get
+        {
+            return m_nowType;
+        }
+        set
+        {
+            if (m_nowType == value)
+                return;
+            m_nowType = value;
+            OnShowItemListChange?.Invoke(value);
+        }
+    }
+
+    public event Action<int> OnSelectItemIdChange;
+    private int m_selectId;
+    public int selectId
+    {
+        get { return m_selectId; }
+        set
+        {
+            if (m_selectId == value)
+                return;
+            m_selectId = value;
+            RemoveNewHero(nowType, value);
+            OnSelectItemIdChange?.Invoke(value);
+        }
+    }
+
+
+    //<绫诲瀷,<id,PhantasmPavilionData>>
+    public Dictionary<PhantasmPavilionType, Dictionary<int, PhantasmPavilionData>> dataDict = new Dictionary<PhantasmPavilionType, Dictionary<int, PhantasmPavilionData>>();
+    public event Action OnUpdateModelInfoEvent;
+    public event Action OnUpdateFacePicInfo;
+    public event Action OnUpdateChatBoxInfoEvent;
+    public event Action OnUpdateTitleInfoEvent;
+    public event Action OnUpdateFaceInfoEvent;
+    public event Action OnTimeOut;
+    public override void Init()
+    {
+        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitializeEvent;
+        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
+        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;
+        PackManager.Instance.RefreshItemEvent += OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        InitTable();
+        InitTabRedPoint();
+    }
+
+    public override void Release()
+    {
+        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent -= OnBeforePlayerDataInitializeEvent;
+        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
+        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;
+        PackManager.Instance.RefreshItemEvent -= OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+    }
+
+    private void OnSecondEvent()
+    {
+        CheckTimeOut();
+    }
+
+
+
+
+    private void OnRefreshItemEvent(PackType type, int arg2, int arg3)
+    {
+        if (type != PackType.Item)
+            return;
+        UpdateRedPoint();
+    }
+
+    private void OnPlayerLoginOk()
+    {
+        InitNowIDDict();
+        LoadLocal();
+        RefreshAttr();
+        UpdateRedPoint();
+    }
+
+    public void OnBeforePlayerDataInitializeEvent()
+    {
+        dataDict.Clear();
+        nowIDDict.Clear();
+    }
+    private void OnPlayerDataRefreshEvent(PlayerDataType type)
+    {
+        UpdateNowIDDict(type);
+    }
+
+    public int GetJumpIndex(PhantasmPavilionType type, int tabType = 0)
+    {
+        if (!TryGetRowCountMax(type, out int rowCountMax) || type != nowType)
+            return 0;
+        int id = selectId;
+        List<int> list = ShowItemList(type, tabType);
+        if (list.IsNullOrEmpty() || !list.Contains(id))
+            return 0;
+        int index = list.IndexOf(id);
+        int rowCount = (int)Math.Ceiling((double)index / rowCountMax);
+        return Mathf.Max(0, rowCount - 1);
+    }
+
+    public void SetSelectItemId(PhantasmPavilionType type, int tabType = 0)
+    {
+        List<int> list = new List<int>();
+        switch (type)
+        {
+            case PhantasmPavilionType.Model:
+                list = ModelConfig.GetTabTypeTitles(tabType);
+                break;
+            case PhantasmPavilionType.Title:
+                list = TitleConfig.GetTabTypeTitles(tabType);
+                break;
+            default:
+                list = GetTableKeys(type);
+                break;
+        }
+        if (list.IsNullOrEmpty() || !TryGetNowShowID(type, out int nowShowID))
+            return;
+
+        int id = nowShowID;
+        if (list.Contains(id))
+        {
+            selectId = id;
+            return;
+        }
+
+        foreach (var key in list)
+        {
+            bool isUnlock = IsUnlock(type, key);
+            if (isUnlock)
+            {
+                selectId = key;
+                return;
+            }
+        }
+
+        selectId = list[0];
+    }
+
+
+    // 妫�鏌ユ槸鍚︽弧瓒斥�滈�氳繃閬撳叿鍗囩骇鈥濈殑鏉′欢
+    public bool CheckCanUpByItem(PhantasmPavilionType type, int id)
+    {
+        bool isUnlock = IsUnlock(type, id);
+        bool isCanStarAdd = HasStarAddAttr(type, id);
+        bool isStarMax = IsStarMax(type, id);
+        int unlockWay = GetUnlockWay(type, id);
+        int unlockValue = GetUnlockValue(type, id);
+        if (!isUnlock || !isCanStarAdd || isStarMax || unlockWay != 2)
+            return false;
+        int itemId = unlockValue;
+        // 閬撳叿閰嶇疆涓嶅瓨鍦�
+        if (!ItemConfig.HasKey(itemId))
+            return false;
+
+        ItemConfig itemConfig = ItemConfig.Get(itemId);
+
+        // 鐜╁绛夌骇涓嶈冻
+        if (itemConfig.UseLV > PlayerDatas.Instance.baseData.LV)
+            return false;
+
+        // 閬撳叿鏁伴噺涓嶈冻
+        var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, itemId);
+        int upNeedCnt = GetUpNeedCnt(type, id);
+        if (hasCnt < upNeedCnt)
+            return false;
+
+        return true;
+    }
+
+
+
+    public void ShowFace(ImageEx imgFace, UIEffectPlayer spine, UIFrame uiFrame, EllipseMask ellipseMask, int id)
+    {
+        PhantasmPavilionType type = PhantasmPavilionType.Face;
+        int UnlockWay = GetUnlockWay(type, id);
+        int unlockValue = GetUnlockValue(type, id);
+        int resourceType = GetResourceType(type, id);
+        string resourceValue = GetResourceValue(type, id);
+        if (UnlockWay == 3 && resourceValue == "")
+        {
+            int heroID = unlockValue;
+            if (!HeroConfig.HasKey(heroID))
+                return;
+            HeroConfig heroConfig = HeroConfig.Get(heroID);
+            int skinID = heroConfig.SkinIDList[0];
+            if (!HeroSkinConfig.HasKey(skinID))
+                return;
+            HeroSkinConfig skinConfig = HeroSkinConfig.Get(skinID);
+            var sprite = UILoader.LoadSprite("HeroHead", skinConfig.SquareIcon);
+            if (sprite == null)
+            {
+                Show(imgFace, spine, uiFrame, resourceType, "herohead_default", null, ellipseMask);
+            }
+            else
+            {
+                Show(imgFace, spine, uiFrame, resourceType, string.Empty, sprite, ellipseMask);
+            }
+        }
+        else
+        {
+            resourceValue = GetResourceValue(type, id);
+            Show(imgFace, spine, uiFrame, resourceType, resourceValue, null, ellipseMask);
+        }
+
+    }
+
+    public void Show(ImageEx imgFace, UIEffectPlayer spine, UIFrame uiFrame, int resourceType, string resourceValue, Sprite sprite = null, EllipseMask ellipseMask = null)
+    {
+        spine.Stop();
+
+        switch (resourceType)
+        {
+            // 闈欐�佸浘
+            case 1:
+                imgFace.enabled = true;
+                spine.enabled = false;
+                uiFrame.enabled = false;
+
+
+
+                if (sprite == null)
+                {
+                    if (!IconConfig.HasKey(resourceValue))
+                        return;
+                    imgFace.SetSprite(resourceValue);
+                }
+                else
+                {
+                    imgFace.overrideSprite = sprite;
+                }
+                break;
+            case 2: // spine
+                imgFace.enabled = true;
+                uiFrame.enabled = false;
+                spine.enabled = true;
+                spine.effectId = int.Parse(resourceValue);
+                spine.isPlaySpineLoop = true;
+                spine.Play();
+                break;
+            // 搴忓垪甯�
+            case 3:
+                imgFace.enabled = true;
+                spine.enabled = false;
+                uiFrame.enabled = true;
+                imgFace.sprite = null;
+
+                if (!UIFrameMgr.Inst.ContainsDynamicImage(resourceValue))
+                    break;
+                //List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(resourceValue);
+                // if (!spriteList.IsNullOrEmpty())
+                // {
+                //     imgFace.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height);
+                // }
+
+                uiFrame.ResetFrame(resourceValue);
+                uiFrame.enabled = true;
+                break;
+        }
+
+        if (ellipseMask != null)
+        {
+            ellipseMask.UpdateChildrenStencil();
+        }
+    }
+
+    public bool TryGetInfo(PhantasmPavilionType type, int id, out PhantasmPavilionData info)
+    {
+        info = null;
+        return dataDict.TryGetValue(type, out var dict) && dict.TryGetValue(id, out info);
+    }
+
+    // 鏈夋病鏈夊睘鎬�
+    public bool HasInitAttr(PhantasmPavilionType type, int id)
+    {
+        if (!Has(type, id))
+            return false;
+        int[] attrIDList = GetAttrIDList(type, id);
+        int[] initAttrValueList = GetInitAttrValueList(type, id);
+        if (attrIDList.IsNullOrEmpty() || initAttrValueList.IsNullOrEmpty() || attrIDList.Length != initAttrValueList.Length)
+            return false;
+        return true;
+    }
+
+
+    //鏄惁宸茬粡鍗囨弧鏄�
+    public bool IsStarMax(PhantasmPavilionType type, int id)
+    {
+        if (!HasStarAddAttr(type, id))
+            return false;
+        if (!TryGetInfo(type, id, out PhantasmPavilionData info))
+            return false;
+        int starMax = GetStarMax(type, id);
+        return info.Star >= starMax;
+    }
+
+    // 鏄惁鍙崌鏄�
+    public bool HasStarAddAttr(PhantasmPavilionType type, int id)
+    {
+        if (!Has(type, id))
+            return false;
+        if (!HasInitAttr(type, id))
+            return false;
+        int[] initAttrValueList = GetInitAttrValueList(type, id);
+        int[] AttrPerStarAddList = GetAttrPerStarAddList(type, id);
+        if (initAttrValueList.IsNullOrEmpty() || AttrPerStarAddList.IsNullOrEmpty() || initAttrValueList.Length != AttrPerStarAddList.Length)
+            return false;
+        return true;
+    }
+
+    public bool IsUsing(PhantasmPavilionType type, int id)
+    {
+        if (!Has(type, id))
+            return false;
+        if (!TryGetNowShowID(type, out int result))
+            return false;
+        return result == id;
+    }
+
+    public List<int> ShowItemList(PhantasmPavilionType type, int tabType = 0)
+    {
+        var resList = new List<int>();
+        switch (type)
+        {
+            case PhantasmPavilionType.Model:
+                resList = ModelConfig.GetTabTypeTitles(tabType);
+                break;
+            case PhantasmPavilionType.Title:
+                resList = TitleConfig.GetTabTypeTitles(tabType);
+                break;
+            default:
+                resList = GetTableKeys(type);
+                break;
+        }
+        resList.Sort((int a, int b) => Cmp(a, b, type));
+        return resList;
+    }
+
+    public int Cmp(int a, int b, PhantasmPavilionType type)
+    {
+        // 鑾峰彇 a 鍜� b 鐨勮В閿佺姸鎬�
+        int stateA = (int)GetUnLockState(type, a);
+        int stateB = (int)GetUnLockState(type, b);
+
+        // 灏嗙姸鎬侀噸鏂板畾涔変负浼樺厛绾ф帓搴忔暟鍊硷細宸叉縺娲�(2) > 鍙縺娲�(1) > 鏈縺娲�(0)
+        int priorityA = stateA == 2 ? 0 : (stateA == 1 ? 1 : 2);
+        int priorityB = stateB == 2 ? 0 : (stateB == 1 ? 1 : 2);
+
+
+        if (priorityA != priorityB)
+        {
+            return priorityA.CompareTo(priorityB);
+        }
+        return a.CompareTo(b);
+    }
+
+    // 闄ら亾鍏疯В閿佸锛屽叾浠栨柟寮忔殏榛樿姘镐箙
+    // 鏄惁鏈夋椂鏁� true 鏈夋椂闂撮檺鍒� false 姘镐箙锛堟棤鏃堕棿闄愬埗锛�
+    public bool IsLimitTime(PhantasmPavilionType type, int id)
+    {
+        if (!Has(type, id))
+            return false;
+
+        // 濡傛灉涓嶆槸鈥滈亾鍏疯В閿佲�濇柟寮忥紝涔熻涓烘案涔�
+        if (GetUnlockWay(type, id) != (int)PhantasmPavilionUnlockWay.Item)
+            return false;
+
+        // 鐗╁搧瀛樺湪涓旀槸鈥滈亾鍏疯В閿佲��,鍙栧喅浜庢湁鏁堟湡
+        int expireMinutes = GetExpireMinutes(type, id);
+        return expireMinutes > 0;
+    }
+
+    //鐗╁搧鏄惁宸茶繃鏈�
+    private bool IsExpired(PhantasmPavilionData info, PhantasmPavilionUnlockWay unlockWay)
+    {
+        // 鍙湁鈥滈亾鍏封�濇柟寮忔墠闇�瑕佹鏌ユ椂鏁�,姝﹀皢瑙i攣(Hero) 鎴� 榛樿(Activate) 瑙嗕负姘镐箙
+        if (unlockWay != PhantasmPavilionUnlockWay.Item)
+            return false;
+
+        // EndTime == 0 琛ㄧず姘镐箙
+        bool isLimitedTime = info.EndTime > 0;
+        if (!isLimitedTime)
+            return false;
+
+        // 鏄檺鏃堕亾鍏凤紝妫�鏌ュ綋鍓嶆椂闂存槸鍚﹀凡缁忚秴杩囦簡鎴鏃堕棿
+        bool timeHasPassed = info.EndTime < TimeUtility.AllSeconds;
+        return timeHasPassed;
+    }
+
+    // 闄ら亾鍏疯В閿佸锛屽叾浠栨柟寮忔殏榛樿姘镐箙
+    // 1 - 榛樿瑙i攣锛屽嵆鍒涜灏卞彲鐢ㄧ殑
+    // 2 - 閬撳叿瑙i攣锛屾敮鎸佹椂鏁堛�佸崌绾э紝 Value閰嶇墿鍝両D
+    // 3 - 鍏宠仈姝﹀皢瑙i攣锛孷alue閰嶆灏咺D
+    public bool IsUnlock(PhantasmPavilionType type, int id)
+    {
+        // 閰嶇疆琛ㄤ腑涓嶅瓨鍦紝瑙嗕负鏈В閿�
+        if (!Has(type, id))
+            return false;
+
+        int unlockWayValue = GetUnlockWay(type, id);
+        int unlockValue = GetUnlockValue(type, id);
+        // 瑙i攣鏂瑰紡鏃犳晥
+        if (!Enum.IsDefined(typeof(PhantasmPavilionUnlockWay), unlockWayValue))
+            return false;
+        var unlockWay = (PhantasmPavilionUnlockWay)unlockWayValue;
+
+        switch (unlockWay)
+        {
+            case PhantasmPavilionUnlockWay.Activate:
+                return true;
+            case PhantasmPavilionUnlockWay.Hero:
+                bool hasHero = HeroManager.Instance.HasHero(unlockValue);
+                return hasHero;
+            case PhantasmPavilionUnlockWay.Item:
+                // 灏佸寘閲屾病鏈�
+                if (!TryGetInfo(type, id, out var info))
+                    return false;
+                // 鐜╁鏁版嵁涓殑鐘舵�佹槸鈥滄湭婵�娲烩��
+                if (!info.State)
+                    return false;
+                // 鏄惁涓衡�滃凡杩囨湡鐨勯亾鍏封��
+                if (IsExpired(info, unlockWay))
+                    return false;
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /// <summary>
+    /// 鑾峰緱褰撳墠鐘舵��
+    /// </summary>
+    /// <returns>0 - 鏈縺娲�, 1 - 鍙縺娲�, 2 - 宸叉縺娲�</returns>
+    public PhantasmPavilionState GetUnLockState(PhantasmPavilionType type, int id)
+    {
+        // 閰嶇疆琛ㄤ腑涓嶅瓨鍦紝瑙嗕负鈥滄湭婵�娲烩��
+        if (!Has(type, id))
+            return PhantasmPavilionState.Locked;
+
+        // 宸茬粡瑙i攣
+        if (IsUnlock(type, id))
+            return PhantasmPavilionState.Activated;
+
+        // 杩愯鍒拌繖閲岋紝璇存槑鐗╁搧鏄�滄湭婵�娲烩�濇垨鈥滃凡杩囨湡鈥濈姸鎬� (IsUnlock 杩斿洖 false)
+        // 鏃犳晥鐨勮В閿佹柟寮�
+        int unlockWayValue = GetUnlockWay(type, id);
+        if (!Enum.IsDefined(typeof(PhantasmPavilionUnlockWay), unlockWayValue))
+            return PhantasmPavilionState.Locked;
+
+        var unlockWay = (PhantasmPavilionUnlockWay)unlockWayValue;
+        int unlockValue = GetUnlockValue(type, id);
+
+        switch (unlockWay)
+        {
+            // 妫�鏌ラ亾鍏锋縺娲绘潯浠�
+            case PhantasmPavilionUnlockWay.Item:
+                return CheckCanActivateByItem(type, id, unlockValue)
+                    ? PhantasmPavilionState.CanActivate
+                    : PhantasmPavilionState.Locked;
+            // 妫�鏌ユ灏嗘縺娲绘潯浠�
+            case PhantasmPavilionUnlockWay.Hero:
+                int heroID = unlockValue;
+                return HeroManager.Instance.HasHero(heroID)
+                    ? PhantasmPavilionState.Activated
+                    : PhantasmPavilionState.Locked;
+            default:
+                return PhantasmPavilionState.Locked;
+        }
+    }
+
+    // 妫�鏌ユ槸鍚︽弧瓒斥�滈�氳繃閬撳叿婵�娲烩�濈殑鏉′欢
+    private bool CheckCanActivateByItem(PhantasmPavilionType type, int id, int itemId)
+    {
+        // 閬撳叿閰嶇疆涓嶅瓨鍦�
+        if (!ItemConfig.HasKey(itemId))
+            return false;
+
+        ItemConfig itemConfig = ItemConfig.Get(itemId);
+
+        // 鐜╁绛夌骇涓嶈冻
+        if (itemConfig.UseLV > PlayerDatas.Instance.baseData.LV)
+            return false;
+
+        // 閬撳叿鏁伴噺涓嶈冻
+        var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, itemId);
+        int unlockNeedCnt = GetUnlockNeedCnt(type, id);
+        if (hasCnt < unlockNeedCnt)
+            return false;
+
+        return true;
+    }
+
+    public void CheckTimeOut()
+    {
+        bool isTimeOut = false;
+        var expiredItems = new Dictionary<PhantasmPavilionType, List<int>>();
+
+        if (dataDict.IsNullOrEmpty())
+            return;
+
+        // 鍗曟閬嶅巻锛氭鏌ラ檺鏃剁墿鍝佸苟鏀堕泦杩囨湡椤圭洰
+        foreach (var kv in dataDict)
+        {
+            var type = kv.Key;
+            var dict = kv.Value;
+            foreach (var kv2 in dict)
+            {
+                var id = kv2.Key;
+                var data = kv2.Value;
+
+                // 鍙鏌ラ檺鏃剁墿鍝�
+                if (!IsLimitTime(type, id))
+                    continue;
+
+                int unlockWay = GetUnlockWay(type, id);
+                bool isExpired = IsExpired(data, (PhantasmPavilionUnlockWay)unlockWay);
+
+                if (isExpired)
+                {
+                    isTimeOut = true;
+
+                    if (!expiredItems.ContainsKey(type))
+                    {
+                        expiredItems[type] = new List<int>();
+                    }
+                    if (!expiredItems[type].Contains(id))
+                    {
+                        expiredItems[type].Add(id);
+                    }
+                }
+            }
+        }
+
+        // 濡傛灉娌℃湁杩囨湡鐗╁搧锛岀洿鎺ヨ繑鍥�
+        if (!isTimeOut)
+            return;
+
+        // 浠巇ataDict涓Щ闄よ繃鏈熺殑椤圭洰
+        if (!expiredItems.IsNullOrEmpty())
+        {
+            foreach (var kv in expiredItems)
+            {
+                var type = kv.Key;
+                var list = kv.Value;
+                if (dataDict.ContainsKey(type))
+                {
+                    foreach (var id in list)
+                    {
+                        dataDict[type].Remove(id);
+                    }
+                }
+            }
+        }
+
+        RefreshAttr();
+        UpdateRedPoint();
+        OnTimeOut?.Invoke();
+    }
+
+    #region 鏀跺皝鍖�
+    public event Action OnUpdateModelStarAdd;
+    public void UpdateModelInfo(HB119_tagSCModelInfo vNetData)
+    {
+        if (vNetData == null)
+            return;
+
+        PhantasmPavilionType type = PhantasmPavilionType.Model;
+        if (!dataDict.ContainsKey(type))
+        {
+            dataDict.Add(type, new Dictionary<int, PhantasmPavilionData>());
+        }
+
+        // 鍒ゆ柇褰撳墠灏佸寘鏄惁鏈変换浣曚竴椤圭殑鏄熺骇澶т簬涔嬪墠鐨勬槦绾�
+        bool hasStarIncreased = false;
+        foreach (var item in vNetData.ModelList)
+        {
+            if (dataDict[type].ContainsKey((int)item.ModelID))
+            {
+                var oldData = dataDict[type][(int)item.ModelID];
+                if (item.Star > oldData.Star)
+                {
+                    hasStarIncreased = true;
+                    break;
+                }
+            }
+        }
+
+        foreach (var item in vNetData.ModelList)
+        {
+            if (!dataDict[type].ContainsKey((int)item.ModelID))
+            {
+                dataDict[type][(int)item.ModelID] = new PhantasmPavilionData();
+            }
+
+            var data = dataDict[type][(int)item.ModelID];
+            data.ID = item.ModelID;
+            data.State = item.State == 1;
+            data.EndTime = item.EndTime;
+            data.Star = item.Star;
+        }
+        RefreshAttr();
+        UpdateRedPoint();
+        if (hasStarIncreased)
+        {
+            OnUpdateModelStarAdd?.Invoke();
+        }
+        OnUpdateModelInfoEvent?.Invoke();
+    }
+
+
+    public void UpdateTitleInfo(HB126_tagSCTitleInfo vNetData)
+    {
+        if (vNetData == null)
+            return;
+        PhantasmPavilionType type = PhantasmPavilionType.Title;
+        if (!dataDict.ContainsKey(type))
+        {
+            dataDict.Add(type, new Dictionary<int, PhantasmPavilionData>());
+        }
+
+        foreach (var item in vNetData.TitleList)
+        {
+            if (!dataDict[type].ContainsKey((int)item.TitleID))
+            {
+                dataDict[type][(int)item.TitleID] = new PhantasmPavilionData();
+            }
+
+            var data = dataDict[type][(int)item.TitleID];
+            data.ID = item.TitleID;
+            data.State = item.State == 1;
+            data.EndTime = item.EndTime;
+            data.Star = item.Star;
+        }
+        RefreshAttr();
+        UpdateRedPoint();
+        OnUpdateTitleInfoEvent?.Invoke();
+    }
+
+
+    public void UpdateChatBoxInfo(HB127_tagSCChatBoxInfo vNetData)
+    {
+        if (vNetData == null)
+            return;
+        PhantasmPavilionType type = PhantasmPavilionType.ChatBox;
+        if (!dataDict.ContainsKey(type))
+        {
+            dataDict.Add(type, new Dictionary<int, PhantasmPavilionData>());
+        }
+
+        foreach (var item in vNetData.BoxList)
+        {
+            if (!dataDict[type].ContainsKey((int)item.BoxID))
+            {
+                dataDict[type][(int)item.BoxID] = new PhantasmPavilionData();
+            }
+
+            var data = dataDict[type][(int)item.BoxID];
+            data.ID = item.BoxID;
+            data.State = item.State == 1;
+            data.EndTime = item.EndTime;
+            data.Star = item.Star;
+        }
+        RefreshAttr();
+        UpdateRedPoint();
+        OnUpdateChatBoxInfoEvent?.Invoke();
+    }
+
+
+    public void UpdateFaceInfo(HB117_tagMCFaceInfo vNetData)
+    {
+        if (vNetData == null)
+            return;
+        PhantasmPavilionType type = PhantasmPavilionType.Face;
+        if (!dataDict.ContainsKey(type))
+        {
+            dataDict.Add(type, new Dictionary<int, PhantasmPavilionData>());
+        }
+
+        foreach (var item in vNetData.FaceList)
+        {
+            if (!dataDict[type].ContainsKey((int)item.FaceID))
+            {
+                dataDict[type][(int)item.FaceID] = new PhantasmPavilionData();
+            }
+
+            var data = dataDict[type][(int)item.FaceID];
+            data.ID = item.FaceID;
+            data.State = item.State == 1;
+            data.EndTime = item.EndTime;
+            data.Star = item.Star;
+        }
+        RefreshAttr();
+        UpdateRedPoint();
+        OnUpdateFaceInfoEvent?.Invoke();
+    }
+
+
+    public void UpdateFacePicInfo(HB118_tagMCFacePicInfo vNetData)
+    {
+        if (vNetData == null)
+            return;
+        PhantasmPavilionType type = PhantasmPavilionType.FacePic;
+        if (!dataDict.ContainsKey(type))
+        {
+            dataDict.Add(type, new Dictionary<int, PhantasmPavilionData>());
+        }
+
+        foreach (var item in vNetData.FacePicList)
+        {
+            if (!dataDict[type].ContainsKey((int)item.FacePicID))
+            {
+                dataDict[type][(int)item.FacePicID] = new PhantasmPavilionData();
+            }
+
+            var data = dataDict[type][(int)item.FacePicID];
+            data.ID = item.FacePicID;
+            data.State = item.State == 1;
+            data.EndTime = item.EndTime;
+            data.Star = item.Star;
+        }
+        RefreshAttr();
+        UpdateRedPoint();
+        OnUpdateFacePicInfo?.Invoke();
+    }
+    #endregion
+
+    public void SendOPPack(PhantasmPavilionType type, PhantasmPavilionOperation op, uint opID)
+    {
+        SendB225Pack((byte)type, (byte)op, opID);
+    }
+
+    public void SendB225Pack(byte type, byte opType, uint opID)
+    {
+        var pack = new CB225_tagCSHJGOP();
+        pack.Type = type;                     // 绫诲瀷 1-褰㈣薄锛�2-澶村儚锛�3-澶村儚妗嗭紱4-姘旀场锛�5-绉板彿	
+        pack.OPType = opType;                 // 鎿嶄綔 1-婵�娲伙紱2-浣╂埓锛�3-鍗镐笅锛�4-鍗囨槦
+        pack.OPID = opID;                     // 鎿嶄綔瀵瑰簲鐨処D锛屽褰㈣薄ID绛�
+        GameNetSystem.Instance.SendInfo(pack);
+    }
+
+}
+
+public class PhantasmPavilionData
+{
+    public uint ID;             //ID
+    public bool State;          //鏄惁宸叉縺娲�
+    public uint EndTime;        //鍒版湡鏃堕棿鎴筹紝0涓烘案涔�
+    public byte Star;           //鏄熺骇
+}
+
+//瀵瑰簲鍙戝寘 1-褰㈣薄锛�2-澶村儚锛�3-澶村儚妗嗭紱4-姘旀场锛�5-绉板彿	
+public enum PhantasmPavilionType
+{
+    Model = 1,                  // 褰㈣薄
+    Face,                       // 澶村儚
+    FacePic,                    // 澶村儚妗�
+    ChatBox,                    // 鑱婂ぉ姘旀场
+    Title,                      //绉板彿
+}
+
+//瀵瑰簲鍙戝寘 1-婵�娲伙紱2-浣╂埓锛�3-鍗镐笅锛�4-鍗囨槦
+public enum PhantasmPavilionOperation
+{
+    Activate = 1,               // 婵�娲�
+    Wear,                       // 浣╂埓
+    Remove,                     // 鍗镐笅
+    UpgradeStar,                // 鍗囨槦
+}
+
+public enum PhantasmPavilionUnlockWay
+{
+    Activate = 1,               // 榛樿(鍒涜鑹插氨鍙互鐢ㄧ殑)
+    Item,                       // 閬撳叿
+    Hero,                       // 姝﹀皢
+}
+
+/// 骞诲闃佺墿鍝佺殑鐘舵��
+public enum PhantasmPavilionState
+{
+    // 鏈縺娲� (0)
+    Locked = 0,
+    // 鍙縺娲� (1) - 婊¤冻婵�娲绘潯浠讹紝浣嗗皻鏈縺娲�
+    CanActivate = 1,
+    //宸叉縺娲� (2) - 宸叉縺娲讳笖鏈繃鏈�
+    Activated = 2
+}
+
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionManager.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionManager.cs.meta
index c7311ca..d9906b0 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionManager.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 1ef87e456d444734991a9ea63aea1e99
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionModel.cs b/Main/System/PhantasmPavilion/PhantasmPavilionModel.cs
deleted file mode 100644
index 7f64a15..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionModel.cs
+++ /dev/null
@@ -1,893 +0,0 @@
-using LitJson;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using UnityEngine;
-
-public enum PhantasmPavilionTab
-{
-    Avatar,                 // 0 - 澶村儚
-    AvatarFrame,            // 1 - 澶村儚妗�
-    ChatExpression,         // 2 - 鑱婂ぉ琛ㄦ儏
-    ChatBubble              // 3 - 鑱婂ぉ姘旀场
-}
-
-public class PhantasmPavilionModel : GameSystemManager<PhantasmPavilionModel>
-{
-    public readonly int MaxItemRowCount = 2;    // 涓�琛屽睍绀簒涓墿鍝�
-    public readonly int MaxEmojiCount = 10;
-    public readonly int FuncId = 236;
-    private PhantasmPavilionTab m_SelectTab;
-    //褰撳墠閫変腑鐨勬爣绛鹃〉
-    public PhantasmPavilionTab selectTab
-    {
-        get { return m_SelectTab; }
-        set
-        {
-            m_SelectTab = value;
-            TabChangeEvent?.Invoke();
-        }
-    }
-
-    private int m_selectItemId;
-    public int selectItemId
-    {
-        get { return m_selectItemId; }
-        set
-        {
-            m_selectItemId = value;
-            ItemIdChangeEvent?.Invoke();
-        }
-    }
-
-    //褰撳墠閫変腑鐨勮〃鎯呭寘缁�
-
-    private int m_SelectEmojiPackID;
-    public int selectEmojiPackID
-    {
-        get { return m_SelectEmojiPackID; }
-        set
-        {
-            m_SelectEmojiPackID = value;
-            EmojiPackIDChangeEvent?.Invoke();
-        }
-    }
-
-    private Dictionary<PhantasmPavilionTab, IPhantasmPavilionTabHandler> handlers = new Dictionary<PhantasmPavilionTab, IPhantasmPavilionTabHandler>();
-    public Dictionary<PhantasmPavilionTab, Dictionary<int, PhantasmPavilionInfo>> infoDict = new Dictionary<PhantasmPavilionTab, Dictionary<int, PhantasmPavilionInfo>>();
-    public Dictionary<PhantasmPavilionTab, Dictionary<int, int>> defaultIDDict = new Dictionary<PhantasmPavilionTab, Dictionary<int, int>>();
-    public Dictionary<PhantasmPavilionTab, int> nowIDDict = new Dictionary<PhantasmPavilionTab, int>();
-
-    // 骞诲闃佸叆鍙g孩鐐� 459
-    Redpoint mainRedPoint = new Redpoint(10101, MainRedDot.PhantasmPavilionRepoint);
-
-    //鏍囩椤电孩鐐� 4591 - 4594
-    public Dictionary<PhantasmPavilionTab, Redpoint> tabRedPointDict = new Dictionary<PhantasmPavilionTab, Redpoint>();
-
-    public Dictionary<PhantasmPavilionTab, Dictionary<int, Redpoint>> itemRedPointDict = new Dictionary<PhantasmPavilionTab, Dictionary<int, Redpoint>>();
-
-    public event Action TabChangeEvent;         //鍒囨崲鏍囩椤�
-    public event Action ItemIdChangeEvent;      //鍒囨崲閫変腑椤�
-    public event Action EmojiPackIDChangeEvent;      //鍒囨崲閫変腑椤�
-    public event Action UpdateFaceInfoEvent;
-    public event Action UpdateFacePicInfoEvent;
-    public event Action UpdateEmojiPackInfoEvent;
-    public event Action UpdateChatBubbleBoxInfoEvent;
-    public Action<string> SendChatAction;
-
-
-    public override void Init()
-    {
-        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;
-        PackManager.Instance.RefreshItemEvent += OnRefreshItemCountEvent;
-        GlobalTimeEvent.Instance.secondEvent += CheckRedPoint;
-        InitHandler();
-        InitTable();
-        InitRedPoint();
-    }
-
-    public override void Release()
-    {
-        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;
-        PackManager.Instance.RefreshItemEvent -= OnRefreshItemCountEvent;
-        GlobalTimeEvent.Instance.fiveSecondEvent -= CheckRedPoint;
-    }
-
-    private void OnRefreshItemCountEvent(PackType type, int arg2, int arg3)
-    {
-        m_CheckRedPoint = true;
-    }
-
-    bool m_CheckRedPoint = false;
-    void CheckRedPoint()
-    {
-        if (m_CheckRedPoint)
-        {
-            UpdateRedPoint();
-            m_CheckRedPoint = false;
-        }
-    }
-
-
-    public void OnBeforePlayerDataInitialize()
-    {
-        infoDict.Clear();
-    }
-
-    public void OnPlayerLoginOk()
-    {
-        selectTab = PhantasmPavilionTab.Avatar;
-        var list = ShowItemList(selectTab, out int fristIndex);
-        if (!list.IsNullOrEmpty())
-            selectItemId = fristIndex;
-
-        nowIDDict[PhantasmPavilionTab.Avatar] = PlayerDatas.Instance.baseData.face;
-        nowIDDict[PhantasmPavilionTab.AvatarFrame] = PlayerDatas.Instance.baseData.facePic;
-        nowIDDict[PhantasmPavilionTab.ChatBubble] = (int)PlayerDatas.Instance.baseData.bubbleId;
-    }
-
-    private void OnPlayerDataRefreshEvent(PlayerDataType type)
-    {
-        if (type == PlayerDataType.Face)
-        {
-            nowIDDict[PhantasmPavilionTab.Avatar] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.Face);
-        }
-        else if (type == PlayerDataType.FacePic)
-        {
-            nowIDDict[PhantasmPavilionTab.AvatarFrame] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.FacePic);
-        }
-        else if (type == PlayerDataType.ExAttr10)
-        {
-            nowIDDict[PhantasmPavilionTab.ChatBubble] = (int)PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr10);
-        }
-
-        if (type == PlayerDataType.LV)
-        {
-            UpdateRedPoint();
-        }
-    }
-
-    private void InitHandler()
-    {
-        handlers = new Dictionary<PhantasmPavilionTab, IPhantasmPavilionTabHandler>();
-        handlers[PhantasmPavilionTab.Avatar] = new PhantasmPavilionAvatarHandler();
-        handlers[PhantasmPavilionTab.AvatarFrame] = new PhantasmPavilionAvatarFrameHandler();
-        handlers[PhantasmPavilionTab.ChatExpression] = new PhantasmPavilionChatExpressionHandler();
-        handlers[PhantasmPavilionTab.ChatBubble] = new PhantasmPavilionChatBubbleHandler();
-    }
-
-    private void InitTable()
-    {
-        InitDefault();
-    }
-
-    private void InitRedPoint()
-    {
-        InitTabRedPoint();
-        InitItemRedPoint(PhantasmPavilionTab.Avatar, PlayerFaceConfig.GetKeys());
-        InitItemRedPoint(PhantasmPavilionTab.AvatarFrame, PlayerFacePicConfig.GetKeys());
-        InitItemRedPoint(PhantasmPavilionTab.ChatExpression, EmojiPackConfig.GetKeys());
-        InitItemRedPoint(PhantasmPavilionTab.ChatBubble, ChatBubbleBoxConfig.GetKeys());
-    }
-
-    private void InitDefault()
-    {
-        var tabValues = Enum.GetValues(typeof(PhantasmPavilionTab));
-        for (int i = 0; i < tabValues.Length; i++)
-        {
-            PhantasmPavilionTab tab = (PhantasmPavilionTab)tabValues.GetValue(i);
-            if (!defaultIDDict.ContainsKey(tab))
-            {
-                defaultIDDict[tab] = new Dictionary<int, int>();
-            }
-        }
-
-        var config = FuncConfigConfig.Get("PhantasmPavilion");
-        var jsonData = JsonMapper.ToObject(config.Numerical1);
-        List<string> keyList = jsonData.Keys.ToList();
-        for (int i = 0; i < keyList.Count; i++)
-        {
-            int key = int.Parse(keyList[i]);
-            int value = int.Parse(jsonData[keyList[i]].ToString());
-            defaultIDDict[PhantasmPavilionTab.Avatar][key] = value;
-        }
-
-        jsonData = JsonMapper.ToObject(config.Numerical2);
-        keyList = jsonData.Keys.ToList();
-        for (int i = 0; i < keyList.Count; i++)
-        {
-            int key = int.Parse(keyList[i]);
-            int value = int.Parse(jsonData[keyList[i]].ToString());
-            defaultIDDict[PhantasmPavilionTab.AvatarFrame][key] = value;
-        }
-        //defaultIDDict[PhantasmPavilionTab.ChatExpression][0] = int.Parse(config.Numerical3);
-        defaultIDDict[PhantasmPavilionTab.ChatBubble][0] = int.Parse(config.Numerical3);
-    }
-
-    private void InitTabRedPoint()
-    {
-        var values = Enum.GetValues(typeof(PhantasmPavilionTab));
-        for (int i = 0; i < values.Length; i++)
-        {
-            PhantasmPavilionTab tab = (PhantasmPavilionTab)values.GetValue(i);
-            int id = MainRedDot.PhantasmPavilionRepoint * 10 + (int)tab + 1;
-            tabRedPointDict[tab] = new Redpoint(MainRedDot.PhantasmPavilionRepoint, id);
-        }
-    }
-
-    private void InitItemRedPoint(PhantasmPavilionTab tab, List<int> idList)
-    {
-        if (!infoDict.ContainsKey(tab))
-            itemRedPointDict[tab] = new Dictionary<int, Redpoint>();
-
-        for (int i = 0; i < idList.Count; i++)
-        {
-            int id = idList[i];
-            int baseValue = MainRedDot.PhantasmPavilionRepoint * 10 + (int)tab + 1;
-            itemRedPointDict[tab][id] = new Redpoint(baseValue, baseValue * 10000 + id);
-        }
-    }
-
-    public void UpdateRedPoint()
-    {
-        var values = Enum.GetValues(typeof(PhantasmPavilionTab));
-        for (int i = 0; i < values.Length; i++)
-        {
-            PhantasmPavilionTab key = (PhantasmPavilionTab)values.GetValue(i);
-            tabRedPointDict[key].state = RedPointState.None;
-            var keyList = itemRedPointDict[key].Keys.ToList();
-            for (int j = 0; j < keyList.Count; j++)
-            {
-                int id = keyList[j];
-                itemRedPointDict[key][id].state = RedPointState.None;
-                //鍙縺娲�
-                if (GetUnLockState(key, id) == 1)
-                {
-                    itemRedPointDict[key][id].state = RedPointState.Simple;
-
-                    if (selectTab != key)
-                    {
-                        tabRedPointDict[key].state = RedPointState.Simple;
-                    }
-                }
-
-            }
-        }
-    }
-
-
-    public bool IsCustom(int faceID, out int customPlayerID)
-    {
-        customPlayerID = 0;
-        if (!PlayerFaceConfig.HasKey(faceID))
-            return false;
-        customPlayerID = PlayerFaceConfig.Get(faceID).CustomPlayerID;
-        if (customPlayerID <= 0)
-            return false;
-        return true;
-    }
-
-
-    //鑾峰彇涓嶅悓鑱屼笟瀵瑰簲鐨勯粯璁ゅ��
-    public bool TryGetDefaultID(PhantasmPavilionTab key, int job, out int defaultID)
-    {
-        defaultID = 0;
-        if (defaultIDDict == null || !defaultIDDict.TryGetValue(key, out var dict) || dict == null)
-            return false;
-        // 灏濊瘯鑾峰彇 job 瀵瑰簲鐨勫�硷紝濡傛灉娌℃湁鍒欒幏鍙� key 涓� 0 鐨勫��
-        return dict.TryGetValue(job, out defaultID) || dict.TryGetValue(0, out defaultID);
-    }
-
-    public bool TryGetNowShowID(PhantasmPavilionTab key, out int result)
-    {
-        result = 0;
-        int job = PlayerDatas.Instance.baseData.Job;
-        // 濡傛灉 nowIDDict 涓虹┖鎴栨病鏈夊綋鍓� ID锛岀洿鎺ュ皾璇曡幏鍙栭粯璁� ID
-        if (nowIDDict == null || !TryGetDefaultID(key, job, out int defaultID))
-            return false;
-
-        // 鑾峰彇褰撳墠 ID锛屽鏋滃瓨鍦ㄥ垯璧嬪�肩粰 result
-        if (nowIDDict.TryGetValue(key, out int nowID) && IsUnlock(key, nowID))
-        {
-            result = nowID;
-        }
-        else
-        {
-            result = defaultID;
-        }
-
-        return true;
-    }
-
-    public bool TryGetInfo(PhantasmPavilionTab tab, int id, out PhantasmPavilionInfo info)
-    {
-        info = new PhantasmPavilionInfo();
-        if (!Has(tab, id))
-            return false;
-        if (infoDict == null || !infoDict.TryGetValue(tab, out var tempInfoDict))
-        {
-            // 瀹氬埗鐨勯粯璁ゆ縺娲�0鏄�
-            if (IsCustom(id, out int customPlayerID))
-            {
-                if (customPlayerID == PlayerDatas.Instance.baseData.PlayerID)
-                {
-                    info = new PhantasmPavilionInfo()
-                    {
-                        ID = id,
-                        Star = 0,
-                        State = true 
-                    };
-                    return true;
-                }
-            }
-            return false;
-        }
-        if (tempInfoDict == null || !tempInfoDict.TryGetValue(id, out info))
-        {
-            // 瀹氬埗鐨勯粯璁ゆ縺娲�0鏄�
-            if (IsCustom(id, out int customPlayerID))
-            {
-                if (customPlayerID == PlayerDatas.Instance.baseData.PlayerID)
-                {
-                    info = new PhantasmPavilionInfo()
-                    {
-                        ID = id,
-                        Star = 0,
-                        State = true
-                    };
-                    return true;
-                }
-            }
-            return false;
-        }
-        return true;
-    }
-
-
-    public List<int> ShowItemList(PhantasmPavilionTab tab, out int fristIndex)
-    {
-        fristIndex = 0;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return new List<int>();
-
-        var resList = handler.GetTableKeys();
-        resList.Sort((int a, int b) => Cmp(a, b, tab));
-
-        if (tab == PhantasmPavilionTab.Avatar)
-        {
-            for (int i = resList.Count - 1; i >= 0; i--)
-            {
-                int id = resList[i];
-                int[] JobShowList = PlayerFaceConfig.Get(id).JobShowList;
-                if (JobShowList != null && !JobShowList.Contains(PlayerDatas.Instance.baseData.Job) && resList.Contains(id))
-                {
-                    resList.Remove(id);
-                }
-            }
-        }
-
-        fristIndex = resList.First();
-        return resList;
-    }
-
-    public int Cmp(int a, int b, PhantasmPavilionTab tab)
-    {
-        // 鑾峰彇 a 鍜� b 鐨勮В閿佺姸鎬�
-        int stateA = GetUnLockState(tab, a);
-        int stateB = GetUnLockState(tab, b);
-
-        // 灏嗙姸鎬侀噸鏂板畾涔変负浼樺厛绾ф帓搴忔暟鍊硷細鍙縺娲� > 宸叉縺娲� > 鏈縺娲绘渶鍚�
-        int priorityA = stateA == 1 ? 0 : (stateA == 2 ? 1 : 2);
-        int priorityB = stateB == 1 ? 0 : (stateB == 2 ? 1 : 2);
-
-        if (priorityA != priorityB)
-        {
-            return priorityA.CompareTo(priorityB);
-        }
-
-        // 濡傛灉婵�娲荤姸鎬佺浉鍚岋紝姣旇緝 SortNum
-        int sortNumA = GetSortNum(tab, a);
-        int sortNumB = GetSortNum(tab, b);
-
-        if (sortNumA != sortNumB)
-        {
-            if (tab == PhantasmPavilionTab.Avatar)
-            {
-                return sortNumB.CompareTo(sortNumA);
-            }
-            else
-            {
-                return sortNumA.CompareTo(sortNumB);
-            }
-        }
-
-        return a.CompareTo(b);
-    }
-
-    ////鑾峰緱褰撳墠鐘舵�� 0 - 鏈縺娲� 1 - 鍙縺娲� 2 - 宸叉縺娲�
-    public int GetUnLockState(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return 0;
-
-        if (IsCustom(id, out int customPlayerID))
-        {
-            if (customPlayerID == PlayerDatas.Instance.baseData.PlayerID)
-                return 2;
-            return 0;
-        }
-
-        //娌℃縺娲�
-        if (!IsUnlock(tab, id))
-        {
-            //娌℃湁濉縺娲荤墿鍝�
-            if (!TryGetUnLockNeedItem(tab, id, out int itemId, out int count))
-                return 0;
-            if (!ItemConfig.HasKey(itemId))
-                return 0;
-            ItemConfig itemConfig = ItemConfig.Get(itemId);
-            if (itemConfig.UseLV > PlayerDatas.Instance.baseData.LV)
-                return 0;
-            //婵�娲荤墿鍝佹暟閲忎笉瓒�
-            var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, itemId);
-            if (hasCnt < count)
-                return 0;
-            return 1;
-        }
-        return 2;
-    }
-
-    //鑾峰緱灞炴�у睍绀烘牱寮忕被鍨�  0 鍔犲彿 1 绠ご false涓嶅睍绀�
-    public bool TryGetAttrShowType(PhantasmPavilionTab tab, int faceId, out int type)
-    {
-        type = 0;
-        //int unLockState = GetUnLockState(tab, faceId);// 0 - 鏈縺娲� 1 - 鍙縺娲� 2 - 宸叉縺娲�
-        // bool isHaveUnLockAttr = TryGetUnLockAttr(tab, selectItemId, out int[] lightAttrTypeArr, out int[] lightAttrValueArr);
-
-        // if (!isHaveUnLockAttr)
-        //     return false;
-
-        return false;
-    }
-
-    
-    #region 琛ㄦ儏鍖呮帴鍏ョ浉鍏�
-
-    public List<int> GetUnlockIDList()
-    {
-        List<int> allList = EmojiPackConfig.GetKeys();
-        List<int> result = new List<int>();
-        for (int i = 0; i < allList.Count; i++)
-        {
-            int id = allList[i];
-            if (IsUnlock(PhantasmPavilionTab.ChatExpression, id))
-            {
-                result.Add(id);
-            }
-        }
-        return result;
-    }
-
-    public List<string> GetEmojiList(int id)
-    {
-        var info = FrameAnimationConfig.GetEmojiPackList();
-        if (info == null || !info.TryGetValue(id, out var list) || list == null)
-            return new List<string>();
-        return list;
-    }
-
-    public int GetShowEmojiInfo(float itemWidth, int id, out int rowCount, out int emojiCount, out int space)
-    {
-        emojiCount = 0;
-        rowCount = 0;
-        space = 0; // 榛樿鍊�
-
-        int minSpace = 5; // 鏈�灏忛棿闅�
-        int maxSpace = 50; // 鏈�澶ч棿闅�
-        int width = Mathf.CeilToInt(itemWidth);
-
-        GetEmojiShowSize(id, out int emojiWidth, out int emojiHeight);
-        List<string> emojiList = GetEmojiList(id);
-        if (emojiList == null || emojiList.Count == 0 || emojiWidth == 0)
-            return 0;
-
-        int listCount = emojiList.Count;
-        emojiCount = Mathf.Min(MaxEmojiCount, Mathf.Min(width / emojiWidth, listCount));
-
-        if (emojiCount > 1)
-        {
-            int availableWidthForSpaces = width - (emojiCount * emojiWidth);
-            space = availableWidthForSpaces / (emojiCount - 1);
-            space = Mathf.Clamp(space, minSpace, maxSpace);
-        }
-        else
-        {
-            space = 0; // 娌℃湁绌洪棿鍙垎閰嶉棿闅旀垨鑰呴棿闅斾箣闂村彧鏈変竴涓〃鎯�
-        }
-
-        rowCount = Mathf.CeilToInt((float)listCount / emojiCount);
-        return 0;
-    }
-
-    // 鑾峰緱琛ㄦ儏鍖呬腑琛ㄦ儏鏈�澶х殑灏哄
-    public void GetEmojiShowSize(int id, out int width, out int height)
-    {
-        width = 0;
-        height = 0;
-
-        List<string> emojiList = GetEmojiList(id);
-        if (emojiList.IsNullOrEmpty())
-            return;
-
-        for (int i = 0; i < emojiList.Count; i++)
-        {
-            string imgSrc = emojiList[i];
-
-            if (UIFrameMgr.Inst.ContainsDynamicImage(imgSrc))
-            {
-                List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(imgSrc);
-                if (!spriteList.IsNullOrEmpty())
-                {
-                    for (int j = 0; j < spriteList.Count; j++)
-                    {
-                        UpdateMaxSize(spriteList[j], ref width, ref height);
-                    }
-                }
-            }
-            else if (IconConfig.HasKey(imgSrc))
-            {
-                UnityEngine.Sprite sprite = UILoader.LoadSprite(imgSrc);
-                UpdateMaxSize(sprite, ref width, ref height);
-            }
-        }
-    }
-
-    // 鏇存柊鏈�澶у昂瀵哥殑鏂规硶
-    private void UpdateMaxSize(UnityEngine.Sprite sprite, ref int width, ref int height)
-    {
-        float nowWidth = sprite.rect.width;
-        float nowHeight = sprite.rect.height;
-        if (width < nowWidth)
-            width = Mathf.CeilToInt(nowWidth);
-        if (height < nowHeight)
-            height = Mathf.CeilToInt(nowHeight);
-    }
-
-    #endregion
-
-    //鑾峰緱鑷繁鐨勮亰澶╂皵娉D
-    public int GetNowChatBubbleID()
-    {
-        PhantasmPavilionTab key = PhantasmPavilionTab.ChatBubble;
-        int job = 0;
-        // 灏濊瘯鑾峰彇褰撳墠 ID
-        if (nowIDDict.TryGetValue(key, out int nowID) && ChatBubbleBoxConfig.HasKey(nowID) && IsUnlock(key, nowID))
-            return nowID;
-        // 濡傛灉褰撳墠 ID 涓嶅瓨鍦ㄦ垨鏈В閿侊紝灏濊瘯鑾峰彇榛樿 ID
-        return TryGetDefaultID(key, job, out int defaultID) ? defaultID : -1;
-    }
-
-    //鑾峰緱鍏朵粬鐜╁鐨勮亰澶╂皵娉D
-    public int GetNowOtherChatBubbleID(int nowID)
-    {
-        PhantasmPavilionTab key = PhantasmPavilionTab.AvatarFrame;
-        // 灏濊瘯鑾峰彇褰撳墠 ID
-        if (ChatBubbleBoxConfig.HasKey(nowID))
-            return nowID;
-        // 濡傛灉褰撳墠 ID 涓嶅瓨鍦ㄦ垨鏈В閿侊紝灏濊瘯鑾峰彇榛樿 ID
-        return TryGetDefaultID(key, 0, out int defaultID) ? defaultID : -1;
-    }
-
-    public bool IsUnlock(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return false;
-        int unlockDefault = GetUnlockDefault(tab, id);
-        //閰嶉粯璁ゆ縺娲荤殑 涓嶅仛鍏朵粬鍒ゅ畾鐩存帴婵�娲�
-        if (unlockDefault == 1)
-            return true;
-        // 灏佸寘涓病鏈�
-        if (!TryGetInfo(tab, id, out var info))
-            return false;
-        // 鐘舵�佹槸鏈縺娲�
-        if (!info.State)
-            return false;
-        // 鏃舵晥涓嶄负姘镐箙 涓旀椂鏁堢敤瀹�
-        if (info.EndTime > 0 && info.EndTime < TimeUtility.AllSeconds)
-            return false;
-        return true;
-    }
-
-    //鏄惁鏈夋椂鏁� true 鏈夋椂闂撮檺鍒� false 姘镐箙锛堟棤鏃堕棿闄愬埗锛�
-    public bool IsLimitTime(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return false;
-        int unlockDefault = GetUnlockDefault(tab, id);
-        int expireMinutes = GetExpireMinutes(tab, id);
-        //娌℃壘鍒�
-        if (unlockDefault == -1 || expireMinutes == -1)
-            return false;
-        //榛樿婵�娲荤殑閮芥槸姘镐箙鐨�,娌℃湁鏃舵晥闄愬埗
-        if (unlockDefault == 1)
-            return false;
-        //鏃舵晥鍒嗛挓閰�0鐨勯兘鏄案涔呯殑,娌℃湁鏃舵晥闄愬埗
-        if (expireMinutes <= 0)
-            return false;
-        return true;
-    }
-
-    
-
-    public void ShowImage(PhantasmPavilionTab tab, int id, ImageEx imgTitle)
-    {
-        if (!Has(tab, id))
-            return;
-        string image = GetImage(tab, id);
-        UIFrame frame = imgTitle.GetComponent<UIFrame>();
-        if (UIFrameMgr.Inst.ContainsDynamicImage(image))
-        {
-            if (frame == null)
-                frame = imgTitle.gameObject.AddComponent<UIFrame>();
-
-            List<UnityEngine.Sprite> spriteList = UIFrameMgr.Inst.GetDynamicImage(image);
-            if (!spriteList.IsNullOrEmpty())
-            {
-                imgTitle.rectTransform.sizeDelta = new Vector2(spriteList[0].rect.width, spriteList[0].rect.height);
-            }
-
-            imgTitle.raycastTarget = false;
-            frame.ResetFrame(image);
-            frame.enabled = true;
-        }
-        else
-        {
-            if (frame != null)
-                frame.enabled = false;
-            imgTitle.SetSprite(image);
-            imgTitle.SetNativeSize();
-        }
-    }
-
-
-
-    #region handler鐩稿叧
-
-    public bool Has(PhantasmPavilionTab tab, int id)
-    {
-        if (!handlers.TryGetValue(tab, out var handler))
-            return false;
-        return handler.Has(id);
-    }
-    public string GetDescriptive(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return string.Empty;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return string.Empty;
-        return handler.GetDescriptive(id);
-    }
-
-    public int GetSortNum(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return 0;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return 0;
-        return handler.GetSortNum(id);
-    }
-
-    public string GetName(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return string.Empty;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return string.Empty;
-        return handler.GetName(id);
-    }
-
-    public string GetImage(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return string.Empty;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return string.Empty;
-        return handler.GetImage(id);
-    }
-
-    public int GetUnlockDefault(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return 0;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return 0;
-        return handler.GetUnlockDefault(id);
-    }
-
-    public int GetExpireMinutes(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return 0;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return 0;
-        return handler.GetExpireMinutes(id);
-    }
-
-    public bool IsUsing(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return false;
-        if (!TryGetNowShowID(tab, out int result))
-            return false;
-        return result == id;
-    }
-
-    public bool TryGetUnLockAttr(PhantasmPavilionTab tab, int id, out int[] lightAttrTypeArr, out int[] lightAttrValueArr)
-    {
-        lightAttrTypeArr = null;
-        lightAttrValueArr = null;
-        if (!Has(tab, id))
-            return false;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return false;
-        return handler.TryGetUnLockAttr(id, out lightAttrTypeArr, out lightAttrValueArr);
-    }
-
-    public bool TryGetUnLockNeedItem(PhantasmPavilionTab tab, int id, out int itemId, out int count)
-    {
-        itemId = 0;
-        count = 0;
-        if (!Has(tab, id))
-            return false;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return false;
-        return handler.TryGetUnLockNeedItem(id, out itemId, out count);
-    }
-
-
-
-    public bool TryGetEffectID(PhantasmPavilionTab tab, int id, out int effectID)
-    {
-        effectID = 0;
-        if (!Has(tab, id))
-            return false;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return false;
-        return handler.TryGetEffectID(id, out effectID);
-    }
-
-
-
-
-    public void SendUsePack(PhantasmPavilionTab tab, int id)
-    {
-        if (!Has(tab, id))
-            return;
-        if (!handlers.TryGetValue(tab, out var handler))
-            return;
-        handler.SendUsePack(id);
-    }
-
-    #endregion
-
-    #region 鍙戝皝鍖�
-
-    public void SendCA323UnLockPack(int itemIndex, int count)
-    {
-        var pack = new CA323_tagCMUseItems();
-        pack.ItemIndex = (byte)itemIndex;
-        pack.UseCnt = (ushort)count;
-        GameNetSystem.Instance.SendInfo(pack);
-    }
-
-    public void SendCB226FaceChange(int faceId)
-    {
-        var pack = new CB226_tagCMFaceChange();
-        pack.FaceID = (uint)faceId;
-        GameNetSystem.Instance.SendInfo(pack);
-    }
-
-
-
-    public void SendCB228FacePicChange(int facePicId)
-    {
-        var pack = new CB228_tagCMFacePicChange();
-        pack.FacePicID = (uint)facePicId;
-        GameNetSystem.Instance.SendInfo(pack);
-    }
-
-
-
-    public void SendCA230SetChatBubbleBox(int id)
-    {
-        CA230_tagCMSetChatBubbleBox pak = new CA230_tagCMSetChatBubbleBox();
-        pak.BubbleBoxType = (byte)id;
-        GameNetSystem.Instance.SendInfo(pak);
-    }
-
-
-    #endregion
-
-    #region 鏀跺皝鍖�
-
-    public void UpdateFaceInfo(HB117_tagMCFaceInfo vNetData)
-    {
-        if (!infoDict.ContainsKey(PhantasmPavilionTab.Avatar))
-            infoDict[PhantasmPavilionTab.Avatar] = new Dictionary<int, PhantasmPavilionInfo>();
-        for (int i = 0; i < vNetData.FaceList.Length; i++)
-        {
-            HB117_tagMCFaceInfo.tagMCFace tagMCFaces = vNetData.FaceList[i];
-            if (!infoDict[PhantasmPavilionTab.Avatar].ContainsKey((int)tagMCFaces.FaceID))
-                infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID] = new PhantasmPavilionInfo();
-            infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID].ID = (int)tagMCFaces.FaceID;
-            infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID].State = tagMCFaces.State == 1;
-            infoDict[PhantasmPavilionTab.Avatar][(int)tagMCFaces.FaceID].EndTime = tagMCFaces.EndTime;
-        }
-        UpdateRedPoint();
-        UpdateFaceInfoEvent?.Invoke();
-    }
-
-    public void UpdateFacePicInfo(HB118_tagMCFacePicInfo vNetData)
-    {
-        if (!infoDict.ContainsKey(PhantasmPavilionTab.AvatarFrame))
-            infoDict[PhantasmPavilionTab.AvatarFrame] = new Dictionary<int, PhantasmPavilionInfo>();
-
-        for (int i = 0; i < vNetData.FacePicList.Length; i++)
-        {
-            HB118_tagMCFacePicInfo.tagMCFacePic tagMCFacePics = vNetData.FacePicList[i];
-            if (!infoDict[PhantasmPavilionTab.AvatarFrame].ContainsKey((int)tagMCFacePics.FacePicID))
-                infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID] = new PhantasmPavilionInfo();
-            infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID].ID = (int)tagMCFacePics.FacePicID;
-            infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID].State = tagMCFacePics.State == 1;
-            infoDict[PhantasmPavilionTab.AvatarFrame][(int)tagMCFacePics.FacePicID].EndTime = tagMCFacePics.EndTime;
-        }
-        UpdateRedPoint();
-        UpdateFacePicInfoEvent?.Invoke();
-    }
-
-    public void UpdateEmojiPackInfo(HA721_tagMCEmojiPackInfo vNetData)
-    {
-        if (!infoDict.ContainsKey(PhantasmPavilionTab.ChatExpression))
-            infoDict[PhantasmPavilionTab.ChatExpression] = new Dictionary<int, PhantasmPavilionInfo>();
-
-        for (int i = 0; i < vNetData.EmojiPackList.Length; i++)
-        {
-            HA721_tagMCEmojiPackInfo.tagMCEmojiPack emojiPack = vNetData.EmojiPackList[i];
-            if (!infoDict[PhantasmPavilionTab.ChatExpression].ContainsKey((int)emojiPack.PackID))
-                infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID] = new PhantasmPavilionInfo();
-            infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID].ID = (int)emojiPack.PackID;
-            infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID].State = emojiPack.State == 1;
-            infoDict[PhantasmPavilionTab.ChatExpression][(int)emojiPack.PackID].EndTime = emojiPack.EndTime;
-        }
-        UpdateRedPoint();
-        UpdateEmojiPackInfoEvent?.Invoke();
-    }
-
-    public void UpdateChatBubbleBoxInfo(HA717_tagMCChatBubbleBoxState vNetData)
-    {
-        if (!infoDict.ContainsKey(PhantasmPavilionTab.ChatBubble))
-            infoDict[PhantasmPavilionTab.ChatBubble] = new Dictionary<int, PhantasmPavilionInfo>();
-
-        for (int i = 0; i < vNetData.BoxList.Length; i++)
-        {
-            HA717_tagMCChatBubbleBoxState.tagMCChatBubbleBox chatBubbleBox = vNetData.BoxList[i];
-            if (!infoDict[PhantasmPavilionTab.ChatBubble].ContainsKey((int)chatBubbleBox.BoxID))
-                infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID] = new PhantasmPavilionInfo();
-            infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID].ID = (int)chatBubbleBox.BoxID;
-            infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID].State = chatBubbleBox.State == 1;
-            infoDict[PhantasmPavilionTab.ChatBubble][(int)chatBubbleBox.BoxID].EndTime = chatBubbleBox.EndTime;
-        }
-        UpdateRedPoint();
-        UpdateChatBubbleBoxInfoEvent?.Invoke();
-    }
-
-    #endregion
-}
-
-public class PhantasmPavilionInfo
-{
-    public int ID;                  //ID
-    public bool State;              //鏄惁宸叉縺娲�
-    public uint EndTime;            //鍒版湡鏃堕棿鎴筹紝0涓烘案涔�
-    public int Star;               //鏄熺骇
-}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionModel.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionModel.cs.meta
deleted file mode 100644
index 92b5bf0..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionModel.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 336548bbdf51c6844a76be570ae7becc
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs
new file mode 100644
index 0000000..5f97812
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs
@@ -0,0 +1,33 @@
+锘縰sing System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionModelCell : MonoBehaviour
+{
+    readonly PhantasmPavilionType type = PhantasmPavilionType.Model;
+    [SerializeField] List<PhantasmPavilionModelItem> items = new List<PhantasmPavilionModelItem>();
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int rowIndex, CellView cellView)
+    {
+        int tabType = cellView.info.Value.infoInt1;
+        List<int> showItemList = manager.ShowItemList(type, tabType);
+        if (showItemList.IsNullOrEmpty() || !manager.TryGetRowCountMax(type, out int rowCountMax))
+            return;
+        for (int i = 0; i < items.Count; i++)
+        {
+            int index = rowIndex * rowCountMax + i;
+            if (!showItemList.IsNullOrEmpty())
+            {
+                if (index < showItemList.Count)
+                {
+                    items[i].SetActive(true);
+                    items[i].Display(showItemList[index]);
+                }
+                else
+                {
+                    items[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs.meta
index c7311ca..e115bf0 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelCell.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: bd8704f99e3542e419d17c23574200e6
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs
new file mode 100644
index 0000000..7a7f5a2
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+public class PhantasmPavilionModelHandler : IPhantasmPavilionHandler
+{
+    public bool HasTableKey(int id)
+    {
+        return ModelConfig.HasKey(id);
+    }
+    public List<int> GetKeyList()
+    {
+        return ModelConfig.GetKeys();
+    }
+    public int GetResourceType(int id)
+    {
+        return 0;
+    }
+    public string GetResourceValue(int id)
+    {
+        return string.Empty;
+    }
+
+    public string GetName(int id)
+    {
+        return ModelConfig.Get(id).Name;
+    }
+    public int GetExpireMinutes(int id)
+    {
+        return ModelConfig.Get(id).ExpireMinutes;
+    }
+    public int GetUnlockWay(int id)
+    {
+        return ModelConfig.Get(id).UnlockWay;
+    }
+    public int GetUnlockValue(int id)
+    {
+        return ModelConfig.Get(id).UnlockValue;
+    }
+    public int GetUnlockNeedCnt(int id)
+    {
+        return ModelConfig.Get(id).UnlockNeedCnt;
+    }
+    public int GetUpNeedCnt(int id)
+    {
+        return ModelConfig.Get(id).UpNeedCnt;
+    }
+    public int GetStarMax(int id)
+    {
+        return ModelConfig.Get(id).StarMax;
+    }
+    public int[] GetAttrIDList(int id)
+    {
+        return ModelConfig.Get(id).AttrIDList;
+    }
+    public int[] GetInitAttrValueList(int id)
+    {
+        return ModelConfig.Get(id).InitAttrValueList;
+    }
+    public int[] GetAttrPerStarAddList(int id)
+    {
+        return ModelConfig.Get(id).AttrPerStarAddList;
+    }
+    public string GetGetWayString(int id)
+    {
+        return ModelConfig.Get(id).GetWayString;
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs.meta
index c7311ca..ddc6ceb 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelHandler.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 0ffc05fccadbe43429af9dee551c9345
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs b/Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs
new file mode 100644
index 0000000..a50a9a4
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs
@@ -0,0 +1,63 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionModelItem : MonoBehaviour
+{
+    [SerializeField] EllipseMask mask;
+    [SerializeField] ImageEx imgBg;
+    [SerializeField] ImageEx imgFace;
+    [SerializeField] Button btnChoose;
+
+    [SerializeField] ImageEx imgLimit;
+    [SerializeField] ImageEx imgLock;
+    [SerializeField] ImageEx imgChoose;
+    [SerializeField] ImageEx imgCanUnlock;
+    [SerializeField] TextEx txtUsing;
+    [SerializeField] Image imgRed;
+
+    readonly PhantasmPavilionType type = PhantasmPavilionType.Model;
+    int id;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        this.id = id;
+        btnChoose.SetListener(() =>
+        {
+            manager.selectId = id;
+        });
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isLimitedTime = manager.IsLimitTime(type, id);
+        bool isUsing = manager.IsUsing(type, id);
+        imgChoose.SetActive(manager.selectId == id);
+        imgLimit.SetActive(state == PhantasmPavilionState.Activated && isLimitedTime);
+        imgLock.SetActive(state != PhantasmPavilionState.Activated);
+        imgCanUnlock.SetActive(state == PhantasmPavilionState.CanActivate);
+        txtUsing.SetActive(state == PhantasmPavilionState.Activated && isUsing);
+
+        if (!ModelConfig.HasKey(id))
+            return;
+        ModelConfig model = ModelConfig.Get(id);
+        int skinID = model.SkinID;
+        if (!HeroSkinConfig.HasKey(skinID))
+            return;
+        HeroSkinConfig skinConfig = HeroSkinConfig.Get(skinID);
+        var sprite = UILoader.LoadSprite("HeroHead", skinConfig.SquareIcon);
+        if (sprite == null)
+        {
+            // 鍐呯綉鏈厤缃椂
+            imgFace.SetSprite("herohead_default");
+        }
+        else
+        {
+            imgFace.overrideSprite = sprite;
+        }
+
+        int resourceType = manager.GetResourceType(type, id);
+        string resourceValue = manager.GetResourceValue(type, id);
+
+        imgBg.SetSprite(model.FaceBg);
+
+        manager.UpdateItemRedPoint(imgRed, type, id);
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs.meta
index c7311ca..9290b09 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelItem.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: ee7ff516c103fef43abe59ed7ce5eeed
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs b/Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs
new file mode 100644
index 0000000..0b95a5a
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs
@@ -0,0 +1,309 @@
+锘縰sing System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionModelWin : UIBase
+{
+    [SerializeField] float modelSize;
+    [SerializeField] float lhSize;
+    [SerializeField] ButtonEx btnAllAdd;
+    [Header("浜岀骇鏍囩椤�")]
+    [SerializeField] GroupButtonEx btnTabType1;
+    [SerializeField] GroupButtonEx btnTabType2;
+
+    [Header("閫変腑椤瑰睍绀�")]
+    //褰撳墠姘旀场
+    [SerializeField] Transform lhframe;
+    [SerializeField] UIHeroController heroIh;
+    [SerializeField] UIHeroController heroModel;
+    [SerializeField] UIEffectPlayer heroAddStar;
+
+    [Header("灞炴�у睍绀�")]
+    [SerializeField] TextEx txtName;
+    [SerializeField] TextEx txtGetWayString;
+    [SerializeField] TextEx txtAddInfo;
+    [SerializeField] TextEx txtUnLockInfo;
+    [SerializeField] TextEx txtNoInfo;
+    [SerializeField] ScrollerController scrInfo;
+
+    [Header("婊氬姩鍒楄〃")]
+    [SerializeField] ScrollerController scrModel;
+
+    [Header("鎸夐挳")]
+    [SerializeField] PhantasmPavilionUnlockButton btnUnlock;
+    [SerializeField] PhantasmPavilionPutOnButton btnPutOn1;
+    [SerializeField] PhantasmPavilionPutOnButton btnPutOn2;
+    [SerializeField] PhantasmPavilionAddStarButton btnAddStar;
+    [SerializeField] TextEx txtRemainingTime1;
+    [SerializeField] TextEx txtRemainingTime2;
+
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnTabType1.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.Model, 0); });
+        btnTabType2.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.Model, 1); });
+        btnAllAdd.AddListener(() => { AttributeManager.Instance.OpenTotalAttributeWin(manager.GetTotalAttr()); });
+    }
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        scrInfo.OnRefreshCell += OnRefreshInfoCell;
+        scrModel.OnRefreshCell += OnRefreshModelCell;
+        manager.OnSelectItemIdChange += OnSelectItemIdChange;
+        PackManager.Instance.RefreshItemEvent += OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;
+        manager.OnUpdateModelInfoEvent += OnUpdateModelInfoEvent;
+        manager.OnTimeOut += OnTimeOut;
+        manager.OnUpdateModelStarAdd += OnUpdateModelStarAdd;
+        InitRedPoint();
+        TabSetActive();
+        SelectTiltleBtn();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        scrInfo.OnRefreshCell -= OnRefreshInfoCell;
+        scrModel.OnRefreshCell -= OnRefreshModelCell;
+        manager.OnSelectItemIdChange -= OnSelectItemIdChange;
+        PackManager.Instance.RefreshItemEvent -= OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;
+        manager.OnUpdateModelInfoEvent -= OnUpdateModelInfoEvent;
+        manager.OnTimeOut -= OnTimeOut;
+        manager.OnUpdateModelStarAdd -= OnUpdateModelStarAdd;
+    }
+
+    private void OnTimeOut()
+    {
+        RefreshAll(manager.nowType, functionOrder + 1);
+    }
+
+    private void OnUpdateModelInfoEvent()
+    {
+        RefreshAll(manager.nowType, functionOrder + 1);
+    }
+
+    private void OnUpdateModelStarAdd()
+    {
+        heroAddStar.Play();
+    }
+
+    void InitRedPoint()
+    {
+        btnTabType1.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.ModelNormal);
+        btnTabType2.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.ModelEvent);
+    }
+
+    void SelectTiltleBtn()
+    {
+        functionOrder = 0;
+        btnTabType1.SelectBtn();
+        SelectTeamFunc(PhantasmPavilionType.Model, 0);
+    }
+
+    void SelectTeamFunc(PhantasmPavilionType type, int order)
+    {
+        manager.SetSelectItemId(type, order + 1);
+        manager.nowType = type;
+        functionOrder = order;
+        CreateAll();
+    }
+
+    private void OnPlayerDataRefreshEvent(PlayerDataType type)
+    {
+        if (type != PlayerDataType.ModelMark)
+            return;
+        RefreshAll(manager.nowType, functionOrder + 1, false);
+    }
+
+    private void OnSecondEvent()
+    {
+        bool isLimitedTime = manager.IsLimitTime(manager.nowType, manager.selectId);
+        if (isLimitedTime)
+        {
+            UpdateTimer(manager.nowType, manager.selectId);
+        }
+    }
+
+    private void OnRefreshItemEvent(PackType type, int arg2, int arg3)
+    {
+        if (type != PackType.Item)
+            return;
+        DisplayButton(manager.nowType, manager.selectId);
+    }
+
+    private void OnSelectItemIdChange(int id)
+    {
+        RefreshAll(manager.nowType, functionOrder + 1, false);
+    }
+
+    private void RefreshAll(PhantasmPavilionType type, int tabType, bool isJump = true)
+    {
+        scrModel.m_Scorller.RefreshActiveCellViews();
+        if (isJump)
+        {
+            scrModel.JumpIndex(manager.GetJumpIndex(type, tabType));
+        }
+        CreateInfoScroller();
+        DisplayButton(type, manager.selectId);
+        DisplayInfo(type, manager.selectId);
+    }
+
+    void CreateAll()
+    {
+        CreateModelScroller();
+        CreateInfoScroller();
+        DisplayButton(manager.nowType, manager.selectId);
+        DisplayInfo(manager.nowType, manager.selectId);
+    }
+
+    private void OnRefreshInfoCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionInfoCell>();
+        _cell?.Display(cell.index, cell);
+    }
+
+    private void OnRefreshModelCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionModelCell>();
+        _cell?.Display(cell.index, cell);
+    }
+
+    public void DisplayInfo(PhantasmPavilionType type, int id)
+    {
+        if (!ModelConfig.HasKey(id))
+            return;
+        ModelConfig model = ModelConfig.Get(id);
+        int skinID = model.SkinID;
+        lhframe.transform.localScale = new Vector3(lhSize, lhSize, lhSize);
+        heroIh.Create(skinID, motionName: "", isLh: true);
+        heroModel.Create(skinID, modelSize);
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+        string name = manager.GetName(type, id);
+        if (isCanStarAdd && manager.TryGetInfo(type, id, out var info) &&
+        state == PhantasmPavilionState.Activated && info.Star > 0)
+        {
+            txtName.text = StringUtility.Contact(name, " ", Language.Get("L1113", info.Star));
+        }
+        else
+        {
+            txtName.text = name;
+        }
+
+        txtGetWayString.text = Language.Get("PhantasmPavilion06", manager.GetGetWayString(type, id));
+
+        bool isHasAttr = manager.HasInitAttr(type, id);        // 鏄惁鏈夎В閿佸睘鎬�
+        txtAddInfo.SetActive(state == PhantasmPavilionState.Activated);
+        txtUnLockInfo.SetActive(state != PhantasmPavilionState.Activated);
+        txtNoInfo.SetActive(!isHasAttr);
+        CreateInfoScroller();
+    }
+
+    public void DisplayButton(PhantasmPavilionType type, int id)
+    {
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+        bool isUsing = manager.IsUsing(type, id);
+        btnUnlock.SetActive(state != PhantasmPavilionState.Activated);
+        btnAddStar.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd);
+        btnPutOn1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd && !isUsing);
+        btnPutOn2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd && !isUsing);
+        btnUnlock.Display(id);
+        btnAddStar.Display(id);
+        btnPutOn1.Display(id);
+        btnPutOn2.Display(id);
+
+
+        UpdateTimer(type, id);
+    }
+
+
+
+    private void CreateInfoScroller()
+    {
+        PhantasmPavilionType type = manager.nowType;
+        int id = manager.selectId;
+        if (!manager.Has(type, id))
+            return;
+        scrInfo.Refresh();
+        int[] attrIDList = manager.GetAttrIDList(type, id);
+        int[] initAttrValueList = manager.GetInitAttrValueList(type, id);
+        if (!attrIDList.IsNullOrEmpty() && !initAttrValueList.IsNullOrEmpty() && attrIDList.Length == initAttrValueList.Length)
+        {
+            for (int i = 0; i < attrIDList.Length; i++)
+            {
+                CellInfo cellInfo = new CellInfo();
+                cellInfo.infoInt1 = id;
+                scrInfo.AddCell(ScrollerDataType.Header, i, cellInfo);
+            }
+        }
+        scrInfo.Restart();
+    }
+
+    public void TabSetActive()
+    {
+        var list = manager.ShowItemList(PhantasmPavilionType.Model, 1);
+        btnTabType1.SetActive(!list.IsNullOrEmpty());
+        list = manager.ShowItemList(PhantasmPavilionType.Model, 2);
+        btnTabType2.SetActive(!list.IsNullOrEmpty());
+    }
+
+    private void CreateModelScroller()
+    {
+        PhantasmPavilionType type = PhantasmPavilionType.Model;
+        scrModel.Refresh();
+        int tabType = functionOrder + 1;
+        List<int> showItemList = manager.ShowItemList(PhantasmPavilionType.Model, tabType);
+        if (!showItemList.IsNullOrEmpty() && manager.TryGetRowCountMax(type, out int rowCountMax))
+        {
+            int rowCount = (int)Math.Ceiling((double)showItemList.Count / rowCountMax);
+            for (int i = 0; i < rowCount; i++)
+            {
+                CellInfo cellInfo = new CellInfo();
+                cellInfo.infoInt1 = tabType;
+                scrModel.AddCell(ScrollerDataType.Header, i, cellInfo);
+            }
+        }
+        scrModel.Restart();
+
+        scrModel.JumpIndex(manager.GetJumpIndex(type, tabType));
+
+    }
+
+    public void UpdateTimer(PhantasmPavilionType type, int id)
+    {
+        bool isUnlock = manager.IsUnlock(type, id);
+        bool isLimitTime = manager.IsLimitTime(type, id);
+        if (!isUnlock || !isLimitTime || !manager.TryGetInfo(type, id, out var info) || info.EndTime <= 0)
+        {
+            txtRemainingTime1.SetActive(false);
+            txtRemainingTime2.SetActive(false);
+            return;
+        }
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+
+        DateTime endDateTime = TimeUtility.OriginalTime.AddSeconds(info.EndTime);
+        TimeSpan remainingTime = endDateTime - TimeUtility.ServerNow;
+        int remainingSeconds = (int)remainingTime.TotalSeconds;
+        txtRemainingTime1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd && remainingSeconds > 0);
+        txtRemainingTime2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd && remainingSeconds > 0);
+        if (remainingSeconds > 0)
+        {
+            string countdownText = TimeUtility.SecondsToShortDHMS(remainingSeconds);
+            txtRemainingTime1.text = Language.Get("PhantasmPavilion10", UIHelper.AppendColor(TextColType.LightGreen, countdownText));
+            txtRemainingTime2.text = Language.Get("PhantasmPavilion10", UIHelper.AppendColor(TextColType.LightGreen, countdownText));
+        }
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs.meta
index c7311ca..770a674 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionModelWin.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 5a0147739c582724c8db0dfee4029498
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs b/Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs
new file mode 100644
index 0000000..ea94402
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs
@@ -0,0 +1,39 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionPutOnButton : MonoBehaviour
+{
+    [SerializeField] ButtonEx btnPutOn;
+    [SerializeField] ImageEx imgPutOn;
+    [SerializeField] TextEx txtPutOn;
+    [SerializeField] Image imgRed;
+    PhantasmPavilionType type;
+    int id;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        type = manager.nowType;
+        this.id = id;
+        btnPutOn.SetListener(() =>
+        {
+            manager.SendOPPack(type, PhantasmPavilionOperation.Wear, (uint)id);
+        });
+        
+        bool isUsing = manager.IsUsing(type, id);
+        if (type == PhantasmPavilionType.Title)
+        {
+            txtPutOn.text = Language.Get("EquipExchangeWin9");
+            btnPutOn.interactable = true;
+            imgPutOn.gray = false;
+        }
+        else
+        {
+
+            txtPutOn.text = Language.Get(isUsing ? "PhantasmPavilion09" : "EquipExchangeWin9");
+            imgPutOn.gray = isUsing;
+            btnPutOn.interactable = !isUsing;
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs.meta
index c7311ca..fc085ce 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionPutOnButton.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 3aae4833e4cc05248ad37c215b956072
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionTabCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionTabCell.cs
deleted file mode 100644
index 1038192..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionTabCell.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-锘縰sing System;
-using UnityEngine;
-
-public class PhantasmPavilionTabCell : CellView
-{
-    [SerializeField] ButtonEx btnTab;
-    [SerializeField] TextEx txtTab;
-    [SerializeField] ImageEx imgChoose;
-    [SerializeField] RedpointBehaviour redpointBehaviour;
-    int iIndex;
-
-    public void Display(int index)
-    {
-        this.iIndex = index;
-        redpointBehaviour.redpointId = MainRedDot.PhantasmPavilionRepoint * 10 + index + 1;
-        txtTab.text = Language.Get(StringUtility.Contact("PhantasmPavilionTab", index));
-        imgChoose.SetActive(index == (int)PhantasmPavilionModel.Instance.selectTab);
-        btnTab.SetListener(OnTabClick);
-    }
-
-    private void OnTabClick()
-    {
-        if (!Enum.IsDefined(typeof(PhantasmPavilionTab), iIndex))
-            return;
-        PhantasmPavilionTab tab = (PhantasmPavilionTab)iIndex;
-        if (tab == PhantasmPavilionModel.Instance.selectTab)
-            return;
-        PhantasmPavilionModel.Instance.selectTab = tab;
-    }
-}
\ No newline at end of file
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionTabCell.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionTabCell.cs.meta
deleted file mode 100644
index 9526b6b..0000000
--- a/Main/System/PhantasmPavilion/PhantasmPavilionTabCell.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 399fb03614c78844794580ff4c8cb06f
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs b/Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs
new file mode 100644
index 0000000..6ddaeb1
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs
@@ -0,0 +1,299 @@
+锘縰sing System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionTitleWin : UIBase
+{
+    [SerializeField] ButtonEx btnAllAdd;
+    [Header("浜岀骇鏍囩椤�")]
+    [SerializeField] GroupButtonEx btnTabType1;
+    [SerializeField] GroupButtonEx btnTabType2;
+
+
+    [Header("閫変腑椤瑰睍绀�")]
+    //褰撳墠姘旀场
+    [SerializeField] ImageEx imgNowChatBox;
+    [SerializeField] UIFrame uiFrameNowChatBox;
+    [SerializeField] UIEffectPlayer UIEffectPlayerNowChatBox;
+
+
+    [Header("灞炴�у睍绀�")]
+    [SerializeField] TextEx txtName;
+    [SerializeField] TextEx txtGetWayString;
+    [SerializeField] TextEx txtAddInfo;
+    [SerializeField] TextEx txtUnLockInfo;
+    [SerializeField] TextEx txtNoInfo;
+    [SerializeField] ScrollerController scrInfo;
+
+    [Header("婊氬姩鍒楄〃")]
+    [SerializeField] ScrollerController scrTitle;
+
+    [Header("鎸夐挳")]
+    [SerializeField] PhantasmPavilionUnlockButton btnUnlock;
+    [SerializeField] PhantasmPavilionPutOnButton btnPutOn1;
+    [SerializeField] PhantasmPavilionPutOnButton btnPutOn2;
+    [SerializeField] PhantasmPavilionAddStarButton btnAddStar;
+    [SerializeField] ButtonEx btnTakeOff1;
+    [SerializeField] ButtonEx btnTakeOff2;
+    [SerializeField] TextEx txtRemainingTime1;
+    [SerializeField] TextEx txtRemainingTime2;
+
+    int nowTabType = 0; // 0-鐨囧 1-娲诲姩
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnTakeOff1.AddListener(() => { manager.SendOPPack(PhantasmPavilionType.Title, PhantasmPavilionOperation.Remove, (uint)manager.selectId); });
+        btnTakeOff2.AddListener(() => { manager.SendOPPack(PhantasmPavilionType.Title, PhantasmPavilionOperation.Remove, (uint)manager.selectId); });
+        btnTabType1.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.Title, 0); });
+        btnTabType2.AddListener(() => { SelectTeamFunc(PhantasmPavilionType.Title, 1); });
+        btnAllAdd.AddListener(() => { AttributeManager.Instance.OpenTotalAttributeWin(manager.GetTotalAttr()); });
+    }
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        scrInfo.OnRefreshCell += OnRefreshInfoCell;
+        scrTitle.OnRefreshCell += OnRefreshTitleCell;
+        manager.OnSelectItemIdChange += OnSelectItemIdChange;
+        PackManager.Instance.RefreshItemEvent += OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;
+        manager.OnUpdateTitleInfoEvent += OnUpdateTitleInfoEvent;
+        manager.OnTimeOut += OnTimeOut;
+        InitRedPoint();
+        TabSetActive();
+        SelectTiltleBtn();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        scrInfo.OnRefreshCell -= OnRefreshInfoCell;
+        scrTitle.OnRefreshCell -= OnRefreshTitleCell;
+        manager.OnSelectItemIdChange -= OnSelectItemIdChange;
+        PackManager.Instance.RefreshItemEvent -= OnRefreshItemEvent;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;
+        manager.OnUpdateTitleInfoEvent -= OnUpdateTitleInfoEvent;
+        manager.OnTimeOut -= OnTimeOut;
+    }
+
+    private void OnUpdateTitleInfoEvent()
+    {
+        RefreshAll(manager.nowType, functionOrder + 1);
+    }
+
+    private void OnTimeOut()
+    {
+        RefreshAll(manager.nowType, functionOrder + 1);
+    }
+
+    void InitRedPoint()
+    {
+        btnTabType1.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.TitlePalace);
+        btnTabType2.redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.TitleEvent);
+    }
+
+    void SelectTiltleBtn()
+    {
+        functionOrder = 0;
+        btnTabType1.SelectBtn();
+        SelectTeamFunc(PhantasmPavilionType.Title, 0);
+    }
+
+    void SelectTeamFunc(PhantasmPavilionType type, int order)
+    {
+        manager.SetSelectItemId(type, order + 1);
+        manager.nowType = type;
+        functionOrder = order;
+        CreateTitleScroller();
+        CreateAll();
+    }
+
+    private void OnPlayerDataRefreshEvent(PlayerDataType type)
+    {
+        if (type != PlayerDataType.ExAttr3)
+            return;
+        RefreshAll(manager.nowType, functionOrder + 1, false);
+    }
+
+    private void OnSecondEvent()
+    {
+        bool isLimitedTime = manager.IsLimitTime(manager.nowType, manager.selectId);
+        if (isLimitedTime)
+        {
+            UpdateTimer(manager.nowType, manager.selectId);
+        }
+    }
+
+    private void OnRefreshItemEvent(PackType type, int arg2, int arg3)
+    {
+        if (type != PackType.Item)
+            return;
+        DisplayButton(manager.nowType, manager.selectId);
+    }
+
+    private void OnSelectItemIdChange(int id)
+    {
+        RefreshAll(manager.nowType, functionOrder + 1, false);
+    }
+
+    private void RefreshAll(PhantasmPavilionType type, int tabType, bool isJump = true)
+    {
+        scrTitle.m_Scorller.RefreshActiveCellViews();
+        if (isJump)
+        {
+            scrTitle.JumpIndex(manager.GetJumpIndex(type, tabType));
+        }
+        CreateInfoScroller();
+        DisplayButton(type, manager.selectId);
+        DisplayInfo(type, manager.selectId);
+    }
+
+    void CreateAll()
+    {
+        CreateTitleScroller();
+        CreateInfoScroller();
+        DisplayButton(manager.nowType, manager.selectId);
+        DisplayInfo(manager.nowType, manager.selectId);
+    }
+    private void OnRefreshInfoCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionInfoCell>();
+        _cell?.Display(cell.index, cell);
+    }
+
+    private void OnRefreshTitleCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PhantasmPavilionTitleCell>();
+        _cell?.Display(cell.index, cell);
+    }
+
+    public void DisplayInfo(PhantasmPavilionType type, int id)
+    {
+        int resourceType = manager.GetResourceType(type, id);
+        string resourceValue = manager.GetResourceValue(type, id);
+        manager.Show(imgNowChatBox, UIEffectPlayerNowChatBox, uiFrameNowChatBox, resourceType, resourceValue);
+        if (resourceType == 1)
+        {
+            imgNowChatBox.SetNativeSize();
+        }
+        txtName.text = manager.GetName(type, id);
+        txtGetWayString.text = Language.Get("PhantasmPavilion06", manager.GetGetWayString(type, id));
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isHasAttr = manager.HasInitAttr(type, id);        // 鏄惁鏈夎В閿佸睘鎬�
+        txtAddInfo.SetActive(state == PhantasmPavilionState.Activated);
+        txtUnLockInfo.SetActive(state != PhantasmPavilionState.Activated);
+        txtNoInfo.SetActive(!isHasAttr);
+        CreateInfoScroller();
+    }
+
+    public void DisplayButton(PhantasmPavilionType type, int id)
+    {
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+        bool isUsing = manager.IsUsing(type, id);
+        btnUnlock.SetActive(state != PhantasmPavilionState.Activated);
+        btnAddStar.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd);
+        btnPutOn1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd && !isUsing);
+        btnPutOn2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd && !isUsing);
+        btnTakeOff1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd && isUsing);
+        btnTakeOff2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd && isUsing);
+
+        btnUnlock.Display(id);
+        btnAddStar.Display(id);
+        btnPutOn1.Display(id);
+        btnPutOn2.Display(id);
+
+        UpdateTimer(type, id);
+    }
+
+    void RefreshScroller(PhantasmPavilionType type)
+    {
+        scrTitle.m_Scorller.RefreshActiveCellViews();
+        CreateInfoScroller();
+    }
+
+
+    private void CreateInfoScroller()
+    {
+        PhantasmPavilionType type = manager.nowType;
+        int id = manager.selectId;
+        if (!manager.Has(type, id))
+            return;
+        scrInfo.Refresh();
+        int[] attrIDList = manager.GetAttrIDList(type, id);
+        int[] initAttrValueList = manager.GetInitAttrValueList(type, id);
+        if (!attrIDList.IsNullOrEmpty() && !initAttrValueList.IsNullOrEmpty() && attrIDList.Length == initAttrValueList.Length)
+        {
+            for (int i = 0; i < attrIDList.Length; i++)
+            {
+                CellInfo cellInfo = new CellInfo();
+                cellInfo.infoInt1 = id;
+                scrInfo.AddCell(ScrollerDataType.Header, i, cellInfo);
+            }
+        }
+        scrInfo.Restart();
+    }
+
+    public void TabSetActive()
+    {
+        var list = manager.ShowItemList(PhantasmPavilionType.Title, 1);
+        btnTabType1.SetActive(!list.IsNullOrEmpty());
+        list = manager.ShowItemList(PhantasmPavilionType.Title, 2);
+        btnTabType2.SetActive(!list.IsNullOrEmpty());
+    }
+
+    private void CreateTitleScroller()
+    {
+        PhantasmPavilionType type = PhantasmPavilionType.Title;
+        scrTitle.Refresh();
+        int tabType = functionOrder + 1;
+        List<int> showItemList = manager.ShowItemList(type, tabType);
+        if (!showItemList.IsNullOrEmpty() && manager.TryGetRowCountMax(type, out int rowCountMax))
+        {
+            int rowCount = (int)Math.Ceiling((double)showItemList.Count / rowCountMax);
+            for (int i = 0; i < rowCount; i++)
+            {
+                CellInfo cellInfo = new CellInfo();
+                cellInfo.infoInt1 = tabType;
+                scrTitle.AddCell(ScrollerDataType.Header, i, cellInfo);
+            }
+        }
+        scrTitle.Restart();
+
+        int jumpIndex = manager.GetJumpIndex(type, tabType);
+        scrTitle.JumpIndex(jumpIndex);
+    }
+
+    public void UpdateTimer(PhantasmPavilionType type, int id)
+    {
+        bool isUnlock = manager.IsUnlock(type, id);
+        bool isLimitTime = manager.IsLimitTime(type, id);
+        if (!isUnlock || !isLimitTime || !manager.TryGetInfo(type, id, out var info) || info.EndTime <= 0)
+        {
+            txtRemainingTime1.SetActive(false);
+            txtRemainingTime2.SetActive(false);
+            return;
+        }
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isCanStarAdd = manager.HasStarAddAttr(type, id);
+
+        DateTime endDateTime = TimeUtility.OriginalTime.AddSeconds(info.EndTime);
+        TimeSpan remainingTime = endDateTime - TimeUtility.ServerNow;
+        int remainingSeconds = (int)remainingTime.TotalSeconds;
+        txtRemainingTime1.SetActive(state == PhantasmPavilionState.Activated && !isCanStarAdd && remainingSeconds > 0);
+        txtRemainingTime2.SetActive(state == PhantasmPavilionState.Activated && isCanStarAdd && remainingSeconds > 0);
+        if (remainingSeconds > 0)
+        {
+            string countdownText = TimeUtility.SecondsToShortDHMS(remainingSeconds);
+            txtRemainingTime1.text = Language.Get("PhantasmPavilion10", UIHelper.AppendColor(TextColType.LightGreen, countdownText));
+            txtRemainingTime2.text = Language.Get("PhantasmPavilion10", UIHelper.AppendColor(TextColType.LightGreen, countdownText));
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs.meta
index c7311ca..68dacce 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTilteWin.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 8ece251320467ab4586b028a67812b60
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs b/Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs
new file mode 100644
index 0000000..497c261
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs
@@ -0,0 +1,33 @@
+锘縰sing System.Collections.Generic;
+using UnityEngine;
+
+public class PhantasmPavilionTitleCell : MonoBehaviour
+{
+    readonly PhantasmPavilionType type = PhantasmPavilionType.Title;
+    [SerializeField] List<PhantasmPavilionTitleItem> items = new List<PhantasmPavilionTitleItem>();
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int rowIndex,CellView cellView)
+    {
+        int tabType = cellView.info.Value.infoInt1;
+        List<int> showItemList = manager.ShowItemList(type, tabType); 
+        if (showItemList.IsNullOrEmpty() || !manager.TryGetRowCountMax(type, out int rowCountMax))
+            return;
+        for (int i = 0; i < items.Count; i++)
+        {
+            int index = rowIndex * rowCountMax + i;
+            if (!showItemList.IsNullOrEmpty())
+            {
+                if (index < showItemList.Count)
+                {
+                    items[i].SetActive(true);
+                    items[i].Display(showItemList[index]);
+                }
+                else
+                {
+                    items[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs.meta
index c7311ca..6f78d10 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTitleCell.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 649c6e14e2e5e644e9ccab0eb1ea76b2
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs b/Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs
new file mode 100644
index 0000000..3037f5f
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs
@@ -0,0 +1,68 @@
+using System.Collections.Generic;
+
+public class PhantasmPavilionTitleHandler : IPhantasmPavilionHandler
+{
+    public bool HasTableKey(int id)
+    {
+        return TitleConfig.HasKey(id);
+    }
+    public List<int> GetKeyList()
+    {
+        return TitleConfig.GetKeys();
+    }
+    public int GetResourceType(int id)
+    {
+        return TitleConfig.Get(id).ResourceType;
+    }
+    public string GetResourceValue(int id)
+    {
+        return TitleConfig.Get(id).ResourceValue;
+    }
+
+    public string GetName(int id)
+    {
+        return TitleConfig.Get(id).Name;
+    }
+    public int GetExpireMinutes(int id)
+    {
+        return TitleConfig.Get(id).ExpireMinutes;
+    }
+    public int GetUnlockWay(int id)
+    {
+        return TitleConfig.Get(id).UnlockWay;
+    }
+    public int GetUnlockValue(int id)
+    {
+        return TitleConfig.Get(id).UnlockValue;
+    }
+    public int GetUnlockNeedCnt(int id)
+    {
+        return TitleConfig.Get(id).UnlockNeedCnt;
+    }
+    public int GetUpNeedCnt(int id)
+    {
+        return TitleConfig.Get(id).UpNeedCnt;
+    }
+    public int GetStarMax(int id)
+    {
+        return TitleConfig.Get(id).StarMax;
+    }
+    public int[] GetAttrIDList(int id)
+    {
+        return TitleConfig.Get(id).AttrIDList;
+    }
+    public int[] GetInitAttrValueList(int id)
+    {
+        return TitleConfig.Get(id).InitAttrValueList;
+    }
+    public int[] GetAttrPerStarAddList(int id)
+    {
+        return TitleConfig.Get(id).AttrPerStarAddList;
+    }
+    public string GetGetWayString(int id)
+    {
+        return TitleConfig.Get(id).GetWayString;
+    }
+
+
+}
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionChatExpressionHandler.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs.meta
similarity index 100%
rename from Main/System/PhantasmPavilion/PhantasmPavilionChatExpressionHandler.cs.meta
rename to Main/System/PhantasmPavilion/PhantasmPavilionTitleHandler.cs.meta
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs b/Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs
new file mode 100644
index 0000000..828e572
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs
@@ -0,0 +1,52 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionTitleItem : MonoBehaviour
+{
+    [SerializeField] ImageEx imgBg;
+    [SerializeField] ImageEx imgFace;
+    [SerializeField] UIFrame uiFrame;
+    [SerializeField] UIEffectPlayer spine;
+    [SerializeField] Button btnChoose;
+
+    [SerializeField] ImageEx imgLimit;
+    [SerializeField] ImageEx imgLock;
+    [SerializeField] ImageEx imgChoose;
+    [SerializeField] ImageEx imgCanUnlock;
+    [SerializeField] Image imgUsing;
+    [SerializeField] Image imgRed;
+
+    readonly PhantasmPavilionType type = PhantasmPavilionType.Title;
+    int id;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        this.id = id;
+        btnChoose.SetListener(() =>
+        {
+            manager.selectId = id;
+        });
+
+        PhantasmPavilionState state = manager.GetUnLockState(type, id);
+        bool isLimitedTime = manager.IsLimitTime(type, id);
+
+        bool isUsing = manager.IsUsing(type, id); 
+        imgChoose.SetActive(manager.selectId == id);
+        imgBg.SetSprite(manager.selectId == id ? "ChatBoxSelect" : "ChatBoxUnSelect");
+        imgLimit.SetActive(state == PhantasmPavilionState.Activated && isLimitedTime);
+        imgLock.SetActive(state != PhantasmPavilionState.Activated);
+        imgCanUnlock.SetActive(state == PhantasmPavilionState.CanActivate);
+        imgUsing.SetActive(state == PhantasmPavilionState.Activated && isUsing);
+
+        int resourceType = manager.GetResourceType(type, id);
+        string resourceValue = manager.GetResourceValue(type, id);
+        manager.Show(imgFace, spine, uiFrame, resourceType, resourceValue);
+        if (resourceType == 1)
+        {
+            imgFace.SetNativeSize();
+        }
+
+        manager.UpdateItemRedPoint(imgRed, type, id);
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs.meta
index c7311ca..494c85c 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionTitleItem.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: e1a963588fc996342bc7cba8779c2b47
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs b/Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs
new file mode 100644
index 0000000..5b25466
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs
@@ -0,0 +1,67 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class PhantasmPavilionUnlockButton : MonoBehaviour
+{
+    [SerializeField] ButtonEx btnUnlock;
+    [SerializeField] ImageEx imgItem;
+    [SerializeField] TextEx txtCount;
+    [SerializeField] Image imgRed;
+    PhantasmPavilionType type;
+    int id;
+    int unlockWay;
+    int unlockValue;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    public void Display(int id)
+    {
+        type = manager.nowType;
+        this.id = id;
+        btnUnlock.SetListener(() =>
+        {
+            if (unlockWay == 2)
+            {
+                var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, unlockValue);
+                int useCnt = manager.GetUnlockNeedCnt(type, id);
+                if (useCnt > hasCnt)
+                {
+                    if (!ItemConfig.HasKey(unlockValue))
+                        return;
+                    string name = ItemConfig.Get(unlockValue).ItemName;
+                    SysNotifyMgr.Instance.ShowTip("UnLockFail2", name);
+                    return;
+                }
+            }
+            else if (unlockWay == 3)
+            {
+                bool hasHero = HeroManager.Instance.HasHero(unlockValue);
+                if (!hasHero)
+                {
+                    SysNotifyMgr.Instance.ShowTip("UnLockFail1");
+                    return;
+                }
+            }
+            manager.SendOPPack(type, PhantasmPavilionOperation.Activate, (uint)id);
+            SysNotifyMgr.Instance.ShowTip("UnLockSuccess");
+        });
+
+        unlockWay = manager.GetUnlockWay(type, id);
+        unlockValue = manager.GetUnlockValue(type, id);
+
+        txtCount.SetActive(unlockWay == 2);
+        imgRed.SetActive(false);
+        if (unlockWay == 2)
+        {
+
+            if (!ItemConfig.HasKey(unlockValue))
+                return;
+            ItemConfig itemConfig = ItemConfig.Get(unlockValue);
+            imgItem.SetSprite(itemConfig.IconKey);
+
+            var hasCnt = PackManager.Instance.GetItemCountByID(PackType.Item, unlockValue);
+            int useCnt = manager.GetUnlockNeedCnt(type, id);
+            txtCount.text = UIHelper.AppendColor(useCnt <= hasCnt ? TextColType.Green : TextColType.Red, Language.Get("BoneField09", hasCnt, useCnt));
+            imgRed.SetActive(useCnt <= hasCnt);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs.meta
index c7311ca..e6385ad 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: b97224cc7b76570489ab5cd011fddcc7
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PhantasmPavilion/PhantasmPavilionWin.cs b/Main/System/PhantasmPavilion/PhantasmPavilionWin.cs
new file mode 100644
index 0000000..5e6ad9e
--- /dev/null
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionWin.cs
@@ -0,0 +1,47 @@
+锘縰sing UnityEngine;
+
+public class PhantasmPavilionWin : FunctionsBaseWin
+{
+    [SerializeField] RedpointBehaviour[] rpTabArr;
+    [SerializeField] ImageEx imgModelBG;
+    PhantasmPavilionManager manager { get { return PhantasmPavilionManager.Instance; } }
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        InitRedPoint();
+        manager.UpdateRedPoint();
+    }
+
+    void InitRedPoint()
+    {
+        tabButtons[0].redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.Model);
+        tabButtons[1].redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.Face);
+        tabButtons[2].redpoint.redpointId = manager.GetRedpointId(PhantasmPavilionRepointType.Title);
+    }
+
+    protected override void OpenSubUIByTabIndex()
+    {
+        imgModelBG.SetActive(functionOrder == 0);
+        switch (functionOrder)
+        {
+            case 0:
+                //褰㈣薄
+                currentSubUI = UIManager.Instance.OpenWindow<PhantasmPavilionModelWin>();
+                manager.nowType = PhantasmPavilionType.Model;
+                break;
+            case 1:
+                //澶村儚
+                currentSubUI = UIManager.Instance.OpenWindow<PhantasmPavilionFaceWin>();
+                manager.nowType = PhantasmPavilionType.Face;
+                break;
+            case 2:
+                //绉板彿
+                currentSubUI = UIManager.Instance.OpenWindow<PhantasmPavilionTitleWin>();
+                manager.nowType = PhantasmPavilionType.Title;
+                break;
+            default:
+                Debug.LogWarning("鏈煡鐨勬爣绛剧储寮�: " + functionOrder);
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta b/Main/System/PhantasmPavilion/PhantasmPavilionWin.cs.meta
similarity index 83%
copy from Main/Config/Configs/PlayerFaceStarConfig.cs.meta
copy to Main/System/PhantasmPavilion/PhantasmPavilionWin.cs.meta
index c7311ca..aebf343 100644
--- a/Main/Config/Configs/PlayerFaceStarConfig.cs.meta
+++ b/Main/System/PhantasmPavilion/PhantasmPavilionWin.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: ccdffb3c82145e64cb12c26fccdfa818
+guid: 6278206cfd4de5e488b690982b22e8d1
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Main/System/PlayerProfile/PlayerProfileWin.cs b/Main/System/PlayerProfile/PlayerProfileWin.cs
index 98c6a8f..69b73c7 100644
--- a/Main/System/PlayerProfile/PlayerProfileWin.cs
+++ b/Main/System/PlayerProfile/PlayerProfileWin.cs
@@ -1,3 +1,4 @@
+using System;
 using UnityEngine;
 
 public class PlayerProfileWin : UIBase
@@ -45,6 +46,11 @@
             GameAgeWarnWin.data = 2;
             UIManager.Instance.OpenWindow<GameAgeWarnWin>();
         });
+        avatarCell.redpoint.redpointId = MainRedDot.PhantasmPavilionRepoint;
+        avatarCell.button.SetListener(() =>
+        {
+            UIManager.Instance.OpenWindow<PhantasmPavilionWin>();
+        });
     }
 
     protected override void OnPreOpen()
@@ -61,6 +67,7 @@
         RenameManager.Instance.OnUpdatePlayerNameCountEvent -= OnUpdatePlayerNameCount;
         RenameManager.Instance.OnUpdateRenameResultEvent -= OnUpdateRenameResultEvent;
     }
+
     private void OnUpdateRenameResultEvent()
     {
         Display();
diff --git a/Main/System/Redpoint/MainRedDot.cs b/Main/System/Redpoint/MainRedDot.cs
index de318a3..d9d482f 100644
--- a/Main/System/Redpoint/MainRedDot.cs
+++ b/Main/System/Redpoint/MainRedDot.cs
@@ -115,7 +115,7 @@
     public const int BlessedLandRedpoint = 444; //娣橀噾绾㈢偣
     public const int CustomizedGiftRedpoint = 448; //鑷�夌ぜ鍖�
     public const int LoginZhanLingRedpoint = 449; //鐧诲綍鎴樹护
-    public const int PhantasmPavilionRepoint = 459; //骞诲闃�
+
     public const int FairyEmbleManageRepoint = 462;//浠欑洘寰界珷绠$悊鍏ュ彛绾㈢偣
     public const int CycleHallRepoint = 463; //杞洖娈�
     public const int YunShiRepoint = 464; //杩愬娍
@@ -125,7 +125,8 @@
     public const int FirstChargeRepoint = 468; //棣栧厖
     public const int BoneFieldRepoint = 469; //鐧介鐩堥噹
     public const int ArenaRepoint = 470; //婕旀鍦�
-    public const int TianziBillboradRepoint= 471; //澶╁瓙鐨勮�冮獙
+    public const int TianziBillboradRepoint = 471; //澶╁瓙鐨勮�冮獙
+    public const int PhantasmPavilionRepoint = 472; //骞诲闃�
     public void Register()
     {
 
diff --git a/Main/Utility/EnumHelper.cs b/Main/Utility/EnumHelper.cs
index 9e47bf8..2843097 100644
--- a/Main/Utility/EnumHelper.cs
+++ b/Main/Utility/EnumHelper.cs
@@ -539,7 +539,7 @@
     LuckValue = 101,                     //骞歌繍鍊�   101
     ExAttr1 = 102,                       //鎵╁睍灞炴��1   102 涓荤嚎宸查�氬叧鍏冲崱
     ExAttr2 = 103,                       //鎵╁睍灞炴��2   103 涓荤嚎褰撳墠鍒锋�墍鍦ㄧ珷鑺傚叧鍗¤褰�
-    ExAttr3 = 104,                       //鎵╁睍灞炴��3   104鍏冪礌鏀诲嚮26
+    ExAttr3 = 104,                       //鎵╁睍灞炴��3   104 绉板彿
     ExAttr4 = 105,                       //鎵╁睍灞炴��4   105鍏冪礌闃插尽27
     ExAttr5 = 106,                       //鎵╁睍灞炴��5   106
     Faction = 107,                       //闃佃惀        107
@@ -553,8 +553,8 @@
     ExAttr7 = 115,                       //鎵╁睍灞炴��7   娉曞疂sp锛岄潪浜夸綅
     ExAttr8 = 116,                       //鎵╁睍灞炴��8   娉曞疂sp锛屼嚎浣�
     ExAttr9 = 117,                       //鎵╁睍灞炴��9   117鎺у埗鎶垫姉34
-    ExAttr10 = 118,                       //鎵╁睍灞炴��10  118杈撳嚭浼ゅ35
-    ModelMark = 119,                       //鍙樺舰妯″瀷Mark  119
+    ExAttr10 = 118,                       //鎵╁睍灞炴��10  姘旀场
+    ModelMark = 119,                       //鍙樺舰妯″瀷Mark  119 褰㈣薄
     PrizeCoin = 120,                       //濂栧姳鐐瑰埜鏁�   120
     ExAttr11 = 121,                       //鎵╁睍灞炴��11  121 鐜伴噾浠e竵锛堜唬閲戝埜锛�
     ExAttr12 = 122,                       //鎵╁睍灞炴��12 璁板綍绂诲紑淇℃伅锛屼富鍔ㄧ寮�娆℃暟*100 + 琚涪娆℃暟*10  + 鏈�鍚庝竴娆℃槸鍚︿富鍔ㄧ寮�鐨勶紝鏆傛椂鏈�澶氱疮璁¤褰曞埌9娆�

--
Gitblit v1.8.0